byollm 0.1.0-alpha.7 → 0.1.0-alpha.8

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  > [!WARNING]
2
- > **Alpha (`0.1.0-alpha.7`) — under active development. Don't use this yet.**
2
+ > **Alpha (`0.1.0-alpha.8`) — under active development. Don't use this yet.**
3
3
  >
4
4
  > Install it deliberately: `npx byollm@alpha`, or `npm install byollm@alpha`.
5
5
  >
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-3E2PGDHL.js";
4
+ } from "./chunk-NEV4JDQE.js";
5
5
 
6
6
  // src/bin.ts
7
7
  process.exitCode = await main(process.argv.slice(2));
@@ -3033,7 +3033,7 @@ async function main(argv) {
3033
3033
  }
3034
3034
 
3035
3035
  // src/index.ts
3036
- var DAEMON_VERSION = "0.1.0-alpha.7";
3036
+ var DAEMON_VERSION = "0.1.0-alpha.8";
3037
3037
  function daemonVersion() {
3038
3038
  return {
3039
3039
  daemon: DAEMON_VERSION,
@@ -3086,4 +3086,4 @@ export {
3086
3086
  runCli,
3087
3087
  main
3088
3088
  };
3089
- //# sourceMappingURL=chunk-3E2PGDHL.js.map
3089
+ //# sourceMappingURL=chunk-NEV4JDQE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/allowlist.ts","../src/cli.ts","../src/budgets.ts","../src/client.ts","../src/config.ts","../src/ssrf.ts","../src/connect.ts","../src/ingress.ts","../src/identity.ts","../src/pairings.ts","../src/spend.ts","../src/paths.ts","../src/runner.ts","../src/backends/index.ts","../src/backends/claude-cli.ts","../src/backends/openai-http.ts","../src/compose.ts"],"sourcesContent":["/**\n * `byollm` — what end users run.\n *\n * The CLI (`byollm connect`, `status`, `log`, `pause`, `allow`) is the\n * product surface; this module is the same machinery as a library, so the\n * conformance kit can drive a real daemon in-process instead of shelling out.\n *\n * @packageDocumentation\n */\n\nimport { PROTOCOL_VERSION } from \"@byollm/protocol\";\n\nexport { Allowlist, normalizeOrigin, type AllowEntry } from \"./allowlist.js\";\n\nexport { main, runCli, type CliIo, type ExitCode } from \"./cli.js\";\n\nexport {\n ClaudeCliBackend,\n IMPLEMENTED_BACKEND_IDS,\n OpenAiHttpBackend,\n childEnv,\n claudeArgv,\n createBackend,\n type Backend,\n type BackendErrorCode,\n type BackendHealth,\n type BackendInit,\n type BackendRequest,\n type BackendResult,\n} from \"./backends/index.js\";\n\nexport { Budgets, type BudgetDecision, type BudgetRefusal } from \"./budgets.js\";\n\nexport { DeviceIdentity } from \"./identity.js\";\n\nexport {\n ClientError,\n ProtocolClient,\n type ClientErrorKind,\n type ClientOptions,\n} from \"./client.js\";\n\nexport { composePrompt } from \"./compose.js\";\n\nexport {\n DEFAULT_CONFIG,\n DaemonConfig,\n loadConfig,\n resolveConfig,\n type BackendConfig,\n type CommunityBudget,\n type ConfigProblem,\n type IngressRetention,\n type LoadedConfig,\n type Limits,\n type ResolvedRoute,\n type RouteConfig,\n} from \"./config.js\";\n\nexport {\n connect,\n currentPlatform,\n type ConnectOptions,\n type ConnectResult,\n} from \"./connect.js\";\n\nexport {\n IngressLog,\n hashText,\n stripControlChars,\n type IngressEntry,\n type IngressOptions,\n type OutcomeEntry,\n type PromptEntry,\n} from \"./ingress.js\";\n\nexport { daemonPaths, defaultRoot, type DaemonPaths } from \"./paths.js\";\n\nexport { SpendLedger, estimateCents } from \"./spend.js\";\n\nexport { Pairings, type Pairing } from \"./pairings.js\";\n\nexport {\n Runner,\n type RunnerEvent,\n type RunnerOptions,\n type RunnerStatus,\n} from \"./runner.js\";\n\nexport {\n BASE_URL_REFUSAL_MESSAGES,\n checkBaseUrl,\n type BaseUrlCheck,\n type BaseUrlRefusal,\n} from \"./ssrf.js\";\n\n/**\n * This daemon's version, reported on pairing and on every heartbeat.\n *\n * Kept in step with `package.json` by a test rather than by a build-time\n * define: an app's runner list shows this string, so a stale one is a lie\n * told to every user, and a literal that a test pins cannot drift quietly.\n */\nexport const DAEMON_VERSION = \"0.1.0-alpha.7\";\n\n/**\n * Everything needed to reason about one daemon — byollm_010 §5.\n *\n * `--version` used to print a package version and nothing else, which is the\n * least useful version string a distributed daemon can have. \"It doesn't work\n * on Windows\" with no platform, no Node version and no protocol version is\n * the most expensive sentence an open-source project receives, and every\n * later capability — deprecation warnings, a minimum-supported-version\n * policy, \"your daemon is N releases behind\" — needs these facts to exist.\n *\n * The same tuple goes in the handshake (byollm_009 §4), deliberately: a\n * support conversation and a version policy should be arguing about the same\n * numbers.\n */\nexport interface DaemonVersion {\n readonly daemon: string;\n readonly protocol: string;\n readonly platform: NodeJS.Platform;\n readonly arch: string;\n readonly node: string;\n}\n\nexport function daemonVersion(): DaemonVersion {\n return {\n daemon: DAEMON_VERSION,\n protocol: PROTOCOL_VERSION,\n platform: process.platform,\n arch: process.arch,\n node: process.versions.node,\n };\n}\n\n/** One line, for `--version` and for pasting into an issue. */\nexport function formatVersion(v: DaemonVersion = daemonVersion()): string {\n return (\n `byollm ${v.daemon} (protocol ${v.protocol})\\n` +\n `${v.platform}-${v.arch}, node ${v.node}\\n`\n );\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { z } from \"zod\";\n\n/**\n * One person, on one server, allowed to run work on this machine.\n *\n * Keyed by **(server origin, user id)** because owner ids are\n * server-namespace-local: `alice` on one app is not `alice` on another, and a\n * list keyed by id alone would silently merge strangers.\n */\nexport const AllowEntry = z\n .object({\n /** Origin of the server that issued the id, e.g. `https://app.example.com`. */\n origin: z.string().min(1),\n /** The app's id for the user. */\n owner: z.string().min(1),\n /** Optional human label, so the list is readable a month later. */\n note: z.string().optional(),\n addedAt: z.number().int().positive(),\n })\n .strict();\nexport type AllowEntry = z.infer<typeof AllowEntry>;\n\nconst AllowFile = z\n .object({\n version: z.literal(1),\n entries: z.array(AllowEntry),\n })\n .strict();\n\n/**\n * The daemon's local `named` allowlist.\n *\n * byollm_001 Rev 1 §B: a `named` job is admitted only when *this* list names\n * its owner. A server's assertion that a runner is allowed is never enough —\n * honouring it would mean obeying the server rather than enforcing against\n * it. One file, every paired app, so the owner has one place to see everyone\n * who can use their machine.\n *\n * The list is **empty by default**, which is what makes a fresh daemon\n * effectively self-only until the owner deliberately widens it.\n */\nexport class Allowlist {\n readonly #path: string;\n #entries: AllowEntry[] = [];\n #loaded = false;\n\n constructor(path: string) {\n this.#path = path;\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.#path, \"utf8\");\n const parsed = AllowFile.safeParse(JSON.parse(raw));\n // A corrupt allowlist reads as empty rather than throwing: failing\n // closed here means refusing community work, which is the safe\n // direction, and the owner sees an empty `byollm allow --list`.\n this.#entries = parsed.success ? parsed.data.entries : [];\n } catch {\n this.#entries = [];\n }\n this.#loaded = true;\n }\n\n #assertLoaded(): void {\n if (!this.#loaded) {\n throw new Error(\"allowlist used before load()\");\n }\n }\n\n /** Does this list admit `owner` on `origin`? */\n admits(origin: string, owner: string): boolean {\n this.#assertLoaded();\n const normalized = normalizeOrigin(origin);\n return this.#entries.some(\n (entry) =>\n normalizeOrigin(entry.origin) === normalized && entry.owner === owner,\n );\n }\n\n /** A predicate bound to one origin, for {@link matchAudience}. */\n predicateFor(origin: string): (owner: string) => boolean {\n return (owner) => this.admits(origin, owner);\n }\n\n list(): readonly AllowEntry[] {\n this.#assertLoaded();\n return [...this.#entries];\n }\n\n async add(entry: Omit<AllowEntry, \"addedAt\">, now: number): Promise<void> {\n this.#assertLoaded();\n const normalized = normalizeOrigin(entry.origin);\n if (this.admits(normalized, entry.owner)) return;\n this.#entries.push(\n AllowEntry.parse({ ...entry, origin: normalized, addedAt: now }),\n );\n await this.#save();\n }\n\n /** Remove an entry. Returns whether anything was removed. */\n async remove(origin: string, owner: string): Promise<boolean> {\n this.#assertLoaded();\n const normalized = normalizeOrigin(origin);\n const before = this.#entries.length;\n this.#entries = this.#entries.filter(\n (entry) =>\n !(\n normalizeOrigin(entry.origin) === normalized && entry.owner === owner\n ),\n );\n if (this.#entries.length === before) return false;\n await this.#save();\n return true;\n }\n\n async #save(): Promise<void> {\n await mkdir(dirname(this.#path), { recursive: true });\n await writeFile(\n this.#path,\n `${JSON.stringify({ version: 1, entries: this.#entries }, null, 2)}\\n`,\n { mode: 0o600 },\n );\n }\n}\n\n/**\n * Compare origins by scheme, host and port only.\n *\n * `https://app.test/` and `https://app.test` must be the same entry — a\n * trailing slash is not a different server, and treating it as one would let\n * an allowlist silently fail to match.\n */\nexport function normalizeOrigin(input: string): string {\n try {\n return new URL(input).origin;\n } catch {\n return input.replace(/\\/+$/, \"\");\n }\n}\n","import { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { hostname, userInfo } from \"node:os\";\nimport { dirname } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport { backendDescriptor, resolveCost } from \"@byollm/protocol\";\nimport { Allowlist, normalizeOrigin } from \"./allowlist.js\";\nimport { Budgets } from \"./budgets.js\";\nimport { ClientError, ProtocolClient } from \"./client.js\";\nimport { DaemonConfig, loadConfig } from \"./config.js\";\nimport { connect } from \"./connect.js\";\nimport { IngressLog, stripControlChars } from \"./ingress.js\";\nimport { fingerprint } from \"@byollm/protocol\";\nimport { DeviceIdentity } from \"./identity.js\";\nimport { Pairings } from \"./pairings.js\";\nimport { SpendLedger } from \"./spend.js\";\nimport { daemonPaths, type DaemonPaths } from \"./paths.js\";\nimport { Runner, type RunnerEvent } from \"./runner.js\";\nimport { DAEMON_VERSION, formatVersion } from \"./index.js\";\n\nconst USAGE = `byollm — run an app's LLM jobs on your own models.\n\n byollm connect <url> pair with an app and start running its jobs\n byollm run [url] run jobs for a paired app (or all of them)\n byollm status what is connected, what is running, what it cost\n byollm log [--full] [-n N] every prompt that has run on this machine\n byollm pause stop claiming new work\n byollm resume start claiming again\n byollm allow <url> <user> let someone else's jobs run here (named audience)\n byollm allow --list who can currently use this machine\n byollm offer <backend> <scope> who a backend is offered to (self|named|public)\n byollm disallow <url> <user>\n byollm forget <url> drop a pairing\n byollm backends what is installed, healthy, and advertised\n\nConfig lives in ~/.byollm/config.json. Everything this daemon has ever run is\nin ~/.byollm/ingress.log — it is yours to read and yours to delete.\n`;\n\n/** Exit codes: 0 fine, 1 a real failure, 2 the user asked for something wrong. */\nexport type ExitCode = 0 | 1 | 2;\n\n/**\n * Everything the CLI touches outside itself.\n *\n * byollm_002 calls the meter the product's soul, which means it has to be\n * testable rather than merely observable by a human at a terminal. Injecting\n * the streams, the state directory and the confirmation prompt lets the tests\n * drive the real commands against a temporary `BYOLLM_HOME`.\n */\nexport interface CliIo {\n readonly out: (text: string) => void;\n readonly err: (text: string) => void;\n /** Answers the scarier-confirmation prompt when widening access. */\n readonly confirm: (question: string) => Promise<boolean>;\n}\n\nconst defaultIo: CliIo = {\n out: (text) => process.stdout.write(text),\n err: (text) => process.stderr.write(text),\n confirm: confirmInteractively,\n};\n\n/** Run one command. Exported so the tests drive the same code a user does. */\nexport async function runCli(\n argv: readonly string[],\n options: {\n paths?: DaemonPaths;\n io?: Partial<CliIo>;\n /**\n * Stops the polling loop. The executable wires this to SIGINT/SIGTERM;\n * anything embedding the CLI (including its tests) can stop it the same\n * way rather than by killing the process.\n */\n signal?: AbortSignal;\n } = {},\n): Promise<ExitCode> {\n const [command, ...rest] = argv;\n const paths = options.paths ?? daemonPaths();\n const io: CliIo = { ...defaultIo, ...options.io };\n const signal = options.signal;\n\n switch (command) {\n case undefined:\n case \"help\":\n case \"--help\":\n case \"-h\":\n io.out(USAGE);\n return 0;\n case \"--version\":\n case \"version\":\n // The full tuple, not a bare version. byollm_010 §5: an issue that\n // arrives without a platform costs a round trip to learn one.\n io.out(formatVersion());\n return 0;\n case \"connect\":\n return commandConnect(paths, rest, io, signal);\n case \"run\":\n return commandRun(paths, rest, io, signal);\n case \"status\":\n return commandStatus(paths, io);\n case \"log\":\n return commandLog(paths, rest, io);\n case \"pause\":\n return commandPause(paths, true, io);\n case \"resume\":\n return commandPause(paths, false, io);\n case \"allow\":\n return commandAllow(paths, rest, io);\n case \"disallow\":\n return commandDisallow(paths, rest, io);\n case \"offer\":\n return commandOffer(paths, rest, io);\n case \"forget\":\n return commandForget(paths, rest, io);\n case \"backends\":\n return commandBackends(paths, io);\n default:\n io.err(`unknown command: ${command}\\n\\n${USAGE}`);\n return 2;\n }\n}\n\n// -- connect -----------------------------------------------------------------\n\nasync function commandConnect(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n signal?: AbortSignal,\n): Promise<ExitCode> {\n const target = args[0];\n if (target === undefined) {\n io.err(\"usage: byollm connect <url>\\n\");\n return 2;\n }\n\n const origin = normalizeOrigin(target);\n const { loaded, ingress, allowlist, budgets, spend } = await context(paths);\n\n for (const problem of loaded.problems) {\n io.err(`config: ${problem.where}: ${problem.message}\\n`);\n }\n\n const client = new ProtocolClient({ origin });\n const runner = new Runner({\n client,\n runnerId: \"pending\",\n owner: \"pending\",\n daemonVersion: DAEMON_VERSION,\n loaded,\n allowlist,\n budgets,\n spend,\n ingress,\n });\n\n const capabilities = await runner.detectCapabilities();\n if (capabilities.length === 0) {\n // Pairing while advertising nothing would produce a runner that silently\n // never receives work — a failure the user could not diagnose.\n io.err(\n \"No backend is reachable, so there is nothing to offer this app yet.\\n\" +\n \"Run `byollm backends` to see what is configured and what is wrong.\\n\",\n );\n return 1;\n }\n\n io.out(`\\nConnecting to ${origin}\\n`);\n\n const result = await connect({\n client,\n daemonVersion: DAEMON_VERSION,\n label: hostLabel(),\n capabilities,\n device: await new DeviceIdentity(paths.keys).publicIdentity(Date.now()),\n onCode: (info) => {\n const minutes = Math.max(\n 1,\n Math.round((info.expiresAt - Date.now()) / 60_000),\n );\n io.out(\n `\\n Open: ${info.verificationUrl}\\n` +\n ` Code: ${info.userCode} (expires in ${String(minutes)}m)\\n\\n` +\n ` waiting for approval…`,\n );\n },\n onPoll: () => {\n io.out(\".\");\n },\n ...(signal === undefined ? {} : { signal }),\n });\n\n if (!result.ok) {\n io.out(`\\n\\n ${result.message}\\n`);\n return 1;\n }\n\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n await pairings.put(result.pairing);\n\n io.out(\n ` paired as ${result.pairing.ownerLabel ?? result.pairing.owner}\\n\\n` +\n `Now running jobs for ${origin}. Ctrl-C to stop.\\n\\n`,\n );\n\n return runLoop(paths, [result.pairing.origin], io, signal);\n}\n\n// -- run ---------------------------------------------------------------------\n\nasync function commandRun(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n signal?: AbortSignal,\n): Promise<ExitCode> {\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n\n const target = args[0];\n const origins =\n target === undefined\n ? pairings.list().map((pairing) => pairing.origin)\n : [normalizeOrigin(target)];\n\n if (origins.length === 0) {\n io.err(\"No apps are paired yet. Run `byollm connect <url>` first.\\n\");\n return 2;\n }\n return runLoop(paths, origins, io, signal);\n}\n\nasync function runLoop(\n paths: DaemonPaths,\n origins: readonly string[],\n io: CliIo,\n signal?: AbortSignal,\n): Promise<ExitCode> {\n const { loaded, ingress, allowlist, budgets, spend } = await context(paths);\n const identity = new DeviceIdentity(paths.keys);\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n\n const controller = new AbortController();\n signal?.addEventListener(\n \"abort\",\n () => {\n controller.abort();\n },\n { once: true },\n );\n const runners: Runner[] = [];\n\n for (const origin of origins) {\n const pairing = pairings.get(origin);\n if (!pairing) {\n io.err(`not paired with ${origin}\\n`);\n continue;\n }\n const runner = new Runner({\n client: new ProtocolClient({\n origin,\n identity: {\n runnerId: pairing.runnerId,\n sign: (input) => identity.signRequest(input),\n },\n }),\n runnerId: pairing.runnerId,\n owner: pairing.owner,\n identity: {\n keys: () => identity.load(Date.now()),\n sitePinned: pairing.site,\n },\n daemonVersion: DAEMON_VERSION,\n loaded,\n allowlist,\n budgets,\n spend,\n ingress,\n onEvent: (event) => {\n report(origin, event, io);\n },\n });\n runners.push(runner);\n }\n\n if (runners.length === 0) return 2;\n\n // Leases are released on the way out, so the app sees work return to the\n // queue at once instead of waiting for a lease to lapse.\n // Only take over the process's signals when nobody handed us one of their\n // own — an embedder (or a test) that passed a signal owns its own lifecycle.\n if (signal === undefined) {\n const stop = (): void => {\n controller.abort();\n // Ctrl-C must end in an exit, whatever the release path does. Without a\n // rejection handler a failing `shutdown` left `process.exit` unreached\n // and killed the daemon on an unhandled rejection instead — the same\n // exit, with a stack trace and a misleading code.\n Promise.all(runners.map((runner) => runner.shutdown(\"shutdown\"))).then(\n () => {\n process.exit(0);\n },\n (error: unknown) => {\n // Leases will lapse on their own; say what happened and leave a\n // non-zero code so a supervisor can tell this apart from a clean\n // stop.\n io.err(`shutdown did not complete cleanly: ${String(error)}\\n`);\n process.exit(1);\n },\n );\n };\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n }\n\n await ingress.applyRetention(Date.now());\n await Promise.all(runners.map((runner) => runner.run(controller.signal)));\n await Promise.all(runners.map((runner) => runner.shutdown(\"shutdown\")));\n return 0;\n}\n\n/**\n * One line per event.\n *\n * Every interpolated string that could contain remote text goes through\n * {@link stripControlChars} first: a refusal reason or an error message may\n * quote a payload, and text that can repaint a terminal can forge output\n * (byollm_004 §5's ANSI/log-injection row).\n */\nfunction report(origin: string, event: RunnerEvent, io: CliIo): void {\n const at = new Date().toISOString().slice(11, 19);\n const host = new URL(origin).host;\n\n switch (event.type) {\n case \"claimed\":\n io.out(`${at} ${host} claimed ${event.kind} ${event.jobId}\\n`);\n break;\n case \"finished\":\n io.out(\n `${at} ${host} ${event.outcome} ${event.jobId} ` +\n `(${String(event.durationMs)}ms)\\n`,\n );\n break;\n case \"refused\":\n io.out(\n `${at} ${host} refused ${event.jobId}: ` +\n `${stripControlChars(event.reason)}\\n`,\n );\n break;\n case \"revoked\":\n io.out(`${at} ${host} this runner was revoked. Stopping.\\n`);\n break;\n case \"error\":\n io.err(`${at} ${host} ${stripControlChars(event.message)}\\n`);\n break;\n case \"heartbeat\":\n break;\n }\n}\n\n// -- status ------------------------------------------------------------------\n\nasync function commandStatus(paths: DaemonPaths, io: CliIo): Promise<ExitCode> {\n const { loaded, ingress, allowlist, budgets, spend } = await context(paths);\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n\n const paused = await isPaused(paths);\n const now = Date.now();\n\n io.out(formatVersion());\n // This machine's fingerprint, so an owner can compare it against what a\n // site shows them (byollm_009 §3). A fingerprint nobody can find is a\n // fingerprint nobody compares.\n io.out(\n `identity: ${await new DeviceIdentity(paths.keys).fingerprint(now)}\\n`,\n );\n io.out(`state: ${paused ? \"PAUSED\" : \"running\"}\\n\\n`);\n\n io.out(\"paired apps\\n\");\n const list = pairings.list();\n if (list.length === 0) {\n io.out(\" (none — run `byollm connect <url>`)\\n\");\n }\n for (const pairing of list) {\n io.out(` ${pairing.origin} as ${pairing.ownerLabel ?? pairing.owner}\\n`);\n // The pinned key, so an owner can check it against what the app shows.\n // A pin nobody can see is a pin nobody can verify.\n io.out(` pinned: ${fingerprint(pairing.site.identity)}\\n`);\n }\n\n io.out(\"\\nroutes\\n\");\n if (loaded.routes.length === 0) {\n io.out(\" (none configured)\\n\");\n }\n for (const route of loaded.routes) {\n io.out(\n ` ${route.kind.padEnd(14)} ${route.backendId}:${route.model} ` +\n `offered to: ${route.offerScope}\\n`,\n );\n }\n for (const problem of loaded.problems) {\n io.out(` ! ${problem.where}: ${problem.message}\\n`);\n }\n\n const allowed = allowlist.list();\n io.out(\"\\nwho can use this machine\\n\");\n io.out(` you, always\\n`);\n if (allowed.length === 0) {\n io.out(\" nobody else\\n\");\n }\n for (const entry of allowed) {\n io.out(\n ` ${entry.owner} on ${entry.origin}` +\n `${entry.note === undefined ? \"\" : ` (${stripControlChars(entry.note)})`}\\n`,\n );\n }\n\n const spentToday = spend.summary(now);\n const metered = loaded.routes.filter((r) => r.cost === \"metered\");\n if (metered.length > 0) {\n io.out(\"\\nmetered backends — your money\\n\");\n for (const route of metered) {\n const spent = spentToday[route.backendKey] ?? 0;\n io.out(\n route.spendAcknowledged\n ? ` ${route.backendKey}: ${spent.toFixed(1)}c spent today of ` +\n `${String(route.spendDailyCapCents ?? 0)}c\\n`\n : ` ${route.backendKey}: not shared — your work only\\n`,\n );\n }\n }\n\n const usage = budgets.usage(now);\n io.out(\"\\ncommunity work done for others\\n\");\n io.out(\n ` ${String(usage.hour)} in the last hour (cap ${String(usage.limits.maxJobsPerHour)}), ` +\n `${String(usage.day)} today (cap ${String(usage.limits.maxJobsPerDay)})\\n`,\n );\n\n const entries = await ingress.read();\n const prompts = entries.filter((entry) => entry.type === \"prompt\");\n const outcomes = entries.filter((entry) => entry.type === \"outcome\");\n io.out(\"\\nthis machine has run\\n\");\n io.out(\n ` ${String(prompts.length)} prompts, ` +\n `${String(outcomes.filter((o) => o.outcome === \"ok\").length)} ok, ` +\n `${String(outcomes.filter((o) => o.outcome === \"error\").length)} failed, ` +\n `${String(outcomes.filter((o) => o.outcome === \"refused\").length)} refused\\n`,\n );\n io.out(\n ` full log: ${paths.ingressLog} (community prompts kept ` +\n `${String(loaded.config.ingress.communityPromptDays)} days, then hashed)\\n`,\n );\n return 0;\n}\n\n// -- log ---------------------------------------------------------------------\n\nasync function commandLog(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const full = args.includes(\"--full\");\n const nIndex = args.findIndex((arg) => arg === \"-n\" || arg === \"--lines\");\n const limit =\n nIndex === -1 ? 20 : Math.max(1, Number(args[nIndex + 1] ?? \"20\") || 20);\n\n const { ingress } = await context(paths);\n const entries = await ingress.read();\n const shown = entries.slice(-limit);\n\n if (shown.length === 0) {\n io.out(\"nothing has run on this machine yet\\n\");\n return 0;\n }\n\n for (const entry of shown) {\n const at = new Date(entry.at).toISOString().replace(\"T\", \" \").slice(0, 19);\n if (entry.type === \"outcome\") {\n io.out(\n `${at} ${entry.outcome.padEnd(8)} ${entry.jobId}` +\n (entry.durationMs === undefined\n ? \"\"\n : ` ${String(entry.durationMs)}ms`) +\n `${entry.detail === undefined ? \"\" : ` ${stripControlChars(entry.detail)}`}\\n`,\n );\n continue;\n }\n\n io.out(\n `${at} ${entry.audience.padEnd(7)} ${entry.kind} ` +\n `via ${entry.backendId}:${entry.model} for ${entry.owner} ` +\n `@ ${new URL(entry.origin).host}\\n`,\n );\n if (entry.prompt === undefined) {\n // Retention removed the text. Say so — a blank line here would read as\n // \"empty prompt\", and zero must never look like unknown.\n io.out(\n ` prompt not retained (${String(entry.promptChars)} chars, ` +\n `sha256 ${entry.promptHash.slice(0, 16)}…)\\n`,\n );\n } else if (full) {\n io.out(`${indent(stripControlChars(entry.prompt))}\\n`);\n } else {\n const firstLine = entry.prompt.split(\"\\n\")[0] ?? \"\";\n io.out(\n ` ${stripControlChars(firstLine.slice(0, 90))}` +\n `${entry.prompt.length > 90 ? \"…\" : \"\"}\\n`,\n );\n }\n }\n if (!full) {\n io.out(`\\n(${String(entries.length)} entries; --full for whole prompts)\\n`);\n }\n return 0;\n}\n\nfunction indent(text: string): string {\n return text\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n}\n\n// -- pause / resume -----------------------------------------------------------\n\nasync function commandPause(\n paths: DaemonPaths,\n pause: boolean,\n io: CliIo,\n): Promise<ExitCode> {\n await mkdir(paths.root, { recursive: true });\n if (pause) {\n await writeFile(paths.pauseFlag, `${new Date().toISOString()}\\n`);\n io.out(\n \"paused — no new work will be claimed. `byollm resume` to start again.\\n\",\n );\n } else {\n await rm(paths.pauseFlag, { force: true });\n io.out(\"resumed\\n\");\n }\n return 0;\n}\n\nasync function isPaused(paths: DaemonPaths): Promise<boolean> {\n try {\n await stat(paths.pauseFlag);\n return true;\n } catch {\n return false;\n }\n}\n\n// -- allow / disallow ---------------------------------------------------------\n\nasync function commandAllow(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const allowlist = new Allowlist(paths.allowlist);\n await allowlist.load();\n\n if (args[0] === \"--list\" || args.length === 0) {\n const entries = allowlist.list();\n if (entries.length === 0) {\n io.out(\n \"Nobody but you can run work on this machine.\\n\" +\n \"`byollm allow <app-url> <user-id>` to change that.\\n\",\n );\n return 0;\n }\n for (const entry of entries) {\n io.out(\n `${entry.owner} on ${entry.origin}` +\n `${entry.note === undefined ? \"\" : ` (${stripControlChars(entry.note)})`}\\n`,\n );\n }\n return 0;\n }\n\n const [rawOrigin, owner, ...noteParts] = args;\n if (rawOrigin === undefined || owner === undefined) {\n io.err(\"usage: byollm allow <app-url> <user-id> [note]\\n\");\n return 2;\n }\n const origin = normalizeOrigin(rawOrigin);\n\n // byollm_002: widening scope requires an explicit confirmation that names\n // what it means. Not a y/N on an ambiguous question — the actual sentence.\n const confirmed = await io.confirm(\n `\\nThis lets jobs belonging to \"${owner}\" on ${origin} run on this machine,\\n` +\n `using your hardware and electricity, whenever your daemon is online.\\n` +\n `Your subscription-backed models are never included — those stay yours alone.\\n\\n` +\n `Allow ${owner} to use this machine?`,\n );\n if (!confirmed) {\n io.out(\"nothing changed\\n\");\n return 0;\n }\n\n await allowlist.add(\n {\n origin,\n owner,\n ...(noteParts.length > 0 ? { note: noteParts.join(\" \") } : {}),\n },\n Date.now(),\n );\n io.out(`allowed ${owner} on ${origin}\\n`);\n return 0;\n}\n\n// -- offer -------------------------------------------------------------------\n\n/**\n * Change who a backend is offered to.\n *\n * This exists because `resolveConfig` tells an owner to run it. A message that\n * names a command nobody wrote is worse than no message: it reads as though\n * the software has an answer when it does not.\n *\n * Widening a metered backend is the one path here that can cost real money, so\n * it is the one path that asks — and the question names the money rather than\n * asking whether the owner is \"sure\"\n * ({@link MUSTS.METERED_DEFAULTS_SELF}, {@link MUSTS.METERED_REQUIRES_CEILING}).\n */\nasync function commandOffer(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const [backendKey, scope, ...rest] = args;\n if (backendKey === undefined || scope === undefined) {\n io.err(\n \"usage: byollm offer <backend> <self|named|public> [--cap <cents>]\\n\",\n );\n return 2;\n }\n if (scope !== \"self\" && scope !== \"named\" && scope !== \"public\") {\n io.err(`\"${scope}\" is not an offer scope — use self, named, or public\\n`);\n return 2;\n }\n\n const capIndex = rest.indexOf(\"--cap\");\n let capCents: number | undefined;\n if (capIndex !== -1) {\n const raw = rest[capIndex + 1];\n const parsed = Number(raw);\n if (raw === undefined || !Number.isFinite(parsed) || parsed <= 0) {\n io.err(\"--cap takes a number of cents per day, greater than zero\\n\");\n return 2;\n }\n capCents = Math.round(parsed);\n }\n\n let raw: string;\n try {\n raw = await readFile(paths.config, \"utf8\");\n } catch {\n io.err(\n `no config at ${paths.config} — nothing to offer yet.\\n` +\n \"Write one, or run `byollm connect <url>` first.\\n\",\n );\n return 1;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n io.err(`${paths.config} is not valid JSON — fix it by hand first\\n`);\n return 1;\n }\n const result = DaemonConfig.safeParse(parsed);\n if (!result.success) {\n io.err(`${paths.config} is not a valid byollm config — fix it first\\n`);\n return 1;\n }\n\n const backend = result.data.backends[backendKey];\n if (!backend) {\n const known = Object.keys(result.data.backends);\n io.err(\n `no backend named \"${backendKey}\" in ${paths.config}\\n` +\n (known.length > 0 ? `configured: ${known.join(\", \")}\\n` : \"\"),\n );\n return 2;\n }\n\n const descriptor = backendDescriptor(backend.backend);\n const baseUrl = backend.baseUrl ?? descriptor.defaultBaseUrl;\n const cost = resolveCost(backend.backend, baseUrl);\n const widening = scope !== \"self\";\n\n // A subscription backend cannot be offered at all, so say that instead of\n // writing a setting that would be silently ignored on the next load.\n if (cost === \"subscription\" && widening) {\n io.err(\n `${descriptor.label} runs on your own subscription, whose terms cover\\n` +\n \"your work and nobody else's. It cannot be offered to other people.\\n\",\n );\n return 1;\n }\n\n if (cost === \"metered\" && widening) {\n const cap = capCents ?? backend.spend?.dailyCapCents;\n if (cap === undefined) {\n io.err(\n `${descriptor.label} bills you per token, so sharing it needs a daily\\n` +\n \"ceiling. Add one: `byollm offer \" +\n `${backendKey} ${scope} --cap <cents>\\`\\n`,\n );\n return 2;\n }\n\n const dollars = (cap / 100).toFixed(2);\n const confirmed = await io.confirm(\n `\\nThis lets other people's jobs run on ${descriptor.label}, which bills\\n` +\n `your account per token. You would be paying for their work, up to\\n` +\n `$${dollars} a day, every day, until you change it.\\n` +\n `Spending stops at that ceiling and resumes the next day.\\n\\n` +\n `Offer ${backendKey} to ${scope === \"public\" ? \"anyone\" : \"people you have allowed\"}?`,\n );\n if (!confirmed) {\n io.out(\"nothing changed\\n\");\n return 0;\n }\n\n result.data.backends[backendKey] = {\n ...backend,\n offer: scope,\n spend: {\n centsPerMillionTokens: backend.spend?.centsPerMillionTokens ?? 1500,\n ...backend.spend,\n acknowledged: true,\n dailyCapCents: cap,\n },\n };\n } else {\n result.data.backends[backendKey] = {\n ...backend,\n offer: scope,\n // Narrowing back to `self` withdraws the consent too, so a later\n // widening has to be agreed to again rather than inherited.\n ...(cost === \"metered\" && !widening && backend.spend !== undefined\n ? { spend: { ...backend.spend, acknowledged: false } }\n : {}),\n };\n }\n\n await mkdir(dirname(paths.config), { recursive: true });\n await writeFile(paths.config, `${JSON.stringify(result.data, null, 2)}\\n`);\n\n const written = result.data.backends[backendKey].spend?.dailyCapCents;\n io.out(\n `${backendKey} is now offered to ${scope}` +\n (written === undefined || !widening\n ? \"\"\n : `, capped at ${String(written)}c a day`) +\n \"\\n\",\n );\n return 0;\n}\n\nasync function commandDisallow(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const [rawOrigin, owner] = args;\n if (rawOrigin === undefined || owner === undefined) {\n io.err(\"usage: byollm disallow <app-url> <user-id>\\n\");\n return 2;\n }\n const allowlist = new Allowlist(paths.allowlist);\n await allowlist.load();\n const removed = await allowlist.remove(normalizeOrigin(rawOrigin), owner);\n io.out(\n removed\n ? `${owner} can no longer use this machine\\n`\n : `${owner} was not on the list — nothing changed\\n`,\n );\n return 0;\n}\n\n// -- forget -------------------------------------------------------------------\n\nasync function commandForget(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const target = args[0];\n if (target === undefined) {\n io.err(\"usage: byollm forget <app-url>\\n\");\n return 2;\n }\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n const removed = await pairings.remove(normalizeOrigin(target));\n io.out(\n removed\n ? `forgot ${normalizeOrigin(target)} — the app may still list this runner ` +\n `until you revoke it there too\\n`\n : `not paired with ${normalizeOrigin(target)}\\n`,\n );\n return 0;\n}\n\n// -- backends ------------------------------------------------------------------\n\nasync function commandBackends(\n paths: DaemonPaths,\n io: CliIo,\n): Promise<ExitCode> {\n const { loaded, ingress, allowlist, budgets, spend } = await context(paths);\n const runner = new Runner({\n client: new ProtocolClient({ origin: \"https://unused.invalid\" }),\n runnerId: \"local\",\n owner: \"local\",\n daemonVersion: DAEMON_VERSION,\n loaded,\n allowlist,\n budgets,\n spend,\n ingress,\n });\n\n const advertised = await runner.detectCapabilities();\n const advertisedKinds = new Set(advertised.map((c) => c.kind));\n\n io.out(\"configured routes\\n\");\n for (const route of loaded.routes) {\n const ok = advertisedKinds.has(route.kind);\n const pays =\n route.cost === \"free\"\n ? \"free (your electricity)\"\n : route.cost === \"subscription\"\n ? \"your subscription — locked to your work\"\n : route.spendAcknowledged\n ? `metered — shared, cap ${String(route.spendDailyCapCents ?? 0)}c/day`\n : \"metered — your money, not shared\";\n io.out(\n ` ${ok ? \"✓\" : \"✗\"} ${route.kind.padEnd(14)} ` +\n `${route.backendId}:${route.model}` +\n `${route.baseUrl === undefined ? \"\" : ` @ ${route.baseUrl}`}\\n` +\n ` ${pays}\\n`,\n );\n }\n for (const problem of loaded.problems) {\n io.out(` ! ${problem.where}: ${problem.message}\\n`);\n }\n io.out(\n `\\n${String(advertised.length)} of ${String(loaded.routes.length)} routes are ` +\n `healthy and will be advertised.\\n` +\n `A route that is not healthy is never offered to an app — the daemon does\\n` +\n `not advertise what it cannot actually run.\\n`,\n );\n return advertised.length === 0 ? 1 : 0;\n}\n\n// -- shared -------------------------------------------------------------------\n\nasync function context(paths: DaemonPaths): Promise<{\n loaded: Awaited<ReturnType<typeof loadConfig>>;\n ingress: IngressLog;\n allowlist: Allowlist;\n budgets: Budgets;\n spend: SpendLedger;\n}> {\n const loaded = await loadConfig(paths.config);\n const ingress = new IngressLog({\n path: paths.ingressLog,\n communityPromptDays: loaded.config.ingress.communityPromptDays,\n keepSelfPrompts: loaded.config.ingress.keepSelfPrompts,\n });\n const allowlist = new Allowlist(paths.allowlist);\n await allowlist.load();\n const budgets = new Budgets(paths.budgets, loaded.config.community);\n await budgets.load(Date.now());\n const spend = new SpendLedger(paths.spend);\n await spend.load(Date.now());\n return { loaded, ingress, allowlist, budgets, spend };\n}\n\n/**\n * Ask, on a real terminal.\n *\n * Refuses outright when stdin is not a TTY: widening who may use someone's\n * machine is not a thing to do on an implied yes from a script.\n */\nasync function confirmInteractively(question: string): Promise<boolean> {\n if (!process.stdin.isTTY) {\n process.stderr.write(\n \"refusing to widen access without an interactive confirmation\\n\",\n );\n return false;\n }\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const answer = await rl.question(`${question} [y/N] `);\n return /^y(es)?$/i.test(answer.trim());\n } finally {\n rl.close();\n }\n}\n\n/**\n * How this machine appears in the app's runner list.\n *\n * `BYOLLM_LABEL` overrides it, because \"todd@Todds-MacBook-Pro\" is more than\n * some people want to hand an app they are only trying out.\n */\nfunction hostLabel(): string {\n const override = process.env[\"BYOLLM_LABEL\"];\n if (override !== undefined && override !== \"\") return override.slice(0, 120);\n try {\n return `${userInfo().username}@${hostname()}`.slice(0, 120);\n } catch {\n return hostname().slice(0, 120);\n }\n}\n\n/** The `byollm` executable. */\nexport async function main(argv: readonly string[]): Promise<ExitCode> {\n try {\n return await runCli(argv);\n } catch (error) {\n process.stderr.write(\n `${error instanceof ClientError || error instanceof Error ? error.message : String(error)}\\n`,\n );\n return 1;\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { z } from \"zod\";\nimport type { CommunityBudget } from \"./config.js\";\n\nconst BudgetFile = z\n .object({\n version: z.literal(1),\n /** Epoch-ms timestamps of community jobs accepted, newest last. */\n accepted: z.array(z.number().int().positive()),\n })\n .strict();\n\nexport type BudgetRefusal = \"hourly-cap\" | \"daily-cap\" | \"payload-too-large\";\n\nexport type BudgetDecision =\n | { readonly ok: true }\n | {\n readonly ok: false;\n readonly refusal: BudgetRefusal;\n readonly detail: string;\n };\n\n/**\n * The owner's ceiling on work done for other people\n * ({@link MUSTS.COMMUNITY_BUDGETS}).\n *\n * byollm_004 §4 distinguishes two directions of abuse, and this is the one\n * aimed *at* the volunteer: a stranger who can enqueue unlimited `public`\n * jobs owns your GPU. Jobs for the machine's own owner are never counted —\n * their machine, their call.\n */\nexport class Budgets {\n readonly #path: string;\n readonly #limits: CommunityBudget;\n #accepted: number[] = [];\n #loaded = false;\n\n constructor(path: string, limits: CommunityBudget) {\n this.#path = path;\n this.#limits = limits;\n }\n\n async load(now: number): Promise<void> {\n try {\n const parsed = BudgetFile.safeParse(\n JSON.parse(await readFile(this.#path, \"utf8\")),\n );\n this.#accepted = parsed.success ? parsed.data.accepted : [];\n } catch {\n this.#accepted = [];\n }\n this.#prune(now);\n this.#loaded = true;\n }\n\n /**\n * May this community job run?\n *\n * @param payloadChars - total payload text length, checked against the\n * stricter community limit rather than the protocol's absolute ceiling.\n */\n check(now: number, payloadChars: number): BudgetDecision {\n if (!this.#loaded) throw new Error(\"budgets used before load()\");\n this.#prune(now);\n\n if (payloadChars > this.#limits.maxPayloadChars) {\n return {\n ok: false,\n refusal: \"payload-too-large\",\n detail:\n `community jobs are limited to ${String(this.#limits.maxPayloadChars)} ` +\n `characters; this one is ${String(payloadChars)}`,\n };\n }\n\n const hour = this.#countSince(now - 3_600_000);\n if (hour >= this.#limits.maxJobsPerHour) {\n return {\n ok: false,\n refusal: \"hourly-cap\",\n detail: `already ran ${String(hour)} community jobs in the last hour`,\n };\n }\n\n const day = this.#countSince(now - 86_400_000);\n if (day >= this.#limits.maxJobsPerDay) {\n return {\n ok: false,\n refusal: \"daily-cap\",\n detail: `already ran ${String(day)} community jobs today`,\n };\n }\n return { ok: true };\n }\n\n /** Count a community job as accepted. Call only after {@link check} passes. */\n async record(now: number): Promise<void> {\n this.#accepted.push(now);\n this.#prune(now);\n await mkdir(dirname(this.#path), { recursive: true });\n await writeFile(\n this.#path,\n JSON.stringify({ version: 1, accepted: this.#accepted }),\n { mode: 0o600 },\n );\n }\n\n /** Current usage, for `byollm status`. */\n usage(now: number): { hour: number; day: number; limits: CommunityBudget } {\n this.#prune(now);\n return {\n hour: this.#countSince(now - 3_600_000),\n day: this.#countSince(now - 86_400_000),\n limits: this.#limits,\n };\n }\n\n #countSince(since: number): number {\n return this.#accepted.filter((at) => at >= since).length;\n }\n\n /** Anything older than a day can never affect either window again. */\n #prune(now: number): void {\n const cutoff = now - 86_400_000;\n this.#accepted = this.#accepted.filter((at) => at >= cutoff);\n }\n}\n","import {\n type ResultDisposition,\n type SealedEnvelope,\n ClaimResponse,\n FetchResponse,\n type PublicIdentity,\n HeartbeatResponse,\n PROTOCOL_VERSION,\n PairPollResponse,\n PairStartResponse,\n ReleaseResponse,\n ResultResponse,\n WireError,\n type Capability,\n type Endpoint,\n} from \"@byollm/protocol\";\nimport { type z } from \"zod\";\n\n/**\n * Why a protocol call failed, from the daemon's seat.\n *\n * byollm_002 requires that \"server unreachable\", \"revoked\", \"no matching\n * work\" and \"backend down\" never share a message. Three of those are\n * distinguishable here; the fourth is a local condition the loop reports\n * itself. \"No matching work\" is deliberately *not* an error — it is a `200`\n * with an empty list.\n */\nexport type ClientErrorKind =\n | \"unreachable\"\n | \"revoked\"\n | \"unauthorized\"\n | \"rejected\"\n /**\n * The server does not speak our protocol version. Its own kind because it\n * is the one refusal a retry can never fix and an upgrade always can — and\n * because a daemon that reports it as a generic rejection sends its owner\n * looking at their network.\n */\n | \"version-unsupported\"\n /**\n * The upstream holds this job for us but has no payload to give yet.\n *\n * Only reachable off the direct plane. A direct site seals when asked,\n * because it holds the keys; a relay must wait for the site to seal to the\n * device that claimed — so \"not yet\" is a normal answer there, and treating\n * it as a refusal drops work the daemon legitimately still holds.\n */\n | \"not-ready\"\n | \"rate-limited\"\n | \"server-error\"\n | \"malformed-response\";\n\nexport class ClientError extends Error {\n override readonly name = \"ClientError\";\n constructor(\n readonly kind: ClientErrorKind,\n message: string,\n /** Seconds the server asked us to wait, when it said. */\n readonly retryAfter?: number,\n ) {\n super(message);\n }\n\n /** Is retrying this same call plausibly useful? */\n get retryable(): boolean {\n return (\n this.kind === \"unreachable\" ||\n this.kind === \"not-ready\" ||\n this.kind === \"rate-limited\" ||\n this.kind === \"server-error\"\n );\n }\n}\n\nexport interface ClientOptions {\n /** The app's origin, e.g. `https://app.example.com`. */\n readonly origin: string;\n /** Bearer token from pairing. Absent while pairing. */\n /**\n * How this daemon proves who it is (byollm_009 §4.2).\n *\n * A signer rather than a key, so the client never holds private material\n * and the daemon decides where keys live. Absent while pairing, which is\n * the one exchange that establishes an identity rather than using one.\n */\n readonly identity?: {\n readonly runnerId: string;\n sign(input: {\n endpoint: string;\n runnerId: string;\n issuedAt: number;\n body: string;\n }): Promise<string> | string;\n };\n /** Per-request timeout. */\n readonly timeoutMs?: number;\n /** Injectable fetch, for tests. */\n readonly fetch?: typeof fetch;\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * The daemon's outbound protocol client.\n *\n * Every call is outbound; nothing here ever listens. That is the whole\n * network posture of the product, and it lives in this one class.\n */\nexport class ProtocolClient {\n readonly #origin: string;\n readonly #identity: ClientOptions[\"identity\"];\n readonly #timeoutMs: number;\n readonly #fetch: typeof fetch;\n\n constructor(options: ClientOptions) {\n this.#origin = options.origin.replace(/\\/+$/, \"\");\n this.#identity = options.identity;\n this.#timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#fetch = options.fetch ?? globalThis.fetch;\n }\n\n /** A client for the same origin that signs as a given runner. */\n withIdentity(\n identity: NonNullable<ClientOptions[\"identity\"]>,\n ): ProtocolClient {\n return new ProtocolClient({\n origin: this.#origin,\n identity,\n timeoutMs: this.#timeoutMs,\n fetch: this.#fetch,\n });\n }\n\n get origin(): string {\n return this.#origin;\n }\n\n async pairStart(input: {\n version: string;\n label: string;\n platform: \"darwin\" | \"linux\" | \"win32\";\n /** This machine's public keys (byollm_009 §5). */\n device: PublicIdentity;\n capabilities: readonly Capability[];\n }): Promise<PairStartResponse> {\n return this.#post(\"pair\", PairStartResponse, {\n protocolVersion: PROTOCOL_VERSION,\n action: \"start\",\n device: input.device,\n daemon: {\n version: input.version,\n label: input.label,\n platform: input.platform,\n },\n capabilities: input.capabilities,\n });\n }\n\n async pairPoll(deviceCode: string): Promise<PairPollResponse> {\n return this.#post(\"pair\", PairPollResponse, {\n protocolVersion: PROTOCOL_VERSION,\n action: \"poll\",\n deviceCode,\n });\n }\n\n /**\n * Collect the payload for a lease this daemon holds (byollm_009 §6).\n *\n * The second half of claim-then-fetch: a claim answers with a stub, and the\n * work is collected by the device that took it.\n */\n async fetch(input: {\n runnerId: string;\n jobId: string;\n leaseId: string;\n }): Promise<FetchResponse> {\n return this.#post(\"fetch\", FetchResponse, {\n protocolVersion: PROTOCOL_VERSION,\n runnerId: input.runnerId,\n jobId: input.jobId,\n leaseId: input.leaseId,\n });\n }\n\n async claim(input: {\n runnerId: string;\n capabilities: readonly Capability[];\n max: number;\n }): Promise<ClaimResponse> {\n return this.#post(\"claim\", ClaimResponse, {\n protocolVersion: PROTOCOL_VERSION,\n runnerId: input.runnerId,\n capabilities: input.capabilities,\n max: input.max,\n });\n }\n\n async heartbeat(input: {\n runnerId: string;\n daemonVersion: string;\n capabilities: readonly Capability[];\n activeLeases: readonly { jobId: string; leaseId: string }[];\n paused: boolean;\n }): Promise<HeartbeatResponse> {\n return this.#post(\"heartbeat\", HeartbeatResponse, {\n protocolVersion: PROTOCOL_VERSION,\n runnerId: input.runnerId,\n daemonVersion: input.daemonVersion,\n capabilities: input.capabilities,\n activeLeases: input.activeLeases,\n paused: input.paused,\n });\n }\n\n async result(input: {\n runnerId: string;\n jobId: string;\n envelope: SealedEnvelope;\n disposition: ResultDisposition;\n model: string;\n backendClass: \"http\" | \"process\";\n durationMs: number;\n }): Promise<ResultResponse> {\n return this.#post(\"result\", ResultResponse, {\n protocolVersion: PROTOCOL_VERSION,\n ...input,\n });\n }\n\n async release(input: {\n runnerId: string;\n leases: readonly { jobId: string; leaseId: string }[];\n reason: \"shutdown\" | \"pause\" | \"revoked\" | \"backend-down\" | \"refused\";\n }): Promise<ReleaseResponse> {\n return this.#post(\"release\", ReleaseResponse, {\n protocolVersion: PROTOCOL_VERSION,\n runnerId: input.runnerId,\n leases: input.leases,\n reason: input.reason,\n });\n }\n\n async #post<T>(\n endpoint: Endpoint,\n schema: z.ZodType<T>,\n body: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n };\n\n // Serialise once and sign exactly those bytes. Signing a re-serialised\n // copy would sign something the server never receives.\n const rawBody = JSON.stringify(body);\n if (this.#identity !== undefined) {\n const issuedAt = Date.now();\n headers[\"x-byollm-runner\"] = this.#identity.runnerId;\n headers[\"x-byollm-issued-at\"] = String(issuedAt);\n headers[\"x-byollm-signature\"] = await this.#identity.sign({\n endpoint,\n runnerId: this.#identity.runnerId,\n issuedAt,\n body: rawBody,\n });\n }\n\n let response: Response;\n try {\n response = await this.#fetch(`${this.#origin}/byollm/${endpoint}`, {\n method: \"POST\",\n headers,\n body: rawBody,\n redirect: \"error\",\n signal: AbortSignal.timeout(this.#timeoutMs),\n });\n } catch (error) {\n // No response at all: the server is unreachable. Distinct from every\n // answer it could have given us, including a refusal.\n throw new ClientError(\n \"unreachable\",\n `could not reach ${this.#origin} (${error instanceof Error ? error.message : \"unknown error\"})`,\n );\n }\n\n const text = await response.text();\n let parsed: unknown;\n try {\n parsed = text === \"\" ? {} : JSON.parse(text);\n } catch {\n throw new ClientError(\n \"malformed-response\",\n `${this.#origin} returned HTTP ${String(response.status)} with a body that is not JSON`,\n );\n }\n\n if (!response.ok) {\n throw this.#toError(response, parsed);\n }\n\n const result = schema.safeParse(parsed);\n if (!result.success) {\n // A server whose response does not match the protocol is not one we can\n // safely guess about.\n throw new ClientError(\n \"malformed-response\",\n `${this.#origin} returned a ${endpoint} response that does not match protocol v${PROTOCOL_VERSION}`,\n );\n }\n return result.data;\n }\n\n #toError(response: Response, body: unknown): ClientError {\n const wire = WireError.safeParse(body);\n const retryAfterHeader = response.headers.get(\"retry-after\");\n const retryAfter =\n wire.success && wire.data.retryAfter !== undefined\n ? wire.data.retryAfter\n : retryAfterHeader !== null && /^\\d+$/.test(retryAfterHeader)\n ? Number(retryAfterHeader)\n : undefined;\n\n const message = wire.success\n ? wire.data.message\n : `${this.#origin} returned HTTP ${String(response.status)}`;\n\n if (wire.success && wire.data.error === \"revoked\") {\n return new ClientError(\"revoked\", message, retryAfter);\n }\n if (\n typeof body === \"object\" &&\n body !== null &&\n (body as { error?: unknown }).error === \"unsupported-protocol-version\"\n ) {\n // The server already composed a message naming the fix; pass it through\n // rather than paraphrasing it into something vaguer.\n return new ClientError(\"version-unsupported\", message, retryAfter);\n }\n switch (response.status) {\n case 401:\n return new ClientError(\"unauthorized\", message, retryAfter);\n case 403:\n return new ClientError(\"revoked\", message, retryAfter);\n case 409:\n return new ClientError(\"not-ready\", message, retryAfter);\n case 429:\n return new ClientError(\"rate-limited\", message, retryAfter);\n case 400:\n case 404:\n // Never retried: the request is wrong, and repeating it stays wrong.\n return new ClientError(\"rejected\", message, retryAfter);\n default:\n return response.status >= 500\n ? new ClientError(\"server-error\", message, retryAfter)\n : new ClientError(\"rejected\", message, retryAfter);\n }\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport {\n BackendIdSchema,\n JobKind,\n OfferScope,\n backendDescriptor,\n effectiveOfferScope,\n resolveCost,\n type BackendCost,\n type BackendId,\n} from \"@byollm/protocol\";\nimport { z } from \"zod\";\nimport { checkBaseUrl } from \"./ssrf.js\";\n\n/**\n * One configured backend instance.\n *\n * `openai-http` may be configured many times — one per model server the owner\n * runs (Ollama here, `mlx_lm.server` there, a llama.cpp box on the LAN). That\n * is byollm_001 Rev 1 §A's \"one backend, N base URLs\".\n */\nexport const BackendConfig = z\n .object({\n backend: BackendIdSchema,\n /** Required for HTTP-class backends; meaningless for process-class. */\n baseUrl: z.string().optional(),\n /**\n * What the owner is willing to run for others. Subscription-class\n * backends ignore this and are locked to `self`\n * ({@link MUSTS.SUBSCRIPTION_SELF_LOCK}).\n */\n offer: OfferScope.default(\"self\"),\n /**\n * Name of an environment variable holding this backend's API key, for a\n * remote OpenAI-compatible server that needs one. The *name*, never the\n * value — a key does not belong in a config file the owner may share.\n */\n apiKeyEnv: z.string().optional(),\n /**\n * Required before a `metered` backend may be offered past `self`\n * ({@link MUSTS.METERED_DEFAULTS_SELF}). There is deliberately no `cost`\n * field: a provider's cost class comes from the protocol registry and is\n * not the owner's to declare ({@link MUSTS.COST_NOT_CONFIGURABLE}).\n */\n spend: z\n .object({\n /** Set by `byollm offer`, which states the consequence in words. */\n acknowledged: z.boolean().default(false),\n /**\n * Ceiling on community spend, in whole cents, per day. A widened\n * metered backend without one is refused\n * ({@link MUSTS.METERED_REQUIRES_CEILING}) — \"unlimited\" is not a\n * thing an owner can mean by accident.\n */\n dailyCapCents: z.number().int().positive().optional(),\n /**\n * What this provider charges, for the ceiling estimate. Providers do\n * not return a price, so the owner supplies one; the default is\n * deliberately high so an unset rate trips the brake early rather\n * than late.\n */\n centsPerMillionTokens: z.number().positive().default(1500),\n })\n .strict()\n .optional(),\n })\n .strict();\nexport type BackendConfig = z.infer<typeof BackendConfig>;\n\n/** Which backend instance and model serves a job kind. */\nexport const RouteConfig = z\n .object({\n /** Key into {@link DaemonConfig.backends}. */\n backend: z.string().min(1),\n /** The model name, owner-chosen. A payload can never influence this. */\n model: z.string().min(1),\n })\n .strict();\nexport type RouteConfig = z.infer<typeof RouteConfig>;\n\n/**\n * Budgets applied to jobs whose owner is not this machine's owner\n * ({@link MUSTS.COMMUNITY_BUDGETS}).\n */\nexport const CommunityBudget = z\n .object({\n maxJobsPerHour: z.number().int().positive().default(20),\n maxJobsPerDay: z.number().int().positive().default(100),\n /** Wall-clock ceiling for one community job. */\n maxWallClockMs: z.number().int().positive().default(120_000),\n /** Output-size ceiling for one community job. */\n maxOutputBytes: z\n .number()\n .int()\n .positive()\n .default(256 * 1024),\n /** Payload-size ceiling — stricter than the protocol's absolute limit. */\n maxPayloadChars: z.number().int().positive().default(100_000),\n })\n .strict();\nexport type CommunityBudget = z.infer<typeof CommunityBudget>;\n\n/** Ingress-log retention (byollm_004 Rev 1). */\nexport const IngressRetention = z\n .object({\n /**\n * How long a `named`/`public` prompt is kept in full before being reduced\n * to a hash. A volunteer must not indefinitely retain strangers' content.\n */\n communityPromptDays: z.number().int().positive().default(7),\n /** Whether the owner's own prompts are kept in full. Their call. */\n keepSelfPrompts: z.boolean().default(true),\n })\n .strict();\nexport type IngressRetention = z.infer<typeof IngressRetention>;\n\n/** Ceilings applied to every job, community or not. */\nexport const Limits = z\n .object({\n maxWallClockMs: z.number().int().positive().default(600_000),\n maxOutputBytes: z\n .number()\n .int()\n .positive()\n .default(4 * 1024 * 1024),\n })\n .strict();\nexport type Limits = z.infer<typeof Limits>;\n\nexport const DaemonConfig = z\n .object({\n backends: z.record(z.string().min(1), BackendConfig),\n // `partialRecord`, not `record`: zod 4's `record` with an enum key\n // demands every member be present, which would force an owner who only\n // wants `llm.generate` to also configure `llm.chat`. Routing one kind and\n // not the other is a legitimate setup — the unrouted kind is simply never\n // advertised.\n routes: z.partialRecord(JobKind, RouteConfig),\n /** How many jobs to run at once. */\n concurrency: z.number().int().min(1).max(32).default(2),\n // `prefault`, not `default`: zod 4's `.default()` takes an *output* value,\n // which would mean restating every nested default here where it could\n // drift. `prefault` feeds `{}` through the schema so the nested defaults\n // stay the single source of truth.\n community: CommunityBudget.prefault({}),\n ingress: IngressRetention.prefault({}),\n limits: Limits.prefault({}),\n })\n .strict();\nexport type DaemonConfig = z.infer<typeof DaemonConfig>;\n\n/** A route resolved against its backend, ready to execute. */\nexport interface ResolvedRoute {\n readonly kind: z.infer<typeof JobKind>;\n readonly backendKey: string;\n readonly backendId: BackendId;\n readonly backendClass: \"http\" | \"process\";\n readonly model: string;\n /** Who pays for this route's tokens. From the registry, never from config. */\n readonly cost: BackendCost;\n /** After the cost rules are applied — never the raw configured value. */\n readonly offerScope: z.infer<typeof OfferScope>;\n /** The owner's spend consent, for a `metered` route. */\n readonly spendAcknowledged: boolean;\n readonly spendDailyCapCents: number | undefined;\n readonly spendCentsPerMillionTokens: number;\n readonly baseUrl: string | undefined;\n readonly apiKeyEnv: string | undefined;\n}\n\nexport interface ConfigProblem {\n readonly where: string;\n readonly message: string;\n}\n\nexport interface LoadedConfig {\n readonly config: DaemonConfig;\n readonly routes: readonly ResolvedRoute[];\n /** Non-fatal problems: a route that cannot be served is dropped, not fatal. */\n readonly problems: readonly ConfigProblem[];\n}\n\n/** The config used when the owner has not written one. */\nexport const DEFAULT_CONFIG: DaemonConfig = DaemonConfig.parse({\n backends: {\n ollama: { backend: \"openai-http\", baseUrl: \"http://127.0.0.1:11434/v1\" },\n },\n routes: {\n \"llm.generate\": { backend: \"ollama\", model: \"llama3.2\" },\n \"llm.chat\": { backend: \"ollama\", model: \"llama3.2\" },\n },\n});\n\n/**\n * Read and resolve `~/.byollm/config.json`.\n *\n * A missing file yields {@link DEFAULT_CONFIG}; a malformed one throws,\n * because silently running with defaults when the owner *did* write a config\n * would execute work under rules they did not choose.\n */\nexport async function loadConfig(path: string): Promise<LoadedConfig> {\n let raw: string;\n try {\n raw = await readFile(path, \"utf8\");\n } catch (error) {\n if (isNotFound(error)) return resolveConfig(DEFAULT_CONFIG);\n throw error;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `${path} is not valid JSON: ${error instanceof Error ? error.message : \"unknown error\"}`,\n { cause: error },\n );\n }\n\n const result = DaemonConfig.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues\n .map((issue) => ` ${issue.path.join(\".\") || \"(root)\"}: ${issue.message}`)\n .join(\"\\n\");\n throw new Error(`${path} is not a valid byollm config:\\n${issues}`);\n }\n return resolveConfig(result.data);\n}\n\n/**\n * Turn a parsed config into executable routes, applying the subscription lock\n * and rejecting unusable backends.\n *\n * A problem here is not fatal: a machine with three routes and one broken\n * backend should serve the other two and say so, rather than refusing to\n * start. What it must never do is *advertise* the broken one\n * ({@link MUSTS.CAPABILITY_IS_DETECTED}).\n */\nexport function resolveConfig(config: DaemonConfig): LoadedConfig {\n const routes: ResolvedRoute[] = [];\n const problems: ConfigProblem[] = [];\n\n for (const [kind, route] of Object.entries(config.routes)) {\n const where = `routes.${kind}`;\n const backend = config.backends[route.backend];\n if (!backend) {\n problems.push({\n where,\n message: `backend \"${route.backend}\" is not defined in backends`,\n });\n continue;\n }\n\n const descriptor = backendDescriptor(backend.backend);\n\n // A named provider supplies its own address; the generic backend and any\n // override still have to be given one.\n const baseUrl = backend.baseUrl ?? descriptor.defaultBaseUrl;\n\n if (descriptor.class === \"http\") {\n if (baseUrl === undefined) {\n problems.push({\n where: `backends.${route.backend}`,\n message: \"an HTTP-class backend needs a baseUrl\",\n });\n continue;\n }\n const check = checkBaseUrl(baseUrl);\n if (!check.ok) {\n problems.push({\n where: `backends.${route.backend}.baseUrl`,\n message: check.detail,\n });\n continue;\n }\n }\n\n // Cost comes from the registry, or from where the request goes — never\n // from config ({@link MUSTS.COST_NOT_CONFIGURABLE},\n // {@link MUSTS.REMOTE_IS_NEVER_FREE}).\n const cost = resolveCost(backend.backend, baseUrl);\n const acknowledged = backend.spend?.acknowledged === true;\n const capCents = backend.spend?.dailyCapCents;\n\n // A widened metered backend without a ceiling is refused rather than\n // silently given an unlimited one ({@link MUSTS.METERED_REQUIRES_CEILING}).\n const widened = backend.offer !== \"self\";\n if (\n cost === \"metered\" &&\n widened &&\n acknowledged &&\n capCents === undefined\n ) {\n problems.push({\n where: `backends.${route.backend}.spend`,\n message:\n \"sharing a metered backend needs spend.dailyCapCents — an \" +\n \"unlimited ceiling is not something anyone means on purpose\",\n });\n continue;\n }\n\n const configured = backend.offer;\n const offerScope = effectiveOfferScope(configured, cost, {\n acknowledged: acknowledged && capCents !== undefined,\n });\n if (offerScope !== configured) {\n problems.push({\n where: `backends.${route.backend}.offer`,\n message:\n cost === \"subscription\"\n ? `\"${configured}\" was ignored: ${descriptor.label} runs on your ` +\n `own subscription, so it is locked to your work only`\n : `\"${configured}\" was narrowed to \"self\": ${descriptor.label} ` +\n `bills you per token. \\`byollm offer ${route.backend} ` +\n `${configured}\\` to share it deliberately, with a ceiling`,\n });\n }\n\n routes.push({\n kind: kind as z.infer<typeof JobKind>,\n backendKey: route.backend,\n backendId: backend.backend,\n backendClass: descriptor.class,\n model: route.model,\n cost,\n offerScope,\n spendAcknowledged: acknowledged,\n spendDailyCapCents: capCents,\n spendCentsPerMillionTokens: backend.spend?.centsPerMillionTokens ?? 1500,\n baseUrl,\n apiKeyEnv: backend.apiKeyEnv,\n });\n }\n\n return { config, routes, problems };\n}\n\nfunction isNotFound(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { code?: unknown }).code === \"ENOENT\"\n );\n}\n","import { isIP } from \"node:net\";\n\n/**\n * Why a base URL was refused.\n */\nexport type BaseUrlRefusal =\n | \"not-a-url\"\n | \"bad-scheme\"\n | \"credentials-in-url\"\n | \"cloud-metadata\"\n | \"link-local\"\n | \"wildcard-address\";\n\nexport type BaseUrlCheck =\n | { readonly ok: true; readonly url: URL }\n | {\n readonly ok: false;\n readonly refusal: BaseUrlRefusal;\n readonly detail: string;\n };\n\n/**\n * Hostnames that resolve to a cloud instance's credential endpoint. Reaching\n * one from a machine running in a cloud VM hands out IAM credentials.\n */\nconst METADATA_HOSTS = new Set([\n \"metadata.google.internal\",\n \"metadata.goog\",\n \"instance-data\",\n \"metadata\",\n]);\n\n/** Literal addresses of the same endpoints. */\nconst METADATA_ADDRESSES = new Set([\n \"169.254.169.254\",\n \"169.254.170.2\",\n \"fd00:ec2::254\",\n]);\n\n/**\n * Validate an owner-configured backend base URL\n * ({@link MUSTS.HTTP_BASE_URL_SAFE}).\n *\n * **What this is and is not.** byollm_004 Rev 1 calls the HTTP-class threat\n * surface \"SSRF-shaped\", and the shape matters: the base URL comes from the\n * machine owner's config and from nowhere else — no payload field can set it,\n * redirect it, or append to it. There is therefore no attacker-controlled\n * input channel into this value at all. What remains is an owner who\n * misconfigures their own machine, and the one case where that is genuinely\n * dangerous is a cloud metadata endpoint.\n *\n * So this deliberately **allows loopback and private LAN addresses**. Blocking\n * them, as a generic SSRF filter would, would refuse\n * `http://127.0.0.1:11434` — which is Ollama's default and the entire point of\n * the product. A filter that breaks the primary path in exchange for no real\n * protection is theatre, and byollm_004's honesty rule forbids claiming it as\n * a guarantee.\n *\n * Redirects are a separate matter and are refused outright by the HTTP\n * backend, so a permitted base URL cannot become a forbidden one in flight.\n */\nexport function checkBaseUrl(raw: string): BaseUrlCheck {\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return {\n ok: false,\n refusal: \"not-a-url\",\n detail: \"base URL is not a valid absolute URL\",\n };\n }\n\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n return {\n ok: false,\n refusal: \"bad-scheme\",\n detail: `base URL scheme ${url.protocol} is not http or https`,\n };\n }\n\n if (url.username !== \"\" || url.password !== \"\") {\n // Credentials in the URL would end up in logs and error messages.\n return {\n ok: false,\n refusal: \"credentials-in-url\",\n detail: \"base URL must not embed a username or password\",\n };\n }\n\n const host = url.hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n\n if (METADATA_HOSTS.has(host) || METADATA_ADDRESSES.has(host)) {\n return {\n ok: false,\n refusal: \"cloud-metadata\",\n detail: `${host} is a cloud metadata endpoint`,\n };\n }\n\n // 169.254.0.0/16 and fe80::/10 — link-local. The metadata addresses above\n // live here too; this catches the rest of the range.\n if (isIP(host) === 4 && host.startsWith(\"169.254.\")) {\n return {\n ok: false,\n refusal: \"link-local\",\n detail: `${host} is link-local`,\n };\n }\n if (isIP(host) === 6 && /^fe[89ab]/.test(host)) {\n return {\n ok: false,\n refusal: \"link-local\",\n detail: `${host} is link-local`,\n };\n }\n\n // A wildcard address is a listening address, not a destination.\n if (host === \"0.0.0.0\" || host === \"::\" || host === \"\") {\n return {\n ok: false,\n refusal: \"wildcard-address\",\n detail: `${host || \"(empty)\"} is not a destination address`,\n };\n }\n\n return { ok: true, url };\n}\n\n/** Human-readable explanations for the trust UI and startup errors. */\nexport const BASE_URL_REFUSAL_MESSAGES: Readonly<\n Record<BaseUrlRefusal, string>\n> = Object.freeze({\n \"not-a-url\": \"that base URL could not be parsed\",\n \"bad-scheme\": \"a backend base URL must be http or https\",\n \"credentials-in-url\":\n \"put credentials in the backend's auth config, not in the URL\",\n \"cloud-metadata\":\n \"that address is a cloud metadata endpoint and would expose instance credentials\",\n \"link-local\": \"link-local addresses are refused\",\n \"wildcard-address\":\n \"that is an address to listen on, not one to connect to — use 127.0.0.1\",\n});\n","import { platform } from \"node:os\";\nimport {\n verifyPublicIdentity,\n type Capability,\n type PublicIdentity,\n} from \"@byollm/protocol\";\nimport { ClientError, type ProtocolClient } from \"./client.js\";\nimport type { Pairing } from \"./pairings.js\";\n\nexport interface ConnectOptions {\n readonly client: ProtocolClient;\n readonly daemonVersion: string;\n readonly label: string;\n readonly capabilities: readonly Capability[];\n /** This machine's public keys, presented at pair start (byollm_009 §5). */\n readonly device: PublicIdentity;\n /** Called once, with what to show the user. */\n readonly onCode: (info: {\n userCode: string;\n verificationUrl: string;\n expiresAt: number;\n }) => void;\n /** Called each poll, so a CLI can show it is still waiting. */\n readonly onPoll?: () => void;\n readonly now?: () => number;\n readonly sleep?: (ms: number) => Promise<void>;\n readonly signal?: AbortSignal;\n}\n\nexport type ConnectResult =\n | { readonly ok: true; readonly pairing: Pairing }\n | {\n readonly ok: false;\n readonly reason: \"denied\" | \"expired\" | \"aborted\";\n readonly message: string;\n };\n\n/**\n * The device-code pairing flow, from the daemon's side.\n *\n * The daemon asks for a code, shows it, and polls. The user approves inside\n * the app's own authenticated session, which is how the server learns who\n * they are — the daemon never asserts an identity and never accepts a pasted\n * long-lived secret ({@link MUSTS.PAIR_INTERACTIVE}).\n *\n * Nothing listens on the user's machine for this. A loopback redirect would\n * be fewer keystrokes and would contradict the product's whole posture, as\n * well as breaking on the headless boxes most likely to be running a model.\n */\nexport async function connect(options: ConnectOptions): Promise<ConnectResult> {\n const now = options.now ?? Date.now;\n const sleep = options.sleep ?? defaultSleep;\n\n const started = await options.client.pairStart({\n version: options.daemonVersion,\n label: options.label,\n platform: currentPlatform(),\n device: options.device,\n capabilities: options.capabilities,\n });\n\n options.onCode({\n userCode: started.userCode,\n verificationUrl: started.verificationUrl,\n expiresAt: started.expiresAt,\n });\n\n for (;;) {\n if (options.signal?.aborted === true) {\n return { ok: false, reason: \"aborted\", message: \"pairing was canceled\" };\n }\n if (now() >= started.expiresAt) {\n return {\n ok: false,\n reason: \"expired\",\n message: \"the pairing code expired before it was approved\",\n };\n }\n\n await sleep(started.pollIntervalMs);\n options.onPoll?.();\n\n let polled;\n try {\n polled = await options.client.pairPoll(started.deviceCode);\n } catch (error) {\n // A blip while waiting for a human is not a failure — keep polling\n // until the code itself expires.\n if (error instanceof ClientError && error.retryable) continue;\n throw error;\n }\n\n switch (polled.status) {\n case \"pending\":\n continue;\n case \"denied\":\n return {\n ok: false,\n reason: \"denied\",\n message: \"the pairing request was declined\",\n };\n case \"expired\":\n return {\n ok: false,\n reason: \"expired\",\n message: \"the pairing code expired before it was approved\",\n };\n case \"approved\":\n // Verify before pinning. A site whose encryption key is not signed by\n // the identity presenting it is either misconfigured or being\n // impersonated, and pinning it would make the impersonation\n // permanent — which is the failure mode pinning exists to prevent,\n // arrived at by pinning.\n if (!verifyPublicIdentity(polled.site)) {\n return {\n ok: false,\n reason: \"denied\",\n message:\n \"this app presented keys that do not verify: its encryption \" +\n \"key is not signed by the identity it claims. Nothing was \" +\n \"paired.\",\n };\n }\n return {\n ok: true,\n pairing: {\n origin: options.client.origin,\n runnerId: polled.runnerId,\n token: polled.runnerToken,\n owner: polled.owner,\n ...(polled.ownerLabel === undefined\n ? {}\n : { ownerLabel: polled.ownerLabel }),\n site: polled.site,\n pairedAt: now(),\n },\n };\n }\n }\n}\n\n/** The platform, narrowed to what the protocol accepts. */\nexport function currentPlatform(): \"darwin\" | \"linux\" | \"win32\" {\n const current = platform();\n if (current === \"darwin\" || current === \"linux\" || current === \"win32\") {\n return current;\n }\n // byollm_002 scopes v1 to macOS and Linux. Anything else reports as linux\n // rather than refusing outright — the protocol field is descriptive, and a\n // BSD user with Ollama running should not be blocked by a label.\n return \"linux\";\n}\n\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n","import { createHash } from \"node:crypto\";\nimport { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { Audience } from \"@byollm/protocol\";\nimport { z } from \"zod\";\n\n/**\n * A prompt about to be executed.\n *\n * Written *before* the backend is called\n * ({@link MUSTS.INGRESS_LOGGED_BEFORE_EXECUTION}), so a job that wedges or\n * crashes the machine still leaves a record of what it was.\n */\nexport const PromptEntry = z\n .object({\n type: z.literal(\"prompt\"),\n at: z.number().int().positive(),\n /** Origin of the server that sent the job. */\n origin: z.string().min(1),\n jobId: z.string().min(1),\n kind: z.string().min(1),\n audience: z.string().min(1),\n /** Who this prompt is *for* — which, for community work, is not you. */\n owner: z.string().min(1),\n backendId: z.string().min(1),\n backendClass: z.string().min(1),\n model: z.string().min(1),\n /** Always present, including after retention drops the text. */\n promptHash: z.string().length(64),\n promptChars: z.number().int().nonnegative(),\n /**\n * The prompt itself. Absent means \"not retained\" — distinct from an empty\n * prompt, which the protocol forbids anyway. Zero and unknown never look\n * alike.\n */\n prompt: z.string().optional(),\n })\n .strict();\nexport type PromptEntry = z.infer<typeof PromptEntry>;\n\n/** How a job ended. A separate line, so the prompt line is never rewritten. */\nexport const OutcomeEntry = z\n .object({\n type: z.literal(\"outcome\"),\n at: z.number().int().positive(),\n jobId: z.string().min(1),\n outcome: z.enum([\"ok\", \"error\", \"canceled\", \"refused\"]),\n /** Present for a job that ran; absent for one refused before execution. */\n durationMs: z.number().int().nonnegative().optional(),\n outputChars: z.number().int().nonnegative().optional(),\n /** Why, for `error` and `refused`. */\n detail: z.string().optional(),\n })\n .strict();\nexport type OutcomeEntry = z.infer<typeof OutcomeEntry>;\n\nexport const IngressEntry = z.discriminatedUnion(\"type\", [\n PromptEntry,\n OutcomeEntry,\n]);\nexport type IngressEntry = z.infer<typeof IngressEntry>;\n\nexport interface IngressOptions {\n readonly path: string;\n /** Days to keep a community prompt in full before reducing it to its hash. */\n readonly communityPromptDays: number;\n /** Whether to record the owner's own prompts in full. */\n readonly keepSelfPrompts: boolean;\n}\n\n/**\n * The append-only record of every prompt that has run on this machine.\n *\n * byollm_002 calls the meter the product's soul. This is it: one JSONL file\n * the owner can read, grep and delete, written before execution rather than\n * after.\n */\nexport class IngressLog {\n readonly #options: IngressOptions;\n\n constructor(options: IngressOptions) {\n this.#options = options;\n }\n\n /** Record a prompt. Await this before starting the backend call. */\n async recordPrompt(input: {\n at: number;\n origin: string;\n jobId: string;\n kind: string;\n audience: Audience;\n owner: string;\n backendId: string;\n backendClass: string;\n model: string;\n prompt: string;\n }): Promise<void> {\n // Community prompts are always kept initially — retention reduces them\n // later. Only the owner's own prompts can be opted out of up front.\n const keepText =\n input.audience === \"self\" ? this.#options.keepSelfPrompts : true;\n\n await this.#append({\n type: \"prompt\",\n at: input.at,\n origin: input.origin,\n jobId: input.jobId,\n kind: input.kind,\n audience: input.audience,\n owner: input.owner,\n backendId: input.backendId,\n backendClass: input.backendClass,\n model: input.model,\n promptHash: hashText(input.prompt),\n promptChars: input.prompt.length,\n ...(keepText ? { prompt: input.prompt } : {}),\n });\n }\n\n /** Record how a job ended. */\n async recordOutcome(input: {\n at: number;\n jobId: string;\n outcome: OutcomeEntry[\"outcome\"];\n durationMs?: number;\n outputChars?: number;\n detail?: string;\n }): Promise<void> {\n await this.#append({\n type: \"outcome\",\n at: input.at,\n jobId: input.jobId,\n outcome: input.outcome,\n ...(input.durationMs === undefined\n ? {}\n : { durationMs: input.durationMs }),\n ...(input.outputChars === undefined\n ? {}\n : { outputChars: input.outputChars }),\n ...(input.detail === undefined ? {} : { detail: input.detail }),\n });\n }\n\n async #append(entry: IngressEntry): Promise<void> {\n await mkdir(dirname(this.#options.path), { recursive: true });\n // JSON.stringify escapes control characters, so a prompt containing ANSI\n // escapes or newlines cannot forge a log line or repaint the terminal of\n // whoever later reads the file ({@link MUSTS.OUTPUT_INERT}).\n await appendFile(this.#options.path, `${JSON.stringify(entry)}\\n`, {\n mode: 0o600,\n });\n }\n\n /** Read the log, oldest first. Malformed lines are skipped, not fatal. */\n async read(): Promise<IngressEntry[]> {\n let raw: string;\n try {\n raw = await readFile(this.#options.path, \"utf8\");\n } catch {\n return [];\n }\n const entries: IngressEntry[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (line.trim() === \"\") continue;\n try {\n const parsed = IngressEntry.safeParse(JSON.parse(line));\n if (parsed.success) entries.push(parsed.data);\n } catch {\n // A truncated final line after a hard kill is expected, not an error.\n }\n }\n return entries;\n }\n\n /**\n * Apply retention: drop the text of community prompts older than the\n * window, keeping the hash, the metadata and the character count.\n *\n * byollm_004 Rev 1: a volunteer must not indefinitely retain strangers'\n * content. The hash stays, so the owner can still prove what ran.\n *\n * @returns how many entries were reduced.\n */\n async applyRetention(now: number): Promise<number> {\n const entries = await this.read();\n const cutoff = now - this.#options.communityPromptDays * 86_400_000;\n let reduced = 0;\n\n const kept = entries.map((entry) => {\n if (entry.type !== \"prompt\") return entry;\n const isCommunity =\n entry.audience === \"named\" || entry.audience === \"public\";\n if (!isCommunity || entry.prompt === undefined || entry.at >= cutoff) {\n return entry;\n }\n reduced += 1;\n const { prompt: _dropped, ...rest } = entry;\n return rest;\n });\n\n if (reduced > 0) {\n // The log is append-only in operation; retention is the one deliberate\n // exception, and it only ever removes text.\n await writeFile(\n this.#options.path,\n `${kept.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`,\n { mode: 0o600 },\n );\n }\n return reduced;\n }\n}\n\n/** SHA-256 of a prompt, hex. */\nexport function hashText(text: string): string {\n return createHash(\"sha256\").update(text, \"utf8\").digest(\"hex\");\n}\n\n/**\n * Replace terminal control sequences before printing untrusted text.\n *\n * Model output and job payloads both reach the owner's terminal through\n * `byollm log` and `byollm status`. Text that can move the cursor or set\n * colours can forge output — the ANSI/log-injection row of byollm_004 §5's\n * corpus. Stored bytes stay verbatim; only the *display* is sanitised, so the\n * log remains an honest record of what actually arrived.\n *\n * Tab and newline are kept: they are legitimate content, not control.\n */\nexport function stripControlChars(text: string): string {\n // eslint-disable-next-line no-control-regex -- matching control characters is the entire purpose\n return text.replace(/[\\u0000-\\u0008\\u000B-\\u001F\\u007F-\\u009F]/g, \"\\uFFFD\");\n}\n","import { chmod, mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport {\n StoredKeys,\n fingerprint,\n generateKeys,\n publicIdentityOf,\n signRequest,\n signWith,\n type PublicIdentity,\n} from \"@byollm/protocol\";\n\n/**\n * This machine's identity — byollm_009 §3.\n *\n * Generated once, at first run, and then never again: the device key *is* the\n * daemon, in a way a runner token never was. A token is a bearer secret a\n * server minted and can reissue; this is the machine saying who it is, and\n * nothing upstream can mint one.\n *\n * That difference is why this file is treated more carefully than the others\n * the daemon writes. Losing it means re-pairing every site. Leaking it means\n * someone else can be this machine.\n */\nexport class DeviceIdentity {\n readonly #path: string;\n #keys: StoredKeys | undefined;\n\n constructor(path: string) {\n this.#path = path;\n }\n\n /**\n * Load the keys, generating them on first run.\n *\n * A corrupt file is **not** silently replaced. Generating fresh keys over\n * an unreadable file would silently orphan every pairing the owner has —\n * every site would see an unknown device and refuse — and it would look\n * like a network problem. Refusing loudly names the file and lets the owner\n * decide, which is the only honest option when the alternative is\n * destroying something unrecoverable.\n */\n async load(now: number): Promise<StoredKeys> {\n if (this.#keys) return this.#keys;\n\n let raw: string;\n try {\n raw = await readFile(this.#path, \"utf8\");\n } catch (error) {\n if (!isNotFound(error)) throw error;\n return this.#create(now);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `${this.#path} is not valid JSON. This file is this machine's ` +\n `identity; delete it only if you accept re-pairing every app.`,\n { cause: error },\n );\n }\n\n const result = StoredKeys.safeParse(parsed);\n if (!result.success) {\n throw new Error(\n `${this.#path} is not a valid key file. This file is this machine's ` +\n `identity; delete it only if you accept re-pairing every app.`,\n );\n }\n\n await this.#warnIfReadable();\n this.#keys = result.data;\n return result.data;\n }\n\n /** The public half, for pairing and the handshake. */\n async publicIdentity(now: number): Promise<PublicIdentity> {\n return publicIdentityOf(await this.load(now));\n }\n\n /** What the owner compares out of band. */\n async fingerprint(now: number): Promise<string> {\n return fingerprint((await this.load(now)).identityPublic);\n }\n\n /** Sign a challenge nonce. */\n async sign(data: Uint8Array, now: number): Promise<string> {\n return signWith(await this.load(now), data);\n }\n\n /** Sign one outgoing protocol request (byollm_009 §4.2). */\n async signRequest(input: {\n endpoint: string;\n runnerId: string;\n issuedAt: number;\n body: string;\n }): Promise<string> {\n return signRequest(await this.load(input.issuedAt), input).signature;\n }\n\n async #create(now: number): Promise<StoredKeys> {\n const keys = generateKeys(now);\n await mkdir(dirname(this.#path), { recursive: true });\n // `wx` so two daemons racing at first start cannot each believe they\n // created the identity — the loser reads what the winner wrote rather\n // than overwriting a key the other has already begun pairing with.\n try {\n await writeFile(this.#path, JSON.stringify(keys, null, 2), {\n mode: 0o600,\n flag: \"wx\",\n });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n return this.load(now);\n }\n throw error;\n }\n this.#keys = keys;\n return keys;\n }\n\n /**\n * Say something if the key file is group- or world-readable.\n *\n * We write `0600`, but a restore from backup, a careless `chmod -R`, or a\n * synced folder can widen it afterwards. Tightening it silently would hide\n * that something else on this machine is treating the file as ordinary\n * data, which is worth knowing.\n *\n * **Windows is exempt, because the check would lie.** Node's `mode` there\n * is synthesized — a writable file reports `0o666` regardless of what was\n * passed to `writeFile`, and `chmod` only toggles the read-only flag. So on\n * Windows this would warn on every start and claim to fix something it had\n * not fixed. The honest position is in `docs/security.md` §3.4: on Windows\n * the key file is protected by the ACLs it inherits from the user profile,\n * not by a mode we set.\n */\n async #warnIfReadable(): Promise<void> {\n if (process.platform === \"win32\") return;\n try {\n const mode = (await stat(this.#path)).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n process.stderr.write(\n `warning: ${this.#path} is mode ${mode.toString(8)} — this machine's\\n` +\n `private key is readable by other users. Fixing to 0600.\\n`,\n );\n await chmod(this.#path, 0o600);\n }\n } catch {\n // A stat failure must not stop a daemon from starting.\n }\n }\n}\n\nfunction isNotFound(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === \"ENOENT\";\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { PublicIdentity } from \"@byollm/protocol\";\nimport { z } from \"zod\";\nimport { normalizeOrigin } from \"./allowlist.js\";\n\n/**\n * One paired server.\n *\n * A daemon may pair with several apps; each pairing is a separate identity\n * with its own token and its own owner. Nothing is shared between them —\n * `owner` from one server means nothing on another\n * ({@link MUSTS.PAIR_ONE_USER}).\n */\nexport const Pairing = z\n .object({\n origin: z.string().min(1),\n runnerId: z.string().min(1),\n /** Bearer token. This file is written 0600 for exactly this reason. */\n token: z.string().min(1),\n /** The app's id for this daemon's owner. */\n owner: z.string().min(1),\n ownerLabel: z.string().optional(),\n /**\n * The site's public keys, pinned at pairing (byollm_009 §5).\n *\n * Pinned rather than fetched: a key re-fetched on each connection is a\n * key an upstream can change, which is the whole thing pinning prevents.\n * The owner can compare `sitePin`'s fingerprint against what the site\n * displays.\n */\n site: PublicIdentity,\n pairedAt: z.number().int().positive(),\n })\n .strict();\nexport type Pairing = z.infer<typeof Pairing>;\n\nconst PairingFile = z\n .object({ version: z.literal(1), pairings: z.array(Pairing) })\n .strict();\n\n/** The daemon's paired servers, on disk. */\nexport class Pairings {\n readonly #path: string;\n #pairings: Pairing[] = [];\n #loaded = false;\n\n constructor(path: string) {\n this.#path = path;\n }\n\n async load(): Promise<void> {\n try {\n const parsed = PairingFile.safeParse(\n JSON.parse(await readFile(this.#path, \"utf8\")),\n );\n this.#pairings = parsed.success ? parsed.data.pairings : [];\n } catch {\n this.#pairings = [];\n }\n this.#loaded = true;\n }\n\n list(): readonly Pairing[] {\n this.#assertLoaded();\n return [...this.#pairings];\n }\n\n get(origin: string): Pairing | undefined {\n this.#assertLoaded();\n const normalized = normalizeOrigin(origin);\n return this.#pairings.find(\n (pairing) => normalizeOrigin(pairing.origin) === normalized,\n );\n }\n\n /** Add or replace the pairing for an origin. Re-pairing supersedes. */\n async put(pairing: Pairing): Promise<void> {\n this.#assertLoaded();\n const normalized = normalizeOrigin(pairing.origin);\n this.#pairings = this.#pairings.filter(\n (existing) => normalizeOrigin(existing.origin) !== normalized,\n );\n this.#pairings.push({ ...pairing, origin: normalized });\n await this.#save();\n }\n\n /** Forget a pairing. Returns whether one was removed. */\n async remove(origin: string): Promise<boolean> {\n this.#assertLoaded();\n const normalized = normalizeOrigin(origin);\n const before = this.#pairings.length;\n this.#pairings = this.#pairings.filter(\n (pairing) => normalizeOrigin(pairing.origin) !== normalized,\n );\n if (this.#pairings.length === before) return false;\n await this.#save();\n return true;\n }\n\n #assertLoaded(): void {\n if (!this.#loaded) throw new Error(\"pairings used before load()\");\n }\n\n async #save(): Promise<void> {\n await mkdir(dirname(this.#path), { recursive: true });\n await writeFile(\n this.#path,\n `${JSON.stringify({ version: 1, pairings: this.#pairings }, null, 2)}\\n`,\n // Tokens live here. Nobody else on a shared machine gets to read them.\n { mode: 0o600 },\n );\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { z } from \"zod\";\n\nconst SpendFile = z\n .object({\n version: z.literal(1),\n /** Per backend key: epoch-ms timestamps and the cents charged. */\n entries: z.record(\n z.string(),\n z.array(\n z.object({ at: z.number().int().positive(), cents: z.number().min(0) }),\n ),\n ),\n })\n .strict();\n\n/**\n * What the owner has spent running other people's work on a metered backend.\n *\n * byollm_007 §4: a widened metered backend must carry a ceiling and stop at\n * it. A ceiling nobody counts against is a comment, so this is the counting.\n *\n * **On accuracy, honestly.** Providers do not return a price, so this\n * estimates from token counts and an owner-supplied rate. It will not match an\n * invoice to the cent. It does not need to: its job is to stop a runaway, and\n * for that a defensible over-estimate is worth more than a precise number\n * arriving too late. The ceiling is a brake, not an accountant.\n */\nexport class SpendLedger {\n readonly #path: string;\n #entries: Record<string, { at: number; cents: number }[]> = {};\n #loaded = false;\n\n constructor(path: string) {\n this.#path = path;\n }\n\n async load(now: number): Promise<void> {\n try {\n const parsed = SpendFile.safeParse(\n JSON.parse(await readFile(this.#path, \"utf8\")),\n );\n this.#entries = parsed.success ? parsed.data.entries : {};\n } catch {\n // A corrupt ledger reads as \"spent nothing\", which would be the unsafe\n // direction — so callers treat a missing ledger as ceiling-reached\n // until it loads cleanly. See `hasReachedCeiling`.\n this.#entries = {};\n }\n this.#prune(now);\n this.#loaded = true;\n }\n\n /** Cents spent on community work for this backend in the last 24 hours. */\n spentTodayCents(backendKey: string, now: number): number {\n this.#assertLoaded();\n const since = now - 86_400_000;\n return (this.#entries[backendKey] ?? [])\n .filter((e) => e.at >= since)\n .reduce((sum, e) => sum + e.cents, 0);\n }\n\n /**\n * Has this backend spent its daily ceiling?\n *\n * A backend with no ceiling reads as reached — not as unlimited. That is\n * the safe direction and it matches the config rule: sharing without a\n * ceiling is refused at load, so reaching this state means something is\n * inconsistent and the brake should be on.\n */\n hasReachedCeiling(\n backendKey: string,\n capCents: number | undefined,\n now: number,\n ): boolean {\n if (capCents === undefined) return true;\n return this.spentTodayCents(backendKey, now) >= capCents;\n }\n\n /** Record an estimated charge for community work. */\n async record(backendKey: string, cents: number, now: number): Promise<void> {\n this.#assertLoaded();\n (this.#entries[backendKey] ??= []).push({ at: now, cents });\n this.#prune(now);\n await mkdir(dirname(this.#path), { recursive: true });\n await writeFile(\n this.#path,\n JSON.stringify({ version: 1, entries: this.#entries }),\n { mode: 0o600 },\n );\n }\n\n /** Everything spent per backend today, for `byollm status`. */\n summary(now: number): Record<string, number> {\n this.#assertLoaded();\n const out: Record<string, number> = {};\n for (const key of Object.keys(this.#entries)) {\n out[key] = this.spentTodayCents(key, now);\n }\n return out;\n }\n\n #assertLoaded(): void {\n if (!this.#loaded) throw new Error(\"spend ledger used before load()\");\n }\n\n /** Anything older than a day can never affect the window again. */\n #prune(now: number): void {\n const cutoff = now - 86_400_000;\n const pruned: Record<string, { at: number; cents: number }[]> = {};\n for (const [key, entries] of Object.entries(this.#entries)) {\n const kept = entries.filter((e) => e.at >= cutoff);\n if (kept.length > 0) pruned[key] = kept;\n }\n this.#entries = pruned;\n }\n}\n\n/**\n * Estimate the cost of a call in cents.\n *\n * Deliberately crude and deliberately generous: characters over four is a\n * rough token count, and the rate is whatever the owner said. Over-estimating\n * trips the brake early, which is the failure everyone prefers.\n */\nexport function estimateCents(\n promptChars: number,\n outputChars: number,\n centsPerMillionTokens: number,\n): number {\n const tokens = (promptChars + outputChars) / 4;\n return (tokens / 1_000_000) * centsPerMillionTokens;\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Where the daemon keeps its state.\n *\n * One directory the owner can `ls`, `cat` and delete. The trust surface is\n * the product (byollm_002), and a trust surface you cannot find is not one.\n */\nexport interface DaemonPaths {\n /** `~/.byollm` — everything below lives here. */\n readonly root: string;\n /** Job routing and backend configuration, owner-authored. */\n readonly config: string;\n /** Paired servers: origin, runner id, token, owner. */\n readonly pairings: string;\n /** The local `named` allowlist — one file, every app. */\n readonly allowlist: string;\n /** Append-only JSONL: every prompt that has run on this machine. */\n readonly ingressLog: string;\n /** Community-job counters, for rate limits and the daily cap. */\n readonly budgets: string;\n /** Estimated money spent running other people's work on metered backends. */\n readonly spend: string;\n /**\n * This machine's device keypairs (byollm_009 §3). The most sensitive file\n * the daemon writes: it is the machine's identity, not a token a server can\n * revoke and reissue.\n */\n readonly keys: string;\n /** Set while the owner has the daemon paused. */\n readonly pauseFlag: string;\n /**\n * Per-job scratch directories. A process-class backend runs with its `cwd`\n * set to an empty one of these and nothing else (byollm_004 §2).\n */\n readonly scratch: string;\n}\n\n/** Resolve the daemon's paths, rooted at `~/.byollm` unless overridden. */\nexport function daemonPaths(root = defaultRoot()): DaemonPaths {\n return {\n root,\n config: join(root, \"config.json\"),\n pairings: join(root, \"pairings.json\"),\n allowlist: join(root, \"allow.json\"),\n ingressLog: join(root, \"ingress.log\"),\n budgets: join(root, \"budgets.json\"),\n spend: join(root, \"spend.json\"),\n keys: join(root, \"keys.json\"),\n pauseFlag: join(root, \"paused\"),\n scratch: join(root, \"scratch\"),\n };\n}\n\n/**\n * `BYOLLM_HOME` exists so the conformance kit and the adversarial suite can\n * run real daemons without touching the developer's own `~/.byollm`.\n */\nexport function defaultRoot(): string {\n return process.env[\"BYOLLM_HOME\"] ?? join(homedir(), \".byollm\");\n}\n","import {\n ENVELOPE_MAX_AGE_MS,\n keyId,\n open,\n publicIdentityOf,\n seal,\n sizeClassCeiling,\n type ClaimedStub,\n type JobPayload,\n type PublicIdentity,\n type SealedEnvelope,\n type StoredKeys,\n REFUSAL_MESSAGES,\n matchAudience,\n type Capability,\n type ClaimedJob,\n type JobOutcome,\n} from \"@byollm/protocol\";\nimport type { Allowlist } from \"./allowlist.js\";\nimport { createBackend, type Backend } from \"./backends/index.js\";\nimport type { Budgets } from \"./budgets.js\";\nimport { ClientError, type ProtocolClient } from \"./client.js\";\nimport { composePrompt } from \"./compose.js\";\nimport type { LoadedConfig, ResolvedRoute } from \"./config.js\";\nimport type { IngressLog } from \"./ingress.js\";\nimport { estimateCents, type SpendLedger } from \"./spend.js\";\n\n/** What the daemon is currently doing, for `byollm status`. */\nexport interface RunnerStatus {\n readonly origin: string;\n readonly owner: string;\n readonly runnerId: string;\n readonly paused: boolean;\n readonly revoked: boolean;\n readonly activeJobs: number;\n readonly capabilities: readonly Capability[];\n /** Set when the last server contact failed — one of the four truths. */\n readonly lastError?: string;\n readonly completed: number;\n readonly refused: number;\n}\n\nexport interface RunnerOptions {\n readonly client: ProtocolClient;\n readonly runnerId: string;\n readonly owner: string;\n readonly daemonVersion: string;\n readonly loaded: LoadedConfig;\n readonly allowlist: Allowlist;\n readonly budgets: Budgets;\n /** Tracks money spent on other people's work, for metered backends. */\n readonly spend: SpendLedger;\n readonly ingress: IngressLog;\n /**\n * How this daemon opens work sealed to it, and what it checks it against.\n *\n * `sitePinned` is the identity taken at pairing (byollm_009 §5). Verifying\n * against it — rather than against anything the envelope claims — is what\n * makes a relay unable to substitute work: it can produce an envelope this\n * machine can open, but not one signed by the site.\n */\n readonly identity?: {\n keys(): Promise<StoredKeys>;\n readonly sitePinned: PublicIdentity;\n };\n /** Heartbeat cadence before jitter. */\n readonly heartbeatMs?: number;\n readonly now?: () => number;\n /** Notified on every state change, so the CLI can render progress. */\n readonly onEvent?: (event: RunnerEvent) => void;\n /** Injectable backend factory, so tests need no real model server. */\n readonly backendFactory?: (route: ResolvedRoute) => Backend;\n}\n\nexport type RunnerEvent =\n | { readonly type: \"heartbeat\"; readonly capabilities: number }\n | { readonly type: \"claimed\"; readonly jobId: string; readonly kind: string }\n | {\n readonly type: \"refused\";\n readonly jobId: string;\n readonly reason: string;\n }\n | {\n readonly type: \"finished\";\n readonly jobId: string;\n readonly outcome: string;\n readonly durationMs: number;\n }\n | { readonly type: \"revoked\" }\n | { readonly type: \"error\"; readonly message: string };\n\nconst DEFAULT_HEARTBEAT_MS = 10_000;\n\n/**\n * The daemon's loop: heartbeat, claim, execute, report.\n *\n * Everything that makes the daemon a *trust anchor* rather than a worker\n * happens in {@link Runner.admit} and {@link Runner.runJob} — the local\n * audience check, the budget check, and the ingress write that precedes\n * execution. The loop itself is deliberately dull.\n */\nexport class Runner {\n readonly #options: RunnerOptions;\n readonly #backends = new Map<string, Backend>();\n /**\n * Jobs in flight, by job id → the grant and how to stop it.\n *\n * The lease id is kept because every lease-scoped call has to name the\n * grant it means: a release that names only the job releases whatever\n * lease exists when it arrives, which for a replayed request is not the\n * one this daemon meant (byollm_009 §4.2, `Lease.id`).\n */\n readonly #active = new Map<\n string,\n { controller: AbortController; leaseId: string }\n >();\n readonly #now: () => number;\n #capabilities: Capability[] = [];\n #paused = false;\n #revoked = false;\n #stopped = false;\n #lastError: string | undefined;\n #completed = 0;\n #refused = 0;\n\n constructor(options: RunnerOptions) {\n this.#options = options;\n this.#now = options.now ?? Date.now;\n }\n\n status(): RunnerStatus {\n return {\n origin: this.#options.client.origin,\n owner: this.#options.owner,\n runnerId: this.#options.runnerId,\n paused: this.#paused,\n revoked: this.#revoked,\n activeJobs: this.#active.size,\n capabilities: [...this.#capabilities],\n ...(this.#lastError === undefined ? {} : { lastError: this.#lastError }),\n completed: this.#completed,\n refused: this.#refused,\n };\n }\n\n pause(): void {\n this.#paused = true;\n }\n\n resume(): void {\n this.#paused = false;\n }\n\n /**\n * Build the capability matrix: owner config intersected with what is\n * actually reachable and healthy right now\n * ({@link MUSTS.CAPABILITY_IS_DETECTED}).\n *\n * A configured route whose backend is down simply does not appear. The\n * daemon then receives no work for it, which is the correct outcome and one\n * the owner can see in `byollm status`.\n */\n async detectCapabilities(): Promise<Capability[]> {\n const capabilities: Capability[] = [];\n\n for (const route of this.#options.loaded.routes) {\n const backend = this.#backendFor(route);\n const health = await backend.health();\n if (!health.healthy) continue;\n\n // If the backend enumerates its models, honour that: advertising a\n // model the server does not have would be advertising a lie.\n if (\n health.models.length > 0 &&\n !modelPresent(health.models, route.model)\n ) {\n continue;\n }\n\n capabilities.push({\n kind: route.kind,\n backendId: route.backendId,\n backendClass: route.backendClass,\n model: route.model,\n offerScope: route.offerScope,\n });\n }\n\n this.#capabilities = capabilities;\n return capabilities;\n }\n\n #backendFor(route: ResolvedRoute): Backend {\n const key = `${route.backendKey}:${route.backendId}`;\n let backend = this.#backends.get(key);\n if (!backend) {\n backend =\n this.#options.backendFactory?.(route) ??\n createBackend(route.backendId, {\n baseUrl: route.baseUrl,\n apiKeyEnv: route.apiKeyEnv,\n });\n this.#backends.set(key, backend);\n }\n return backend;\n }\n\n /**\n * Has this route spent the owner's daily ceiling on other people's work?\n *\n * Only meaningful for `metered` routes; `free` and `subscription` never\n * reach here in a way that matters, because the matcher refuses them for\n * other reasons first ({@link MUSTS.METERED_REQUIRES_CEILING}).\n */\n #spendCeilingReached(route: ResolvedRoute): boolean {\n if (route.cost !== \"metered\") return false;\n return this.#options.spend.hasReachedCeiling(\n route.backendKey,\n route.spendDailyCapCents,\n this.#now(),\n );\n }\n\n #routeFor(kind: string): ResolvedRoute | undefined {\n return this.#options.loaded.routes.find((route) => route.kind === kind);\n }\n\n /**\n * Decide whether this machine will run a claimed job.\n *\n * The server already applied its own version of the audience rules, and\n * that is not what this checks. This is the daemon enforcing against the\n * server: the local `named` allowlist\n * ({@link MUSTS.NAMED_LOCAL_ALLOWLIST}), the subscription self-lock, and\n * the owner's community budgets. A job that fails here is released with\n * reason `refused`, which the server remembers so it is never offered back.\n */\n admit(job: ClaimedStub): { ok: true } | { ok: false; reason: string } {\n const route = this.#routeFor(job.kind);\n if (!route) {\n // An unknown or unrouted kind is refused, never guessed\n // ({@link MUSTS.KIND_TYPED_ONLY}).\n return { ok: false, reason: REFUSAL_MESSAGES[\"no-capability\"] };\n }\n\n const match = matchAudience(\n {\n owner: job.owner,\n audience: job.audience,\n audienceAllow: job.audienceAllow,\n },\n {\n owner: this.#options.owner,\n offerScope: route.offerScope,\n cost: route.cost,\n spend: {\n acknowledged: route.spendAcknowledged,\n ceilingReached: this.#spendCeilingReached(route),\n },\n // The daemon's own list — the whole point of Rev 1 §B.\n locallyAllows: this.#options.allowlist.predicateFor(\n this.#options.client.origin,\n ),\n },\n );\n if (!match.ok) {\n return { ok: false, reason: REFUSAL_MESSAGES[match.refusal] };\n }\n\n if (job.owner !== this.#options.owner) {\n // From the stub's bucket, because admission happens before the payload\n // is fetched. The ceiling is charged rather than a midpoint: refusing\n // slightly too eagerly is the safe direction for someone else's work on\n // the owner's machine.\n const decision = this.#options.budgets.check(\n this.#now(),\n sizeClassCeiling(job.sizeClass),\n );\n if (!decision.ok) return { ok: false, reason: decision.detail };\n }\n\n return { ok: true };\n }\n\n /**\n * Execute one admitted job.\n *\n * Order is load-bearing: the ingress write is awaited *before* the backend\n * is touched ({@link MUSTS.INGRESS_LOGGED_BEFORE_EXECUTION}), so a job that\n * hangs the machine still leaves a record of what it was.\n */\n async runJob(job: ClaimedJob): Promise<JobOutcome> {\n const route = this.#routeFor(job.kind);\n if (!route) {\n return {\n outcome: \"error\",\n code: \"no-capability\",\n message: \"this machine has no route for that job kind\",\n retryable: false,\n };\n }\n\n const controller = new AbortController();\n this.#active.set(job.id, { controller, leaseId: job.lease.id });\n\n const prompt = composePrompt(job);\n const community = job.owner !== this.#options.owner;\n const limits = this.#options.loaded.config;\n\n await this.#options.ingress.recordPrompt({\n at: this.#now(),\n origin: this.#options.client.origin,\n jobId: job.id,\n kind: job.kind,\n audience: job.audience,\n owner: job.owner,\n backendId: route.backendId,\n backendClass: route.backendClass,\n model: route.model,\n prompt,\n });\n\n if (community) await this.#options.budgets.record(this.#now());\n\n try {\n const backend = this.#backendFor(route);\n const result = await backend.execute({\n prompt,\n model: route.model,\n // Community jobs run under the owner's tighter ceiling.\n timeoutMs: community\n ? Math.min(\n limits.community.maxWallClockMs,\n limits.limits.maxWallClockMs,\n )\n : limits.limits.maxWallClockMs,\n maxOutputBytes: community\n ? Math.min(\n limits.community.maxOutputBytes,\n limits.limits.maxOutputBytes,\n )\n : limits.limits.maxOutputBytes,\n signal: controller.signal,\n });\n\n const outcome: JobOutcome = result.ok\n ? { outcome: \"ok\", text: result.text }\n : result.code === \"canceled\"\n ? { outcome: \"canceled\" }\n : {\n outcome: \"error\",\n code: result.code,\n message: result.message,\n retryable: result.retryable,\n };\n\n await this.#options.ingress.recordOutcome({\n at: this.#now(),\n jobId: job.id,\n outcome: outcome.outcome,\n durationMs: result.durationMs,\n outputChars: result.ok ? result.text.length : 0,\n ...(result.ok ? {} : { detail: result.message }),\n });\n\n // Community work on a metered backend spends the owner's money, so it\n // goes on the ledger the ceiling is checked against. Own work is not\n // counted: their machine, their key, their call.\n if (community && route.cost === \"metered\") {\n await this.#options.spend.record(\n route.backendKey,\n estimateCents(\n prompt.length,\n result.ok ? result.text.length : 0,\n route.spendCentsPerMillionTokens,\n ),\n this.#now(),\n );\n }\n\n this.#completed += 1;\n this.#options.onEvent?.({\n type: \"finished\",\n jobId: job.id,\n outcome: outcome.outcome,\n durationMs: result.durationMs,\n });\n return outcome;\n } finally {\n this.#active.delete(job.id);\n }\n }\n\n /** Abort a job's in-flight backend call ({@link MUSTS.CANCEL_HONORED}). */\n cancelJob(jobId: string): void {\n this.#active.get(jobId)?.controller.abort();\n }\n\n /** Abort everything — revocation, or shutdown. */\n cancelAll(): void {\n for (const { controller } of this.#active.values()) controller.abort();\n }\n\n /**\n * Run until stopped.\n *\n * Resumable and idempotent by job id: a daemon that dies mid-job loses\n * nothing, because the server reclaims the lease and offers the job again.\n */\n async run(signal: AbortSignal): Promise<void> {\n const heartbeatMs = this.#options.heartbeatMs ?? DEFAULT_HEARTBEAT_MS;\n\n while (!signal.aborted && !this.#stopped) {\n try {\n await this.tick();\n this.#lastError = undefined;\n } catch (error) {\n this.#lastError =\n error instanceof Error ? error.message : \"unknown error\";\n this.#options.onEvent?.({\n type: \"error\",\n message: this.#lastError,\n });\n if (error instanceof ClientError && error.kind === \"revoked\") {\n this.#revoked = true;\n this.cancelAll();\n this.#options.onEvent?.({ type: \"revoked\" });\n return;\n }\n const backoff =\n error instanceof ClientError && error.retryAfter !== undefined\n ? error.retryAfter * 1000\n : heartbeatMs;\n await sleep(backoff, signal);\n continue;\n }\n // Jitter so a fleet of daemons does not synchronise into a thundering\n // herd against one server.\n await sleep(heartbeatMs * (0.85 + Math.random() * 0.3), signal);\n }\n }\n\n /** One heartbeat-and-claim cycle. Exposed so tests can step deterministically. */\n async tick(): Promise<void> {\n const capabilities = await this.detectCapabilities();\n\n const heartbeat = await this.#options.client.heartbeat({\n runnerId: this.#options.runnerId,\n daemonVersion: this.#options.daemonVersion,\n capabilities,\n activeLeases: [...this.#active.entries()].map(([jobId, held]) => ({\n jobId,\n leaseId: held.leaseId,\n })),\n paused: this.#paused,\n });\n this.#options.onEvent?.({\n type: \"heartbeat\",\n capabilities: capabilities.length,\n });\n\n if (heartbeat.revoked) {\n this.#revoked = true;\n this.cancelAll();\n this.#options.onEvent?.({ type: \"revoked\" });\n this.#stopped = true;\n return;\n }\n\n // A job the server says we lost must be abandoned, not finished\n // ({@link MUSTS.LEASE_HONORED}).\n for (const jobId of heartbeat.lost) this.cancelJob(jobId);\n for (const jobId of heartbeat.cancel) this.cancelJob(jobId);\n\n if (this.#paused || capabilities.length === 0) return;\n\n const free = this.#options.loaded.config.concurrency - this.#active.size;\n if (free <= 0) return;\n\n const { jobs } = await this.#options.client.claim({\n runnerId: this.#options.runnerId,\n capabilities,\n max: free,\n });\n\n // Not awaited: claimed jobs run concurrently up to the owner's limit, and\n // the loop keeps heartbeating so their leases stay alive.\n //\n // The `catch` is load-bearing. Without it, a failure in the background\n // handler — an ingress write that cannot land because the disk is full or\n // the state directory has gone — becomes an unhandled rejection and takes\n // the whole daemon down. The lease lapses instead and the server offers\n // the job again, which is the recovery the protocol is built around.\n for (const job of jobs) {\n void this.#handle(job).catch((error: unknown) => {\n this.#lastError =\n error instanceof Error ? error.message : \"unknown error\";\n this.#options.onEvent?.({ type: \"error\", message: this.#lastError });\n });\n }\n }\n\n async #handle(job: ClaimedStub): Promise<void> {\n this.#options.onEvent?.({\n type: \"claimed\",\n jobId: job.id,\n kind: job.kind,\n });\n\n const admission = this.admit(job);\n if (!admission.ok) {\n this.#refused += 1;\n await this.#options.ingress.recordOutcome({\n at: this.#now(),\n jobId: job.id,\n outcome: \"refused\",\n detail: admission.reason,\n });\n this.#options.onEvent?.({\n type: \"refused\",\n jobId: job.id,\n reason: admission.reason,\n });\n await this.#safely(() =>\n this.#options.client.release({\n runnerId: this.#options.runnerId,\n leases: [{ jobId: job.id, leaseId: job.lease.id }],\n reason: \"refused\",\n }),\n );\n return;\n }\n\n // Only now, after this daemon has decided it will run the work, does the\n // payload arrive (byollm_009 §6). A daemon that declines on its own\n // allowlist never receives the prompt at all — which was not true when\n // the payload rode along with the claim.\n const fetched = await this.#fetchWhenSealed(job);\n if (!fetched) return;\n const payload = await this.#openPayload(job, fetched.envelope);\n\n const route = this.#routeFor(job.kind);\n const outcome = await this.runJob({ ...job, payload });\n\n const envelope = await this.#sealOutcome(job, outcome);\n\n await this.#safely(() =>\n this.#options.client.result({\n runnerId: this.#options.runnerId,\n jobId: job.id,\n envelope,\n disposition: outcome.outcome,\n model: route?.model ?? \"unknown\",\n backendClass: route?.backendClass ?? \"http\",\n durationMs: 0,\n }),\n );\n }\n\n /**\n * Seal a finished outcome back to the site that sent the work.\n *\n * The return leg of {@link ByollmRunner.#openPayload}, and it exists for the\n * same reason: an answer is as sensitive as the prompt that produced it. A\n * relay that is denied one and handed the other has been denied nothing.\n *\n * The signature also does work the payload leg does not need. `RESULT_\n * PROVENANCE` says a result is attributable to a device; until now that\n * rested on the request signature, which covers the request and expires with\n * it. This binds the *outcome itself* to the device's key, so what the app\n * eventually reads carries its own proof of who produced it.\n */\n async #sealOutcome(\n job: ClaimedStub,\n outcome: JobOutcome,\n ): Promise<SealedEnvelope> {\n const identity = this.#options.identity;\n if (!identity) {\n // Unreachable in practice, and the reason is load-bearing: `#openPayload`\n // makes the same check before any work runs, so a keyless daemon fails\n // there — having spent nothing — rather than here, having spent a whole\n // job and lost the answer. Anything that moves the fetch after execution\n // turns this branch into wasted compute.\n throw new Error(\"this daemon has no keys, so it cannot seal a result\");\n }\n const keys = await identity.keys();\n return seal({\n plaintext: JSON.stringify(outcome),\n senderKeys: keys,\n recipientEncryptionPublic: identity.sitePinned.encryption,\n context: {\n jobId: job.id,\n senderKeyId: keyId(publicIdentityOf(keys).identity),\n recipientKeyId: keyId(identity.sitePinned.identity),\n deadlineAt: Date.now() + ENVELOPE_MAX_AGE_MS,\n direction: \"result\",\n },\n });\n }\n\n /**\n * Collect the payload, waiting if the upstream does not have it yet.\n *\n * On the direct plane this always succeeds first time: the site *is* the\n * upstream, so it seals when asked. Through a relay the two are different\n * parties — the site must be told which device claimed before it can seal to\n * it — and `not-ready` is a normal answer for as long as that takes.\n *\n * Discovered by the skeleton relay, which is the reason it exists: the\n * original claim-then-fetch had no wait here, so the first relayed job was\n * claimed, refused with a 409 the daemon treated as a rejection, and\n * abandoned while still holding a perfectly good lease.\n *\n * Bounded, and by the lease rather than by a retry count: waiting past our\n * own lease means racing whoever gets the job next. Returning `null` gives\n * the job up quietly — the upstream's `awaiting-payload` timer will requeue\n * it, and the stub was never lost.\n */\n async #fetchWhenSealed(\n job: ClaimedStub,\n ): Promise<{ envelope: SealedEnvelope } | null> {\n const deadline = Math.min(job.lease.expiresAt, this.#now() + 30_000);\n let delay = 50;\n for (;;) {\n try {\n return await this.#options.client.fetch({\n runnerId: this.#options.runnerId,\n jobId: job.id,\n leaseId: job.lease.id,\n });\n } catch (error) {\n const notReady =\n error instanceof ClientError && error.kind === \"not-ready\";\n if (!notReady) throw error;\n if (this.#now() + delay >= deadline) {\n this.#options.onEvent?.({\n type: \"error\",\n message: `gave up waiting for the payload of ${job.id}`,\n });\n return null;\n }\n await new Promise((resolve) => setTimeout(resolve, delay));\n // Backs off, but stays responsive: a site that is merely slow should\n // not cost the whole lease, and one that is gone is not worth polling.\n delay = Math.min(delay * 2, 1_000);\n }\n }\n }\n\n /**\n * Open work sealed to this machine, or refuse to run it.\n *\n * A failure here is not a job failure to be reported — it is a claim that\n * the work came from the pinned site, which did not hold. Running it anyway\n * would be running whatever an intermediary supplied, on the owner's\n * hardware and their subscription.\n */\n async #openPayload(\n job: ClaimedStub,\n envelope: SealedEnvelope,\n ): Promise<JobPayload> {\n const identity = this.#options.identity;\n if (!identity) {\n throw new Error(\n \"this daemon has no keys, so it cannot open work sealed to it\",\n );\n }\n const keys = await identity.keys();\n const opened = await open({\n envelope,\n recipientKeys: keys,\n senderIdentityPublic: identity.sitePinned.identity,\n expected: {\n jobId: job.id,\n senderKeyId: keyId(identity.sitePinned.identity),\n recipientKeyId: keyId(publicIdentityOf(keys).identity),\n direction: \"payload\",\n },\n });\n if (!opened.ok) {\n throw new Error(\n `refusing job ${job.id}: its payload did not verify as coming from ` +\n `the app this machine paired with (${opened.reason})`,\n );\n }\n return JSON.parse(opened.plaintext) as JobPayload;\n }\n\n /**\n * Report-and-forget.\n *\n * A failed *report* must not crash the loop or re-run the job: the lease\n * will lapse and the server will offer the work again, which is exactly the\n * recovery the protocol is built around.\n */\n async #safely(action: () => Promise<unknown>): Promise<void> {\n try {\n await action();\n } catch (error) {\n this.#lastError =\n error instanceof Error ? error.message : \"unknown error\";\n }\n }\n\n /** Release everything on shutdown, so nothing waits for a lease to lapse. */\n async shutdown(reason: \"shutdown\" | \"pause\"): Promise<void> {\n this.#stopped = true;\n const leases = [...this.#active.entries()].map(([jobId, held]) => ({\n jobId,\n leaseId: held.leaseId,\n }));\n this.cancelAll();\n if (leases.length === 0) return;\n await this.#safely(() =>\n this.#options.client.release({\n runnerId: this.#options.runnerId,\n leases,\n reason,\n }),\n );\n }\n}\n\n/** Case-insensitive model match that tolerates Ollama's `:latest` suffix. */\nfunction modelPresent(models: readonly string[], wanted: string): boolean {\n const target = wanted.toLowerCase();\n return models.some((model) => {\n const id = model.toLowerCase();\n return (\n id === target || id === `${target}:latest` || `${id}:latest` === target\n );\n });\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n}\n","import {\n BACKEND_IDS,\n backendDescriptor,\n type BackendId,\n} from \"@byollm/protocol\";\nimport { ClaudeCliBackend } from \"./claude-cli.js\";\nimport { OpenAiHttpBackend } from \"./openai-http.js\";\nimport type { Backend, BackendInit } from \"./types.js\";\n\n/**\n * Construct a backend instance.\n *\n * The switch is exhaustive over {@link BackendId}, so adding a backend to the\n * protocol registry without implementing it here is a compile error rather\n * than a runtime surprise — and adding one without adversarial rows fails the\n * suite's coverage check.\n */\nexport function createBackend(id: BackendId, init: BackendInit): Backend {\n // Providers are registry entries, not implementations (byollm_007 §3):\n // every HTTP-class id speaks OpenAI-compatible /v1/chat/completions, so they\n // all share one transport and one adversarial corpus. Adding a provider is a\n // line in the registry, not a new class to review.\n if (backendDescriptor(id).class === \"process\") {\n return new ClaudeCliBackend();\n }\n return new OpenAiHttpBackend(init);\n}\n\n/** Every backend the daemon can construct. */\nexport const IMPLEMENTED_BACKEND_IDS: readonly BackendId[] = BACKEND_IDS;\n\nexport { ClaudeCliBackend, childEnv, claudeArgv } from \"./claude-cli.js\";\nexport { OpenAiHttpBackend } from \"./openai-http.js\";\nexport type {\n Backend,\n BackendErrorCode,\n BackendHealth,\n BackendInit,\n BackendRequest,\n BackendResult,\n} from \"./types.js\";\n","import { execFile, spawn } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { delimiter, join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { BackendClass, BackendId } from \"@byollm/protocol\";\nimport type {\n Backend,\n BackendHealth,\n BackendRequest,\n BackendResult,\n} from \"./types.js\";\n\n/**\n * The exact argv this backend ever runs, minus the model.\n *\n * A frozen literal, not a builder, so there is no code path that appends to\n * it and no mechanism to pass job-supplied arguments\n * ({@link MUSTS.NO_SHELL_INTERPOLATION}). The adversarial suite asserts that\n * every hostile payload it throws produces exactly this argv.\n *\n * - `--print` — non-interactive, answer and exit.\n * - `--output-format text` — plain text, no envelope to misparse.\n * - `--tools \"\"` — the CLI's own switch for *disabling every built-in tool*.\n * byollm_004 §2 requires the model have no tools; this is the flag that\n * delivers it. Verified against the shipped CLI, not assumed.\n * - `--strict-mcp-config` with an empty `--mcp-config` — no MCP servers, and\n * none inherited from the user's own settings.\n * - `--no-session-persistence` — a job leaves no session behind.\n */\nconst FIXED_ARGV = Object.freeze([\n \"--print\",\n \"--output-format\",\n \"text\",\n \"--tools\",\n \"\",\n \"--strict-mcp-config\",\n \"--mcp-config\",\n '{\"mcpServers\":{}}',\n \"--no-session-persistence\",\n]);\n\n/**\n * Environment variables a `claude` child is allowed to see.\n *\n * Everything else is dropped, so a prompt that says \"read your environment\"\n * finds nothing worth having ({@link MUSTS.STRIPPED_CHILD_ENV}).\n *\n * `HOME` is present and that is a deliberate, documented compromise: the CLI\n * reads its subscription credentials from the user's own config directory, so\n * removing `HOME` would remove the authentication this backend exists to use.\n * The honest statement is in `docs/security.md` — the child can reach the\n * filesystem the user can reach, and what stops it doing anything with that\n * is having no tools, not the environment.\n *\n * `ANTHROPIC_API_KEY` is deliberately **absent**: byollm_002 requires that\n * billing cannot silently move from the subscription to a metered key.\n */\nconst ENV_ALLOWLIST = Object.freeze([\n \"PATH\",\n \"HOME\",\n \"LANG\",\n \"LC_ALL\",\n \"TZ\",\n \"TMPDIR\",\n]);\n\n/**\n * The Windows half of the same compromise `HOME` documents above.\n *\n * The CLI stores its subscription credentials under the user's profile, which\n * on Windows is named by `USERPROFILE` / `APPDATA` rather than `HOME`. Without\n * them the child starts and then cannot authenticate — the backend reports\n * healthy and every job fails, which is a worse failure than not starting.\n *\n * `SystemRoot` and `windir` are here because Windows resolves core DLLs\n * (including the socket stack) through them; a child without them fails in\n * ways that look nothing like a missing variable. `TEMP`/`TMP` are the\n * platform's `TMPDIR`, and `PATHEXT` is how Windows resolves an extensionless\n * command name at all.\n *\n * This widens the allowlist on Windows only. The rule byollm_004 §2 states —\n * the child sees an allowlist, never the daemon's environment — is unchanged.\n */\nconst WINDOWS_ENV_ALLOWLIST = Object.freeze([\n \"USERPROFILE\",\n \"APPDATA\",\n \"LOCALAPPDATA\",\n \"TEMP\",\n \"TMP\",\n \"SystemRoot\",\n \"windir\",\n \"PATHEXT\",\n]);\n\n/** Build the child's environment from the allowlist. */\nexport function childEnv(\n source: NodeJS.ProcessEnv = process.env,\n platform: NodeJS.Platform = process.platform,\n): Record<string, string> {\n const allowed =\n platform === \"win32\"\n ? [...ENV_ALLOWLIST, ...WINDOWS_ENV_ALLOWLIST]\n : ENV_ALLOWLIST;\n\n const env: Record<string, string> = {};\n for (const name of allowed) {\n const value = source[name];\n if (value !== undefined) env[name] = value;\n }\n // Signals to the CLI that it is not attached to a terminal, so it never\n // tries to render interactive UI into a pipe.\n env[\"CI\"] = \"1\";\n return env;\n}\n\n/** The argv this backend would run for a given model. Exported for the suite. */\nexport function claudeArgv(model: string): readonly string[] {\n return Object.freeze([...FIXED_ARGV, \"--model\", model]);\n}\n\n/** What to actually execute, and anything that must precede the CLI's own argv. */\nexport interface ClaudeLaunch {\n readonly command: string;\n readonly prefixArgs: readonly string[];\n}\n\n/**\n * Where the `claude` entry point really is on Windows.\n *\n * npm installs `claude` as `claude.cmd` and `claude.ps1` — there is no `.exe`.\n * Node refuses to spawn a `.cmd` without a shell (hardened after\n * CVE-2024-27980), so `spawn(\"claude\")` fails with ENOENT and this backend can\n * never report healthy on Windows.\n *\n * `shell: true` would fix the symptom and breach\n * {@link MUSTS.NO_SHELL_INTERPOLATION}, so it is not on the table. Instead we\n * find the JavaScript the shim would have run and run it under the Node binary\n * already executing this daemon: no shell, and the CLI's own argv is still the\n * frozen literal above, passed through untouched.\n */\nfunction findWindowsEntry(\n binary: string,\n source: NodeJS.ProcessEnv,\n): string | null {\n const dirs = (source[\"PATH\"] ?? \"\").split(delimiter).filter(Boolean);\n\n for (const dir of dirs) {\n // The npm global layout: the shim sits beside the package it launches.\n const direct = join(\n dir,\n \"node_modules\",\n \"@anthropic-ai\",\n \"claude-code\",\n \"cli.js\",\n );\n if (existsSync(direct)) return direct;\n\n // Otherwise read the shim, which names its target script. Cheap, and it\n // survives layouts we have not seen — pnpm and Volta both differ from npm.\n const shim = join(dir, `${binary}.cmd`);\n if (!existsSync(shim)) continue;\n try {\n const match = /\"?([A-Za-z]:\\\\[^\"\\r\\n]*?\\.js|%~dp0[^\"\\r\\n]*?\\.js)\"?/.exec(\n readFileSync(shim, \"utf8\"),\n );\n if (!match?.[1]) continue;\n const target = match[1].replace(/%~dp0\\\\?/i, `${dir}\\\\`);\n if (existsSync(target)) return target;\n } catch {\n // An unreadable shim is not an error worth failing over; try the next\n // directory and let health() report the honest \"not installed\".\n }\n }\n return null;\n}\n\n/**\n * Resolve what to spawn for the CLI on this platform.\n *\n * Everywhere but Windows this is the identity: the binary name, no prefix. The\n * caller's argv is unchanged on every platform, which is what keeps the\n * adversarial suite's argv assertions meaningful.\n */\nconst launchCache = new Map<string, ClaudeLaunch>();\n\n/** Drop the memo, for tests that change PATH between calls. */\nexport function resetClaudeLaunchCache(): void {\n launchCache.clear();\n}\n\nexport function resolveClaudeLaunch(\n binary = \"claude\",\n platform: NodeJS.Platform = process.platform,\n source: NodeJS.ProcessEnv = process.env,\n): ClaudeLaunch {\n // Memoized because this runs on every `health()` and every `execute()`, and\n // on Windows walks each PATH entry with two `existsSync` calls. At the\n // default concurrency that is a synchronous filesystem crawl on the job\n // dispatch path, blocking the event loop while other jobs are in flight.\n //\n // Safe to cache: the answer is a function of the binary name, the platform\n // and PATH, none of which change meaningfully inside one daemon process. A\n // CLI installed while the daemon runs is picked up on restart — the same\n // thing already true of config.\n const key = `${platform}\\u0000${binary}\\u0000${source[\"PATH\"] ?? \"\"}`;\n const cached = launchCache.get(key);\n if (cached) return cached;\n const resolved = resolveUncached(binary, platform, source);\n launchCache.set(key, resolved);\n return resolved;\n}\n\nfunction resolveUncached(\n binary: string,\n platform: NodeJS.Platform,\n source: NodeJS.ProcessEnv,\n): ClaudeLaunch {\n if (platform !== \"win32\") return { command: binary, prefixArgs: [] };\n\n // A JavaScript entry point runs under this Node, wherever it came from. On\n // Unix a `#!/usr/bin/env node` script is executable and spawns directly;\n // Windows has no shebang, so the same file has to be handed to Node\n // explicitly. The adversarial suite's probe is exactly such a script, which\n // is why that suite could not run on Windows at all.\n if (/\\.[cm]?js$/i.test(binary)) {\n return { command: process.execPath, prefixArgs: [binary] };\n }\n\n // A real executable needs no help.\n if (/[\\\\/]/.test(binary) || /\\.(exe|com|bat|cmd)$/i.test(binary)) {\n return { command: binary, prefixArgs: [] };\n }\n\n const entry = findWindowsEntry(binary, source);\n return entry === null\n ? { command: binary, prefixArgs: [] }\n : { command: process.execPath, prefixArgs: [entry] };\n}\n\n/**\n * The process-class backend: the user's own `claude` CLI, on their own\n * subscription.\n *\n * Subscription-class, so its offer scope is locked to `self`\n * ({@link MUSTS.SUBSCRIPTION_SELF_LOCK}) — one account runs one person's work.\n *\n * Every requirement of byollm_004 §2 applies here and is implemented here:\n * fixed argv, prompt on stdin, stripped environment, empty scratch `cwd`, no\n * inherited descriptors beyond the three std streams, hard timeout, hard\n * output cap.\n */\nexport class ClaudeCliBackend implements Backend {\n readonly id: BackendId = \"claude-cli\";\n readonly class: BackendClass = \"process\";\n readonly #binary: string;\n\n /**\n * @param binary - which executable to run. Defaults to `claude` and is\n * **not reachable from configuration**: {@link createBackend} constructs\n * this with no arguments, and {@link BackendInit} has no field for it. It\n * exists so the adversarial suite can substitute a probe that reports the\n * argv, environment, cwd and stdin it actually received — which is the only\n * way to *prove* byollm_004 §2 rather than assert it.\n */\n constructor(binary = \"claude\") {\n this.#binary = binary;\n }\n\n async health(): Promise<BackendHealth> {\n const version = await new Promise<string | null>((resolve) => {\n // execFile, never exec: no shell is involved even for our own fixed\n // arguments (the eslint rule bans the shell-invoking variants outright).\n const launch = resolveClaudeLaunch(this.#binary);\n execFile(\n launch.command,\n [...launch.prefixArgs, \"--version\"],\n { timeout: 10_000, env: childEnv() },\n (error, stdout) => {\n resolve(error ? null : stdout.trim());\n },\n );\n });\n\n if (version === null) {\n return {\n healthy: false,\n models: [],\n detail:\n \"the `claude` CLI is not installed or not on PATH \" +\n \"(https://claude.com/claude-code)\",\n };\n }\n // The CLI does not enumerate models, and inventing a list would breach\n // \"never advertise what isn't real\". The configured model is the claim,\n // and a wrong one surfaces as `model-not-found` on first use.\n return { healthy: true, models: [] };\n }\n\n async execute(request: BackendRequest): Promise<BackendResult> {\n const started = Date.now();\n // An empty directory of our own making. The child's `cwd` is never the\n // daemon's, never the user's home, and never anything a payload named.\n const scratch = await mkdtemp(join(tmpdir(), \"byollm-job-\"));\n\n try {\n return await this.#spawn(request, scratch, started);\n } finally {\n await rm(scratch, { recursive: true, force: true });\n }\n }\n\n async #spawn(\n request: BackendRequest,\n scratch: string,\n started: number,\n ): Promise<BackendResult> {\n return new Promise<BackendResult>((resolve) => {\n // Check before spawning, not only via the listener below: a job\n // cancelled between the claim and this line arrives with its signal\n // already aborted, and `addEventListener(\"abort\")` never fires for a\n // signal that has already fired. Without this the child would spawn and\n // run to completion after the owner had already said stop.\n if (request.signal.aborted) {\n resolve({\n ok: false,\n code: \"canceled\",\n message: \"the job was canceled before it started\",\n retryable: false,\n durationMs: Date.now() - started,\n });\n return;\n }\n\n // The CLI's own argv is `claudeArgv(model)` on every platform. On Windows\n // `prefixArgs` carries the path to the script Node is being asked to run,\n // which is an argument to Node and not to the model's command line.\n const launch = resolveClaudeLaunch(this.#binary);\n const child = spawn(\n launch.command,\n [...launch.prefixArgs, ...claudeArgv(request.model)],\n {\n cwd: scratch,\n env: childEnv(),\n // Exactly the three std streams. Nothing else is inherited, so the\n // child cannot reach a descriptor the daemon happens to hold open.\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n // No shell, ever. With `shell: false` the argv array is passed to\n // execvp verbatim and metacharacters in it are just bytes.\n shell: false,\n detached: false,\n },\n );\n\n let stdout = \"\";\n let stderr = \"\";\n let outputBytes = 0;\n let settled = false;\n let exited = false;\n let reason: \"timeout\" | \"canceled\" | \"output-too-large\" | null = null;\n\n const finish = (result: BackendResult): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n request.signal.removeEventListener(\"abort\", onAbort);\n resolve(result);\n };\n\n const kill = (why: typeof reason): void => {\n reason = why;\n // SIGTERM first, SIGKILL shortly after: a wedged child must not be\n // able to outlive its budget by ignoring the polite signal.\n //\n // The escalation is gated on `exited`, which we set from the `close`\n // event, and NOT on `child.killed` — that flag means \"a signal was\n // sent\", not \"the process died\", so gating on it would mean the\n // SIGKILL never fires against exactly the child that ignores SIGTERM.\n child.kill(\"SIGTERM\");\n setTimeout(() => {\n if (!exited) child.kill(\"SIGKILL\");\n }, 2_000).unref();\n };\n\n const timer = setTimeout(() => {\n kill(\"timeout\");\n }, request.timeoutMs);\n\n const onAbort = (): void => {\n kill(\"canceled\");\n };\n request.signal.addEventListener(\"abort\", onAbort, { once: true });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n outputBytes += chunk.byteLength;\n if (outputBytes > request.maxOutputBytes) {\n kill(\"output-too-large\");\n return;\n }\n stdout += chunk.toString(\"utf8\");\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n // Bounded independently: a chatty stderr must not exhaust memory\n // either, and it is only ever used for a diagnostic message.\n if (stderr.length < 8_192) stderr += chunk.toString(\"utf8\");\n });\n\n child.on(\"error\", (error: Error) => {\n finish({\n ok: false,\n code: \"backend-unreachable\",\n message: `could not start the claude CLI: ${error.message}`,\n retryable: false,\n durationMs: Date.now() - started,\n });\n });\n\n child.on(\"close\", (code) => {\n exited = true;\n const durationMs = Date.now() - started;\n\n if (reason === \"canceled\") {\n finish({\n ok: false,\n code: \"canceled\",\n message: \"the job was canceled\",\n retryable: false,\n durationMs,\n });\n return;\n }\n if (reason === \"timeout\") {\n finish({\n ok: false,\n code: \"timeout\",\n message: `the model did not answer within ${String(request.timeoutMs)}ms`,\n retryable: true,\n durationMs,\n });\n return;\n }\n if (reason === \"output-too-large\") {\n finish({\n ok: false,\n code: \"output-too-large\",\n message: `the model produced more than ${String(request.maxOutputBytes)} bytes`,\n retryable: false,\n durationMs,\n });\n return;\n }\n if (code !== 0) {\n finish({\n ok: false,\n code: \"backend-error\",\n message:\n stderr.trim() === \"\"\n ? `the claude CLI exited with status ${String(code)}`\n : `the claude CLI failed: ${firstLine(stderr)}`,\n retryable: false,\n durationMs,\n });\n return;\n }\n finish({ ok: true, text: stdout, durationMs });\n });\n\n // The prompt goes here and nowhere else: on stdin, as bytes, after the\n // argv is already fixed. This is the line byollm_004 §2 is about.\n child.stdin.on(\"error\", () => {\n // A child that died before reading stdin surfaces through `close`.\n });\n child.stdin.end(request.prompt, \"utf8\");\n });\n }\n}\n\n/** First line of stderr, for a one-line diagnostic. */\nfunction firstLine(text: string): string {\n return text.trim().split(\"\\n\")[0] ?? \"\";\n}\n","import type { BackendClass, BackendId } from \"@byollm/protocol\";\nimport { checkBaseUrl } from \"../ssrf.js\";\nimport type {\n Backend,\n BackendHealth,\n BackendInit,\n BackendRequest,\n BackendResult,\n} from \"./types.js\";\n\n/**\n * The HTTP-class backend: any server speaking OpenAI-compatible\n * `/v1/chat/completions`.\n *\n * One implementation covers Ollama, `mlx_lm.server`, llama.cpp server and\n * vLLM (byollm_001 Rev 1 §A) — the collapse that puts MLX inference in v1.\n *\n * **Why this is the safest class.** It spawns nothing, so byollm_004 §2's\n * argv, stdin, environment and sandbox requirements do not apply *by\n * construction* rather than by discipline. The prompt travels as a JSON\n * string in a request body; there is no command line for it to escape into\n * because there is no command line.\n *\n * What remains is the destination, and that is nailed down: the base URL\n * comes from owner config, is validated once at load and again here, and\n * redirects are refused so a permitted URL cannot become a forbidden one in\n * flight ({@link MUSTS.HTTP_BASE_URL_SAFE}).\n */\nexport class OpenAiHttpBackend implements Backend {\n readonly id: BackendId = \"openai-http\";\n readonly class: BackendClass = \"http\";\n readonly #baseUrl: URL;\n readonly #apiKeyEnv: string | undefined;\n\n constructor(init: BackendInit) {\n if (init.baseUrl === undefined) {\n throw new Error(\"openai-http backend requires a baseUrl\");\n }\n const check = checkBaseUrl(init.baseUrl);\n if (!check.ok) {\n throw new Error(`refusing base URL: ${check.detail}`);\n }\n this.#baseUrl = check.url;\n this.#apiKeyEnv = init.apiKeyEnv;\n }\n\n /**\n * Build a URL under the configured base.\n *\n * The path is a hardcoded literal from this file — never anything derived\n * from a job — and the result is re-checked against the base's origin so a\n * surprising `baseUrl` (say, one with a `..` path) cannot walk elsewhere.\n */\n #endpoint(path: \"chat/completions\" | \"models\"): URL {\n const base = this.#baseUrl.href.endsWith(\"/\")\n ? this.#baseUrl.href\n : `${this.#baseUrl.href}/`;\n const url = new URL(path, base);\n if (url.origin !== this.#baseUrl.origin) {\n throw new Error(\"computed endpoint left the configured origin\");\n }\n return url;\n }\n\n #headers(): Record<string, string> {\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n };\n if (this.#apiKeyEnv !== undefined) {\n const key = process.env[this.#apiKeyEnv];\n if (key !== undefined && key !== \"\") {\n headers[\"authorization\"] = `Bearer ${key}`;\n }\n }\n return headers;\n }\n\n async health(): Promise<BackendHealth> {\n try {\n const response = await fetch(this.#endpoint(\"models\"), {\n method: \"GET\",\n headers: this.#headers(),\n redirect: \"error\",\n signal: AbortSignal.timeout(5_000),\n });\n if (!response.ok) {\n return {\n healthy: false,\n models: [],\n detail: `model list returned HTTP ${String(response.status)}`,\n };\n }\n const body: unknown = await response.json();\n return { healthy: true, models: extractModelIds(body) };\n } catch (error) {\n return {\n healthy: false,\n models: [],\n detail: describeFetchError(error, this.#baseUrl.origin),\n };\n }\n }\n\n async execute(request: BackendRequest): Promise<BackendResult> {\n const started = Date.now();\n // One timeout governs the call whether it stalls before or during the\n // response body — a server that accepts and then dribbles forever must\n // not be able to wedge the machine.\n const timeout = AbortSignal.timeout(request.timeoutMs);\n const signal = AbortSignal.any([request.signal, timeout]);\n\n try {\n const response = await fetch(this.#endpoint(\"chat/completions\"), {\n method: \"POST\",\n headers: this.#headers(),\n // The payload is a JSON string field. Nothing about it is parsed as\n // configuration, and `model` comes from owner config.\n body: JSON.stringify({\n model: request.model,\n messages: [{ role: \"user\", content: request.prompt }],\n stream: false,\n }),\n redirect: \"error\",\n signal,\n });\n\n if (response.status === 401 || response.status === 403) {\n return this.#fail(\n \"unauthorized\",\n \"the model server rejected our credentials\",\n false,\n started,\n );\n }\n if (response.status === 404) {\n return this.#fail(\n \"model-not-found\",\n `the model server does not know \"${request.model}\"`,\n false,\n started,\n );\n }\n if (!response.ok) {\n return this.#fail(\n \"backend-error\",\n `the model server returned HTTP ${String(response.status)}`,\n response.status >= 500,\n started,\n );\n }\n\n const text = await readCapped(response, request.maxOutputBytes, signal);\n if (text === null) {\n // A hostile or broken local model producing unbounded output must not\n // be able to exhaust memory — byollm_004 §5's zip-bomb row.\n return this.#fail(\n \"output-too-large\",\n `the model produced more than ${String(request.maxOutputBytes)} bytes`,\n false,\n started,\n );\n }\n\n const content = extractContent(text);\n if (content === null) {\n return this.#fail(\n \"backend-error\",\n \"the model server's response was not in OpenAI chat-completion shape\",\n false,\n started,\n );\n }\n return { ok: true, text: content, durationMs: Date.now() - started };\n } catch (error) {\n if (request.signal.aborted) {\n return this.#fail(\"canceled\", \"the job was canceled\", false, started);\n }\n if (isAbort(error)) {\n return this.#fail(\n \"timeout\",\n `the model did not answer within ${String(request.timeoutMs)}ms`,\n true,\n started,\n );\n }\n return this.#fail(\n \"backend-unreachable\",\n describeFetchError(error, this.#baseUrl.origin),\n true,\n started,\n );\n }\n }\n\n #fail(\n code: Exclude<BackendResult & { ok: false }, never>[\"code\"],\n message: string,\n retryable: boolean,\n started: number,\n ): BackendResult {\n return {\n ok: false,\n code,\n message,\n retryable,\n durationMs: Date.now() - started,\n };\n }\n}\n\n/**\n * Read a response body, refusing to buffer past `maxBytes`.\n *\n * `response.text()` would happily allocate whatever the server sends. Reading\n * the stream and stopping at the cap is what makes the ceiling real.\n *\n * @returns the text, or null if the cap was exceeded.\n */\nasync function readCapped(\n response: Response,\n maxBytes: number,\n signal: AbortSignal,\n): Promise<string | null> {\n const body = response.body;\n if (body === null) return \"\";\n\n // `getReader()` is typed as `any` chunks under this lib target; the stream\n // is bytes, and saying so is what lets the cap arithmetic below be checked.\n const reader = (body as ReadableStream<Uint8Array>).getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n for (;;) {\n signal.throwIfAborted();\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel();\n return null;\n }\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n return new TextDecoder().decode(concat(chunks, total));\n}\n\nfunction concat(chunks: readonly Uint8Array[], total: number): Uint8Array {\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return out;\n}\n\n/** Pull the assistant text out of an OpenAI chat-completion response. */\nfunction extractContent(raw: string): string | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const choices = (parsed as { choices?: unknown }).choices;\n if (!Array.isArray(choices) || choices.length === 0) return null;\n const message = (choices[0] as { message?: unknown }).message;\n if (typeof message !== \"object\" || message === null) return null;\n const content = (message as { content?: unknown }).content;\n return typeof content === \"string\" ? content : null;\n}\n\n/** Model ids from an OpenAI `/v1/models` response. */\nfunction extractModelIds(body: unknown): string[] {\n if (typeof body !== \"object\" || body === null) return [];\n const data = (body as { data?: unknown }).data;\n if (!Array.isArray(data)) return [];\n return data\n .map((entry) =>\n typeof entry === \"object\" && entry !== null\n ? (entry as { id?: unknown }).id\n : undefined,\n )\n .filter((id): id is string => typeof id === \"string\");\n}\n\nfunction isAbort(error: unknown): boolean {\n return (\n error instanceof Error &&\n (error.name === \"AbortError\" || error.name === \"TimeoutError\")\n );\n}\n\n/**\n * A reachability failure the owner can act on.\n *\n * Deliberately names the origin and not the underlying error text, which for\n * `fetch` is often a bare \"fetch failed\" that tells nobody anything.\n */\nfunction describeFetchError(error: unknown, origin: string): string {\n const cause =\n error instanceof Error && \"cause\" in error && error.cause instanceof Error\n ? error.cause.message\n : error instanceof Error\n ? error.message\n : \"unknown error\";\n return `could not reach the model server at ${origin} (${cause})`;\n}\n","import type { ClaimedJob } from \"@byollm/protocol\";\n\n/**\n * Reduce a job's payload to the single string a backend receives.\n *\n * This is the narrowest point in the daemon: everything upstream deals in a\n * job, everything downstream deals in text and an owner-chosen model. By\n * construction there is nothing left for a payload to influence.\n *\n * **On `system`.** byollm_004 §2 forbids payload text on a command line, and\n * the `claude` CLI's only system-prompt input is the argv flag\n * `--system-prompt` — so a payload's `system` can never be passed that way.\n * It is folded into the stdin text instead, under a plain delimiter. That\n * costs a little role fidelity on process-class backends and is documented\n * rather than papered over; HTTP-class backends could carry the role natively\n * but use the same composition so a job produces identical text on either\n * class, which is what makes results comparable across runners.\n */\nexport function composePrompt(job: ClaimedJob): string {\n if (job.kind === \"llm.generate\") {\n const payload = job.payload as { prompt: string; system?: string };\n return joinSections([systemSection(payload.system), payload.prompt]);\n }\n\n const payload = job.payload as {\n messages: { role: string; content: string }[];\n system?: string;\n };\n const turns = payload.messages\n .map((message) => `${roleLabel(message.role)}: ${message.content}`)\n .join(\"\\n\\n\");\n return joinSections([systemSection(payload.system), turns]);\n}\n\nfunction systemSection(system: string | undefined): string | undefined {\n if (system === undefined || system.trim() === \"\") return undefined;\n return `System instructions:\\n${system}`;\n}\n\nfunction roleLabel(role: string): string {\n switch (role) {\n case \"assistant\":\n return \"Assistant\";\n case \"system\":\n return \"System\";\n default:\n return \"User\";\n }\n}\n\nfunction joinSections(sections: readonly (string | undefined)[]): string {\n return sections.filter((section) => section !== undefined).join(\"\\n\\n\");\n}\n"],"mappings":";AAUA,SAAS,oBAAAA,yBAAwB;;;ACVjC,SAAS,OAAO,UAAU,iBAAiB;AAC3C,SAAS,eAAe;AACxB,SAAS,SAAS;AASX,IAAM,aAAa,EACvB,OAAO;AAAA;AAAA,EAEN,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAExB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEvB,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AACrC,CAAC,EACA,OAAO;AAGV,IAAM,YAAY,EACf,OAAO;AAAA,EACN,SAAS,EAAE,QAAQ,CAAC;AAAA,EACpB,SAAS,EAAE,MAAM,UAAU;AAC7B,CAAC,EACA,OAAO;AAcH,IAAM,YAAN,MAAgB;AAAA,EACZ;AAAA,EACT,WAAyB,CAAC;AAAA,EAC1B,UAAU;AAAA,EAEV,YAAY,MAAc;AACxB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI;AACF,YAAM,MAAM,MAAM,SAAS,KAAK,OAAO,MAAM;AAC7C,YAAM,SAAS,UAAU,UAAU,KAAK,MAAM,GAAG,CAAC;AAIlD,WAAK,WAAW,OAAO,UAAU,OAAO,KAAK,UAAU,CAAC;AAAA,IAC1D,QAAQ;AACN,WAAK,WAAW,CAAC;AAAA,IACnB;AACA,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,gBAAsB;AACpB,QAAI,CAAC,KAAK,SAAS;AACjB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAAA,EACF;AAAA;AAAA,EAGA,OAAO,QAAgB,OAAwB;AAC7C,SAAK,cAAc;AACnB,UAAM,aAAa,gBAAgB,MAAM;AACzC,WAAO,KAAK,SAAS;AAAA,MACnB,CAAC,UACC,gBAAgB,MAAM,MAAM,MAAM,cAAc,MAAM,UAAU;AAAA,IACpE;AAAA,EACF;AAAA;AAAA,EAGA,aAAa,QAA4C;AACvD,WAAO,CAAC,UAAU,KAAK,OAAO,QAAQ,KAAK;AAAA,EAC7C;AAAA,EAEA,OAA8B;AAC5B,SAAK,cAAc;AACnB,WAAO,CAAC,GAAG,KAAK,QAAQ;AAAA,EAC1B;AAAA,EAEA,MAAM,IAAI,OAAoC,KAA4B;AACxE,SAAK,cAAc;AACnB,UAAM,aAAa,gBAAgB,MAAM,MAAM;AAC/C,QAAI,KAAK,OAAO,YAAY,MAAM,KAAK,EAAG;AAC1C,SAAK,SAAS;AAAA,MACZ,WAAW,MAAM,EAAE,GAAG,OAAO,QAAQ,YAAY,SAAS,IAAI,CAAC;AAAA,IACjE;AACA,UAAM,KAAK,MAAM;AAAA,EACnB;AAAA;AAAA,EAGA,MAAM,OAAO,QAAgB,OAAiC;AAC5D,SAAK,cAAc;AACnB,UAAM,aAAa,gBAAgB,MAAM;AACzC,UAAM,SAAS,KAAK,SAAS;AAC7B,SAAK,WAAW,KAAK,SAAS;AAAA,MAC5B,CAAC,UACC,EACE,gBAAgB,MAAM,MAAM,MAAM,cAAc,MAAM,UAAU;AAAA,IAEtE;AACA,QAAI,KAAK,SAAS,WAAW,OAAQ,QAAO;AAC5C,UAAM,KAAK,MAAM;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,MAAM,QAAQ,KAAK,KAAK,GAAG,EAAE,WAAW,KAAK,CAAC;AACpD,UAAM;AAAA,MACJ,KAAK;AAAA,MACL,GAAG,KAAK,UAAU,EAAE,SAAS,GAAG,SAAS,KAAK,SAAS,GAAG,MAAM,CAAC,CAAC;AAAA;AAAA,MAClE,EAAE,MAAM,IAAM;AAAA,IAChB;AAAA,EACF;AACF;AASO,SAAS,gBAAgB,OAAuB;AACrD,MAAI;AACF,WAAO,IAAI,IAAI,KAAK,EAAE;AAAA,EACxB,QAAQ;AACN,WAAO,MAAM,QAAQ,QAAQ,EAAE;AAAA,EACjC;AACF;;;AC7IA,SAAS,SAAAC,QAAO,YAAAC,WAAU,MAAAC,KAAI,QAAAC,OAAM,aAAAC,kBAAiB;AACrD,SAAS,UAAU,gBAAgB;AACnC,SAAS,WAAAC,gBAAe;AACxB,SAAS,uBAAuB;AAChC,SAAS,qBAAAC,oBAAmB,eAAAC,oBAAmB;;;ACJ/C,SAAS,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AAC3C,SAAS,WAAAC,gBAAe;AACxB,SAAS,KAAAC,UAAS;AAGlB,IAAM,aAAaA,GAChB,OAAO;AAAA,EACN,SAASA,GAAE,QAAQ,CAAC;AAAA;AAAA,EAEpB,UAAUA,GAAE,MAAMA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC;AAC/C,CAAC,EACA,OAAO;AAqBH,IAAM,UAAN,MAAc;AAAA,EACV;AAAA,EACA;AAAA,EACT,YAAsB,CAAC;AAAA,EACvB,UAAU;AAAA,EAEV,YAAY,MAAc,QAAyB;AACjD,SAAK,QAAQ;AACb,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,KAAK,KAA4B;AACrC,QAAI;AACF,YAAM,SAAS,WAAW;AAAA,QACxB,KAAK,MAAM,MAAMH,UAAS,KAAK,OAAO,MAAM,CAAC;AAAA,MAC/C;AACA,WAAK,YAAY,OAAO,UAAU,OAAO,KAAK,WAAW,CAAC;AAAA,IAC5D,QAAQ;AACN,WAAK,YAAY,CAAC;AAAA,IACpB;AACA,SAAK,OAAO,GAAG;AACf,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KAAa,cAAsC;AACvD,QAAI,CAAC,KAAK,QAAS,OAAM,IAAI,MAAM,4BAA4B;AAC/D,SAAK,OAAO,GAAG;AAEf,QAAI,eAAe,KAAK,QAAQ,iBAAiB;AAC/C,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,QACE,iCAAiC,OAAO,KAAK,QAAQ,eAAe,CAAC,4BAC1C,OAAO,YAAY,CAAC;AAAA,MACnD;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,YAAY,MAAM,IAAS;AAC7C,QAAI,QAAQ,KAAK,QAAQ,gBAAgB;AACvC,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,QAAQ,eAAe,OAAO,IAAI,CAAC;AAAA,MACrC;AAAA,IACF;AAEA,UAAM,MAAM,KAAK,YAAY,MAAM,KAAU;AAC7C,QAAI,OAAO,KAAK,QAAQ,eAAe;AACrC,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,QAAQ,eAAe,OAAO,GAAG,CAAC;AAAA,MACpC;AAAA,IACF;AACA,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB;AAAA;AAAA,EAGA,MAAM,OAAO,KAA4B;AACvC,SAAK,UAAU,KAAK,GAAG;AACvB,SAAK,OAAO,GAAG;AACf,UAAMD,OAAMG,SAAQ,KAAK,KAAK,GAAG,EAAE,WAAW,KAAK,CAAC;AACpD,UAAMD;AAAA,MACJ,KAAK;AAAA,MACL,KAAK,UAAU,EAAE,SAAS,GAAG,UAAU,KAAK,UAAU,CAAC;AAAA,MACvD,EAAE,MAAM,IAAM;AAAA,IAChB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,KAAqE;AACzE,SAAK,OAAO,GAAG;AACf,WAAO;AAAA,MACL,MAAM,KAAK,YAAY,MAAM,IAAS;AAAA,MACtC,KAAK,KAAK,YAAY,MAAM,KAAU;AAAA,MACtC,QAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAAA,EAEA,YAAY,OAAuB;AACjC,WAAO,KAAK,UAAU,OAAO,CAAC,OAAO,MAAM,KAAK,EAAE;AAAA,EACpD;AAAA;AAAA,EAGA,OAAO,KAAmB;AACxB,UAAM,SAAS,MAAM;AACrB,SAAK,YAAY,KAAK,UAAU,OAAO,CAAC,OAAO,MAAM,MAAM;AAAA,EAC7D;AACF;;;AC/HA;AAAA,EAGE;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,OAAuB;AAoChB,IAAM,cAAN,cAA0B,MAAM;AAAA,EAErC,YACW,MACT,SAES,YACT;AACA,UAAM,OAAO;AALJ;AAGA;AAAA,EAGX;AAAA,EANW;AAAA,EAGA;AAAA,EALO,OAAO;AAAA;AAAA,EAWzB,IAAI,YAAqB;AACvB,WACE,KAAK,SAAS,iBACd,KAAK,SAAS,eACd,KAAK,SAAS,kBACd,KAAK,SAAS;AAAA,EAElB;AACF;AA4BA,IAAM,qBAAqB;AAQpB,IAAM,iBAAN,MAAM,gBAAe;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,SAAwB;AAClC,SAAK,UAAU,QAAQ,OAAO,QAAQ,QAAQ,EAAE;AAChD,SAAK,YAAY,QAAQ;AACzB,SAAK,aAAa,QAAQ,aAAa;AACvC,SAAK,SAAS,QAAQ,SAAS,WAAW;AAAA,EAC5C;AAAA;AAAA,EAGA,aACE,UACgB;AAChB,WAAO,IAAI,gBAAe;AAAA,MACxB,QAAQ,KAAK;AAAA,MACb;AAAA,MACA,WAAW,KAAK;AAAA,MAChB,OAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,SAAiB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,UAAU,OAOe;AAC7B,WAAO,KAAK,MAAM,QAAQ,mBAAmB;AAAA,MAC3C,iBAAiB;AAAA,MACjB,QAAQ;AAAA,MACR,QAAQ,MAAM;AAAA,MACd,QAAQ;AAAA,QACN,SAAS,MAAM;AAAA,QACf,OAAO,MAAM;AAAA,QACb,UAAU,MAAM;AAAA,MAClB;AAAA,MACA,cAAc,MAAM;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,SAAS,YAA+C;AAC5D,WAAO,KAAK,MAAM,QAAQ,kBAAkB;AAAA,MAC1C,iBAAiB;AAAA,MACjB,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,MAAM,OAIe;AACzB,WAAO,KAAK,MAAM,SAAS,eAAe;AAAA,MACxC,iBAAiB;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,SAAS,MAAM;AAAA,IACjB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAM,OAIe;AACzB,WAAO,KAAK,MAAM,SAAS,eAAe;AAAA,MACxC,iBAAiB;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,cAAc,MAAM;AAAA,MACpB,KAAK,MAAM;AAAA,IACb,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,UAAU,OAMe;AAC7B,WAAO,KAAK,MAAM,aAAa,mBAAmB;AAAA,MAChD,iBAAiB;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,eAAe,MAAM;AAAA,MACrB,cAAc,MAAM;AAAA,MACpB,cAAc,MAAM;AAAA,MACpB,QAAQ,MAAM;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO,OAQe;AAC1B,WAAO,KAAK,MAAM,UAAU,gBAAgB;AAAA,MAC1C,iBAAiB;AAAA,MACjB,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ,OAIe;AAC3B,WAAO,KAAK,MAAM,WAAW,iBAAiB;AAAA,MAC5C,iBAAiB;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,QAAQ,MAAM;AAAA,MACd,QAAQ,MAAM;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MACJ,UACA,QACA,MACY;AACZ,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV;AAIA,UAAM,UAAU,KAAK,UAAU,IAAI;AACnC,QAAI,KAAK,cAAc,QAAW;AAChC,YAAM,WAAW,KAAK,IAAI;AAC1B,cAAQ,iBAAiB,IAAI,KAAK,UAAU;AAC5C,cAAQ,oBAAoB,IAAI,OAAO,QAAQ;AAC/C,cAAQ,oBAAoB,IAAI,MAAM,KAAK,UAAU,KAAK;AAAA,QACxD;AAAA,QACA,UAAU,KAAK,UAAU;AAAA,QACzB;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,KAAK,OAAO,GAAG,KAAK,OAAO,WAAW,QAAQ,IAAI;AAAA,QACjE,QAAQ;AAAA,QACR;AAAA,QACA,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ,YAAY,QAAQ,KAAK,UAAU;AAAA,MAC7C,CAAC;AAAA,IACH,SAAS,OAAO;AAGd,YAAM,IAAI;AAAA,QACR;AAAA,QACA,mBAAmB,KAAK,OAAO,KAAK,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC9F;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAI;AACJ,QAAI;AACF,eAAS,SAAS,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI;AAAA,IAC7C,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,QACA,GAAG,KAAK,OAAO,kBAAkB,OAAO,SAAS,MAAM,CAAC;AAAA,MAC1D;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,KAAK,SAAS,UAAU,MAAM;AAAA,IACtC;AAEA,UAAM,SAAS,OAAO,UAAU,MAAM;AACtC,QAAI,CAAC,OAAO,SAAS;AAGnB,YAAM,IAAI;AAAA,QACR;AAAA,QACA,GAAG,KAAK,OAAO,eAAe,QAAQ,2CAA2C,gBAAgB;AAAA,MACnG;AAAA,IACF;AACA,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,SAAS,UAAoB,MAA4B;AACvD,UAAM,OAAO,UAAU,UAAU,IAAI;AACrC,UAAM,mBAAmB,SAAS,QAAQ,IAAI,aAAa;AAC3D,UAAM,aACJ,KAAK,WAAW,KAAK,KAAK,eAAe,SACrC,KAAK,KAAK,aACV,qBAAqB,QAAQ,QAAQ,KAAK,gBAAgB,IACxD,OAAO,gBAAgB,IACvB;AAER,UAAM,UAAU,KAAK,UACjB,KAAK,KAAK,UACV,GAAG,KAAK,OAAO,kBAAkB,OAAO,SAAS,MAAM,CAAC;AAE5D,QAAI,KAAK,WAAW,KAAK,KAAK,UAAU,WAAW;AACjD,aAAO,IAAI,YAAY,WAAW,SAAS,UAAU;AAAA,IACvD;AACA,QACE,OAAO,SAAS,YAChB,SAAS,QACR,KAA6B,UAAU,gCACxC;AAGA,aAAO,IAAI,YAAY,uBAAuB,SAAS,UAAU;AAAA,IACnE;AACA,YAAQ,SAAS,QAAQ;AAAA,MACvB,KAAK;AACH,eAAO,IAAI,YAAY,gBAAgB,SAAS,UAAU;AAAA,MAC5D,KAAK;AACH,eAAO,IAAI,YAAY,WAAW,SAAS,UAAU;AAAA,MACvD,KAAK;AACH,eAAO,IAAI,YAAY,aAAa,SAAS,UAAU;AAAA,MACzD,KAAK;AACH,eAAO,IAAI,YAAY,gBAAgB,SAAS,UAAU;AAAA,MAC5D,KAAK;AAAA,MACL,KAAK;AAEH,eAAO,IAAI,YAAY,YAAY,SAAS,UAAU;AAAA,MACxD;AACE,eAAO,SAAS,UAAU,MACtB,IAAI,YAAY,gBAAgB,SAAS,UAAU,IACnD,IAAI,YAAY,YAAY,SAAS,UAAU;AAAA,IACvD;AAAA,EACF;AACF;;;ACtWA,SAAS,YAAAG,iBAAgB;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,KAAAC,UAAS;;;ACXlB,SAAS,YAAY;AAyBrB,IAAM,iBAAiB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,IAAM,qBAAqB,oBAAI,IAAI;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAwBM,SAAS,aAAa,KAA2B;AACtD,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,GAAG;AAAA,EACnB,QAAQ;AACN,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,IAAI,aAAa,WAAW,IAAI,aAAa,UAAU;AACzD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,mBAAmB,IAAI,QAAQ;AAAA,IACzC;AAAA,EACF;AAEA,MAAI,IAAI,aAAa,MAAM,IAAI,aAAa,IAAI;AAE9C,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,OAAO,IAAI,SAAS,YAAY,EAAE,QAAQ,YAAY,EAAE;AAE9D,MAAI,eAAe,IAAI,IAAI,KAAK,mBAAmB,IAAI,IAAI,GAAG;AAC5D,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,GAAG,IAAI;AAAA,IACjB;AAAA,EACF;AAIA,MAAI,KAAK,IAAI,MAAM,KAAK,KAAK,WAAW,UAAU,GAAG;AACnD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,GAAG,IAAI;AAAA,IACjB;AAAA,EACF;AACA,MAAI,KAAK,IAAI,MAAM,KAAK,YAAY,KAAK,IAAI,GAAG;AAC9C,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,GAAG,IAAI;AAAA,IACjB;AAAA,EACF;AAGA,MAAI,SAAS,aAAa,SAAS,QAAQ,SAAS,IAAI;AACtD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,QAAQ,GAAG,QAAQ,SAAS;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,MAAM,IAAI;AACzB;AAGO,IAAM,4BAET,OAAO,OAAO;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,sBACE;AAAA,EACF,kBACE;AAAA,EACF,cAAc;AAAA,EACd,oBACE;AACJ,CAAC;;;ADzHM,IAAM,gBAAgBC,GAC1B,OAAO;AAAA,EACN,SAAS;AAAA;AAAA,EAET,SAASA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7B,OAAO,WAAW,QAAQ,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhC,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/B,OAAOA,GACJ,OAAO;AAAA;AAAA,IAEN,cAAcA,GAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOvC,eAAeA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOpD,uBAAuBA,GAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,IAAI;AAAA,EAC3D,CAAC,EACA,OAAO,EACP,SAAS;AACd,CAAC,EACA,OAAO;AAIH,IAAM,cAAcA,GACxB,OAAO;AAAA;AAAA,EAEN,SAASA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEzB,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AACzB,CAAC,EACA,OAAO;AAOH,IAAM,kBAAkBA,GAC5B,OAAO;AAAA,EACN,gBAAgBA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE;AAAA,EACtD,eAAeA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAG;AAAA;AAAA,EAEtD,gBAAgBA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,IAAO;AAAA;AAAA,EAE3D,gBAAgBA,GACb,OAAO,EACP,IAAI,EACJ,SAAS,EACT,QAAQ,MAAM,IAAI;AAAA;AAAA,EAErB,iBAAiBA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAO;AAC9D,CAAC,EACA,OAAO;AAIH,IAAM,mBAAmBA,GAC7B,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKN,qBAAqBA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA;AAAA,EAE1D,iBAAiBA,GAAE,QAAQ,EAAE,QAAQ,IAAI;AAC3C,CAAC,EACA,OAAO;AAIH,IAAM,SAASA,GACnB,OAAO;AAAA,EACN,gBAAgBA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAO;AAAA,EAC3D,gBAAgBA,GACb,OAAO,EACP,IAAI,EACJ,SAAS,EACT,QAAQ,IAAI,OAAO,IAAI;AAC5B,CAAC,EACA,OAAO;AAGH,IAAM,eAAeA,GACzB,OAAO;AAAA,EACN,UAAUA,GAAE,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC,GAAG,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnD,QAAQA,GAAE,cAAc,SAAS,WAAW;AAAA;AAAA,EAE5C,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKtD,WAAW,gBAAgB,SAAS,CAAC,CAAC;AAAA,EACtC,SAAS,iBAAiB,SAAS,CAAC,CAAC;AAAA,EACrC,QAAQ,OAAO,SAAS,CAAC,CAAC;AAC5B,CAAC,EACA,OAAO;AAmCH,IAAM,iBAA+B,aAAa,MAAM;AAAA,EAC7D,UAAU;AAAA,IACR,QAAQ,EAAE,SAAS,eAAe,SAAS,4BAA4B;AAAA,EACzE;AAAA,EACA,QAAQ;AAAA,IACN,gBAAgB,EAAE,SAAS,UAAU,OAAO,WAAW;AAAA,IACvD,YAAY,EAAE,SAAS,UAAU,OAAO,WAAW;AAAA,EACrD;AACF,CAAC;AASD,eAAsB,WAAW,MAAqC;AACpE,MAAI;AACJ,MAAI;AACF,UAAM,MAAMC,UAAS,MAAM,MAAM;AAAA,EACnC,SAAS,OAAO;AACd,QAAI,WAAW,KAAK,EAAG,QAAO,cAAc,cAAc;AAC1D,UAAM;AAAA,EACR;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,GAAG,IAAI,uBAAuB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACtF,EAAE,OAAO,MAAM;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,SAAS,aAAa,UAAU,MAAM;AAC5C,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,SAAS,OAAO,MAAM,OACzB,IAAI,CAAC,UAAU,KAAK,MAAM,KAAK,KAAK,GAAG,KAAK,QAAQ,KAAK,MAAM,OAAO,EAAE,EACxE,KAAK,IAAI;AACZ,UAAM,IAAI,MAAM,GAAG,IAAI;AAAA,EAAmC,MAAM,EAAE;AAAA,EACpE;AACA,SAAO,cAAc,OAAO,IAAI;AAClC;AAWO,SAAS,cAAc,QAAoC;AAChE,QAAM,SAA0B,CAAC;AACjC,QAAM,WAA4B,CAAC;AAEnC,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AACzD,UAAM,QAAQ,UAAU,IAAI;AAC5B,UAAM,UAAU,OAAO,SAAS,MAAM,OAAO;AAC7C,QAAI,CAAC,SAAS;AACZ,eAAS,KAAK;AAAA,QACZ;AAAA,QACA,SAAS,YAAY,MAAM,OAAO;AAAA,MACpC,CAAC;AACD;AAAA,IACF;AAEA,UAAM,aAAa,kBAAkB,QAAQ,OAAO;AAIpD,UAAM,UAAU,QAAQ,WAAW,WAAW;AAE9C,QAAI,WAAW,UAAU,QAAQ;AAC/B,UAAI,YAAY,QAAW;AACzB,iBAAS,KAAK;AAAA,UACZ,OAAO,YAAY,MAAM,OAAO;AAAA,UAChC,SAAS;AAAA,QACX,CAAC;AACD;AAAA,MACF;AACA,YAAM,QAAQ,aAAa,OAAO;AAClC,UAAI,CAAC,MAAM,IAAI;AACb,iBAAS,KAAK;AAAA,UACZ,OAAO,YAAY,MAAM,OAAO;AAAA,UAChC,SAAS,MAAM;AAAA,QACjB,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAKA,UAAM,OAAO,YAAY,QAAQ,SAAS,OAAO;AACjD,UAAM,eAAe,QAAQ,OAAO,iBAAiB;AACrD,UAAM,WAAW,QAAQ,OAAO;AAIhC,UAAM,UAAU,QAAQ,UAAU;AAClC,QACE,SAAS,aACT,WACA,gBACA,aAAa,QACb;AACA,eAAS,KAAK;AAAA,QACZ,OAAO,YAAY,MAAM,OAAO;AAAA,QAChC,SACE;AAAA,MAEJ,CAAC;AACD;AAAA,IACF;AAEA,UAAM,aAAa,QAAQ;AAC3B,UAAM,aAAa,oBAAoB,YAAY,MAAM;AAAA,MACvD,cAAc,gBAAgB,aAAa;AAAA,IAC7C,CAAC;AACD,QAAI,eAAe,YAAY;AAC7B,eAAS,KAAK;AAAA,QACZ,OAAO,YAAY,MAAM,OAAO;AAAA,QAChC,SACE,SAAS,iBACL,IAAI,UAAU,kBAAkB,WAAW,KAAK,sEAEhD,IAAI,UAAU,6BAA6B,WAAW,KAAK,wCACpB,MAAM,OAAO,IACjD,UAAU;AAAA,MACrB,CAAC;AAAA,IACH;AAEA,WAAO,KAAK;AAAA,MACV;AAAA,MACA,YAAY,MAAM;AAAA,MAClB,WAAW,QAAQ;AAAA,MACnB,cAAc,WAAW;AAAA,MACzB,OAAO,MAAM;AAAA,MACb;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,MACpB,4BAA4B,QAAQ,OAAO,yBAAyB;AAAA,MACpE;AAAA,MACA,WAAW,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,QAAQ,QAAQ,SAAS;AACpC;AAEA,SAAS,WAAW,OAAyB;AAC3C,SACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACT,MAA6B,SAAS;AAE3C;;;AEzVA,SAAS,gBAAgB;AACzB;AAAA,EACE;AAAA,OAGK;AA4CP,eAAsB,QAAQ,SAAiD;AAC7E,QAAM,MAAM,QAAQ,OAAO,KAAK;AAChC,QAAMC,SAAQ,QAAQ,SAAS;AAE/B,QAAM,UAAU,MAAM,QAAQ,OAAO,UAAU;AAAA,IAC7C,SAAS,QAAQ;AAAA,IACjB,OAAO,QAAQ;AAAA,IACf,UAAU,gBAAgB;AAAA,IAC1B,QAAQ,QAAQ;AAAA,IAChB,cAAc,QAAQ;AAAA,EACxB,CAAC;AAED,UAAQ,OAAO;AAAA,IACb,UAAU,QAAQ;AAAA,IAClB,iBAAiB,QAAQ;AAAA,IACzB,WAAW,QAAQ;AAAA,EACrB,CAAC;AAED,aAAS;AACP,QAAI,QAAQ,QAAQ,YAAY,MAAM;AACpC,aAAO,EAAE,IAAI,OAAO,QAAQ,WAAW,SAAS,uBAAuB;AAAA,IACzE;AACA,QAAI,IAAI,KAAK,QAAQ,WAAW;AAC9B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAMA,OAAM,QAAQ,cAAc;AAClC,YAAQ,SAAS;AAEjB,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,QAAQ,OAAO,SAAS,QAAQ,UAAU;AAAA,IAC3D,SAAS,OAAO;AAGd,UAAI,iBAAiB,eAAe,MAAM,UAAW;AACrD,YAAM;AAAA,IACR;AAEA,YAAQ,OAAO,QAAQ;AAAA,MACrB,KAAK;AACH;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,QAAQ;AAAA,UACR,SAAS;AAAA,QACX;AAAA,MACF,KAAK;AACH,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,QAAQ;AAAA,UACR,SAAS;AAAA,QACX;AAAA,MACF,KAAK;AAMH,YAAI,CAAC,qBAAqB,OAAO,IAAI,GAAG;AACtC,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,QAAQ;AAAA,YACR,SACE;AAAA,UAGJ;AAAA,QACF;AACA,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,SAAS;AAAA,YACP,QAAQ,QAAQ,OAAO;AAAA,YACvB,UAAU,OAAO;AAAA,YACjB,OAAO,OAAO;AAAA,YACd,OAAO,OAAO;AAAA,YACd,GAAI,OAAO,eAAe,SACtB,CAAC,IACD,EAAE,YAAY,OAAO,WAAW;AAAA,YACpC,MAAM,OAAO;AAAA,YACb,UAAU,IAAI;AAAA,UAChB;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AACF;AAGO,SAAS,kBAAgD;AAC9D,QAAM,UAAU,SAAS;AACzB,MAAI,YAAY,YAAY,YAAY,WAAW,YAAY,SAAS;AACtE,WAAO;AAAA,EACT;AAIA,SAAO;AACT;AAEA,IAAM,eAAe,CAAC,OACpB,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;;;AC1JlD,SAAS,kBAAkB;AAC3B,SAAS,YAAY,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AACvD,SAAS,WAAAC,gBAAe;AAExB,SAAS,KAAAC,UAAS;AASX,IAAM,cAAcA,GACxB,OAAO;AAAA,EACN,MAAMA,GAAE,QAAQ,QAAQ;AAAA,EACxB,IAAIA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA;AAAA,EAE9B,QAAQA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAE1B,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,WAAWA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,cAAcA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEvB,YAAYA,GAAE,OAAO,EAAE,OAAO,EAAE;AAAA,EAChC,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1C,QAAQA,GAAE,OAAO,EAAE,SAAS;AAC9B,CAAC,EACA,OAAO;AAIH,IAAM,eAAeA,GACzB,OAAO;AAAA,EACN,MAAMA,GAAE,QAAQ,SAAS;AAAA,EACzB,IAAIA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAC9B,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,SAASA,GAAE,KAAK,CAAC,MAAM,SAAS,YAAY,SAAS,CAAC;AAAA;AAAA,EAEtD,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACpD,aAAaA,GAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA;AAAA,EAErD,QAAQA,GAAE,OAAO,EAAE,SAAS;AAC9B,CAAC,EACA,OAAO;AAGH,IAAM,eAAeA,GAAE,mBAAmB,QAAQ;AAAA,EACvD;AAAA,EACA;AACF,CAAC;AAkBM,IAAM,aAAN,MAAiB;AAAA,EACb;AAAA,EAET,YAAY,SAAyB;AACnC,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,aAAa,OAWD;AAGhB,UAAM,WACJ,MAAM,aAAa,SAAS,KAAK,SAAS,kBAAkB;AAE9D,UAAM,KAAK,QAAQ;AAAA,MACjB,MAAM;AAAA,MACN,IAAI,MAAM;AAAA,MACV,QAAQ,MAAM;AAAA,MACd,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,WAAW,MAAM;AAAA,MACjB,cAAc,MAAM;AAAA,MACpB,OAAO,MAAM;AAAA,MACb,YAAY,SAAS,MAAM,MAAM;AAAA,MACjC,aAAa,MAAM,OAAO;AAAA,MAC1B,GAAI,WAAW,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,cAAc,OAOF;AAChB,UAAM,KAAK,QAAQ;AAAA,MACjB,MAAM;AAAA,MACN,IAAI,MAAM;AAAA,MACV,OAAO,MAAM;AAAA,MACb,SAAS,MAAM;AAAA,MACf,GAAI,MAAM,eAAe,SACrB,CAAC,IACD,EAAE,YAAY,MAAM,WAAW;AAAA,MACnC,GAAI,MAAM,gBAAgB,SACtB,CAAC,IACD,EAAE,aAAa,MAAM,YAAY;AAAA,MACrC,GAAI,MAAM,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;AAAA,IAC/D,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ,OAAoC;AAChD,UAAMJ,OAAMG,SAAQ,KAAK,SAAS,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAI5D,UAAM,WAAW,KAAK,SAAS,MAAM,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,GAAM;AAAA,MACjE,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,OAAgC;AACpC,QAAI;AACJ,QAAI;AACF,YAAM,MAAMF,UAAS,KAAK,SAAS,MAAM,MAAM;AAAA,IACjD,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AACA,UAAM,UAA0B,CAAC;AACjC,eAAW,QAAQ,IAAI,MAAM,IAAI,GAAG;AAClC,UAAI,KAAK,KAAK,MAAM,GAAI;AACxB,UAAI;AACF,cAAM,SAAS,aAAa,UAAU,KAAK,MAAM,IAAI,CAAC;AACtD,YAAI,OAAO,QAAS,SAAQ,KAAK,OAAO,IAAI;AAAA,MAC9C,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,eAAe,KAA8B;AACjD,UAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAM,SAAS,MAAM,KAAK,SAAS,sBAAsB;AACzD,QAAI,UAAU;AAEd,UAAM,OAAO,QAAQ,IAAI,CAAC,UAAU;AAClC,UAAI,MAAM,SAAS,SAAU,QAAO;AACpC,YAAM,cACJ,MAAM,aAAa,WAAW,MAAM,aAAa;AACnD,UAAI,CAAC,eAAe,MAAM,WAAW,UAAa,MAAM,MAAM,QAAQ;AACpE,eAAO;AAAA,MACT;AACA,iBAAW;AACX,YAAM,EAAE,QAAQ,UAAU,GAAG,KAAK,IAAI;AACtC,aAAO;AAAA,IACT,CAAC;AAED,QAAI,UAAU,GAAG;AAGf,YAAMC;AAAA,QACJ,KAAK,SAAS;AAAA,QACd,GAAG,KAAK,IAAI,CAAC,UAAU,KAAK,UAAU,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,QACxD,EAAE,MAAM,IAAM;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAGO,SAAS,SAAS,MAAsB;AAC7C,SAAO,WAAW,QAAQ,EAAE,OAAO,MAAM,MAAM,EAAE,OAAO,KAAK;AAC/D;AAaO,SAAS,kBAAkB,MAAsB;AAEtD,SAAO,KAAK,QAAQ,8CAA8C,QAAQ;AAC5E;;;AN7NA,SAAS,eAAAG,oBAAmB;;;AOX5B,SAAS,OAAO,SAAAC,QAAO,YAAAC,WAAU,MAAM,aAAAC,kBAAiB;AACxD,SAAS,WAAAC,gBAAe;AACxB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAcA,IAAM,iBAAN,MAAqB;AAAA,EACjB;AAAA,EACT;AAAA,EAEA,YAAY,MAAc;AACxB,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,KAAK,KAAkC;AAC3C,QAAI,KAAK,MAAO,QAAO,KAAK;AAE5B,QAAI;AACJ,QAAI;AACF,YAAM,MAAMF,UAAS,KAAK,OAAO,MAAM;AAAA,IACzC,SAAS,OAAO;AACd,UAAI,CAACG,YAAW,KAAK,EAAG,OAAM;AAC9B,aAAO,KAAK,QAAQ,GAAG;AAAA,IACzB;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,GAAG;AAAA,IACzB,SAAS,OAAO;AACd,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,KAAK;AAAA,QAEb,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AAEA,UAAM,SAAS,WAAW,UAAU,MAAM;AAC1C,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,KAAK;AAAA,MAEf;AAAA,IACF;AAEA,UAAM,KAAK,gBAAgB;AAC3B,SAAK,QAAQ,OAAO;AACpB,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA,EAGA,MAAM,eAAe,KAAsC;AACzD,WAAO,iBAAiB,MAAM,KAAK,KAAK,GAAG,CAAC;AAAA,EAC9C;AAAA;AAAA,EAGA,MAAM,YAAY,KAA8B;AAC9C,WAAO,aAAa,MAAM,KAAK,KAAK,GAAG,GAAG,cAAc;AAAA,EAC1D;AAAA;AAAA,EAGA,MAAM,KAAK,MAAkB,KAA8B;AACzD,WAAO,SAAS,MAAM,KAAK,KAAK,GAAG,GAAG,IAAI;AAAA,EAC5C;AAAA;AAAA,EAGA,MAAM,YAAY,OAKE;AAClB,WAAO,YAAY,MAAM,KAAK,KAAK,MAAM,QAAQ,GAAG,KAAK,EAAE;AAAA,EAC7D;AAAA,EAEA,MAAM,QAAQ,KAAkC;AAC9C,UAAM,OAAO,aAAa,GAAG;AAC7B,UAAMJ,OAAMG,SAAQ,KAAK,KAAK,GAAG,EAAE,WAAW,KAAK,CAAC;AAIpD,QAAI;AACF,YAAMD,WAAU,KAAK,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG;AAAA,QACzD,MAAM;AAAA,QACN,MAAM;AAAA,MACR,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAK,MAAgC,SAAS,UAAU;AACtD,eAAO,KAAK,KAAK,GAAG;AAAA,MACtB;AACA,YAAM;AAAA,IACR;AACA,SAAK,QAAQ;AACb,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,kBAAiC;AACrC,QAAI,QAAQ,aAAa,QAAS;AAClC,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,KAAK,KAAK,GAAG,OAAO;AAC7C,WAAK,OAAO,QAAW,GAAG;AACxB,gBAAQ,OAAO;AAAA,UACb,YAAY,KAAK,KAAK,YAAY,KAAK,SAAS,CAAC,CAAC;AAAA;AAAA;AAAA,QAEpD;AACA,cAAM,MAAM,KAAK,OAAO,GAAK;AAAA,MAC/B;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;AAEA,SAASE,YAAW,OAAyB;AAC3C,SAAQ,OAA6C,SAAS;AAChE;;;AC9JA,SAAS,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AAC3C,SAAS,WAAAC,gBAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,KAAAC,UAAS;AAWX,IAAM,UAAUC,GACpB,OAAO;AAAA,EACN,QAAQA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAE1B,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAEvB,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,YAAYA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShC,MAAM;AAAA,EACN,UAAUA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AACtC,CAAC,EACA,OAAO;AAGV,IAAM,cAAcA,GACjB,OAAO,EAAE,SAASA,GAAE,QAAQ,CAAC,GAAG,UAAUA,GAAE,MAAM,OAAO,EAAE,CAAC,EAC5D,OAAO;AAGH,IAAM,WAAN,MAAe;AAAA,EACX;AAAA,EACT,YAAuB,CAAC;AAAA,EACxB,UAAU;AAAA,EAEV,YAAY,MAAc;AACxB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI;AACF,YAAM,SAAS,YAAY;AAAA,QACzB,KAAK,MAAM,MAAMC,UAAS,KAAK,OAAO,MAAM,CAAC;AAAA,MAC/C;AACA,WAAK,YAAY,OAAO,UAAU,OAAO,KAAK,WAAW,CAAC;AAAA,IAC5D,QAAQ;AACN,WAAK,YAAY,CAAC;AAAA,IACpB;AACA,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,OAA2B;AACzB,SAAK,cAAc;AACnB,WAAO,CAAC,GAAG,KAAK,SAAS;AAAA,EAC3B;AAAA,EAEA,IAAI,QAAqC;AACvC,SAAK,cAAc;AACnB,UAAM,aAAa,gBAAgB,MAAM;AACzC,WAAO,KAAK,UAAU;AAAA,MACpB,CAAC,YAAY,gBAAgB,QAAQ,MAAM,MAAM;AAAA,IACnD;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,IAAI,SAAiC;AACzC,SAAK,cAAc;AACnB,UAAM,aAAa,gBAAgB,QAAQ,MAAM;AACjD,SAAK,YAAY,KAAK,UAAU;AAAA,MAC9B,CAAC,aAAa,gBAAgB,SAAS,MAAM,MAAM;AAAA,IACrD;AACA,SAAK,UAAU,KAAK,EAAE,GAAG,SAAS,QAAQ,WAAW,CAAC;AACtD,UAAM,KAAK,MAAM;AAAA,EACnB;AAAA;AAAA,EAGA,MAAM,OAAO,QAAkC;AAC7C,SAAK,cAAc;AACnB,UAAM,aAAa,gBAAgB,MAAM;AACzC,UAAM,SAAS,KAAK,UAAU;AAC9B,SAAK,YAAY,KAAK,UAAU;AAAA,MAC9B,CAAC,YAAY,gBAAgB,QAAQ,MAAM,MAAM;AAAA,IACnD;AACA,QAAI,KAAK,UAAU,WAAW,OAAQ,QAAO;AAC7C,UAAM,KAAK,MAAM;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,gBAAsB;AACpB,QAAI,CAAC,KAAK,QAAS,OAAM,IAAI,MAAM,6BAA6B;AAAA,EAClE;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAMC,OAAMC,SAAQ,KAAK,KAAK,GAAG,EAAE,WAAW,KAAK,CAAC;AACpD,UAAMC;AAAA,MACJ,KAAK;AAAA,MACL,GAAG,KAAK,UAAU,EAAE,SAAS,GAAG,UAAU,KAAK,UAAU,GAAG,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA,MAEpE,EAAE,MAAM,IAAM;AAAA,IAChB;AAAA,EACF;AACF;;;ACjHA,SAAS,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AAC3C,SAAS,WAAAC,gBAAe;AACxB,SAAS,KAAAC,UAAS;AAElB,IAAM,YAAYA,GACf,OAAO;AAAA,EACN,SAASA,GAAE,QAAQ,CAAC;AAAA;AAAA,EAEpB,SAASA,GAAE;AAAA,IACTA,GAAE,OAAO;AAAA,IACTA,GAAE;AAAA,MACAA,GAAE,OAAO,EAAE,IAAIA,GAAE,OAAO,EAAE,IAAI,EAAE,SAAS,GAAG,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;AAAA,IACxE;AAAA,EACF;AACF,CAAC,EACA,OAAO;AAcH,IAAM,cAAN,MAAkB;AAAA,EACd;AAAA,EACT,WAA4D,CAAC;AAAA,EAC7D,UAAU;AAAA,EAEV,YAAY,MAAc;AACxB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAM,KAAK,KAA4B;AACrC,QAAI;AACF,YAAM,SAAS,UAAU;AAAA,QACvB,KAAK,MAAM,MAAMH,UAAS,KAAK,OAAO,MAAM,CAAC;AAAA,MAC/C;AACA,WAAK,WAAW,OAAO,UAAU,OAAO,KAAK,UAAU,CAAC;AAAA,IAC1D,QAAQ;AAIN,WAAK,WAAW,CAAC;AAAA,IACnB;AACA,SAAK,OAAO,GAAG;AACf,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA,EAGA,gBAAgB,YAAoB,KAAqB;AACvD,SAAK,cAAc;AACnB,UAAM,QAAQ,MAAM;AACpB,YAAQ,KAAK,SAAS,UAAU,KAAK,CAAC,GACnC,OAAO,CAAC,MAAM,EAAE,MAAM,KAAK,EAC3B,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,kBACE,YACA,UACA,KACS;AACT,QAAI,aAAa,OAAW,QAAO;AACnC,WAAO,KAAK,gBAAgB,YAAY,GAAG,KAAK;AAAA,EAClD;AAAA;AAAA,EAGA,MAAM,OAAO,YAAoB,OAAe,KAA4B;AAC1E,SAAK,cAAc;AACnB,KAAC,KAAK,SAAS,UAAU,MAAM,CAAC,GAAG,KAAK,EAAE,IAAI,KAAK,MAAM,CAAC;AAC1D,SAAK,OAAO,GAAG;AACf,UAAMD,OAAMG,SAAQ,KAAK,KAAK,GAAG,EAAE,WAAW,KAAK,CAAC;AACpD,UAAMD;AAAA,MACJ,KAAK;AAAA,MACL,KAAK,UAAU,EAAE,SAAS,GAAG,SAAS,KAAK,SAAS,CAAC;AAAA,MACrD,EAAE,MAAM,IAAM;AAAA,IAChB;AAAA,EACF;AAAA;AAAA,EAGA,QAAQ,KAAqC;AAC3C,SAAK,cAAc;AACnB,UAAM,MAA8B,CAAC;AACrC,eAAW,OAAO,OAAO,KAAK,KAAK,QAAQ,GAAG;AAC5C,UAAI,GAAG,IAAI,KAAK,gBAAgB,KAAK,GAAG;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AAAA,EAEA,gBAAsB;AACpB,QAAI,CAAC,KAAK,QAAS,OAAM,IAAI,MAAM,iCAAiC;AAAA,EACtE;AAAA;AAAA,EAGA,OAAO,KAAmB;AACxB,UAAM,SAAS,MAAM;AACrB,UAAM,SAA0D,CAAC;AACjE,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,KAAK,QAAQ,GAAG;AAC1D,YAAM,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,MAAM,MAAM;AACjD,UAAI,KAAK,SAAS,EAAG,QAAO,GAAG,IAAI;AAAA,IACrC;AACA,SAAK,WAAW;AAAA,EAClB;AACF;AASO,SAAS,cACd,aACA,aACA,uBACQ;AACR,QAAM,UAAU,cAAc,eAAe;AAC7C,SAAQ,SAAS,MAAa;AAChC;;;ACrIA,SAAS,eAAe;AACxB,SAAS,YAAY;AAuCd,SAAS,YAAY,OAAO,YAAY,GAAgB;AAC7D,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,KAAK,MAAM,aAAa;AAAA,IAChC,UAAU,KAAK,MAAM,eAAe;AAAA,IACpC,WAAW,KAAK,MAAM,YAAY;AAAA,IAClC,YAAY,KAAK,MAAM,aAAa;AAAA,IACpC,SAAS,KAAK,MAAM,cAAc;AAAA,IAClC,OAAO,KAAK,MAAM,YAAY;AAAA,IAC9B,MAAM,KAAK,MAAM,WAAW;AAAA,IAC5B,WAAW,KAAK,MAAM,QAAQ;AAAA,IAC9B,SAAS,KAAK,MAAM,SAAS;AAAA,EAC/B;AACF;AAMO,SAAS,cAAsB;AACpC,SAAO,QAAQ,IAAI,aAAa,KAAK,KAAK,QAAQ,GAAG,SAAS;AAChE;;;AC7DA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAAG;AAAA,EACA;AAAA,EACA;AAAA,EAMA;AAAA,EACA;AAAA,OAIK;;;ACjBP;AAAA,EACE;AAAA,EACA,qBAAAC;AAAA,OAEK;;;ACJP,SAAS,UAAU,aAAa;AAChC,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,UAAU;AAC5B,SAAS,WAAW,QAAAC,aAAY;AAChC,SAAS,cAAc;AA0BvB,IAAM,aAAa,OAAO,OAAO;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAkBD,IAAM,gBAAgB,OAAO,OAAO;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAmBD,IAAM,wBAAwB,OAAO,OAAO;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,SAAS,SACd,SAA4B,QAAQ,KACpCC,YAA4B,QAAQ,UACZ;AACxB,QAAM,UACJA,cAAa,UACT,CAAC,GAAG,eAAe,GAAG,qBAAqB,IAC3C;AAEN,QAAM,MAA8B,CAAC;AACrC,aAAW,QAAQ,SAAS;AAC1B,UAAM,QAAQ,OAAO,IAAI;AACzB,QAAI,UAAU,OAAW,KAAI,IAAI,IAAI;AAAA,EACvC;AAGA,MAAI,IAAI,IAAI;AACZ,SAAO;AACT;AAGO,SAAS,WAAW,OAAkC;AAC3D,SAAO,OAAO,OAAO,CAAC,GAAG,YAAY,WAAW,KAAK,CAAC;AACxD;AAsBA,SAAS,iBACP,QACA,QACe;AACf,QAAM,QAAQ,OAAO,MAAM,KAAK,IAAI,MAAM,SAAS,EAAE,OAAO,OAAO;AAEnE,aAAW,OAAO,MAAM;AAEtB,UAAM,SAASD;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,WAAW,MAAM,EAAG,QAAO;AAI/B,UAAM,OAAOA,MAAK,KAAK,GAAG,MAAM,MAAM;AACtC,QAAI,CAAC,WAAW,IAAI,EAAG;AACvB,QAAI;AACF,YAAM,QAAQ,sDAAsD;AAAA,QAClE,aAAa,MAAM,MAAM;AAAA,MAC3B;AACA,UAAI,CAAC,QAAQ,CAAC,EAAG;AACjB,YAAM,SAAS,MAAM,CAAC,EAAE,QAAQ,aAAa,GAAG,GAAG,IAAI;AACvD,UAAI,WAAW,MAAM,EAAG,QAAO;AAAA,IACjC,QAAQ;AAAA,IAGR;AAAA,EACF;AACA,SAAO;AACT;AASA,IAAM,cAAc,oBAAI,IAA0B;AAO3C,SAAS,oBACd,SAAS,UACTE,YAA4B,QAAQ,UACpC,SAA4B,QAAQ,KACtB;AAUd,QAAM,MAAM,GAAGA,SAAQ,KAAS,MAAM,KAAS,OAAO,MAAM,KAAK,EAAE;AACnE,QAAM,SAAS,YAAY,IAAI,GAAG;AAClC,MAAI,OAAQ,QAAO;AACnB,QAAM,WAAW,gBAAgB,QAAQA,WAAU,MAAM;AACzD,cAAY,IAAI,KAAK,QAAQ;AAC7B,SAAO;AACT;AAEA,SAAS,gBACP,QACAA,WACA,QACc;AACd,MAAIA,cAAa,QAAS,QAAO,EAAE,SAAS,QAAQ,YAAY,CAAC,EAAE;AAOnE,MAAI,cAAc,KAAK,MAAM,GAAG;AAC9B,WAAO,EAAE,SAAS,QAAQ,UAAU,YAAY,CAAC,MAAM,EAAE;AAAA,EAC3D;AAGA,MAAI,QAAQ,KAAK,MAAM,KAAK,wBAAwB,KAAK,MAAM,GAAG;AAChE,WAAO,EAAE,SAAS,QAAQ,YAAY,CAAC,EAAE;AAAA,EAC3C;AAEA,QAAM,QAAQ,iBAAiB,QAAQ,MAAM;AAC7C,SAAO,UAAU,OACb,EAAE,SAAS,QAAQ,YAAY,CAAC,EAAE,IAClC,EAAE,SAAS,QAAQ,UAAU,YAAY,CAAC,KAAK,EAAE;AACvD;AAcO,IAAM,mBAAN,MAA0C;AAAA,EACtC,KAAgB;AAAA,EAChB,QAAsB;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUT,YAAY,SAAS,UAAU;AAC7B,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,SAAiC;AACrC,UAAM,UAAU,MAAM,IAAI,QAAuB,CAAC,YAAY;AAG5D,YAAM,SAAS,oBAAoB,KAAK,OAAO;AAC/C;AAAA,QACE,OAAO;AAAA,QACP,CAAC,GAAG,OAAO,YAAY,WAAW;AAAA,QAClC,EAAE,SAAS,KAAQ,KAAK,SAAS,EAAE;AAAA,QACnC,CAAC,OAAO,WAAW;AACjB,kBAAQ,QAAQ,OAAO,OAAO,KAAK,CAAC;AAAA,QACtC;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,YAAY,MAAM;AACpB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ,CAAC;AAAA,QACT,QACE;AAAA,MAEJ;AAAA,IACF;AAIA,WAAO,EAAE,SAAS,MAAM,QAAQ,CAAC,EAAE;AAAA,EACrC;AAAA,EAEA,MAAM,QAAQ,SAAiD;AAC7D,UAAM,UAAU,KAAK,IAAI;AAGzB,UAAM,UAAU,MAAM,QAAQC,MAAK,OAAO,GAAG,aAAa,CAAC;AAE3D,QAAI;AACF,aAAO,MAAM,KAAK,OAAO,SAAS,SAAS,OAAO;AAAA,IACpD,UAAE;AACA,YAAM,GAAG,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,MAAM,OACJ,SACA,SACA,SACwB;AACxB,WAAO,IAAI,QAAuB,CAAC,YAAY;AAM7C,UAAI,QAAQ,OAAO,SAAS;AAC1B,gBAAQ;AAAA,UACN,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA,UACX,YAAY,KAAK,IAAI,IAAI;AAAA,QAC3B,CAAC;AACD;AAAA,MACF;AAKA,YAAM,SAAS,oBAAoB,KAAK,OAAO;AAC/C,YAAM,QAAQ;AAAA,QACZ,OAAO;AAAA,QACP,CAAC,GAAG,OAAO,YAAY,GAAG,WAAW,QAAQ,KAAK,CAAC;AAAA,QACnD;AAAA,UACE,KAAK;AAAA,UACL,KAAK,SAAS;AAAA;AAAA;AAAA,UAGd,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA;AAAA;AAAA,UAG9B,OAAO;AAAA,UACP,UAAU;AAAA,QACZ;AAAA,MACF;AAEA,UAAI,SAAS;AACb,UAAI,SAAS;AACb,UAAI,cAAc;AAClB,UAAI,UAAU;AACd,UAAI,SAAS;AACb,UAAI,SAA6D;AAEjE,YAAM,SAAS,CAAC,WAAgC;AAC9C,YAAI,QAAS;AACb,kBAAU;AACV,qBAAa,KAAK;AAClB,gBAAQ,OAAO,oBAAoB,SAAS,OAAO;AACnD,gBAAQ,MAAM;AAAA,MAChB;AAEA,YAAM,OAAO,CAAC,QAA6B;AACzC,iBAAS;AAQT,cAAM,KAAK,SAAS;AACpB,mBAAW,MAAM;AACf,cAAI,CAAC,OAAQ,OAAM,KAAK,SAAS;AAAA,QACnC,GAAG,GAAK,EAAE,MAAM;AAAA,MAClB;AAEA,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,SAAS;AAAA,MAChB,GAAG,QAAQ,SAAS;AAEpB,YAAM,UAAU,MAAY;AAC1B,aAAK,UAAU;AAAA,MACjB;AACA,cAAQ,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAEhE,YAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB;AACzC,uBAAe,MAAM;AACrB,YAAI,cAAc,QAAQ,gBAAgB;AACxC,eAAK,kBAAkB;AACvB;AAAA,QACF;AACA,kBAAU,MAAM,SAAS,MAAM;AAAA,MACjC,CAAC;AAED,YAAM,OAAO,GAAG,QAAQ,CAAC,UAAkB;AAGzC,YAAI,OAAO,SAAS,KAAO,WAAU,MAAM,SAAS,MAAM;AAAA,MAC5D,CAAC;AAED,YAAM,GAAG,SAAS,CAAC,UAAiB;AAClC,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,SAAS,mCAAmC,MAAM,OAAO;AAAA,UACzD,WAAW;AAAA,UACX,YAAY,KAAK,IAAI,IAAI;AAAA,QAC3B,CAAC;AAAA,MACH,CAAC;AAED,YAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,iBAAS;AACT,cAAM,aAAa,KAAK,IAAI,IAAI;AAEhC,YAAI,WAAW,YAAY;AACzB,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,WAAW;AAAA,YACX;AAAA,UACF,CAAC;AACD;AAAA,QACF;AACA,YAAI,WAAW,WAAW;AACxB,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM;AAAA,YACN,SAAS,mCAAmC,OAAO,QAAQ,SAAS,CAAC;AAAA,YACrE,WAAW;AAAA,YACX;AAAA,UACF,CAAC;AACD;AAAA,QACF;AACA,YAAI,WAAW,oBAAoB;AACjC,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM;AAAA,YACN,SAAS,gCAAgC,OAAO,QAAQ,cAAc,CAAC;AAAA,YACvE,WAAW;AAAA,YACX;AAAA,UACF,CAAC;AACD;AAAA,QACF;AACA,YAAI,SAAS,GAAG;AACd,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,MAAM;AAAA,YACN,SACE,OAAO,KAAK,MAAM,KACd,qCAAqC,OAAO,IAAI,CAAC,KACjD,0BAA0B,UAAU,MAAM,CAAC;AAAA,YACjD,WAAW;AAAA,YACX;AAAA,UACF,CAAC;AACD;AAAA,QACF;AACA,eAAO,EAAE,IAAI,MAAM,MAAM,QAAQ,WAAW,CAAC;AAAA,MAC/C,CAAC;AAID,YAAM,MAAM,GAAG,SAAS,MAAM;AAAA,MAE9B,CAAC;AACD,YAAM,MAAM,IAAI,QAAQ,QAAQ,MAAM;AAAA,IACxC,CAAC;AAAA,EACH;AACF;AAGA,SAAS,UAAU,MAAsB;AACvC,SAAO,KAAK,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,KAAK;AACvC;;;ACrcO,IAAM,oBAAN,MAA2C;AAAA,EACvC,KAAgB;AAAA,EAChB,QAAsB;AAAA,EACtB;AAAA,EACA;AAAA,EAET,YAAY,MAAmB;AAC7B,QAAI,KAAK,YAAY,QAAW;AAC9B,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,UAAM,QAAQ,aAAa,KAAK,OAAO;AACvC,QAAI,CAAC,MAAM,IAAI;AACb,YAAM,IAAI,MAAM,sBAAsB,MAAM,MAAM,EAAE;AAAA,IACtD;AACA,SAAK,WAAW,MAAM;AACtB,SAAK,aAAa,KAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAU,MAA0C;AAClD,UAAM,OAAO,KAAK,SAAS,KAAK,SAAS,GAAG,IACxC,KAAK,SAAS,OACd,GAAG,KAAK,SAAS,IAAI;AACzB,UAAM,MAAM,IAAI,IAAI,MAAM,IAAI;AAC9B,QAAI,IAAI,WAAW,KAAK,SAAS,QAAQ;AACvC,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AACA,WAAO;AAAA,EACT;AAAA,EAEA,WAAmC;AACjC,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,QAAQ;AAAA,IACV;AACA,QAAI,KAAK,eAAe,QAAW;AACjC,YAAM,MAAM,QAAQ,IAAI,KAAK,UAAU;AACvC,UAAI,QAAQ,UAAa,QAAQ,IAAI;AACnC,gBAAQ,eAAe,IAAI,UAAU,GAAG;AAAA,MAC1C;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAiC;AACrC,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK,UAAU,QAAQ,GAAG;AAAA,QACrD,QAAQ;AAAA,QACR,SAAS,KAAK,SAAS;AAAA,QACvB,UAAU;AAAA,QACV,QAAQ,YAAY,QAAQ,GAAK;AAAA,MACnC,CAAC;AACD,UAAI,CAAC,SAAS,IAAI;AAChB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,QAAQ,CAAC;AAAA,UACT,QAAQ,4BAA4B,OAAO,SAAS,MAAM,CAAC;AAAA,QAC7D;AAAA,MACF;AACA,YAAM,OAAgB,MAAM,SAAS,KAAK;AAC1C,aAAO,EAAE,SAAS,MAAM,QAAQ,gBAAgB,IAAI,EAAE;AAAA,IACxD,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ,CAAC;AAAA,QACT,QAAQ,mBAAmB,OAAO,KAAK,SAAS,MAAM;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,SAAiD;AAC7D,UAAM,UAAU,KAAK,IAAI;AAIzB,UAAM,UAAU,YAAY,QAAQ,QAAQ,SAAS;AACrD,UAAM,SAAS,YAAY,IAAI,CAAC,QAAQ,QAAQ,OAAO,CAAC;AAExD,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK,UAAU,kBAAkB,GAAG;AAAA,QAC/D,QAAQ;AAAA,QACR,SAAS,KAAK,SAAS;AAAA;AAAA;AAAA,QAGvB,MAAM,KAAK,UAAU;AAAA,UACnB,OAAO,QAAQ;AAAA,UACf,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,QAAQ,OAAO,CAAC;AAAA,UACpD,QAAQ;AAAA,QACV,CAAC;AAAA,QACD,UAAU;AAAA,QACV;AAAA,MACF,CAAC;AAED,UAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,eAAO,KAAK;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,SAAS,WAAW,KAAK;AAC3B,eAAO,KAAK;AAAA,UACV;AAAA,UACA,mCAAmC,QAAQ,KAAK;AAAA,UAChD;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,SAAS,IAAI;AAChB,eAAO,KAAK;AAAA,UACV;AAAA,UACA,kCAAkC,OAAO,SAAS,MAAM,CAAC;AAAA,UACzD,SAAS,UAAU;AAAA,UACnB;AAAA,QACF;AAAA,MACF;AAEA,YAAM,OAAO,MAAM,WAAW,UAAU,QAAQ,gBAAgB,MAAM;AACtE,UAAI,SAAS,MAAM;AAGjB,eAAO,KAAK;AAAA,UACV;AAAA,UACA,gCAAgC,OAAO,QAAQ,cAAc,CAAC;AAAA,UAC9D;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,YAAM,UAAU,eAAe,IAAI;AACnC,UAAI,YAAY,MAAM;AACpB,eAAO,KAAK;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE,IAAI,MAAM,MAAM,SAAS,YAAY,KAAK,IAAI,IAAI,QAAQ;AAAA,IACrE,SAAS,OAAO;AACd,UAAI,QAAQ,OAAO,SAAS;AAC1B,eAAO,KAAK,MAAM,YAAY,wBAAwB,OAAO,OAAO;AAAA,MACtE;AACA,UAAI,QAAQ,KAAK,GAAG;AAClB,eAAO,KAAK;AAAA,UACV;AAAA,UACA,mCAAmC,OAAO,QAAQ,SAAS,CAAC;AAAA,UAC5D;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,aAAO,KAAK;AAAA,QACV;AAAA,QACA,mBAAmB,OAAO,KAAK,SAAS,MAAM;AAAA,QAC9C;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MACE,MACA,SACA,WACA,SACe;AACf,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,KAAK,IAAI,IAAI;AAAA,IAC3B;AAAA,EACF;AACF;AAUA,eAAe,WACb,UACA,UACA,QACwB;AACxB,QAAM,OAAO,SAAS;AACtB,MAAI,SAAS,KAAM,QAAO;AAI1B,QAAM,SAAU,KAAoC,UAAU;AAC9D,QAAM,SAAuB,CAAC;AAC9B,MAAI,QAAQ;AACZ,MAAI;AACF,eAAS;AACP,aAAO,eAAe;AACtB,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,eAAS,MAAM;AACf,UAAI,QAAQ,UAAU;AACpB,cAAM,OAAO,OAAO;AACpB,eAAO;AAAA,MACT;AACA,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACA,SAAO,IAAI,YAAY,EAAE,OAAO,OAAO,QAAQ,KAAK,CAAC;AACvD;AAEA,SAAS,OAAO,QAA+B,OAA2B;AACxE,QAAM,MAAM,IAAI,WAAW,KAAK;AAChC,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,QAAI,IAAI,OAAO,MAAM;AACrB,cAAU,MAAM;AAAA,EAClB;AACA,SAAO;AACT;AAGA,SAAS,eAAe,KAA4B;AAClD,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,OAAO,WAAW,YAAY,WAAW,KAAM,QAAO;AAC1D,QAAM,UAAW,OAAiC;AAClD,MAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,EAAG,QAAO;AAC5D,QAAM,UAAW,QAAQ,CAAC,EAA4B;AACtD,MAAI,OAAO,YAAY,YAAY,YAAY,KAAM,QAAO;AAC5D,QAAM,UAAW,QAAkC;AACnD,SAAO,OAAO,YAAY,WAAW,UAAU;AACjD;AAGA,SAAS,gBAAgB,MAAyB;AAChD,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO,CAAC;AACvD,QAAM,OAAQ,KAA4B;AAC1C,MAAI,CAAC,MAAM,QAAQ,IAAI,EAAG,QAAO,CAAC;AAClC,SAAO,KACJ;AAAA,IAAI,CAAC,UACJ,OAAO,UAAU,YAAY,UAAU,OAClC,MAA2B,KAC5B;AAAA,EACN,EACC,OAAO,CAAC,OAAqB,OAAO,OAAO,QAAQ;AACxD;AAEA,SAAS,QAAQ,OAAyB;AACxC,SACE,iBAAiB,UAChB,MAAM,SAAS,gBAAgB,MAAM,SAAS;AAEnD;AAQA,SAAS,mBAAmB,OAAgB,QAAwB;AAClE,QAAM,QACJ,iBAAiB,SAAS,WAAW,SAAS,MAAM,iBAAiB,QACjE,MAAM,MAAM,UACZ,iBAAiB,QACf,MAAM,UACN;AACR,SAAO,uCAAuC,MAAM,KAAK,KAAK;AAChE;;;AFvSO,SAAS,cAAc,IAAe,MAA4B;AAKvE,MAAIC,mBAAkB,EAAE,EAAE,UAAU,WAAW;AAC7C,WAAO,IAAI,iBAAiB;AAAA,EAC9B;AACA,SAAO,IAAI,kBAAkB,IAAI;AACnC;AAGO,IAAM,0BAAgD;;;AGXtD,SAAS,cAAc,KAAyB;AACrD,MAAI,IAAI,SAAS,gBAAgB;AAC/B,UAAMC,WAAU,IAAI;AACpB,WAAO,aAAa,CAAC,cAAcA,SAAQ,MAAM,GAAGA,SAAQ,MAAM,CAAC;AAAA,EACrE;AAEA,QAAM,UAAU,IAAI;AAIpB,QAAM,QAAQ,QAAQ,SACnB,IAAI,CAAC,YAAY,GAAG,UAAU,QAAQ,IAAI,CAAC,KAAK,QAAQ,OAAO,EAAE,EACjE,KAAK,MAAM;AACd,SAAO,aAAa,CAAC,cAAc,QAAQ,MAAM,GAAG,KAAK,CAAC;AAC5D;AAEA,SAAS,cAAc,QAAgD;AACrE,MAAI,WAAW,UAAa,OAAO,KAAK,MAAM,GAAI,QAAO;AACzD,SAAO;AAAA,EAAyB,MAAM;AACxC;AAEA,SAAS,UAAU,MAAsB;AACvC,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,aAAa,UAAmD;AACvE,SAAO,SAAS,OAAO,CAAC,YAAY,YAAY,MAAS,EAAE,KAAK,MAAM;AACxE;;;AJuCA,IAAM,uBAAuB;AAUtB,IAAM,SAAN,MAAa;AAAA,EACT;AAAA,EACA,YAAY,oBAAI,IAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrC,UAAU,oBAAI,IAGrB;AAAA,EACO;AAAA,EACT,gBAA8B,CAAC;AAAA,EAC/B,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA,aAAa;AAAA,EACb,WAAW;AAAA,EAEX,YAAY,SAAwB;AAClC,SAAK,WAAW;AAChB,SAAK,OAAO,QAAQ,OAAO,KAAK;AAAA,EAClC;AAAA,EAEA,SAAuB;AACrB,WAAO;AAAA,MACL,QAAQ,KAAK,SAAS,OAAO;AAAA,MAC7B,OAAO,KAAK,SAAS;AAAA,MACrB,UAAU,KAAK,SAAS;AAAA,MACxB,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK;AAAA,MACd,YAAY,KAAK,QAAQ;AAAA,MACzB,cAAc,CAAC,GAAG,KAAK,aAAa;AAAA,MACpC,GAAI,KAAK,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW,KAAK,WAAW;AAAA,MACtE,WAAW,KAAK;AAAA,MAChB,SAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,SAAe;AACb,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,qBAA4C;AAChD,UAAM,eAA6B,CAAC;AAEpC,eAAW,SAAS,KAAK,SAAS,OAAO,QAAQ;AAC/C,YAAM,UAAU,KAAK,YAAY,KAAK;AACtC,YAAM,SAAS,MAAM,QAAQ,OAAO;AACpC,UAAI,CAAC,OAAO,QAAS;AAIrB,UACE,OAAO,OAAO,SAAS,KACvB,CAAC,aAAa,OAAO,QAAQ,MAAM,KAAK,GACxC;AACA;AAAA,MACF;AAEA,mBAAa,KAAK;AAAA,QAChB,MAAM,MAAM;AAAA,QACZ,WAAW,MAAM;AAAA,QACjB,cAAc,MAAM;AAAA,QACpB,OAAO,MAAM;AAAA,QACb,YAAY,MAAM;AAAA,MACpB,CAAC;AAAA,IACH;AAEA,SAAK,gBAAgB;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,OAA+B;AACzC,UAAM,MAAM,GAAG,MAAM,UAAU,IAAI,MAAM,SAAS;AAClD,QAAI,UAAU,KAAK,UAAU,IAAI,GAAG;AACpC,QAAI,CAAC,SAAS;AACZ,gBACE,KAAK,SAAS,iBAAiB,KAAK,KACpC,cAAc,MAAM,WAAW;AAAA,QAC7B,SAAS,MAAM;AAAA,QACf,WAAW,MAAM;AAAA,MACnB,CAAC;AACH,WAAK,UAAU,IAAI,KAAK,OAAO;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,qBAAqB,OAA+B;AAClD,QAAI,MAAM,SAAS,UAAW,QAAO;AACrC,WAAO,KAAK,SAAS,MAAM;AAAA,MACzB,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,UAAU,MAAyC;AACjD,WAAO,KAAK,SAAS,OAAO,OAAO,KAAK,CAAC,UAAU,MAAM,SAAS,IAAI;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,KAAgE;AACpE,UAAM,QAAQ,KAAK,UAAU,IAAI,IAAI;AACrC,QAAI,CAAC,OAAO;AAGV,aAAO,EAAE,IAAI,OAAO,QAAQ,iBAAiB,eAAe,EAAE;AAAA,IAChE;AAEA,UAAM,QAAQ;AAAA,MACZ;AAAA,QACE,OAAO,IAAI;AAAA,QACX,UAAU,IAAI;AAAA,QACd,eAAe,IAAI;AAAA,MACrB;AAAA,MACA;AAAA,QACE,OAAO,KAAK,SAAS;AAAA,QACrB,YAAY,MAAM;AAAA,QAClB,MAAM,MAAM;AAAA,QACZ,OAAO;AAAA,UACL,cAAc,MAAM;AAAA,UACpB,gBAAgB,KAAK,qBAAqB,KAAK;AAAA,QACjD;AAAA;AAAA,QAEA,eAAe,KAAK,SAAS,UAAU;AAAA,UACrC,KAAK,SAAS,OAAO;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,MAAM,IAAI;AACb,aAAO,EAAE,IAAI,OAAO,QAAQ,iBAAiB,MAAM,OAAO,EAAE;AAAA,IAC9D;AAEA,QAAI,IAAI,UAAU,KAAK,SAAS,OAAO;AAKrC,YAAM,WAAW,KAAK,SAAS,QAAQ;AAAA,QACrC,KAAK,KAAK;AAAA,QACV,iBAAiB,IAAI,SAAS;AAAA,MAChC;AACA,UAAI,CAAC,SAAS,GAAI,QAAO,EAAE,IAAI,OAAO,QAAQ,SAAS,OAAO;AAAA,IAChE;AAEA,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OAAO,KAAsC;AACjD,UAAM,QAAQ,KAAK,UAAU,IAAI,IAAI;AACrC,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM;AAAA,QACN,SAAS;AAAA,QACT,WAAW;AAAA,MACb;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,gBAAgB;AACvC,SAAK,QAAQ,IAAI,IAAI,IAAI,EAAE,YAAY,SAAS,IAAI,MAAM,GAAG,CAAC;AAE9D,UAAM,SAAS,cAAc,GAAG;AAChC,UAAM,YAAY,IAAI,UAAU,KAAK,SAAS;AAC9C,UAAM,SAAS,KAAK,SAAS,OAAO;AAEpC,UAAM,KAAK,SAAS,QAAQ,aAAa;AAAA,MACvC,IAAI,KAAK,KAAK;AAAA,MACd,QAAQ,KAAK,SAAS,OAAO;AAAA,MAC7B,OAAO,IAAI;AAAA,MACX,MAAM,IAAI;AAAA,MACV,UAAU,IAAI;AAAA,MACd,OAAO,IAAI;AAAA,MACX,WAAW,MAAM;AAAA,MACjB,cAAc,MAAM;AAAA,MACpB,OAAO,MAAM;AAAA,MACb;AAAA,IACF,CAAC;AAED,QAAI,UAAW,OAAM,KAAK,SAAS,QAAQ,OAAO,KAAK,KAAK,CAAC;AAE7D,QAAI;AACF,YAAM,UAAU,KAAK,YAAY,KAAK;AACtC,YAAM,SAAS,MAAM,QAAQ,QAAQ;AAAA,QACnC;AAAA,QACA,OAAO,MAAM;AAAA;AAAA,QAEb,WAAW,YACP,KAAK;AAAA,UACH,OAAO,UAAU;AAAA,UACjB,OAAO,OAAO;AAAA,QAChB,IACA,OAAO,OAAO;AAAA,QAClB,gBAAgB,YACZ,KAAK;AAAA,UACH,OAAO,UAAU;AAAA,UACjB,OAAO,OAAO;AAAA,QAChB,IACA,OAAO,OAAO;AAAA,QAClB,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,YAAM,UAAsB,OAAO,KAC/B,EAAE,SAAS,MAAM,MAAM,OAAO,KAAK,IACnC,OAAO,SAAS,aACd,EAAE,SAAS,WAAW,IACtB;AAAA,QACE,SAAS;AAAA,QACT,MAAM,OAAO;AAAA,QACb,SAAS,OAAO;AAAA,QAChB,WAAW,OAAO;AAAA,MACpB;AAEN,YAAM,KAAK,SAAS,QAAQ,cAAc;AAAA,QACxC,IAAI,KAAK,KAAK;AAAA,QACd,OAAO,IAAI;AAAA,QACX,SAAS,QAAQ;AAAA,QACjB,YAAY,OAAO;AAAA,QACnB,aAAa,OAAO,KAAK,OAAO,KAAK,SAAS;AAAA,QAC9C,GAAI,OAAO,KAAK,CAAC,IAAI,EAAE,QAAQ,OAAO,QAAQ;AAAA,MAChD,CAAC;AAKD,UAAI,aAAa,MAAM,SAAS,WAAW;AACzC,cAAM,KAAK,SAAS,MAAM;AAAA,UACxB,MAAM;AAAA,UACN;AAAA,YACE,OAAO;AAAA,YACP,OAAO,KAAK,OAAO,KAAK,SAAS;AAAA,YACjC,MAAM;AAAA,UACR;AAAA,UACA,KAAK,KAAK;AAAA,QACZ;AAAA,MACF;AAEA,WAAK,cAAc;AACnB,WAAK,SAAS,UAAU;AAAA,QACtB,MAAM;AAAA,QACN,OAAO,IAAI;AAAA,QACX,SAAS,QAAQ;AAAA,QACjB,YAAY,OAAO;AAAA,MACrB,CAAC;AACD,aAAO;AAAA,IACT,UAAE;AACA,WAAK,QAAQ,OAAO,IAAI,EAAE;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA,EAGA,UAAU,OAAqB;AAC7B,SAAK,QAAQ,IAAI,KAAK,GAAG,WAAW,MAAM;AAAA,EAC5C;AAAA;AAAA,EAGA,YAAkB;AAChB,eAAW,EAAE,WAAW,KAAK,KAAK,QAAQ,OAAO,EAAG,YAAW,MAAM;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,IAAI,QAAoC;AAC5C,UAAM,cAAc,KAAK,SAAS,eAAe;AAEjD,WAAO,CAAC,OAAO,WAAW,CAAC,KAAK,UAAU;AACxC,UAAI;AACF,cAAM,KAAK,KAAK;AAChB,aAAK,aAAa;AAAA,MACpB,SAAS,OAAO;AACd,aAAK,aACH,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,aAAK,SAAS,UAAU;AAAA,UACtB,MAAM;AAAA,UACN,SAAS,KAAK;AAAA,QAChB,CAAC;AACD,YAAI,iBAAiB,eAAe,MAAM,SAAS,WAAW;AAC5D,eAAK,WAAW;AAChB,eAAK,UAAU;AACf,eAAK,SAAS,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C;AAAA,QACF;AACA,cAAM,UACJ,iBAAiB,eAAe,MAAM,eAAe,SACjD,MAAM,aAAa,MACnB;AACN,cAAM,MAAM,SAAS,MAAM;AAC3B;AAAA,MACF;AAGA,YAAM,MAAM,eAAe,OAAO,KAAK,OAAO,IAAI,MAAM,MAAM;AAAA,IAChE;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,OAAsB;AAC1B,UAAM,eAAe,MAAM,KAAK,mBAAmB;AAEnD,UAAM,YAAY,MAAM,KAAK,SAAS,OAAO,UAAU;AAAA,MACrD,UAAU,KAAK,SAAS;AAAA,MACxB,eAAe,KAAK,SAAS;AAAA,MAC7B;AAAA,MACA,cAAc,CAAC,GAAG,KAAK,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,IAAI,OAAO;AAAA,QAChE;AAAA,QACA,SAAS,KAAK;AAAA,MAChB,EAAE;AAAA,MACF,QAAQ,KAAK;AAAA,IACf,CAAC;AACD,SAAK,SAAS,UAAU;AAAA,MACtB,MAAM;AAAA,MACN,cAAc,aAAa;AAAA,IAC7B,CAAC;AAED,QAAI,UAAU,SAAS;AACrB,WAAK,WAAW;AAChB,WAAK,UAAU;AACf,WAAK,SAAS,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,WAAK,WAAW;AAChB;AAAA,IACF;AAIA,eAAW,SAAS,UAAU,KAAM,MAAK,UAAU,KAAK;AACxD,eAAW,SAAS,UAAU,OAAQ,MAAK,UAAU,KAAK;AAE1D,QAAI,KAAK,WAAW,aAAa,WAAW,EAAG;AAE/C,UAAM,OAAO,KAAK,SAAS,OAAO,OAAO,cAAc,KAAK,QAAQ;AACpE,QAAI,QAAQ,EAAG;AAEf,UAAM,EAAE,KAAK,IAAI,MAAM,KAAK,SAAS,OAAO,MAAM;AAAA,MAChD,UAAU,KAAK,SAAS;AAAA,MACxB;AAAA,MACA,KAAK;AAAA,IACP,CAAC;AAUD,eAAW,OAAO,MAAM;AACtB,WAAK,KAAK,QAAQ,GAAG,EAAE,MAAM,CAAC,UAAmB;AAC/C,aAAK,aACH,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,aAAK,SAAS,UAAU,EAAE,MAAM,SAAS,SAAS,KAAK,WAAW,CAAC;AAAA,MACrE,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,KAAiC;AAC7C,SAAK,SAAS,UAAU;AAAA,MACtB,MAAM;AAAA,MACN,OAAO,IAAI;AAAA,MACX,MAAM,IAAI;AAAA,IACZ,CAAC;AAED,UAAM,YAAY,KAAK,MAAM,GAAG;AAChC,QAAI,CAAC,UAAU,IAAI;AACjB,WAAK,YAAY;AACjB,YAAM,KAAK,SAAS,QAAQ,cAAc;AAAA,QACxC,IAAI,KAAK,KAAK;AAAA,QACd,OAAO,IAAI;AAAA,QACX,SAAS;AAAA,QACT,QAAQ,UAAU;AAAA,MACpB,CAAC;AACD,WAAK,SAAS,UAAU;AAAA,QACtB,MAAM;AAAA,QACN,OAAO,IAAI;AAAA,QACX,QAAQ,UAAU;AAAA,MACpB,CAAC;AACD,YAAM,KAAK;AAAA,QAAQ,MACjB,KAAK,SAAS,OAAO,QAAQ;AAAA,UAC3B,UAAU,KAAK,SAAS;AAAA,UACxB,QAAQ,CAAC,EAAE,OAAO,IAAI,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC;AAAA,UACjD,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AACA;AAAA,IACF;AAMA,UAAM,UAAU,MAAM,KAAK,iBAAiB,GAAG;AAC/C,QAAI,CAAC,QAAS;AACd,UAAM,UAAU,MAAM,KAAK,aAAa,KAAK,QAAQ,QAAQ;AAE7D,UAAM,QAAQ,KAAK,UAAU,IAAI,IAAI;AACrC,UAAM,UAAU,MAAM,KAAK,OAAO,EAAE,GAAG,KAAK,QAAQ,CAAC;AAErD,UAAM,WAAW,MAAM,KAAK,aAAa,KAAK,OAAO;AAErD,UAAM,KAAK;AAAA,MAAQ,MACjB,KAAK,SAAS,OAAO,OAAO;AAAA,QAC1B,UAAU,KAAK,SAAS;AAAA,QACxB,OAAO,IAAI;AAAA,QACX;AAAA,QACA,aAAa,QAAQ;AAAA,QACrB,OAAO,OAAO,SAAS;AAAA,QACvB,cAAc,OAAO,gBAAgB;AAAA,QACrC,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,aACJ,KACA,SACyB;AACzB,UAAM,WAAW,KAAK,SAAS;AAC/B,QAAI,CAAC,UAAU;AAMb,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACvE;AACA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,WAAO,KAAK;AAAA,MACV,WAAW,KAAK,UAAU,OAAO;AAAA,MACjC,YAAY;AAAA,MACZ,2BAA2B,SAAS,WAAW;AAAA,MAC/C,SAAS;AAAA,QACP,OAAO,IAAI;AAAA,QACX,aAAa,MAAMC,kBAAiB,IAAI,EAAE,QAAQ;AAAA,QAClD,gBAAgB,MAAM,SAAS,WAAW,QAAQ;AAAA,QAClD,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,MAAM,iBACJ,KAC8C;AAC9C,UAAM,WAAW,KAAK,IAAI,IAAI,MAAM,WAAW,KAAK,KAAK,IAAI,GAAM;AACnE,QAAI,QAAQ;AACZ,eAAS;AACP,UAAI;AACF,eAAO,MAAM,KAAK,SAAS,OAAO,MAAM;AAAA,UACtC,UAAU,KAAK,SAAS;AAAA,UACxB,OAAO,IAAI;AAAA,UACX,SAAS,IAAI,MAAM;AAAA,QACrB,CAAC;AAAA,MACH,SAAS,OAAO;AACd,cAAM,WACJ,iBAAiB,eAAe,MAAM,SAAS;AACjD,YAAI,CAAC,SAAU,OAAM;AACrB,YAAI,KAAK,KAAK,IAAI,SAAS,UAAU;AACnC,eAAK,SAAS,UAAU;AAAA,YACtB,MAAM;AAAA,YACN,SAAS,sCAAsC,IAAI,EAAE;AAAA,UACvD,CAAC;AACD,iBAAO;AAAA,QACT;AACA,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAGzD,gBAAQ,KAAK,IAAI,QAAQ,GAAG,GAAK;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,aACJ,KACA,UACqB;AACrB,UAAM,WAAW,KAAK,SAAS;AAC/B,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAM,SAAS,MAAM,KAAK;AAAA,MACxB;AAAA,MACA,eAAe;AAAA,MACf,sBAAsB,SAAS,WAAW;AAAA,MAC1C,UAAU;AAAA,QACR,OAAO,IAAI;AAAA,QACX,aAAa,MAAM,SAAS,WAAW,QAAQ;AAAA,QAC/C,gBAAgB,MAAMA,kBAAiB,IAAI,EAAE,QAAQ;AAAA,QACrD,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AACD,QAAI,CAAC,OAAO,IAAI;AACd,YAAM,IAAI;AAAA,QACR,gBAAgB,IAAI,EAAE,iFACiB,OAAO,MAAM;AAAA,MACtD;AAAA,IACF;AACA,WAAO,KAAK,MAAM,OAAO,SAAS;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QAAQ,QAA+C;AAC3D,QAAI;AACF,YAAM,OAAO;AAAA,IACf,SAAS,OAAO;AACd,WAAK,aACH,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,SAAS,QAA6C;AAC1D,SAAK,WAAW;AAChB,UAAM,SAAS,CAAC,GAAG,KAAK,QAAQ,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,IAAI,OAAO;AAAA,MACjE;AAAA,MACA,SAAS,KAAK;AAAA,IAChB,EAAE;AACF,SAAK,UAAU;AACf,QAAI,OAAO,WAAW,EAAG;AACzB,UAAM,KAAK;AAAA,MAAQ,MACjB,KAAK,SAAS,OAAO,QAAQ;AAAA,QAC3B,UAAU,KAAK,SAAS;AAAA,QACxB;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAGA,SAAS,aAAa,QAA2B,QAAyB;AACxE,QAAM,SAAS,OAAO,YAAY;AAClC,SAAO,OAAO,KAAK,CAAC,UAAU;AAC5B,UAAM,KAAK,MAAM,YAAY;AAC7B,WACE,OAAO,UAAU,OAAO,GAAG,MAAM,aAAa,GAAG,EAAE,cAAc;AAAA,EAErE,CAAC;AACH;AAEA,SAAS,MAAM,IAAY,QAAoC;AAC7D,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,WAAW,SAAS,EAAE;AACpC,WAAO;AAAA,MACL;AAAA,MACA,MAAM;AACJ,qBAAa,KAAK;AAClB,gBAAQ;AAAA,MACV;AAAA,MACA,EAAE,MAAM,KAAK;AAAA,IACf;AAAA,EACF,CAAC;AACH;;;AXvtBA,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqCd,IAAM,YAAmB;AAAA,EACvB,KAAK,CAAC,SAAS,QAAQ,OAAO,MAAM,IAAI;AAAA,EACxC,KAAK,CAAC,SAAS,QAAQ,OAAO,MAAM,IAAI;AAAA,EACxC,SAAS;AACX;AAGA,eAAsB,OACpB,MACA,UASI,CAAC,GACc;AACnB,QAAM,CAAC,SAAS,GAAG,IAAI,IAAI;AAC3B,QAAM,QAAQ,QAAQ,SAAS,YAAY;AAC3C,QAAM,KAAY,EAAE,GAAG,WAAW,GAAG,QAAQ,GAAG;AAChD,QAAM,SAAS,QAAQ;AAEvB,UAAQ,SAAS;AAAA,IACf,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,SAAG,IAAI,KAAK;AACZ,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAGH,SAAG,IAAI,cAAc,CAAC;AACtB,aAAO;AAAA,IACT,KAAK;AACH,aAAO,eAAe,OAAO,MAAM,IAAI,MAAM;AAAA,IAC/C,KAAK;AACH,aAAO,WAAW,OAAO,MAAM,IAAI,MAAM;AAAA,IAC3C,KAAK;AACH,aAAO,cAAc,OAAO,EAAE;AAAA,IAChC,KAAK;AACH,aAAO,WAAW,OAAO,MAAM,EAAE;AAAA,IACnC,KAAK;AACH,aAAO,aAAa,OAAO,MAAM,EAAE;AAAA,IACrC,KAAK;AACH,aAAO,aAAa,OAAO,OAAO,EAAE;AAAA,IACtC,KAAK;AACH,aAAO,aAAa,OAAO,MAAM,EAAE;AAAA,IACrC,KAAK;AACH,aAAO,gBAAgB,OAAO,MAAM,EAAE;AAAA,IACxC,KAAK;AACH,aAAO,aAAa,OAAO,MAAM,EAAE;AAAA,IACrC,KAAK;AACH,aAAO,cAAc,OAAO,MAAM,EAAE;AAAA,IACtC,KAAK;AACH,aAAO,gBAAgB,OAAO,EAAE;AAAA,IAClC;AACE,SAAG,IAAI,oBAAoB,OAAO;AAAA;AAAA,EAAO,KAAK,EAAE;AAChD,aAAO;AAAA,EACX;AACF;AAIA,eAAe,eACb,OACA,MACA,IACA,QACmB;AACnB,QAAM,SAAS,KAAK,CAAC;AACrB,MAAI,WAAW,QAAW;AACxB,OAAG,IAAI,+BAA+B;AACtC,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,gBAAgB,MAAM;AACrC,QAAM,EAAE,QAAQ,SAAS,WAAW,SAAS,MAAM,IAAI,MAAM,QAAQ,KAAK;AAE1E,aAAW,WAAW,OAAO,UAAU;AACrC,OAAG,IAAI,WAAW,QAAQ,KAAK,KAAK,QAAQ,OAAO;AAAA,CAAI;AAAA,EACzD;AAEA,QAAM,SAAS,IAAI,eAAe,EAAE,OAAO,CAAC;AAC5C,QAAM,SAAS,IAAI,OAAO;AAAA,IACxB;AAAA,IACA,UAAU;AAAA,IACV,OAAO;AAAA,IACP,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,eAAe,MAAM,OAAO,mBAAmB;AACrD,MAAI,aAAa,WAAW,GAAG;AAG7B,OAAG;AAAA,MACD;AAAA,IAEF;AACA,WAAO;AAAA,EACT;AAEA,KAAG,IAAI;AAAA,gBAAmB,MAAM;AAAA,CAAI;AAEpC,QAAM,SAAS,MAAM,QAAQ;AAAA,IAC3B;AAAA,IACA,eAAe;AAAA,IACf,OAAO,UAAU;AAAA,IACjB;AAAA,IACA,QAAQ,MAAM,IAAI,eAAe,MAAM,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;AAAA,IACtE,QAAQ,CAAC,SAAS;AAChB,YAAM,UAAU,KAAK;AAAA,QACnB;AAAA,QACA,KAAK,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,GAAM;AAAA,MACnD;AACA,SAAG;AAAA,QACD;AAAA,WAAc,KAAK,eAAe;AAAA,WACpB,KAAK,QAAQ,qBAAqB,OAAO,OAAO,CAAC;AAAA;AAAA;AAAA,MAEjE;AAAA,IACF;AAAA,IACA,QAAQ,MAAM;AACZ,SAAG,IAAI,GAAG;AAAA,IACZ;AAAA,IACA,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO;AAAA,EAC3C,CAAC;AAED,MAAI,CAAC,OAAO,IAAI;AACd,OAAG,IAAI;AAAA;AAAA,IAAS,OAAO,OAAO;AAAA,CAAI;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,IAAI,SAAS,MAAM,QAAQ;AAC5C,QAAM,SAAS,KAAK;AACpB,QAAM,SAAS,IAAI,OAAO,OAAO;AAEjC,KAAG;AAAA,IACD,cAAc,OAAO,QAAQ,cAAc,OAAO,QAAQ,KAAK;AAAA;AAAA,uBACrC,MAAM;AAAA;AAAA;AAAA,EAClC;AAEA,SAAO,QAAQ,OAAO,CAAC,OAAO,QAAQ,MAAM,GAAG,IAAI,MAAM;AAC3D;AAIA,eAAe,WACb,OACA,MACA,IACA,QACmB;AACnB,QAAM,WAAW,IAAI,SAAS,MAAM,QAAQ;AAC5C,QAAM,SAAS,KAAK;AAEpB,QAAM,SAAS,KAAK,CAAC;AACrB,QAAM,UACJ,WAAW,SACP,SAAS,KAAK,EAAE,IAAI,CAAC,YAAY,QAAQ,MAAM,IAC/C,CAAC,gBAAgB,MAAM,CAAC;AAE9B,MAAI,QAAQ,WAAW,GAAG;AACxB,OAAG,IAAI,6DAA6D;AACpE,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,OAAO,SAAS,IAAI,MAAM;AAC3C;AAEA,eAAe,QACb,OACA,SACA,IACA,QACmB;AACnB,QAAM,EAAE,QAAQ,SAAS,WAAW,SAAS,MAAM,IAAI,MAAM,QAAQ,KAAK;AAC1E,QAAM,WAAW,IAAI,eAAe,MAAM,IAAI;AAC9C,QAAM,WAAW,IAAI,SAAS,MAAM,QAAQ;AAC5C,QAAM,SAAS,KAAK;AAEpB,QAAM,aAAa,IAAI,gBAAgB;AACvC,UAAQ;AAAA,IACN;AAAA,IACA,MAAM;AACJ,iBAAW,MAAM;AAAA,IACnB;AAAA,IACA,EAAE,MAAM,KAAK;AAAA,EACf;AACA,QAAM,UAAoB,CAAC;AAE3B,aAAW,UAAU,SAAS;AAC5B,UAAM,UAAU,SAAS,IAAI,MAAM;AACnC,QAAI,CAAC,SAAS;AACZ,SAAG,IAAI,mBAAmB,MAAM;AAAA,CAAI;AACpC;AAAA,IACF;AACA,UAAM,SAAS,IAAI,OAAO;AAAA,MACxB,QAAQ,IAAI,eAAe;AAAA,QACzB;AAAA,QACA,UAAU;AAAA,UACR,UAAU,QAAQ;AAAA,UAClB,MAAM,CAAC,UAAU,SAAS,YAAY,KAAK;AAAA,QAC7C;AAAA,MACF,CAAC;AAAA,MACD,UAAU,QAAQ;AAAA,MAClB,OAAO,QAAQ;AAAA,MACf,UAAU;AAAA,QACR,MAAM,MAAM,SAAS,KAAK,KAAK,IAAI,CAAC;AAAA,QACpC,YAAY,QAAQ;AAAA,MACtB;AAAA,MACA,eAAe;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,CAAC,UAAU;AAClB,eAAO,QAAQ,OAAO,EAAE;AAAA,MAC1B;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,MAAM;AAAA,EACrB;AAEA,MAAI,QAAQ,WAAW,EAAG,QAAO;AAMjC,MAAI,WAAW,QAAW;AACxB,UAAM,OAAO,MAAY;AACvB,iBAAW,MAAM;AAKjB,cAAQ,IAAI,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS,UAAU,CAAC,CAAC,EAAE;AAAA,QAChE,MAAM;AACJ,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,QACA,CAAC,UAAmB;AAIlB,aAAG,IAAI,sCAAsC,OAAO,KAAK,CAAC;AAAA,CAAI;AAC9D,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AACA,YAAQ,GAAG,UAAU,IAAI;AACzB,YAAQ,GAAG,WAAW,IAAI;AAAA,EAC5B;AAEA,QAAM,QAAQ,eAAe,KAAK,IAAI,CAAC;AACvC,QAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI,WAAW,MAAM,CAAC,CAAC;AACxE,QAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,WAAW,OAAO,SAAS,UAAU,CAAC,CAAC;AACtE,SAAO;AACT;AAUA,SAAS,OAAO,QAAgB,OAAoB,IAAiB;AACnE,QAAM,MAAK,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,IAAI,EAAE;AAChD,QAAM,OAAO,IAAI,IAAI,MAAM,EAAE;AAE7B,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,SAAG,IAAI,GAAG,EAAE,IAAI,IAAI,YAAY,MAAM,IAAI,IAAI,MAAM,KAAK;AAAA,CAAI;AAC7D;AAAA,IACF,KAAK;AACH,SAAG;AAAA,QACD,GAAG,EAAE,IAAI,IAAI,IAAI,MAAM,OAAO,IAAI,MAAM,KAAK,KACvC,OAAO,MAAM,UAAU,CAAC;AAAA;AAAA,MAChC;AACA;AAAA,IACF,KAAK;AACH,SAAG;AAAA,QACD,GAAG,EAAE,IAAI,IAAI,YAAY,MAAM,KAAK,KAC/B,kBAAkB,MAAM,MAAM,CAAC;AAAA;AAAA,MACtC;AACA;AAAA,IACF,KAAK;AACH,SAAG,IAAI,GAAG,EAAE,IAAI,IAAI;AAAA,CAAuC;AAC3D;AAAA,IACF,KAAK;AACH,SAAG,IAAI,GAAG,EAAE,IAAI,IAAI,IAAI,kBAAkB,MAAM,OAAO,CAAC;AAAA,CAAI;AAC5D;AAAA,IACF,KAAK;AACH;AAAA,EACJ;AACF;AAIA,eAAe,cAAc,OAAoB,IAA8B;AAC7E,QAAM,EAAE,QAAQ,SAAS,WAAW,SAAS,MAAM,IAAI,MAAM,QAAQ,KAAK;AAC1E,QAAM,WAAW,IAAI,SAAS,MAAM,QAAQ;AAC5C,QAAM,SAAS,KAAK;AAEpB,QAAM,SAAS,MAAM,SAAS,KAAK;AACnC,QAAM,MAAM,KAAK,IAAI;AAErB,KAAG,IAAI,cAAc,CAAC;AAItB,KAAG;AAAA,IACD,aAAa,MAAM,IAAI,eAAe,MAAM,IAAI,EAAE,YAAY,GAAG,CAAC;AAAA;AAAA,EACpE;AACA,KAAG,IAAI,UAAU,SAAS,WAAW,SAAS;AAAA;AAAA,CAAM;AAEpD,KAAG,IAAI,eAAe;AACtB,QAAM,OAAO,SAAS,KAAK;AAC3B,MAAI,KAAK,WAAW,GAAG;AACrB,OAAG,IAAI,8CAAyC;AAAA,EAClD;AACA,aAAW,WAAW,MAAM;AAC1B,OAAG,IAAI,KAAK,QAAQ,MAAM,QAAQ,QAAQ,cAAc,QAAQ,KAAK;AAAA,CAAI;AAGzE,OAAG,IAAI,eAAeC,aAAY,QAAQ,KAAK,QAAQ,CAAC;AAAA,CAAI;AAAA,EAC9D;AAEA,KAAG,IAAI,YAAY;AACnB,MAAI,OAAO,OAAO,WAAW,GAAG;AAC9B,OAAG,IAAI,uBAAuB;AAAA,EAChC;AACA,aAAW,SAAS,OAAO,QAAQ;AACjC,OAAG;AAAA,MACD,KAAK,MAAM,KAAK,OAAO,EAAE,CAAC,IAAI,MAAM,SAAS,IAAI,MAAM,KAAK,iBAC3C,MAAM,UAAU;AAAA;AAAA,IACnC;AAAA,EACF;AACA,aAAW,WAAW,OAAO,UAAU;AACrC,OAAG,IAAI,OAAO,QAAQ,KAAK,KAAK,QAAQ,OAAO;AAAA,CAAI;AAAA,EACrD;AAEA,QAAM,UAAU,UAAU,KAAK;AAC/B,KAAG,IAAI,8BAA8B;AACrC,KAAG,IAAI;AAAA,CAAiB;AACxB,MAAI,QAAQ,WAAW,GAAG;AACxB,OAAG,IAAI,iBAAiB;AAAA,EAC1B;AACA,aAAW,SAAS,SAAS;AAC3B,OAAG;AAAA,MACD,KAAK,MAAM,KAAK,OAAO,MAAM,MAAM,GAC9B,MAAM,SAAS,SAAY,KAAK,KAAK,kBAAkB,MAAM,IAAI,CAAC,GAAG;AAAA;AAAA,IAC5E;AAAA,EACF;AAEA,QAAM,aAAa,MAAM,QAAQ,GAAG;AACpC,QAAM,UAAU,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS;AAChE,MAAI,QAAQ,SAAS,GAAG;AACtB,OAAG,IAAI,wCAAmC;AAC1C,eAAW,SAAS,SAAS;AAC3B,YAAM,QAAQ,WAAW,MAAM,UAAU,KAAK;AAC9C,SAAG;AAAA,QACD,MAAM,oBACF,KAAK,MAAM,UAAU,KAAK,MAAM,QAAQ,CAAC,CAAC,oBACrC,OAAO,MAAM,sBAAsB,CAAC,CAAC;AAAA,IAC1C,KAAK,MAAM,UAAU;AAAA;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,KAAG,IAAI,oCAAoC;AAC3C,KAAG;AAAA,IACD,KAAK,OAAO,MAAM,IAAI,CAAC,0BAA0B,OAAO,MAAM,OAAO,cAAc,CAAC,MAC/E,OAAO,MAAM,GAAG,CAAC,eAAe,OAAO,MAAM,OAAO,aAAa,CAAC;AAAA;AAAA,EACzE;AAEA,QAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,QAAM,UAAU,QAAQ,OAAO,CAAC,UAAU,MAAM,SAAS,QAAQ;AACjE,QAAM,WAAW,QAAQ,OAAO,CAAC,UAAU,MAAM,SAAS,SAAS;AACnE,KAAG,IAAI,0BAA0B;AACjC,KAAG;AAAA,IACD,KAAK,OAAO,QAAQ,MAAM,CAAC,aACtB,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,QACzD,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,OAAO,EAAE,MAAM,CAAC,YAC5D,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,SAAS,EAAE,MAAM,CAAC;AAAA;AAAA,EACrE;AACA,KAAG;AAAA,IACD,eAAe,MAAM,UAAU,6BAC1B,OAAO,OAAO,OAAO,QAAQ,mBAAmB,CAAC;AAAA;AAAA,EACxD;AACA,SAAO;AACT;AAIA,eAAe,WACb,OACA,MACA,IACmB;AACnB,QAAM,OAAO,KAAK,SAAS,QAAQ;AACnC,QAAM,SAAS,KAAK,UAAU,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,SAAS;AACxE,QAAM,QACJ,WAAW,KAAK,KAAK,KAAK,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,KAAK,IAAI,KAAK,EAAE;AAEzE,QAAM,EAAE,QAAQ,IAAI,MAAM,QAAQ,KAAK;AACvC,QAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,QAAM,QAAQ,QAAQ,MAAM,CAAC,KAAK;AAElC,MAAI,MAAM,WAAW,GAAG;AACtB,OAAG,IAAI,uCAAuC;AAC9C,WAAO;AAAA,EACT;AAEA,aAAW,SAAS,OAAO;AACzB,UAAM,KAAK,IAAI,KAAK,MAAM,EAAE,EAAE,YAAY,EAAE,QAAQ,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE;AACzE,QAAI,MAAM,SAAS,WAAW;AAC5B,SAAG;AAAA,QACD,GAAG,EAAE,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,IAAI,MAAM,KAAK,MAC7C,MAAM,eAAe,SAClB,KACA,IAAI,OAAO,MAAM,UAAU,CAAC,QAChC,GAAG,MAAM,WAAW,SAAY,KAAK,KAAK,kBAAkB,MAAM,MAAM,CAAC,EAAE;AAAA;AAAA,MAC/E;AACA;AAAA,IACF;AAEA,OAAG;AAAA,MACD,GAAG,EAAE,KAAK,MAAM,SAAS,OAAO,CAAC,CAAC,IAAI,MAAM,IAAI,QACvC,MAAM,SAAS,IAAI,MAAM,KAAK,SAAS,MAAM,KAAK,MACpD,IAAI,IAAI,MAAM,MAAM,EAAE,IAAI;AAAA;AAAA,IACnC;AACA,QAAI,MAAM,WAAW,QAAW;AAG9B,SAAG;AAAA,QACD,mCAAmC,OAAO,MAAM,WAAW,CAAC,kBAChD,MAAM,WAAW,MAAM,GAAG,EAAE,CAAC;AAAA;AAAA,MAC3C;AAAA,IACF,WAAW,MAAM;AACf,SAAG,IAAI,GAAG,OAAO,kBAAkB,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,IACvD,OAAO;AACL,YAAMC,aAAY,MAAM,OAAO,MAAM,IAAI,EAAE,CAAC,KAAK;AACjD,SAAG;AAAA,QACD,cAAc,kBAAkBA,WAAU,MAAM,GAAG,EAAE,CAAC,CAAC,GAClD,MAAM,OAAO,SAAS,KAAK,WAAM,EAAE;AAAA;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,MAAM;AACT,OAAG,IAAI;AAAA,GAAM,OAAO,QAAQ,MAAM,CAAC;AAAA,CAAuC;AAAA,EAC5E;AACA,SAAO;AACT;AAEA,SAAS,OAAO,MAAsB;AACpC,SAAO,KACJ,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,cAAc,IAAI,EAAE,EAClC,KAAK,IAAI;AACd;AAIA,eAAe,aACb,OACA,OACA,IACmB;AACnB,QAAMC,OAAM,MAAM,MAAM,EAAE,WAAW,KAAK,CAAC;AAC3C,MAAI,OAAO;AACT,UAAMC,WAAU,MAAM,WAAW,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,CAAI;AAChE,OAAG;AAAA,MACD;AAAA,IACF;AAAA,EACF,OAAO;AACL,UAAMC,IAAG,MAAM,WAAW,EAAE,OAAO,KAAK,CAAC;AACzC,OAAG,IAAI,WAAW;AAAA,EACpB;AACA,SAAO;AACT;AAEA,eAAe,SAAS,OAAsC;AAC5D,MAAI;AACF,UAAMC,MAAK,MAAM,SAAS;AAC1B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,eAAe,aACb,OACA,MACA,IACmB;AACnB,QAAM,YAAY,IAAI,UAAU,MAAM,SAAS;AAC/C,QAAM,UAAU,KAAK;AAErB,MAAI,KAAK,CAAC,MAAM,YAAY,KAAK,WAAW,GAAG;AAC7C,UAAM,UAAU,UAAU,KAAK;AAC/B,QAAI,QAAQ,WAAW,GAAG;AACxB,SAAG;AAAA,QACD;AAAA,MAEF;AACA,aAAO;AAAA,IACT;AACA,eAAW,SAAS,SAAS;AAC3B,SAAG;AAAA,QACD,GAAG,MAAM,KAAK,QAAQ,MAAM,MAAM,GAC7B,MAAM,SAAS,SAAY,KAAK,MAAM,kBAAkB,MAAM,IAAI,CAAC,GAAG;AAAA;AAAA,MAC7E;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,CAAC,WAAW,OAAO,GAAG,SAAS,IAAI;AACzC,MAAI,cAAc,UAAa,UAAU,QAAW;AAClD,OAAG,IAAI,kDAAkD;AACzD,WAAO;AAAA,EACT;AACA,QAAM,SAAS,gBAAgB,SAAS;AAIxC,QAAM,YAAY,MAAM,GAAG;AAAA,IACzB;AAAA,+BAAkC,KAAK,QAAQ,MAAM;AAAA;AAAA;AAAA;AAAA,QAG1C,KAAK;AAAA,EAClB;AACA,MAAI,CAAC,WAAW;AACd,OAAG,IAAI,mBAAmB;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAAA,IACd;AAAA,MACE;AAAA,MACA;AAAA,MACA,GAAI,UAAU,SAAS,IAAI,EAAE,MAAM,UAAU,KAAK,GAAG,EAAE,IAAI,CAAC;AAAA,IAC9D;AAAA,IACA,KAAK,IAAI;AAAA,EACX;AACA,KAAG,IAAI,WAAW,KAAK,OAAO,MAAM;AAAA,CAAI;AACxC,SAAO;AACT;AAgBA,eAAe,aACb,OACA,MACA,IACmB;AACnB,QAAM,CAAC,YAAY,OAAO,GAAG,IAAI,IAAI;AACrC,MAAI,eAAe,UAAa,UAAU,QAAW;AACnD,OAAG;AAAA,MACD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,MAAI,UAAU,UAAU,UAAU,WAAW,UAAU,UAAU;AAC/D,OAAG,IAAI,IAAI,KAAK;AAAA,CAAwD;AACxE,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,KAAK,QAAQ,OAAO;AACrC,MAAI;AACJ,MAAI,aAAa,IAAI;AACnB,UAAMC,OAAM,KAAK,WAAW,CAAC;AAC7B,UAAMC,UAAS,OAAOD,IAAG;AACzB,QAAIA,SAAQ,UAAa,CAAC,OAAO,SAASC,OAAM,KAAKA,WAAU,GAAG;AAChE,SAAG,IAAI,4DAA4D;AACnE,aAAO;AAAA,IACT;AACA,eAAW,KAAK,MAAMA,OAAM;AAAA,EAC9B;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,MAAMC,UAAS,MAAM,QAAQ,MAAM;AAAA,EAC3C,QAAQ;AACN,OAAG;AAAA,MACD,gBAAgB,MAAM,MAAM;AAAA;AAAA;AAAA,IAE9B;AACA,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,QAAQ;AACN,OAAG,IAAI,GAAG,MAAM,MAAM;AAAA,CAA6C;AACnE,WAAO;AAAA,EACT;AACA,QAAM,SAAS,aAAa,UAAU,MAAM;AAC5C,MAAI,CAAC,OAAO,SAAS;AACnB,OAAG,IAAI,GAAG,MAAM,MAAM;AAAA,CAAgD;AACtE,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,OAAO,KAAK,SAAS,UAAU;AAC/C,MAAI,CAAC,SAAS;AACZ,UAAM,QAAQ,OAAO,KAAK,OAAO,KAAK,QAAQ;AAC9C,OAAG;AAAA,MACD,qBAAqB,UAAU,QAAQ,MAAM,MAAM;AAAA,KAChD,MAAM,SAAS,IAAI,eAAe,MAAM,KAAK,IAAI,CAAC;AAAA,IAAO;AAAA,IAC9D;AACA,WAAO;AAAA,EACT;AAEA,QAAM,aAAaC,mBAAkB,QAAQ,OAAO;AACpD,QAAM,UAAU,QAAQ,WAAW,WAAW;AAC9C,QAAM,OAAOC,aAAY,QAAQ,SAAS,OAAO;AACjD,QAAM,WAAW,UAAU;AAI3B,MAAI,SAAS,kBAAkB,UAAU;AACvC,OAAG;AAAA,MACD,GAAG,WAAW,KAAK;AAAA;AAAA;AAAA,IAErB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,aAAa,UAAU;AAClC,UAAM,MAAM,YAAY,QAAQ,OAAO;AACvC,QAAI,QAAQ,QAAW;AACrB,SAAG;AAAA,QACD,GAAG,WAAW,KAAK;AAAA,mCAEd,UAAU,IAAI,KAAK;AAAA;AAAA,MAC1B;AACA,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,MAAM,KAAK,QAAQ,CAAC;AACrC,UAAM,YAAY,MAAM,GAAG;AAAA,MACzB;AAAA,uCAA0C,WAAW,KAAK;AAAA;AAAA,GAEpD,OAAO;AAAA;AAAA;AAAA,QAEF,UAAU,OAAO,UAAU,WAAW,WAAW,yBAAyB;AAAA,IACvF;AACA,QAAI,CAAC,WAAW;AACd,SAAG,IAAI,mBAAmB;AAC1B,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,SAAS,UAAU,IAAI;AAAA,MACjC,GAAG;AAAA,MACH,OAAO;AAAA,MACP,OAAO;AAAA,QACL,uBAAuB,QAAQ,OAAO,yBAAyB;AAAA,QAC/D,GAAG,QAAQ;AAAA,QACX,cAAc;AAAA,QACd,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,EACF,OAAO;AACL,WAAO,KAAK,SAAS,UAAU,IAAI;AAAA,MACjC,GAAG;AAAA,MACH,OAAO;AAAA;AAAA;AAAA,MAGP,GAAI,SAAS,aAAa,CAAC,YAAY,QAAQ,UAAU,SACrD,EAAE,OAAO,EAAE,GAAG,QAAQ,OAAO,cAAc,MAAM,EAAE,IACnD,CAAC;AAAA,IACP;AAAA,EACF;AAEA,QAAMR,OAAMS,SAAQ,MAAM,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AACtD,QAAMR,WAAU,MAAM,QAAQ,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAEzE,QAAM,UAAU,OAAO,KAAK,SAAS,UAAU,EAAE,OAAO;AACxD,KAAG;AAAA,IACD,GAAG,UAAU,sBAAsB,KAAK,MACrC,YAAY,UAAa,CAAC,WACvB,KACA,eAAe,OAAO,OAAO,CAAC,aAClC;AAAA,EACJ;AACA,SAAO;AACT;AAEA,eAAe,gBACb,OACA,MACA,IACmB;AACnB,QAAM,CAAC,WAAW,KAAK,IAAI;AAC3B,MAAI,cAAc,UAAa,UAAU,QAAW;AAClD,OAAG,IAAI,8CAA8C;AACrD,WAAO;AAAA,EACT;AACA,QAAM,YAAY,IAAI,UAAU,MAAM,SAAS;AAC/C,QAAM,UAAU,KAAK;AACrB,QAAM,UAAU,MAAM,UAAU,OAAO,gBAAgB,SAAS,GAAG,KAAK;AACxE,KAAG;AAAA,IACD,UACI,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA;AAAA,EACd;AACA,SAAO;AACT;AAIA,eAAe,cACb,OACA,MACA,IACmB;AACnB,QAAM,SAAS,KAAK,CAAC;AACrB,MAAI,WAAW,QAAW;AACxB,OAAG,IAAI,kCAAkC;AACzC,WAAO;AAAA,EACT;AACA,QAAM,WAAW,IAAI,SAAS,MAAM,QAAQ;AAC5C,QAAM,SAAS,KAAK;AACpB,QAAM,UAAU,MAAM,SAAS,OAAO,gBAAgB,MAAM,CAAC;AAC7D,KAAG;AAAA,IACD,UACI,UAAU,gBAAgB,MAAM,CAAC;AAAA,IAEjC,mBAAmB,gBAAgB,MAAM,CAAC;AAAA;AAAA,EAChD;AACA,SAAO;AACT;AAIA,eAAe,gBACb,OACA,IACmB;AACnB,QAAM,EAAE,QAAQ,SAAS,WAAW,SAAS,MAAM,IAAI,MAAM,QAAQ,KAAK;AAC1E,QAAM,SAAS,IAAI,OAAO;AAAA,IACxB,QAAQ,IAAI,eAAe,EAAE,QAAQ,yBAAyB,CAAC;AAAA,IAC/D,UAAU;AAAA,IACV,OAAO;AAAA,IACP,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,aAAa,MAAM,OAAO,mBAAmB;AACnD,QAAM,kBAAkB,IAAI,IAAI,WAAW,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAE7D,KAAG,IAAI,qBAAqB;AAC5B,aAAW,SAAS,OAAO,QAAQ;AACjC,UAAM,KAAK,gBAAgB,IAAI,MAAM,IAAI;AACzC,UAAM,OACJ,MAAM,SAAS,SACX,4BACA,MAAM,SAAS,iBACb,iDACA,MAAM,oBACJ,8BAAyB,OAAO,MAAM,sBAAsB,CAAC,CAAC,UAC9D;AACV,OAAG;AAAA,MACD,KAAK,KAAK,WAAM,QAAG,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC,IACvC,MAAM,SAAS,IAAI,MAAM,KAAK,GAC9B,MAAM,YAAY,SAAY,KAAK,MAAM,MAAM,OAAO,EAAE;AAAA,QAClD,IAAI;AAAA;AAAA,IACjB;AAAA,EACF;AACA,aAAW,WAAW,OAAO,UAAU;AACrC,OAAG,IAAI,OAAO,QAAQ,KAAK,KAAK,QAAQ,OAAO;AAAA,CAAI;AAAA,EACrD;AACA,KAAG;AAAA,IACD;AAAA,EAAK,OAAO,WAAW,MAAM,CAAC,OAAO,OAAO,OAAO,OAAO,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA,EAInE;AACA,SAAO,WAAW,WAAW,IAAI,IAAI;AACvC;AAIA,eAAe,QAAQ,OAMpB;AACD,QAAM,SAAS,MAAM,WAAW,MAAM,MAAM;AAC5C,QAAM,UAAU,IAAI,WAAW;AAAA,IAC7B,MAAM,MAAM;AAAA,IACZ,qBAAqB,OAAO,OAAO,QAAQ;AAAA,IAC3C,iBAAiB,OAAO,OAAO,QAAQ;AAAA,EACzC,CAAC;AACD,QAAM,YAAY,IAAI,UAAU,MAAM,SAAS;AAC/C,QAAM,UAAU,KAAK;AACrB,QAAM,UAAU,IAAI,QAAQ,MAAM,SAAS,OAAO,OAAO,SAAS;AAClE,QAAM,QAAQ,KAAK,KAAK,IAAI,CAAC;AAC7B,QAAM,QAAQ,IAAI,YAAY,MAAM,KAAK;AACzC,QAAM,MAAM,KAAK,KAAK,IAAI,CAAC;AAC3B,SAAO,EAAE,QAAQ,SAAS,WAAW,SAAS,MAAM;AACtD;AAQA,eAAe,qBAAqB,UAAoC;AACtE,MAAI,CAAC,QAAQ,MAAM,OAAO;AACxB,YAAQ,OAAO;AAAA,MACb;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,MAAI;AACF,UAAM,SAAS,MAAM,GAAG,SAAS,GAAG,QAAQ,SAAS;AACrD,WAAO,YAAY,KAAK,OAAO,KAAK,CAAC;AAAA,EACvC,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;AAQA,SAAS,YAAoB;AAC3B,QAAM,WAAW,QAAQ,IAAI,cAAc;AAC3C,MAAI,aAAa,UAAa,aAAa,GAAI,QAAO,SAAS,MAAM,GAAG,GAAG;AAC3E,MAAI;AACF,WAAO,GAAG,SAAS,EAAE,QAAQ,IAAI,SAAS,CAAC,GAAG,MAAM,GAAG,GAAG;AAAA,EAC5D,QAAQ;AACN,WAAO,SAAS,EAAE,MAAM,GAAG,GAAG;AAAA,EAChC;AACF;AAGA,eAAsB,KAAK,MAA4C;AACrE,MAAI;AACF,WAAO,MAAM,OAAO,IAAI;AAAA,EAC1B,SAAS,OAAO;AACd,YAAQ,OAAO;AAAA,MACb,GAAG,iBAAiB,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA;AAAA,IAC3F;AACA,WAAO;AAAA,EACT;AACF;;;AFn0BO,IAAM,iBAAiB;AAwBvB,SAAS,gBAA+B;AAC7C,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,UAAUS;AAAA,IACV,UAAU,QAAQ;AAAA,IAClB,MAAM,QAAQ;AAAA,IACd,MAAM,QAAQ,SAAS;AAAA,EACzB;AACF;AAGO,SAAS,cAAc,IAAmB,cAAc,GAAW;AACxE,SACE,UAAU,EAAE,MAAM,cAAc,EAAE,QAAQ;AAAA,EACvC,EAAE,QAAQ,IAAI,EAAE,IAAI,UAAU,EAAE,IAAI;AAAA;AAE3C;","names":["PROTOCOL_VERSION","mkdir","readFile","rm","stat","writeFile","dirname","backendDescriptor","resolveCost","mkdir","readFile","writeFile","dirname","z","readFile","z","z","readFile","sleep","mkdir","readFile","writeFile","dirname","z","fingerprint","mkdir","readFile","writeFile","dirname","isNotFound","mkdir","readFile","writeFile","dirname","z","z","readFile","mkdir","dirname","writeFile","mkdir","readFile","writeFile","dirname","z","publicIdentityOf","backendDescriptor","join","platform","platform","join","backendDescriptor","payload","publicIdentityOf","fingerprint","firstLine","mkdir","writeFile","rm","stat","raw","parsed","readFile","backendDescriptor","resolveCost","dirname","PROTOCOL_VERSION"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/allowlist.ts","../src/cli.ts","../src/budgets.ts","../src/client.ts","../src/config.ts","../src/ssrf.ts","../src/connect.ts","../src/ingress.ts","../src/identity.ts","../src/pairings.ts","../src/spend.ts","../src/paths.ts","../src/runner.ts","../src/backends/index.ts","../src/backends/claude-cli.ts","../src/backends/openai-http.ts","../src/compose.ts"],"sourcesContent":["/**\n * `byollm` — what end users run.\n *\n * The CLI (`byollm connect`, `status`, `log`, `pause`, `allow`) is the\n * product surface; this module is the same machinery as a library, so the\n * conformance kit can drive a real daemon in-process instead of shelling out.\n *\n * @packageDocumentation\n */\n\nimport { PROTOCOL_VERSION } from \"@byollm/protocol\";\n\nexport { Allowlist, normalizeOrigin, type AllowEntry } from \"./allowlist.js\";\n\nexport { main, runCli, type CliIo, type ExitCode } from \"./cli.js\";\n\nexport {\n ClaudeCliBackend,\n IMPLEMENTED_BACKEND_IDS,\n OpenAiHttpBackend,\n childEnv,\n claudeArgv,\n createBackend,\n type Backend,\n type BackendErrorCode,\n type BackendHealth,\n type BackendInit,\n type BackendRequest,\n type BackendResult,\n} from \"./backends/index.js\";\n\nexport { Budgets, type BudgetDecision, type BudgetRefusal } from \"./budgets.js\";\n\nexport { DeviceIdentity } from \"./identity.js\";\n\nexport {\n ClientError,\n ProtocolClient,\n type ClientErrorKind,\n type ClientOptions,\n} from \"./client.js\";\n\nexport { composePrompt } from \"./compose.js\";\n\nexport {\n DEFAULT_CONFIG,\n DaemonConfig,\n loadConfig,\n resolveConfig,\n type BackendConfig,\n type CommunityBudget,\n type ConfigProblem,\n type IngressRetention,\n type LoadedConfig,\n type Limits,\n type ResolvedRoute,\n type RouteConfig,\n} from \"./config.js\";\n\nexport {\n connect,\n currentPlatform,\n type ConnectOptions,\n type ConnectResult,\n} from \"./connect.js\";\n\nexport {\n IngressLog,\n hashText,\n stripControlChars,\n type IngressEntry,\n type IngressOptions,\n type OutcomeEntry,\n type PromptEntry,\n} from \"./ingress.js\";\n\nexport { daemonPaths, defaultRoot, type DaemonPaths } from \"./paths.js\";\n\nexport { SpendLedger, estimateCents } from \"./spend.js\";\n\nexport { Pairings, type Pairing } from \"./pairings.js\";\n\nexport {\n Runner,\n type RunnerEvent,\n type RunnerOptions,\n type RunnerStatus,\n} from \"./runner.js\";\n\nexport {\n BASE_URL_REFUSAL_MESSAGES,\n checkBaseUrl,\n type BaseUrlCheck,\n type BaseUrlRefusal,\n} from \"./ssrf.js\";\n\n/**\n * This daemon's version, reported on pairing and on every heartbeat.\n *\n * Kept in step with `package.json` by a test rather than by a build-time\n * define: an app's runner list shows this string, so a stale one is a lie\n * told to every user, and a literal that a test pins cannot drift quietly.\n */\nexport const DAEMON_VERSION = \"0.1.0-alpha.8\";\n\n/**\n * Everything needed to reason about one daemon — byollm_010 §5.\n *\n * `--version` used to print a package version and nothing else, which is the\n * least useful version string a distributed daemon can have. \"It doesn't work\n * on Windows\" with no platform, no Node version and no protocol version is\n * the most expensive sentence an open-source project receives, and every\n * later capability — deprecation warnings, a minimum-supported-version\n * policy, \"your daemon is N releases behind\" — needs these facts to exist.\n *\n * The same tuple goes in the handshake (byollm_009 §4), deliberately: a\n * support conversation and a version policy should be arguing about the same\n * numbers.\n */\nexport interface DaemonVersion {\n readonly daemon: string;\n readonly protocol: string;\n readonly platform: NodeJS.Platform;\n readonly arch: string;\n readonly node: string;\n}\n\nexport function daemonVersion(): DaemonVersion {\n return {\n daemon: DAEMON_VERSION,\n protocol: PROTOCOL_VERSION,\n platform: process.platform,\n arch: process.arch,\n node: process.versions.node,\n };\n}\n\n/** One line, for `--version` and for pasting into an issue. */\nexport function formatVersion(v: DaemonVersion = daemonVersion()): string {\n return (\n `byollm ${v.daemon} (protocol ${v.protocol})\\n` +\n `${v.platform}-${v.arch}, node ${v.node}\\n`\n );\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { z } from \"zod\";\n\n/**\n * One person, on one server, allowed to run work on this machine.\n *\n * Keyed by **(server origin, user id)** because owner ids are\n * server-namespace-local: `alice` on one app is not `alice` on another, and a\n * list keyed by id alone would silently merge strangers.\n */\nexport const AllowEntry = z\n .object({\n /** Origin of the server that issued the id, e.g. `https://app.example.com`. */\n origin: z.string().min(1),\n /** The app's id for the user. */\n owner: z.string().min(1),\n /** Optional human label, so the list is readable a month later. */\n note: z.string().optional(),\n addedAt: z.number().int().positive(),\n })\n .strict();\nexport type AllowEntry = z.infer<typeof AllowEntry>;\n\nconst AllowFile = z\n .object({\n version: z.literal(1),\n entries: z.array(AllowEntry),\n })\n .strict();\n\n/**\n * The daemon's local `named` allowlist.\n *\n * byollm_001 Rev 1 §B: a `named` job is admitted only when *this* list names\n * its owner. A server's assertion that a runner is allowed is never enough —\n * honouring it would mean obeying the server rather than enforcing against\n * it. One file, every paired app, so the owner has one place to see everyone\n * who can use their machine.\n *\n * The list is **empty by default**, which is what makes a fresh daemon\n * effectively self-only until the owner deliberately widens it.\n */\nexport class Allowlist {\n readonly #path: string;\n #entries: AllowEntry[] = [];\n #loaded = false;\n\n constructor(path: string) {\n this.#path = path;\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.#path, \"utf8\");\n const parsed = AllowFile.safeParse(JSON.parse(raw));\n // A corrupt allowlist reads as empty rather than throwing: failing\n // closed here means refusing community work, which is the safe\n // direction, and the owner sees an empty `byollm allow --list`.\n this.#entries = parsed.success ? parsed.data.entries : [];\n } catch {\n this.#entries = [];\n }\n this.#loaded = true;\n }\n\n #assertLoaded(): void {\n if (!this.#loaded) {\n throw new Error(\"allowlist used before load()\");\n }\n }\n\n /** Does this list admit `owner` on `origin`? */\n admits(origin: string, owner: string): boolean {\n this.#assertLoaded();\n const normalized = normalizeOrigin(origin);\n return this.#entries.some(\n (entry) =>\n normalizeOrigin(entry.origin) === normalized && entry.owner === owner,\n );\n }\n\n /** A predicate bound to one origin, for {@link matchAudience}. */\n predicateFor(origin: string): (owner: string) => boolean {\n return (owner) => this.admits(origin, owner);\n }\n\n list(): readonly AllowEntry[] {\n this.#assertLoaded();\n return [...this.#entries];\n }\n\n async add(entry: Omit<AllowEntry, \"addedAt\">, now: number): Promise<void> {\n this.#assertLoaded();\n const normalized = normalizeOrigin(entry.origin);\n if (this.admits(normalized, entry.owner)) return;\n this.#entries.push(\n AllowEntry.parse({ ...entry, origin: normalized, addedAt: now }),\n );\n await this.#save();\n }\n\n /** Remove an entry. Returns whether anything was removed. */\n async remove(origin: string, owner: string): Promise<boolean> {\n this.#assertLoaded();\n const normalized = normalizeOrigin(origin);\n const before = this.#entries.length;\n this.#entries = this.#entries.filter(\n (entry) =>\n !(\n normalizeOrigin(entry.origin) === normalized && entry.owner === owner\n ),\n );\n if (this.#entries.length === before) return false;\n await this.#save();\n return true;\n }\n\n async #save(): Promise<void> {\n await mkdir(dirname(this.#path), { recursive: true });\n await writeFile(\n this.#path,\n `${JSON.stringify({ version: 1, entries: this.#entries }, null, 2)}\\n`,\n { mode: 0o600 },\n );\n }\n}\n\n/**\n * Compare origins by scheme, host and port only.\n *\n * `https://app.test/` and `https://app.test` must be the same entry — a\n * trailing slash is not a different server, and treating it as one would let\n * an allowlist silently fail to match.\n */\nexport function normalizeOrigin(input: string): string {\n try {\n return new URL(input).origin;\n } catch {\n return input.replace(/\\/+$/, \"\");\n }\n}\n","import { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { hostname, userInfo } from \"node:os\";\nimport { dirname } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport { backendDescriptor, resolveCost } from \"@byollm/protocol\";\nimport { Allowlist, normalizeOrigin } from \"./allowlist.js\";\nimport { Budgets } from \"./budgets.js\";\nimport { ClientError, ProtocolClient } from \"./client.js\";\nimport { DaemonConfig, loadConfig } from \"./config.js\";\nimport { connect } from \"./connect.js\";\nimport { IngressLog, stripControlChars } from \"./ingress.js\";\nimport { fingerprint } from \"@byollm/protocol\";\nimport { DeviceIdentity } from \"./identity.js\";\nimport { Pairings } from \"./pairings.js\";\nimport { SpendLedger } from \"./spend.js\";\nimport { daemonPaths, type DaemonPaths } from \"./paths.js\";\nimport { Runner, type RunnerEvent } from \"./runner.js\";\nimport { DAEMON_VERSION, formatVersion } from \"./index.js\";\n\nconst USAGE = `byollm — run an app's LLM jobs on your own models.\n\n byollm connect <url> pair with an app and start running its jobs\n byollm run [url] run jobs for a paired app (or all of them)\n byollm status what is connected, what is running, what it cost\n byollm log [--full] [-n N] every prompt that has run on this machine\n byollm pause stop claiming new work\n byollm resume start claiming again\n byollm allow <url> <user> let someone else's jobs run here (named audience)\n byollm allow --list who can currently use this machine\n byollm offer <backend> <scope> who a backend is offered to (self|named|public)\n byollm disallow <url> <user>\n byollm forget <url> drop a pairing\n byollm backends what is installed, healthy, and advertised\n\nConfig lives in ~/.byollm/config.json. Everything this daemon has ever run is\nin ~/.byollm/ingress.log — it is yours to read and yours to delete.\n`;\n\n/** Exit codes: 0 fine, 1 a real failure, 2 the user asked for something wrong. */\nexport type ExitCode = 0 | 1 | 2;\n\n/**\n * Everything the CLI touches outside itself.\n *\n * byollm_002 calls the meter the product's soul, which means it has to be\n * testable rather than merely observable by a human at a terminal. Injecting\n * the streams, the state directory and the confirmation prompt lets the tests\n * drive the real commands against a temporary `BYOLLM_HOME`.\n */\nexport interface CliIo {\n readonly out: (text: string) => void;\n readonly err: (text: string) => void;\n /** Answers the scarier-confirmation prompt when widening access. */\n readonly confirm: (question: string) => Promise<boolean>;\n}\n\nconst defaultIo: CliIo = {\n out: (text) => process.stdout.write(text),\n err: (text) => process.stderr.write(text),\n confirm: confirmInteractively,\n};\n\n/** Run one command. Exported so the tests drive the same code a user does. */\nexport async function runCli(\n argv: readonly string[],\n options: {\n paths?: DaemonPaths;\n io?: Partial<CliIo>;\n /**\n * Stops the polling loop. The executable wires this to SIGINT/SIGTERM;\n * anything embedding the CLI (including its tests) can stop it the same\n * way rather than by killing the process.\n */\n signal?: AbortSignal;\n } = {},\n): Promise<ExitCode> {\n const [command, ...rest] = argv;\n const paths = options.paths ?? daemonPaths();\n const io: CliIo = { ...defaultIo, ...options.io };\n const signal = options.signal;\n\n switch (command) {\n case undefined:\n case \"help\":\n case \"--help\":\n case \"-h\":\n io.out(USAGE);\n return 0;\n case \"--version\":\n case \"version\":\n // The full tuple, not a bare version. byollm_010 §5: an issue that\n // arrives without a platform costs a round trip to learn one.\n io.out(formatVersion());\n return 0;\n case \"connect\":\n return commandConnect(paths, rest, io, signal);\n case \"run\":\n return commandRun(paths, rest, io, signal);\n case \"status\":\n return commandStatus(paths, io);\n case \"log\":\n return commandLog(paths, rest, io);\n case \"pause\":\n return commandPause(paths, true, io);\n case \"resume\":\n return commandPause(paths, false, io);\n case \"allow\":\n return commandAllow(paths, rest, io);\n case \"disallow\":\n return commandDisallow(paths, rest, io);\n case \"offer\":\n return commandOffer(paths, rest, io);\n case \"forget\":\n return commandForget(paths, rest, io);\n case \"backends\":\n return commandBackends(paths, io);\n default:\n io.err(`unknown command: ${command}\\n\\n${USAGE}`);\n return 2;\n }\n}\n\n// -- connect -----------------------------------------------------------------\n\nasync function commandConnect(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n signal?: AbortSignal,\n): Promise<ExitCode> {\n const target = args[0];\n if (target === undefined) {\n io.err(\"usage: byollm connect <url>\\n\");\n return 2;\n }\n\n const origin = normalizeOrigin(target);\n const { loaded, ingress, allowlist, budgets, spend } = await context(paths);\n\n for (const problem of loaded.problems) {\n io.err(`config: ${problem.where}: ${problem.message}\\n`);\n }\n\n const client = new ProtocolClient({ origin });\n const runner = new Runner({\n client,\n runnerId: \"pending\",\n owner: \"pending\",\n daemonVersion: DAEMON_VERSION,\n loaded,\n allowlist,\n budgets,\n spend,\n ingress,\n });\n\n const capabilities = await runner.detectCapabilities();\n if (capabilities.length === 0) {\n // Pairing while advertising nothing would produce a runner that silently\n // never receives work — a failure the user could not diagnose.\n io.err(\n \"No backend is reachable, so there is nothing to offer this app yet.\\n\" +\n \"Run `byollm backends` to see what is configured and what is wrong.\\n\",\n );\n return 1;\n }\n\n io.out(`\\nConnecting to ${origin}\\n`);\n\n const result = await connect({\n client,\n daemonVersion: DAEMON_VERSION,\n label: hostLabel(),\n capabilities,\n device: await new DeviceIdentity(paths.keys).publicIdentity(Date.now()),\n onCode: (info) => {\n const minutes = Math.max(\n 1,\n Math.round((info.expiresAt - Date.now()) / 60_000),\n );\n io.out(\n `\\n Open: ${info.verificationUrl}\\n` +\n ` Code: ${info.userCode} (expires in ${String(minutes)}m)\\n\\n` +\n ` waiting for approval…`,\n );\n },\n onPoll: () => {\n io.out(\".\");\n },\n ...(signal === undefined ? {} : { signal }),\n });\n\n if (!result.ok) {\n io.out(`\\n\\n ${result.message}\\n`);\n return 1;\n }\n\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n await pairings.put(result.pairing);\n\n io.out(\n ` paired as ${result.pairing.ownerLabel ?? result.pairing.owner}\\n\\n` +\n `Now running jobs for ${origin}. Ctrl-C to stop.\\n\\n`,\n );\n\n return runLoop(paths, [result.pairing.origin], io, signal);\n}\n\n// -- run ---------------------------------------------------------------------\n\nasync function commandRun(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n signal?: AbortSignal,\n): Promise<ExitCode> {\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n\n const target = args[0];\n const origins =\n target === undefined\n ? pairings.list().map((pairing) => pairing.origin)\n : [normalizeOrigin(target)];\n\n if (origins.length === 0) {\n io.err(\"No apps are paired yet. Run `byollm connect <url>` first.\\n\");\n return 2;\n }\n return runLoop(paths, origins, io, signal);\n}\n\nasync function runLoop(\n paths: DaemonPaths,\n origins: readonly string[],\n io: CliIo,\n signal?: AbortSignal,\n): Promise<ExitCode> {\n const { loaded, ingress, allowlist, budgets, spend } = await context(paths);\n const identity = new DeviceIdentity(paths.keys);\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n\n const controller = new AbortController();\n signal?.addEventListener(\n \"abort\",\n () => {\n controller.abort();\n },\n { once: true },\n );\n const runners: Runner[] = [];\n\n for (const origin of origins) {\n const pairing = pairings.get(origin);\n if (!pairing) {\n io.err(`not paired with ${origin}\\n`);\n continue;\n }\n const runner = new Runner({\n client: new ProtocolClient({\n origin,\n identity: {\n runnerId: pairing.runnerId,\n sign: (input) => identity.signRequest(input),\n },\n }),\n runnerId: pairing.runnerId,\n owner: pairing.owner,\n identity: {\n keys: () => identity.load(Date.now()),\n sitePinned: pairing.site,\n },\n daemonVersion: DAEMON_VERSION,\n loaded,\n allowlist,\n budgets,\n spend,\n ingress,\n onEvent: (event) => {\n report(origin, event, io);\n },\n });\n runners.push(runner);\n }\n\n if (runners.length === 0) return 2;\n\n // Leases are released on the way out, so the app sees work return to the\n // queue at once instead of waiting for a lease to lapse.\n // Only take over the process's signals when nobody handed us one of their\n // own — an embedder (or a test) that passed a signal owns its own lifecycle.\n if (signal === undefined) {\n const stop = (): void => {\n controller.abort();\n // Ctrl-C must end in an exit, whatever the release path does. Without a\n // rejection handler a failing `shutdown` left `process.exit` unreached\n // and killed the daemon on an unhandled rejection instead — the same\n // exit, with a stack trace and a misleading code.\n Promise.all(runners.map((runner) => runner.shutdown(\"shutdown\"))).then(\n () => {\n process.exit(0);\n },\n (error: unknown) => {\n // Leases will lapse on their own; say what happened and leave a\n // non-zero code so a supervisor can tell this apart from a clean\n // stop.\n io.err(`shutdown did not complete cleanly: ${String(error)}\\n`);\n process.exit(1);\n },\n );\n };\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n }\n\n await ingress.applyRetention(Date.now());\n await Promise.all(runners.map((runner) => runner.run(controller.signal)));\n await Promise.all(runners.map((runner) => runner.shutdown(\"shutdown\")));\n return 0;\n}\n\n/**\n * One line per event.\n *\n * Every interpolated string that could contain remote text goes through\n * {@link stripControlChars} first: a refusal reason or an error message may\n * quote a payload, and text that can repaint a terminal can forge output\n * (byollm_004 §5's ANSI/log-injection row).\n */\nfunction report(origin: string, event: RunnerEvent, io: CliIo): void {\n const at = new Date().toISOString().slice(11, 19);\n const host = new URL(origin).host;\n\n switch (event.type) {\n case \"claimed\":\n io.out(`${at} ${host} claimed ${event.kind} ${event.jobId}\\n`);\n break;\n case \"finished\":\n io.out(\n `${at} ${host} ${event.outcome} ${event.jobId} ` +\n `(${String(event.durationMs)}ms)\\n`,\n );\n break;\n case \"refused\":\n io.out(\n `${at} ${host} refused ${event.jobId}: ` +\n `${stripControlChars(event.reason)}\\n`,\n );\n break;\n case \"revoked\":\n io.out(`${at} ${host} this runner was revoked. Stopping.\\n`);\n break;\n case \"error\":\n io.err(`${at} ${host} ${stripControlChars(event.message)}\\n`);\n break;\n case \"heartbeat\":\n break;\n }\n}\n\n// -- status ------------------------------------------------------------------\n\nasync function commandStatus(paths: DaemonPaths, io: CliIo): Promise<ExitCode> {\n const { loaded, ingress, allowlist, budgets, spend } = await context(paths);\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n\n const paused = await isPaused(paths);\n const now = Date.now();\n\n io.out(formatVersion());\n // This machine's fingerprint, so an owner can compare it against what a\n // site shows them (byollm_009 §3). A fingerprint nobody can find is a\n // fingerprint nobody compares.\n io.out(\n `identity: ${await new DeviceIdentity(paths.keys).fingerprint(now)}\\n`,\n );\n io.out(`state: ${paused ? \"PAUSED\" : \"running\"}\\n\\n`);\n\n io.out(\"paired apps\\n\");\n const list = pairings.list();\n if (list.length === 0) {\n io.out(\" (none — run `byollm connect <url>`)\\n\");\n }\n for (const pairing of list) {\n io.out(` ${pairing.origin} as ${pairing.ownerLabel ?? pairing.owner}\\n`);\n // The pinned key, so an owner can check it against what the app shows.\n // A pin nobody can see is a pin nobody can verify.\n io.out(` pinned: ${fingerprint(pairing.site.identity)}\\n`);\n }\n\n io.out(\"\\nroutes\\n\");\n if (loaded.routes.length === 0) {\n io.out(\" (none configured)\\n\");\n }\n for (const route of loaded.routes) {\n io.out(\n ` ${route.kind.padEnd(14)} ${route.backendId}:${route.model} ` +\n `offered to: ${route.offerScope}\\n`,\n );\n }\n for (const problem of loaded.problems) {\n io.out(` ! ${problem.where}: ${problem.message}\\n`);\n }\n\n const allowed = allowlist.list();\n io.out(\"\\nwho can use this machine\\n\");\n io.out(` you, always\\n`);\n if (allowed.length === 0) {\n io.out(\" nobody else\\n\");\n }\n for (const entry of allowed) {\n io.out(\n ` ${entry.owner} on ${entry.origin}` +\n `${entry.note === undefined ? \"\" : ` (${stripControlChars(entry.note)})`}\\n`,\n );\n }\n\n const spentToday = spend.summary(now);\n const metered = loaded.routes.filter((r) => r.cost === \"metered\");\n if (metered.length > 0) {\n io.out(\"\\nmetered backends — your money\\n\");\n for (const route of metered) {\n const spent = spentToday[route.backendKey] ?? 0;\n io.out(\n route.spendAcknowledged\n ? ` ${route.backendKey}: ${spent.toFixed(1)}c spent today of ` +\n `${String(route.spendDailyCapCents ?? 0)}c\\n`\n : ` ${route.backendKey}: not shared — your work only\\n`,\n );\n }\n }\n\n const usage = budgets.usage(now);\n io.out(\"\\ncommunity work done for others\\n\");\n io.out(\n ` ${String(usage.hour)} in the last hour (cap ${String(usage.limits.maxJobsPerHour)}), ` +\n `${String(usage.day)} today (cap ${String(usage.limits.maxJobsPerDay)})\\n`,\n );\n\n const entries = await ingress.read();\n const prompts = entries.filter((entry) => entry.type === \"prompt\");\n const outcomes = entries.filter((entry) => entry.type === \"outcome\");\n io.out(\"\\nthis machine has run\\n\");\n io.out(\n ` ${String(prompts.length)} prompts, ` +\n `${String(outcomes.filter((o) => o.outcome === \"ok\").length)} ok, ` +\n `${String(outcomes.filter((o) => o.outcome === \"error\").length)} failed, ` +\n `${String(outcomes.filter((o) => o.outcome === \"refused\").length)} refused\\n`,\n );\n io.out(\n ` full log: ${paths.ingressLog} (community prompts kept ` +\n `${String(loaded.config.ingress.communityPromptDays)} days, then hashed)\\n`,\n );\n return 0;\n}\n\n// -- log ---------------------------------------------------------------------\n\nasync function commandLog(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const full = args.includes(\"--full\");\n const nIndex = args.findIndex((arg) => arg === \"-n\" || arg === \"--lines\");\n const limit =\n nIndex === -1 ? 20 : Math.max(1, Number(args[nIndex + 1] ?? \"20\") || 20);\n\n const { ingress } = await context(paths);\n const entries = await ingress.read();\n const shown = entries.slice(-limit);\n\n if (shown.length === 0) {\n io.out(\"nothing has run on this machine yet\\n\");\n return 0;\n }\n\n for (const entry of shown) {\n const at = new Date(entry.at).toISOString().replace(\"T\", \" \").slice(0, 19);\n if (entry.type === \"outcome\") {\n io.out(\n `${at} ${entry.outcome.padEnd(8)} ${entry.jobId}` +\n (entry.durationMs === undefined\n ? \"\"\n : ` ${String(entry.durationMs)}ms`) +\n `${entry.detail === undefined ? \"\" : ` ${stripControlChars(entry.detail)}`}\\n`,\n );\n continue;\n }\n\n io.out(\n `${at} ${entry.audience.padEnd(7)} ${entry.kind} ` +\n `via ${entry.backendId}:${entry.model} for ${entry.owner} ` +\n `@ ${new URL(entry.origin).host}\\n`,\n );\n if (entry.prompt === undefined) {\n // Retention removed the text. Say so — a blank line here would read as\n // \"empty prompt\", and zero must never look like unknown.\n io.out(\n ` prompt not retained (${String(entry.promptChars)} chars, ` +\n `sha256 ${entry.promptHash.slice(0, 16)}…)\\n`,\n );\n } else if (full) {\n io.out(`${indent(stripControlChars(entry.prompt))}\\n`);\n } else {\n const firstLine = entry.prompt.split(\"\\n\")[0] ?? \"\";\n io.out(\n ` ${stripControlChars(firstLine.slice(0, 90))}` +\n `${entry.prompt.length > 90 ? \"…\" : \"\"}\\n`,\n );\n }\n }\n if (!full) {\n io.out(`\\n(${String(entries.length)} entries; --full for whole prompts)\\n`);\n }\n return 0;\n}\n\nfunction indent(text: string): string {\n return text\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n}\n\n// -- pause / resume -----------------------------------------------------------\n\nasync function commandPause(\n paths: DaemonPaths,\n pause: boolean,\n io: CliIo,\n): Promise<ExitCode> {\n await mkdir(paths.root, { recursive: true });\n if (pause) {\n await writeFile(paths.pauseFlag, `${new Date().toISOString()}\\n`);\n io.out(\n \"paused — no new work will be claimed. `byollm resume` to start again.\\n\",\n );\n } else {\n await rm(paths.pauseFlag, { force: true });\n io.out(\"resumed\\n\");\n }\n return 0;\n}\n\nasync function isPaused(paths: DaemonPaths): Promise<boolean> {\n try {\n await stat(paths.pauseFlag);\n return true;\n } catch {\n return false;\n }\n}\n\n// -- allow / disallow ---------------------------------------------------------\n\nasync function commandAllow(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const allowlist = new Allowlist(paths.allowlist);\n await allowlist.load();\n\n if (args[0] === \"--list\" || args.length === 0) {\n const entries = allowlist.list();\n if (entries.length === 0) {\n io.out(\n \"Nobody but you can run work on this machine.\\n\" +\n \"`byollm allow <app-url> <user-id>` to change that.\\n\",\n );\n return 0;\n }\n for (const entry of entries) {\n io.out(\n `${entry.owner} on ${entry.origin}` +\n `${entry.note === undefined ? \"\" : ` (${stripControlChars(entry.note)})`}\\n`,\n );\n }\n return 0;\n }\n\n const [rawOrigin, owner, ...noteParts] = args;\n if (rawOrigin === undefined || owner === undefined) {\n io.err(\"usage: byollm allow <app-url> <user-id> [note]\\n\");\n return 2;\n }\n const origin = normalizeOrigin(rawOrigin);\n\n // byollm_002: widening scope requires an explicit confirmation that names\n // what it means. Not a y/N on an ambiguous question — the actual sentence.\n const confirmed = await io.confirm(\n `\\nThis lets jobs belonging to \"${owner}\" on ${origin} run on this machine,\\n` +\n `using your hardware and electricity, whenever your daemon is online.\\n` +\n `Your subscription-backed models are never included — those stay yours alone.\\n\\n` +\n `Allow ${owner} to use this machine?`,\n );\n if (!confirmed) {\n io.out(\"nothing changed\\n\");\n return 0;\n }\n\n await allowlist.add(\n {\n origin,\n owner,\n ...(noteParts.length > 0 ? { note: noteParts.join(\" \") } : {}),\n },\n Date.now(),\n );\n io.out(`allowed ${owner} on ${origin}\\n`);\n return 0;\n}\n\n// -- offer -------------------------------------------------------------------\n\n/**\n * Change who a backend is offered to.\n *\n * This exists because `resolveConfig` tells an owner to run it. A message that\n * names a command nobody wrote is worse than no message: it reads as though\n * the software has an answer when it does not.\n *\n * Widening a metered backend is the one path here that can cost real money, so\n * it is the one path that asks — and the question names the money rather than\n * asking whether the owner is \"sure\"\n * ({@link MUSTS.METERED_DEFAULTS_SELF}, {@link MUSTS.METERED_REQUIRES_CEILING}).\n */\nasync function commandOffer(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const [backendKey, scope, ...rest] = args;\n if (backendKey === undefined || scope === undefined) {\n io.err(\n \"usage: byollm offer <backend> <self|named|public> [--cap <cents>]\\n\",\n );\n return 2;\n }\n if (scope !== \"self\" && scope !== \"named\" && scope !== \"public\") {\n io.err(`\"${scope}\" is not an offer scope — use self, named, or public\\n`);\n return 2;\n }\n\n const capIndex = rest.indexOf(\"--cap\");\n let capCents: number | undefined;\n if (capIndex !== -1) {\n const raw = rest[capIndex + 1];\n const parsed = Number(raw);\n if (raw === undefined || !Number.isFinite(parsed) || parsed <= 0) {\n io.err(\"--cap takes a number of cents per day, greater than zero\\n\");\n return 2;\n }\n capCents = Math.round(parsed);\n }\n\n let raw: string;\n try {\n raw = await readFile(paths.config, \"utf8\");\n } catch {\n io.err(\n `no config at ${paths.config} — nothing to offer yet.\\n` +\n \"Write one, or run `byollm connect <url>` first.\\n\",\n );\n return 1;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n io.err(`${paths.config} is not valid JSON — fix it by hand first\\n`);\n return 1;\n }\n const result = DaemonConfig.safeParse(parsed);\n if (!result.success) {\n io.err(`${paths.config} is not a valid byollm config — fix it first\\n`);\n return 1;\n }\n\n const backend = result.data.backends[backendKey];\n if (!backend) {\n const known = Object.keys(result.data.backends);\n io.err(\n `no backend named \"${backendKey}\" in ${paths.config}\\n` +\n (known.length > 0 ? `configured: ${known.join(\", \")}\\n` : \"\"),\n );\n return 2;\n }\n\n const descriptor = backendDescriptor(backend.backend);\n const baseUrl = backend.baseUrl ?? descriptor.defaultBaseUrl;\n const cost = resolveCost(backend.backend, baseUrl);\n const widening = scope !== \"self\";\n\n // A subscription backend cannot be offered at all, so say that instead of\n // writing a setting that would be silently ignored on the next load.\n if (cost === \"subscription\" && widening) {\n io.err(\n `${descriptor.label} runs on your own subscription, whose terms cover\\n` +\n \"your work and nobody else's. It cannot be offered to other people.\\n\",\n );\n return 1;\n }\n\n if (cost === \"metered\" && widening) {\n const cap = capCents ?? backend.spend?.dailyCapCents;\n if (cap === undefined) {\n io.err(\n `${descriptor.label} bills you per token, so sharing it needs a daily\\n` +\n \"ceiling. Add one: `byollm offer \" +\n `${backendKey} ${scope} --cap <cents>\\`\\n`,\n );\n return 2;\n }\n\n const dollars = (cap / 100).toFixed(2);\n const confirmed = await io.confirm(\n `\\nThis lets other people's jobs run on ${descriptor.label}, which bills\\n` +\n `your account per token. You would be paying for their work, up to\\n` +\n `$${dollars} a day, every day, until you change it.\\n` +\n `Spending stops at that ceiling and resumes the next day.\\n\\n` +\n `Offer ${backendKey} to ${scope === \"public\" ? \"anyone\" : \"people you have allowed\"}?`,\n );\n if (!confirmed) {\n io.out(\"nothing changed\\n\");\n return 0;\n }\n\n result.data.backends[backendKey] = {\n ...backend,\n offer: scope,\n spend: {\n centsPerMillionTokens: backend.spend?.centsPerMillionTokens ?? 1500,\n ...backend.spend,\n acknowledged: true,\n dailyCapCents: cap,\n },\n };\n } else {\n result.data.backends[backendKey] = {\n ...backend,\n offer: scope,\n // Narrowing back to `self` withdraws the consent too, so a later\n // widening has to be agreed to again rather than inherited.\n ...(cost === \"metered\" && !widening && backend.spend !== undefined\n ? { spend: { ...backend.spend, acknowledged: false } }\n : {}),\n };\n }\n\n await mkdir(dirname(paths.config), { recursive: true });\n await writeFile(paths.config, `${JSON.stringify(result.data, null, 2)}\\n`);\n\n const written = result.data.backends[backendKey].spend?.dailyCapCents;\n io.out(\n `${backendKey} is now offered to ${scope}` +\n (written === undefined || !widening\n ? \"\"\n : `, capped at ${String(written)}c a day`) +\n \"\\n\",\n );\n return 0;\n}\n\nasync function commandDisallow(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const [rawOrigin, owner] = args;\n if (rawOrigin === undefined || owner === undefined) {\n io.err(\"usage: byollm disallow <app-url> <user-id>\\n\");\n return 2;\n }\n const allowlist = new Allowlist(paths.allowlist);\n await allowlist.load();\n const removed = await allowlist.remove(normalizeOrigin(rawOrigin), owner);\n io.out(\n removed\n ? `${owner} can no longer use this machine\\n`\n : `${owner} was not on the list — nothing changed\\n`,\n );\n return 0;\n}\n\n// -- forget -------------------------------------------------------------------\n\nasync function commandForget(\n paths: DaemonPaths,\n args: readonly string[],\n io: CliIo,\n): Promise<ExitCode> {\n const target = args[0];\n if (target === undefined) {\n io.err(\"usage: byollm forget <app-url>\\n\");\n return 2;\n }\n const pairings = new Pairings(paths.pairings);\n await pairings.load();\n const removed = await pairings.remove(normalizeOrigin(target));\n io.out(\n removed\n ? `forgot ${normalizeOrigin(target)} — the app may still list this runner ` +\n `until you revoke it there too\\n`\n : `not paired with ${normalizeOrigin(target)}\\n`,\n );\n return 0;\n}\n\n// -- backends ------------------------------------------------------------------\n\nasync function commandBackends(\n paths: DaemonPaths,\n io: CliIo,\n): Promise<ExitCode> {\n const { loaded, ingress, allowlist, budgets, spend } = await context(paths);\n const runner = new Runner({\n client: new ProtocolClient({ origin: \"https://unused.invalid\" }),\n runnerId: \"local\",\n owner: \"local\",\n daemonVersion: DAEMON_VERSION,\n loaded,\n allowlist,\n budgets,\n spend,\n ingress,\n });\n\n const advertised = await runner.detectCapabilities();\n const advertisedKinds = new Set(advertised.map((c) => c.kind));\n\n io.out(\"configured routes\\n\");\n for (const route of loaded.routes) {\n const ok = advertisedKinds.has(route.kind);\n const pays =\n route.cost === \"free\"\n ? \"free (your electricity)\"\n : route.cost === \"subscription\"\n ? \"your subscription — locked to your work\"\n : route.spendAcknowledged\n ? `metered — shared, cap ${String(route.spendDailyCapCents ?? 0)}c/day`\n : \"metered — your money, not shared\";\n io.out(\n ` ${ok ? \"✓\" : \"✗\"} ${route.kind.padEnd(14)} ` +\n `${route.backendId}:${route.model}` +\n `${route.baseUrl === undefined ? \"\" : ` @ ${route.baseUrl}`}\\n` +\n ` ${pays}\\n`,\n );\n }\n for (const problem of loaded.problems) {\n io.out(` ! ${problem.where}: ${problem.message}\\n`);\n }\n io.out(\n `\\n${String(advertised.length)} of ${String(loaded.routes.length)} routes are ` +\n `healthy and will be advertised.\\n` +\n `A route that is not healthy is never offered to an app — the daemon does\\n` +\n `not advertise what it cannot actually run.\\n`,\n );\n return advertised.length === 0 ? 1 : 0;\n}\n\n// -- shared -------------------------------------------------------------------\n\nasync function context(paths: DaemonPaths): Promise<{\n loaded: Awaited<ReturnType<typeof loadConfig>>;\n ingress: IngressLog;\n allowlist: Allowlist;\n budgets: Budgets;\n spend: SpendLedger;\n}> {\n const loaded = await loadConfig(paths.config);\n const ingress = new IngressLog({\n path: paths.ingressLog,\n communityPromptDays: loaded.config.ingress.communityPromptDays,\n keepSelfPrompts: loaded.config.ingress.keepSelfPrompts,\n });\n const allowlist = new Allowlist(paths.allowlist);\n await allowlist.load();\n const budgets = new Budgets(paths.budgets, loaded.config.community);\n await budgets.load(Date.now());\n const spend = new SpendLedger(paths.spend);\n await spend.load(Date.now());\n return { loaded, ingress, allowlist, budgets, spend };\n}\n\n/**\n * Ask, on a real terminal.\n *\n * Refuses outright when stdin is not a TTY: widening who may use someone's\n * machine is not a thing to do on an implied yes from a script.\n */\nasync function confirmInteractively(question: string): Promise<boolean> {\n if (!process.stdin.isTTY) {\n process.stderr.write(\n \"refusing to widen access without an interactive confirmation\\n\",\n );\n return false;\n }\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n const answer = await rl.question(`${question} [y/N] `);\n return /^y(es)?$/i.test(answer.trim());\n } finally {\n rl.close();\n }\n}\n\n/**\n * How this machine appears in the app's runner list.\n *\n * `BYOLLM_LABEL` overrides it, because \"todd@Todds-MacBook-Pro\" is more than\n * some people want to hand an app they are only trying out.\n */\nfunction hostLabel(): string {\n const override = process.env[\"BYOLLM_LABEL\"];\n if (override !== undefined && override !== \"\") return override.slice(0, 120);\n try {\n return `${userInfo().username}@${hostname()}`.slice(0, 120);\n } catch {\n return hostname().slice(0, 120);\n }\n}\n\n/** The `byollm` executable. */\nexport async function main(argv: readonly string[]): Promise<ExitCode> {\n try {\n return await runCli(argv);\n } catch (error) {\n process.stderr.write(\n `${error instanceof ClientError || error instanceof Error ? error.message : String(error)}\\n`,\n );\n return 1;\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { z } from \"zod\";\nimport type { CommunityBudget } from \"./config.js\";\n\nconst BudgetFile = z\n .object({\n version: z.literal(1),\n /** Epoch-ms timestamps of community jobs accepted, newest last. */\n accepted: z.array(z.number().int().positive()),\n })\n .strict();\n\nexport type BudgetRefusal = \"hourly-cap\" | \"daily-cap\" | \"payload-too-large\";\n\nexport type BudgetDecision =\n | { readonly ok: true }\n | {\n readonly ok: false;\n readonly refusal: BudgetRefusal;\n readonly detail: string;\n };\n\n/**\n * The owner's ceiling on work done for other people\n * ({@link MUSTS.COMMUNITY_BUDGETS}).\n *\n * byollm_004 §4 distinguishes two directions of abuse, and this is the one\n * aimed *at* the volunteer: a stranger who can enqueue unlimited `public`\n * jobs owns your GPU. Jobs for the machine's own owner are never counted —\n * their machine, their call.\n */\nexport class Budgets {\n readonly #path: string;\n readonly #limits: CommunityBudget;\n #accepted: number[] = [];\n #loaded = false;\n\n constructor(path: string, limits: CommunityBudget) {\n this.#path = path;\n this.#limits = limits;\n }\n\n async load(now: number): Promise<void> {\n try {\n const parsed = BudgetFile.safeParse(\n JSON.parse(await readFile(this.#path, \"utf8\")),\n );\n this.#accepted = parsed.success ? parsed.data.accepted : [];\n } catch {\n this.#accepted = [];\n }\n this.#prune(now);\n this.#loaded = true;\n }\n\n /**\n * May this community job run?\n *\n * @param payloadChars - total payload text length, checked against the\n * stricter community limit rather than the protocol's absolute ceiling.\n */\n check(now: number, payloadChars: number): BudgetDecision {\n if (!this.#loaded) throw new Error(\"budgets used before load()\");\n this.#prune(now);\n\n if (payloadChars > this.#limits.maxPayloadChars) {\n return {\n ok: false,\n refusal: \"payload-too-large\",\n detail:\n `community jobs are limited to ${String(this.#limits.maxPayloadChars)} ` +\n `characters; this one is ${String(payloadChars)}`,\n };\n }\n\n const hour = this.#countSince(now - 3_600_000);\n if (hour >= this.#limits.maxJobsPerHour) {\n return {\n ok: false,\n refusal: \"hourly-cap\",\n detail: `already ran ${String(hour)} community jobs in the last hour`,\n };\n }\n\n const day = this.#countSince(now - 86_400_000);\n if (day >= this.#limits.maxJobsPerDay) {\n return {\n ok: false,\n refusal: \"daily-cap\",\n detail: `already ran ${String(day)} community jobs today`,\n };\n }\n return { ok: true };\n }\n\n /** Count a community job as accepted. Call only after {@link check} passes. */\n async record(now: number): Promise<void> {\n this.#accepted.push(now);\n this.#prune(now);\n await mkdir(dirname(this.#path), { recursive: true });\n await writeFile(\n this.#path,\n JSON.stringify({ version: 1, accepted: this.#accepted }),\n { mode: 0o600 },\n );\n }\n\n /** Current usage, for `byollm status`. */\n usage(now: number): { hour: number; day: number; limits: CommunityBudget } {\n this.#prune(now);\n return {\n hour: this.#countSince(now - 3_600_000),\n day: this.#countSince(now - 86_400_000),\n limits: this.#limits,\n };\n }\n\n #countSince(since: number): number {\n return this.#accepted.filter((at) => at >= since).length;\n }\n\n /** Anything older than a day can never affect either window again. */\n #prune(now: number): void {\n const cutoff = now - 86_400_000;\n this.#accepted = this.#accepted.filter((at) => at >= cutoff);\n }\n}\n","import {\n type ResultDisposition,\n type SealedEnvelope,\n ClaimResponse,\n FetchResponse,\n type PublicIdentity,\n HeartbeatResponse,\n PROTOCOL_VERSION,\n PairPollResponse,\n PairStartResponse,\n ReleaseResponse,\n ResultResponse,\n WireError,\n type Capability,\n type Endpoint,\n} from \"@byollm/protocol\";\nimport { type z } from \"zod\";\n\n/**\n * Why a protocol call failed, from the daemon's seat.\n *\n * byollm_002 requires that \"server unreachable\", \"revoked\", \"no matching\n * work\" and \"backend down\" never share a message. Three of those are\n * distinguishable here; the fourth is a local condition the loop reports\n * itself. \"No matching work\" is deliberately *not* an error — it is a `200`\n * with an empty list.\n */\nexport type ClientErrorKind =\n | \"unreachable\"\n | \"revoked\"\n | \"unauthorized\"\n | \"rejected\"\n /**\n * The server does not speak our protocol version. Its own kind because it\n * is the one refusal a retry can never fix and an upgrade always can — and\n * because a daemon that reports it as a generic rejection sends its owner\n * looking at their network.\n */\n | \"version-unsupported\"\n /**\n * The upstream holds this job for us but has no payload to give yet.\n *\n * Only reachable off the direct plane. A direct site seals when asked,\n * because it holds the keys; a relay must wait for the site to seal to the\n * device that claimed — so \"not yet\" is a normal answer there, and treating\n * it as a refusal drops work the daemon legitimately still holds.\n */\n | \"not-ready\"\n | \"rate-limited\"\n | \"server-error\"\n | \"malformed-response\";\n\nexport class ClientError extends Error {\n override readonly name = \"ClientError\";\n constructor(\n readonly kind: ClientErrorKind,\n message: string,\n /** Seconds the server asked us to wait, when it said. */\n readonly retryAfter?: number,\n ) {\n super(message);\n }\n\n /** Is retrying this same call plausibly useful? */\n get retryable(): boolean {\n return (\n this.kind === \"unreachable\" ||\n this.kind === \"not-ready\" ||\n this.kind === \"rate-limited\" ||\n this.kind === \"server-error\"\n );\n }\n}\n\nexport interface ClientOptions {\n /** The app's origin, e.g. `https://app.example.com`. */\n readonly origin: string;\n /** Bearer token from pairing. Absent while pairing. */\n /**\n * How this daemon proves who it is (byollm_009 §4.2).\n *\n * A signer rather than a key, so the client never holds private material\n * and the daemon decides where keys live. Absent while pairing, which is\n * the one exchange that establishes an identity rather than using one.\n */\n readonly identity?: {\n readonly runnerId: string;\n sign(input: {\n endpoint: string;\n runnerId: string;\n issuedAt: number;\n body: string;\n }): Promise<string> | string;\n };\n /** Per-request timeout. */\n readonly timeoutMs?: number;\n /** Injectable fetch, for tests. */\n readonly fetch?: typeof fetch;\n}\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * The daemon's outbound protocol client.\n *\n * Every call is outbound; nothing here ever listens. That is the whole\n * network posture of the product, and it lives in this one class.\n */\nexport class ProtocolClient {\n readonly #origin: string;\n readonly #identity: ClientOptions[\"identity\"];\n readonly #timeoutMs: number;\n readonly #fetch: typeof fetch;\n\n constructor(options: ClientOptions) {\n this.#origin = options.origin.replace(/\\/+$/, \"\");\n this.#identity = options.identity;\n this.#timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#fetch = options.fetch ?? globalThis.fetch;\n }\n\n /** A client for the same origin that signs as a given runner. */\n withIdentity(\n identity: NonNullable<ClientOptions[\"identity\"]>,\n ): ProtocolClient {\n return new ProtocolClient({\n origin: this.#origin,\n identity,\n timeoutMs: this.#timeoutMs,\n fetch: this.#fetch,\n });\n }\n\n get origin(): string {\n return this.#origin;\n }\n\n async pairStart(input: {\n version: string;\n label: string;\n platform: \"darwin\" | \"linux\" | \"win32\";\n /** This machine's public keys (byollm_009 §5). */\n device: PublicIdentity;\n capabilities: readonly Capability[];\n }): Promise<PairStartResponse> {\n return this.#post(\"pair\", PairStartResponse, {\n protocolVersion: PROTOCOL_VERSION,\n action: \"start\",\n device: input.device,\n daemon: {\n version: input.version,\n label: input.label,\n platform: input.platform,\n },\n capabilities: input.capabilities,\n });\n }\n\n async pairPoll(deviceCode: string): Promise<PairPollResponse> {\n return this.#post(\"pair\", PairPollResponse, {\n protocolVersion: PROTOCOL_VERSION,\n action: \"poll\",\n deviceCode,\n });\n }\n\n /**\n * Collect the payload for a lease this daemon holds (byollm_009 §6).\n *\n * The second half of claim-then-fetch: a claim answers with a stub, and the\n * work is collected by the device that took it.\n */\n async fetch(input: {\n runnerId: string;\n jobId: string;\n leaseId: string;\n }): Promise<FetchResponse> {\n return this.#post(\"fetch\", FetchResponse, {\n protocolVersion: PROTOCOL_VERSION,\n runnerId: input.runnerId,\n jobId: input.jobId,\n leaseId: input.leaseId,\n });\n }\n\n async claim(input: {\n runnerId: string;\n capabilities: readonly Capability[];\n max: number;\n }): Promise<ClaimResponse> {\n return this.#post(\"claim\", ClaimResponse, {\n protocolVersion: PROTOCOL_VERSION,\n runnerId: input.runnerId,\n capabilities: input.capabilities,\n max: input.max,\n });\n }\n\n async heartbeat(input: {\n runnerId: string;\n daemonVersion: string;\n capabilities: readonly Capability[];\n activeLeases: readonly { jobId: string; leaseId: string }[];\n paused: boolean;\n }): Promise<HeartbeatResponse> {\n return this.#post(\"heartbeat\", HeartbeatResponse, {\n protocolVersion: PROTOCOL_VERSION,\n runnerId: input.runnerId,\n daemonVersion: input.daemonVersion,\n capabilities: input.capabilities,\n activeLeases: input.activeLeases,\n paused: input.paused,\n });\n }\n\n async result(input: {\n runnerId: string;\n jobId: string;\n envelope: SealedEnvelope;\n disposition: ResultDisposition;\n model: string;\n backendClass: \"http\" | \"process\";\n durationMs: number;\n }): Promise<ResultResponse> {\n return this.#post(\"result\", ResultResponse, {\n protocolVersion: PROTOCOL_VERSION,\n ...input,\n });\n }\n\n async release(input: {\n runnerId: string;\n leases: readonly { jobId: string; leaseId: string }[];\n reason: \"shutdown\" | \"pause\" | \"revoked\" | \"backend-down\" | \"refused\";\n }): Promise<ReleaseResponse> {\n return this.#post(\"release\", ReleaseResponse, {\n protocolVersion: PROTOCOL_VERSION,\n runnerId: input.runnerId,\n leases: input.leases,\n reason: input.reason,\n });\n }\n\n async #post<T>(\n endpoint: Endpoint,\n schema: z.ZodType<T>,\n body: unknown,\n ): Promise<T> {\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n };\n\n // Serialise once and sign exactly those bytes. Signing a re-serialised\n // copy would sign something the server never receives.\n const rawBody = JSON.stringify(body);\n if (this.#identity !== undefined) {\n const issuedAt = Date.now();\n headers[\"x-byollm-runner\"] = this.#identity.runnerId;\n headers[\"x-byollm-issued-at\"] = String(issuedAt);\n headers[\"x-byollm-signature\"] = await this.#identity.sign({\n endpoint,\n runnerId: this.#identity.runnerId,\n issuedAt,\n body: rawBody,\n });\n }\n\n let response: Response;\n try {\n response = await this.#fetch(`${this.#origin}/byollm/${endpoint}`, {\n method: \"POST\",\n headers,\n body: rawBody,\n redirect: \"error\",\n signal: AbortSignal.timeout(this.#timeoutMs),\n });\n } catch (error) {\n // No response at all: the server is unreachable. Distinct from every\n // answer it could have given us, including a refusal.\n throw new ClientError(\n \"unreachable\",\n `could not reach ${this.#origin} (${error instanceof Error ? error.message : \"unknown error\"})`,\n );\n }\n\n const text = await response.text();\n let parsed: unknown;\n try {\n parsed = text === \"\" ? {} : JSON.parse(text);\n } catch {\n throw new ClientError(\n \"malformed-response\",\n `${this.#origin} returned HTTP ${String(response.status)} with a body that is not JSON`,\n );\n }\n\n if (!response.ok) {\n throw this.#toError(response, parsed);\n }\n\n const result = schema.safeParse(parsed);\n if (!result.success) {\n // A server whose response does not match the protocol is not one we can\n // safely guess about.\n throw new ClientError(\n \"malformed-response\",\n `${this.#origin} returned a ${endpoint} response that does not match protocol v${PROTOCOL_VERSION}`,\n );\n }\n return result.data;\n }\n\n #toError(response: Response, body: unknown): ClientError {\n const wire = WireError.safeParse(body);\n const retryAfterHeader = response.headers.get(\"retry-after\");\n const retryAfter =\n wire.success && wire.data.retryAfter !== undefined\n ? wire.data.retryAfter\n : retryAfterHeader !== null && /^\\d+$/.test(retryAfterHeader)\n ? Number(retryAfterHeader)\n : undefined;\n\n const message = wire.success\n ? wire.data.message\n : `${this.#origin} returned HTTP ${String(response.status)}`;\n\n if (wire.success && wire.data.error === \"revoked\") {\n return new ClientError(\"revoked\", message, retryAfter);\n }\n if (\n typeof body === \"object\" &&\n body !== null &&\n (body as { error?: unknown }).error === \"unsupported-protocol-version\"\n ) {\n // The server already composed a message naming the fix; pass it through\n // rather than paraphrasing it into something vaguer.\n return new ClientError(\"version-unsupported\", message, retryAfter);\n }\n switch (response.status) {\n case 401:\n return new ClientError(\"unauthorized\", message, retryAfter);\n case 403:\n return new ClientError(\"revoked\", message, retryAfter);\n case 409:\n return new ClientError(\"not-ready\", message, retryAfter);\n case 429:\n return new ClientError(\"rate-limited\", message, retryAfter);\n case 400:\n case 404:\n // Never retried: the request is wrong, and repeating it stays wrong.\n return new ClientError(\"rejected\", message, retryAfter);\n default:\n return response.status >= 500\n ? new ClientError(\"server-error\", message, retryAfter)\n : new ClientError(\"rejected\", message, retryAfter);\n }\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport {\n BackendIdSchema,\n JobKind,\n OfferScope,\n backendDescriptor,\n effectiveOfferScope,\n resolveCost,\n type BackendCost,\n type BackendId,\n} from \"@byollm/protocol\";\nimport { z } from \"zod\";\nimport { checkBaseUrl } from \"./ssrf.js\";\n\n/**\n * One configured backend instance.\n *\n * `openai-http` may be configured many times — one per model server the owner\n * runs (Ollama here, `mlx_lm.server` there, a llama.cpp box on the LAN). That\n * is byollm_001 Rev 1 §A's \"one backend, N base URLs\".\n */\nexport const BackendConfig = z\n .object({\n backend: BackendIdSchema,\n /** Required for HTTP-class backends; meaningless for process-class. */\n baseUrl: z.string().optional(),\n /**\n * What the owner is willing to run for others. Subscription-class\n * backends ignore this and are locked to `self`\n * ({@link MUSTS.SUBSCRIPTION_SELF_LOCK}).\n */\n offer: OfferScope.default(\"self\"),\n /**\n * Name of an environment variable holding this backend's API key, for a\n * remote OpenAI-compatible server that needs one. The *name*, never the\n * value — a key does not belong in a config file the owner may share.\n */\n apiKeyEnv: z.string().optional(),\n /**\n * Required before a `metered` backend may be offered past `self`\n * ({@link MUSTS.METERED_DEFAULTS_SELF}). There is deliberately no `cost`\n * field: a provider's cost class comes from the protocol registry and is\n * not the owner's to declare ({@link MUSTS.COST_NOT_CONFIGURABLE}).\n */\n spend: z\n .object({\n /** Set by `byollm offer`, which states the consequence in words. */\n acknowledged: z.boolean().default(false),\n /**\n * Ceiling on community spend, in whole cents, per day. A widened\n * metered backend without one is refused\n * ({@link MUSTS.METERED_REQUIRES_CEILING}) — \"unlimited\" is not a\n * thing an owner can mean by accident.\n */\n dailyCapCents: z.number().int().positive().optional(),\n /**\n * What this provider charges, for the ceiling estimate. Providers do\n * not return a price, so the owner supplies one; the default is\n * deliberately high so an unset rate trips the brake early rather\n * than late.\n */\n centsPerMillionTokens: z.number().positive().default(1500),\n })\n .strict()\n .optional(),\n })\n .strict();\nexport type BackendConfig = z.infer<typeof BackendConfig>;\n\n/** Which backend instance and model serves a job kind. */\nexport const RouteConfig = z\n .object({\n /** Key into {@link DaemonConfig.backends}. */\n backend: z.string().min(1),\n /** The model name, owner-chosen. A payload can never influence this. */\n model: z.string().min(1),\n })\n .strict();\nexport type RouteConfig = z.infer<typeof RouteConfig>;\n\n/**\n * Budgets applied to jobs whose owner is not this machine's owner\n * ({@link MUSTS.COMMUNITY_BUDGETS}).\n */\nexport const CommunityBudget = z\n .object({\n maxJobsPerHour: z.number().int().positive().default(20),\n maxJobsPerDay: z.number().int().positive().default(100),\n /** Wall-clock ceiling for one community job. */\n maxWallClockMs: z.number().int().positive().default(120_000),\n /** Output-size ceiling for one community job. */\n maxOutputBytes: z\n .number()\n .int()\n .positive()\n .default(256 * 1024),\n /** Payload-size ceiling — stricter than the protocol's absolute limit. */\n maxPayloadChars: z.number().int().positive().default(100_000),\n })\n .strict();\nexport type CommunityBudget = z.infer<typeof CommunityBudget>;\n\n/** Ingress-log retention (byollm_004 Rev 1). */\nexport const IngressRetention = z\n .object({\n /**\n * How long a `named`/`public` prompt is kept in full before being reduced\n * to a hash. A volunteer must not indefinitely retain strangers' content.\n */\n communityPromptDays: z.number().int().positive().default(7),\n /** Whether the owner's own prompts are kept in full. Their call. */\n keepSelfPrompts: z.boolean().default(true),\n })\n .strict();\nexport type IngressRetention = z.infer<typeof IngressRetention>;\n\n/** Ceilings applied to every job, community or not. */\nexport const Limits = z\n .object({\n maxWallClockMs: z.number().int().positive().default(600_000),\n maxOutputBytes: z\n .number()\n .int()\n .positive()\n .default(4 * 1024 * 1024),\n })\n .strict();\nexport type Limits = z.infer<typeof Limits>;\n\nexport const DaemonConfig = z\n .object({\n backends: z.record(z.string().min(1), BackendConfig),\n // `partialRecord`, not `record`: zod 4's `record` with an enum key\n // demands every member be present, which would force an owner who only\n // wants `llm.generate` to also configure `llm.chat`. Routing one kind and\n // not the other is a legitimate setup — the unrouted kind is simply never\n // advertised.\n routes: z.partialRecord(JobKind, RouteConfig),\n /** How many jobs to run at once. */\n concurrency: z.number().int().min(1).max(32).default(2),\n // `prefault`, not `default`: zod 4's `.default()` takes an *output* value,\n // which would mean restating every nested default here where it could\n // drift. `prefault` feeds `{}` through the schema so the nested defaults\n // stay the single source of truth.\n community: CommunityBudget.prefault({}),\n ingress: IngressRetention.prefault({}),\n limits: Limits.prefault({}),\n })\n .strict();\nexport type DaemonConfig = z.infer<typeof DaemonConfig>;\n\n/** A route resolved against its backend, ready to execute. */\nexport interface ResolvedRoute {\n readonly kind: z.infer<typeof JobKind>;\n readonly backendKey: string;\n readonly backendId: BackendId;\n readonly backendClass: \"http\" | \"process\";\n readonly model: string;\n /** Who pays for this route's tokens. From the registry, never from config. */\n readonly cost: BackendCost;\n /** After the cost rules are applied — never the raw configured value. */\n readonly offerScope: z.infer<typeof OfferScope>;\n /** The owner's spend consent, for a `metered` route. */\n readonly spendAcknowledged: boolean;\n readonly spendDailyCapCents: number | undefined;\n readonly spendCentsPerMillionTokens: number;\n readonly baseUrl: string | undefined;\n readonly apiKeyEnv: string | undefined;\n}\n\nexport interface ConfigProblem {\n readonly where: string;\n readonly message: string;\n}\n\nexport interface LoadedConfig {\n readonly config: DaemonConfig;\n readonly routes: readonly ResolvedRoute[];\n /** Non-fatal problems: a route that cannot be served is dropped, not fatal. */\n readonly problems: readonly ConfigProblem[];\n}\n\n/** The config used when the owner has not written one. */\nexport const DEFAULT_CONFIG: DaemonConfig = DaemonConfig.parse({\n backends: {\n ollama: { backend: \"openai-http\", baseUrl: \"http://127.0.0.1:11434/v1\" },\n },\n routes: {\n \"llm.generate\": { backend: \"ollama\", model: \"llama3.2\" },\n \"llm.chat\": { backend: \"ollama\", model: \"llama3.2\" },\n },\n});\n\n/**\n * Read and resolve `~/.byollm/config.json`.\n *\n * A missing file yields {@link DEFAULT_CONFIG}; a malformed one throws,\n * because silently running with defaults when the owner *did* write a config\n * would execute work under rules they did not choose.\n */\nexport async function loadConfig(path: string): Promise<LoadedConfig> {\n let raw: string;\n try {\n raw = await readFile(path, \"utf8\");\n } catch (error) {\n if (isNotFound(error)) return resolveConfig(DEFAULT_CONFIG);\n throw error;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `${path} is not valid JSON: ${error instanceof Error ? error.message : \"unknown error\"}`,\n { cause: error },\n );\n }\n\n const result = DaemonConfig.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues\n .map((issue) => ` ${issue.path.join(\".\") || \"(root)\"}: ${issue.message}`)\n .join(\"\\n\");\n throw new Error(`${path} is not a valid byollm config:\\n${issues}`);\n }\n return resolveConfig(result.data);\n}\n\n/**\n * Turn a parsed config into executable routes, applying the subscription lock\n * and rejecting unusable backends.\n *\n * A problem here is not fatal: a machine with three routes and one broken\n * backend should serve the other two and say so, rather than refusing to\n * start. What it must never do is *advertise* the broken one\n * ({@link MUSTS.CAPABILITY_IS_DETECTED}).\n */\nexport function resolveConfig(config: DaemonConfig): LoadedConfig {\n const routes: ResolvedRoute[] = [];\n const problems: ConfigProblem[] = [];\n\n for (const [kind, route] of Object.entries(config.routes)) {\n const where = `routes.${kind}`;\n const backend = config.backends[route.backend];\n if (!backend) {\n problems.push({\n where,\n message: `backend \"${route.backend}\" is not defined in backends`,\n });\n continue;\n }\n\n const descriptor = backendDescriptor(backend.backend);\n\n // A named provider supplies its own address; the generic backend and any\n // override still have to be given one.\n const baseUrl = backend.baseUrl ?? descriptor.defaultBaseUrl;\n\n if (descriptor.class === \"http\") {\n if (baseUrl === undefined) {\n problems.push({\n where: `backends.${route.backend}`,\n message: \"an HTTP-class backend needs a baseUrl\",\n });\n continue;\n }\n const check = checkBaseUrl(baseUrl);\n if (!check.ok) {\n problems.push({\n where: `backends.${route.backend}.baseUrl`,\n message: check.detail,\n });\n continue;\n }\n }\n\n // Cost comes from the registry, or from where the request goes — never\n // from config ({@link MUSTS.COST_NOT_CONFIGURABLE},\n // {@link MUSTS.REMOTE_IS_NEVER_FREE}).\n const cost = resolveCost(backend.backend, baseUrl);\n const acknowledged = backend.spend?.acknowledged === true;\n const capCents = backend.spend?.dailyCapCents;\n\n // A widened metered backend without a ceiling is refused rather than\n // silently given an unlimited one ({@link MUSTS.METERED_REQUIRES_CEILING}).\n const widened = backend.offer !== \"self\";\n if (\n cost === \"metered\" &&\n widened &&\n acknowledged &&\n capCents === undefined\n ) {\n problems.push({\n where: `backends.${route.backend}.spend`,\n message:\n \"sharing a metered backend needs spend.dailyCapCents — an \" +\n \"unlimited ceiling is not something anyone means on purpose\",\n });\n continue;\n }\n\n const configured = backend.offer;\n const offerScope = effectiveOfferScope(configured, cost, {\n acknowledged: acknowledged && capCents !== undefined,\n });\n if (offerScope !== configured) {\n problems.push({\n where: `backends.${route.backend}.offer`,\n message:\n cost === \"subscription\"\n ? `\"${configured}\" was ignored: ${descriptor.label} runs on your ` +\n `own subscription, so it is locked to your work only`\n : `\"${configured}\" was narrowed to \"self\": ${descriptor.label} ` +\n `bills you per token. \\`byollm offer ${route.backend} ` +\n `${configured}\\` to share it deliberately, with a ceiling`,\n });\n }\n\n routes.push({\n kind: kind as z.infer<typeof JobKind>,\n backendKey: route.backend,\n backendId: backend.backend,\n backendClass: descriptor.class,\n model: route.model,\n cost,\n offerScope,\n spendAcknowledged: acknowledged,\n spendDailyCapCents: capCents,\n spendCentsPerMillionTokens: backend.spend?.centsPerMillionTokens ?? 1500,\n baseUrl,\n apiKeyEnv: backend.apiKeyEnv,\n });\n }\n\n return { config, routes, problems };\n}\n\nfunction isNotFound(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { code?: unknown }).code === \"ENOENT\"\n );\n}\n","import { isIP } from \"node:net\";\n\n/**\n * Why a base URL was refused.\n */\nexport type BaseUrlRefusal =\n | \"not-a-url\"\n | \"bad-scheme\"\n | \"credentials-in-url\"\n | \"cloud-metadata\"\n | \"link-local\"\n | \"wildcard-address\";\n\nexport type BaseUrlCheck =\n | { readonly ok: true; readonly url: URL }\n | {\n readonly ok: false;\n readonly refusal: BaseUrlRefusal;\n readonly detail: string;\n };\n\n/**\n * Hostnames that resolve to a cloud instance's credential endpoint. Reaching\n * one from a machine running in a cloud VM hands out IAM credentials.\n */\nconst METADATA_HOSTS = new Set([\n \"metadata.google.internal\",\n \"metadata.goog\",\n \"instance-data\",\n \"metadata\",\n]);\n\n/** Literal addresses of the same endpoints. */\nconst METADATA_ADDRESSES = new Set([\n \"169.254.169.254\",\n \"169.254.170.2\",\n \"fd00:ec2::254\",\n]);\n\n/**\n * Validate an owner-configured backend base URL\n * ({@link MUSTS.HTTP_BASE_URL_SAFE}).\n *\n * **What this is and is not.** byollm_004 Rev 1 calls the HTTP-class threat\n * surface \"SSRF-shaped\", and the shape matters: the base URL comes from the\n * machine owner's config and from nowhere else — no payload field can set it,\n * redirect it, or append to it. There is therefore no attacker-controlled\n * input channel into this value at all. What remains is an owner who\n * misconfigures their own machine, and the one case where that is genuinely\n * dangerous is a cloud metadata endpoint.\n *\n * So this deliberately **allows loopback and private LAN addresses**. Blocking\n * them, as a generic SSRF filter would, would refuse\n * `http://127.0.0.1:11434` — which is Ollama's default and the entire point of\n * the product. A filter that breaks the primary path in exchange for no real\n * protection is theatre, and byollm_004's honesty rule forbids claiming it as\n * a guarantee.\n *\n * Redirects are a separate matter and are refused outright by the HTTP\n * backend, so a permitted base URL cannot become a forbidden one in flight.\n */\nexport function checkBaseUrl(raw: string): BaseUrlCheck {\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return {\n ok: false,\n refusal: \"not-a-url\",\n detail: \"base URL is not a valid absolute URL\",\n };\n }\n\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n return {\n ok: false,\n refusal: \"bad-scheme\",\n detail: `base URL scheme ${url.protocol} is not http or https`,\n };\n }\n\n if (url.username !== \"\" || url.password !== \"\") {\n // Credentials in the URL would end up in logs and error messages.\n return {\n ok: false,\n refusal: \"credentials-in-url\",\n detail: \"base URL must not embed a username or password\",\n };\n }\n\n const host = url.hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n\n if (METADATA_HOSTS.has(host) || METADATA_ADDRESSES.has(host)) {\n return {\n ok: false,\n refusal: \"cloud-metadata\",\n detail: `${host} is a cloud metadata endpoint`,\n };\n }\n\n // 169.254.0.0/16 and fe80::/10 — link-local. The metadata addresses above\n // live here too; this catches the rest of the range.\n if (isIP(host) === 4 && host.startsWith(\"169.254.\")) {\n return {\n ok: false,\n refusal: \"link-local\",\n detail: `${host} is link-local`,\n };\n }\n if (isIP(host) === 6 && /^fe[89ab]/.test(host)) {\n return {\n ok: false,\n refusal: \"link-local\",\n detail: `${host} is link-local`,\n };\n }\n\n // A wildcard address is a listening address, not a destination.\n if (host === \"0.0.0.0\" || host === \"::\" || host === \"\") {\n return {\n ok: false,\n refusal: \"wildcard-address\",\n detail: `${host || \"(empty)\"} is not a destination address`,\n };\n }\n\n return { ok: true, url };\n}\n\n/** Human-readable explanations for the trust UI and startup errors. */\nexport const BASE_URL_REFUSAL_MESSAGES: Readonly<\n Record<BaseUrlRefusal, string>\n> = Object.freeze({\n \"not-a-url\": \"that base URL could not be parsed\",\n \"bad-scheme\": \"a backend base URL must be http or https\",\n \"credentials-in-url\":\n \"put credentials in the backend's auth config, not in the URL\",\n \"cloud-metadata\":\n \"that address is a cloud metadata endpoint and would expose instance credentials\",\n \"link-local\": \"link-local addresses are refused\",\n \"wildcard-address\":\n \"that is an address to listen on, not one to connect to — use 127.0.0.1\",\n});\n","import { platform } from \"node:os\";\nimport {\n verifyPublicIdentity,\n type Capability,\n type PublicIdentity,\n} from \"@byollm/protocol\";\nimport { ClientError, type ProtocolClient } from \"./client.js\";\nimport type { Pairing } from \"./pairings.js\";\n\nexport interface ConnectOptions {\n readonly client: ProtocolClient;\n readonly daemonVersion: string;\n readonly label: string;\n readonly capabilities: readonly Capability[];\n /** This machine's public keys, presented at pair start (byollm_009 §5). */\n readonly device: PublicIdentity;\n /** Called once, with what to show the user. */\n readonly onCode: (info: {\n userCode: string;\n verificationUrl: string;\n expiresAt: number;\n }) => void;\n /** Called each poll, so a CLI can show it is still waiting. */\n readonly onPoll?: () => void;\n readonly now?: () => number;\n readonly sleep?: (ms: number) => Promise<void>;\n readonly signal?: AbortSignal;\n}\n\nexport type ConnectResult =\n | { readonly ok: true; readonly pairing: Pairing }\n | {\n readonly ok: false;\n readonly reason: \"denied\" | \"expired\" | \"aborted\";\n readonly message: string;\n };\n\n/**\n * The device-code pairing flow, from the daemon's side.\n *\n * The daemon asks for a code, shows it, and polls. The user approves inside\n * the app's own authenticated session, which is how the server learns who\n * they are — the daemon never asserts an identity and never accepts a pasted\n * long-lived secret ({@link MUSTS.PAIR_INTERACTIVE}).\n *\n * Nothing listens on the user's machine for this. A loopback redirect would\n * be fewer keystrokes and would contradict the product's whole posture, as\n * well as breaking on the headless boxes most likely to be running a model.\n */\nexport async function connect(options: ConnectOptions): Promise<ConnectResult> {\n const now = options.now ?? Date.now;\n const sleep = options.sleep ?? defaultSleep;\n\n const started = await options.client.pairStart({\n version: options.daemonVersion,\n label: options.label,\n platform: currentPlatform(),\n device: options.device,\n capabilities: options.capabilities,\n });\n\n options.onCode({\n userCode: started.userCode,\n verificationUrl: started.verificationUrl,\n expiresAt: started.expiresAt,\n });\n\n for (;;) {\n if (options.signal?.aborted === true) {\n return { ok: false, reason: \"aborted\", message: \"pairing was canceled\" };\n }\n if (now() >= started.expiresAt) {\n return {\n ok: false,\n reason: \"expired\",\n message: \"the pairing code expired before it was approved\",\n };\n }\n\n await sleep(started.pollIntervalMs);\n options.onPoll?.();\n\n let polled;\n try {\n polled = await options.client.pairPoll(started.deviceCode);\n } catch (error) {\n // A blip while waiting for a human is not a failure — keep polling\n // until the code itself expires.\n if (error instanceof ClientError && error.retryable) continue;\n throw error;\n }\n\n switch (polled.status) {\n case \"pending\":\n continue;\n case \"denied\":\n return {\n ok: false,\n reason: \"denied\",\n message: \"the pairing request was declined\",\n };\n case \"expired\":\n return {\n ok: false,\n reason: \"expired\",\n message: \"the pairing code expired before it was approved\",\n };\n case \"approved\":\n // Verify before pinning. A site whose encryption key is not signed by\n // the identity presenting it is either misconfigured or being\n // impersonated, and pinning it would make the impersonation\n // permanent — which is the failure mode pinning exists to prevent,\n // arrived at by pinning.\n if (!verifyPublicIdentity(polled.site)) {\n return {\n ok: false,\n reason: \"denied\",\n message:\n \"this app presented keys that do not verify: its encryption \" +\n \"key is not signed by the identity it claims. Nothing was \" +\n \"paired.\",\n };\n }\n return {\n ok: true,\n pairing: {\n origin: options.client.origin,\n runnerId: polled.runnerId,\n token: polled.runnerToken,\n owner: polled.owner,\n ...(polled.ownerLabel === undefined\n ? {}\n : { ownerLabel: polled.ownerLabel }),\n site: polled.site,\n pairedAt: now(),\n },\n };\n }\n }\n}\n\n/** The platform, narrowed to what the protocol accepts. */\nexport function currentPlatform(): \"darwin\" | \"linux\" | \"win32\" {\n const current = platform();\n if (current === \"darwin\" || current === \"linux\" || current === \"win32\") {\n return current;\n }\n // byollm_002 scopes v1 to macOS and Linux. Anything else reports as linux\n // rather than refusing outright — the protocol field is descriptive, and a\n // BSD user with Ollama running should not be blocked by a label.\n return \"linux\";\n}\n\nconst defaultSleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n","import { createHash } from \"node:crypto\";\nimport { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport type { Audience } from \"@byollm/protocol\";\nimport { z } from \"zod\";\n\n/**\n * A prompt about to be executed.\n *\n * Written *before* the backend is called\n * ({@link MUSTS.INGRESS_LOGGED_BEFORE_EXECUTION}), so a job that wedges or\n * crashes the machine still leaves a record of what it was.\n */\nexport const PromptEntry = z\n .object({\n type: z.literal(\"prompt\"),\n at: z.number().int().positive(),\n /** Origin of the server that sent the job. */\n origin: z.string().min(1),\n jobId: z.string().min(1),\n kind: z.string().min(1),\n audience: z.string().min(1),\n /** Who this prompt is *for* — which, for community work, is not you. */\n owner: z.string().min(1),\n backendId: z.string().min(1),\n backendClass: z.string().min(1),\n model: z.string().min(1),\n /** Always present, including after retention drops the text. */\n promptHash: z.string().length(64),\n promptChars: z.number().int().nonnegative(),\n /**\n * The prompt itself. Absent means \"not retained\" — distinct from an empty\n * prompt, which the protocol forbids anyway. Zero and unknown never look\n * alike.\n */\n prompt: z.string().optional(),\n })\n .strict();\nexport type PromptEntry = z.infer<typeof PromptEntry>;\n\n/** How a job ended. A separate line, so the prompt line is never rewritten. */\nexport const OutcomeEntry = z\n .object({\n type: z.literal(\"outcome\"),\n at: z.number().int().positive(),\n jobId: z.string().min(1),\n outcome: z.enum([\"ok\", \"error\", \"canceled\", \"refused\"]),\n /** Present for a job that ran; absent for one refused before execution. */\n durationMs: z.number().int().nonnegative().optional(),\n outputChars: z.number().int().nonnegative().optional(),\n /** Why, for `error` and `refused`. */\n detail: z.string().optional(),\n })\n .strict();\nexport type OutcomeEntry = z.infer<typeof OutcomeEntry>;\n\nexport const IngressEntry = z.discriminatedUnion(\"type\", [\n PromptEntry,\n OutcomeEntry,\n]);\nexport type IngressEntry = z.infer<typeof IngressEntry>;\n\nexport interface IngressOptions {\n readonly path: string;\n /** Days to keep a community prompt in full before reducing it to its hash. */\n readonly communityPromptDays: number;\n /** Whether to record the owner's own prompts in full. */\n readonly keepSelfPrompts: boolean;\n}\n\n/**\n * The append-only record of every prompt that has run on this machine.\n *\n * byollm_002 calls the meter the product's soul. This is it: one JSONL file\n * the owner can read, grep and delete, written before execution rather than\n * after.\n */\nexport class IngressLog {\n readonly #options: IngressOptions;\n\n constructor(options: IngressOptions) {\n this.#options = options;\n }\n\n /** Record a prompt. Await this before starting the backend call. */\n async recordPrompt(input: {\n at: number;\n origin: string;\n jobId: string;\n kind: string;\n audience: Audience;\n owner: string;\n backendId: string;\n backendClass: string;\n model: string;\n prompt: string;\n }): Promise<void> {\n // Community prompts are always kept initially — retention reduces them\n // later. Only the owner's own prompts can be opted out of up front.\n const keepText =\n input.audience === \"self\" ? this.#options.keepSelfPrompts : true;\n\n await this.#append({\n type: \"prompt\",\n at: input.at,\n origin: input.origin,\n jobId: input.jobId,\n kind: input.kind,\n audience: input.audience,\n owner: input.owner,\n backendId: input.backendId,\n backendClass: input.backendClass,\n model: input.model,\n promptHash: hashText(input.prompt),\n promptChars: input.prompt.length,\n ...(keepText ? { prompt: input.prompt } : {}),\n });\n }\n\n /** Record how a job ended. */\n async recordOutcome(input: {\n at: number;\n jobId: string;\n outcome: OutcomeEntry[\"outcome\"];\n durationMs?: number;\n outputChars?: number;\n detail?: string;\n }): Promise<void> {\n await this.#append({\n type: \"outcome\",\n at: input.at,\n jobId: input.jobId,\n outcome: input.outcome,\n ...(input.durationMs === undefined\n ? {}\n : { durationMs: input.durationMs }),\n ...(input.outputChars === undefined\n ? {}\n : { outputChars: input.outputChars }),\n ...(input.detail === undefined ? {} : { detail: input.detail }),\n });\n }\n\n async #append(entry: IngressEntry): Promise<void> {\n await mkdir(dirname(this.#options.path), { recursive: true });\n // JSON.stringify escapes control characters, so a prompt containing ANSI\n // escapes or newlines cannot forge a log line or repaint the terminal of\n // whoever later reads the file ({@link MUSTS.OUTPUT_INERT}).\n await appendFile(this.#options.path, `${JSON.stringify(entry)}\\n`, {\n mode: 0o600,\n });\n }\n\n /** Read the log, oldest first. Malformed lines are skipped, not fatal. */\n async read(): Promise<IngressEntry[]> {\n let raw: string;\n try {\n raw = await readFile(this.#options.path, \"utf8\");\n } catch {\n return [];\n }\n const entries: IngressEntry[] = [];\n for (const line of raw.split(\"\\n\")) {\n if (line.trim() === \"\") continue;\n try {\n const parsed = IngressEntry.safeParse(JSON.parse(line));\n if (parsed.success) entries.push(parsed.data);\n } catch {\n // A truncated final line after a hard kill is expected, not an error.\n }\n }\n return entries;\n }\n\n /**\n * Apply retention: drop the text of community prompts older than the\n * window, keeping the hash, the metadata and the character count.\n *\n * byollm_004 Rev 1: a volunteer must not indefinitely retain strangers'\n * content. The hash stays, so the owner can still prove what ran.\n *\n * @returns how many entries were reduced.\n */\n async applyRetention(now: number): Promise<number> {\n const entries = await this.read();\n const cutoff = now - this.#options.communityPromptDays * 86_400_000;\n let reduced = 0;\n\n const kept = entries.map((entry) => {\n if (entry.type !== \"prompt\") return entry;\n const isCommunity =\n entry.audience === \"named\" || entry.audience === \"public\";\n if (!isCommunity || entry.prompt === undefined || entry.at >= cutoff) {\n return entry;\n }\n reduced += 1;\n const { prompt: _dropped, ...rest } = entry;\n return rest;\n });\n\n if (reduced > 0) {\n // The log is append-only in operation; retention is the one deliberate\n // exception, and it only ever removes text.\n await writeFile(\n this.#options.path,\n `${kept.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`,\n { mode: 0o600 },\n );\n }\n return reduced;\n }\n}\n\n/** SHA-256 of a prompt, hex. */\nexport function hashText(text: string): string {\n return createHash(\"sha256\").update(text, \"utf8\").digest(\"hex\");\n}\n\n/**\n * Replace terminal control sequences before printing untrusted text.\n *\n * Model output and job payloads both reach the owner's terminal through\n * `byollm log` and `byollm status`. Text that can move the cursor or set\n * colours can forge output — the ANSI/log-injection row of byollm_004 §5's\n * corpus. Stored bytes stay verbatim; only the *display* is sanitised, so the\n * log remains an honest record of what actually arrived.\n *\n * Tab and newline are kept: they are legitimate content, not control.\n */\nexport function stripControlChars(text: string): string {\n // eslint-disable-next-line no-control-regex -- matching control characters is the entire purpose\n return text.replace(/[\\u0000-\\u0008\\u000B-\\u001F\\u007F-\\u009F]/g, \"\\uFFFD\");\n}\n","import { chmod, mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport {\n StoredKeys,\n fingerprint,\n generateKeys,\n publicIdentityOf,\n signRequest,\n signWith,\n type PublicIdentity,\n} from \"@byollm/protocol\";\n\n/**\n * This machine's identity — byollm_009 §3.\n *\n * Generated once, at first run, and then never again: the device key *is* the\n * daemon, in a way a runner token never was. A token is a bearer secret a\n * server minted and can reissue; this is the machine saying who it is, and\n * nothing upstream can mint one.\n *\n * That difference is why this file is treated more carefully than the others\n * the daemon writes. Losing it means re-pairing every site. Leaking it means\n * someone else can be this machine.\n */\nexport class DeviceIdentity {\n readonly #path: string;\n #keys: StoredKeys | undefined;\n\n constructor(path: string) {\n this.#path = path;\n }\n\n /**\n * Load the keys, generating them on first run.\n *\n * A corrupt file is **not** silently replaced. Generating fresh keys over\n * an unreadable file would silently orphan every pairing the owner has —\n * every site would see an unknown device and refuse — and it would look\n * like a network problem. Refusing loudly names the file and lets the owner\n * decide, which is the only honest option when the alternative is\n * destroying something unrecoverable.\n */\n async load(now: number): Promise<StoredKeys> {\n if (this.#keys) return this.#keys;\n\n let raw: string;\n try {\n raw = await readFile(this.#path, \"utf8\");\n } catch (error) {\n if (!isNotFound(error)) throw error;\n return this.#create(now);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(\n `${this.#path} is not valid JSON. This file is this machine's ` +\n `identity; delete it only if you accept re-pairing every app.`,\n { cause: error },\n );\n }\n\n const result = StoredKeys.safeParse(parsed);\n if (!result.success) {\n throw new Error(\n `${this.#path} is not a valid key file. This file is this machine's ` +\n `identity; delete it only if you accept re-pairing every app.`,\n );\n }\n\n await this.#warnIfReadable();\n this.#keys = result.data;\n return result.data;\n }\n\n /** The public half, for pairing and the handshake. */\n async publicIdentity(now: number): Promise<PublicIdentity> {\n return publicIdentityOf(await this.load(now));\n }\n\n /** What the owner compares out of band. */\n async fingerprint(now: number): Promise<string> {\n return fingerprint((await this.load(now)).identityPublic);\n }\n\n /** Sign a challenge nonce. */\n async sign(data: Uint8Array, now: number): Promise<string> {\n return signWith(await this.load(now), data);\n }\n\n /** Sign one outgoing protocol request (byollm_009 §4.2). */\n async signRequest(input: {\n endpoint: string;\n runnerId: string;\n issuedAt: number;\n body: string;\n }): Promise<string> {\n return signRequest(await this.load(input.issuedAt), input).signature;\n }\n\n async #create(now: number): Promise<StoredKeys> {\n const keys = generateKeys(now);\n await mkdir(dirname(this.#path), { recursive: true });\n // `wx` so two daemons racing at first start cannot each believe they\n // created the identity — the loser reads what the winner wrote rather\n // than overwriting a key the other has already begun pairing with.\n try {\n await writeFile(this.#path, JSON.stringify(keys, null, 2), {\n mode: 0o600,\n flag: \"wx\",\n });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n return this.load(now);\n }\n throw error;\n }\n this.#keys = keys;\n return keys;\n }\n\n /**\n * Say something if the key file is group- or world-readable.\n *\n * We write `0600`, but a restore from backup, a careless `chmod -R`, or a\n * synced folder can widen it afterwards. Tightening it silently would hide\n * that something else on this machine is treating the file as ordinary\n * data, which is worth knowing.\n *\n * **Windows is exempt, because the check would lie.** Node's `mode` there\n * is synthesized — a writable file reports `0o666` regardless of what was\n * passed to `writeFile`, and `chmod` only toggles the read-only flag. So on\n * Windows this would warn on every start and claim to fix something it had\n * not fixed. The honest position is in `docs/security.md` §3.4: on Windows\n * the key file is protected by the ACLs it inherits from the user profile,\n * not by a mode we set.\n */\n async #warnIfReadable(): Promise<void> {\n if (process.platform === \"win32\") return;\n try {\n const mode = (await stat(this.#path)).mode & 0o777;\n if ((mode & 0o077) !== 0) {\n process.stderr.write(\n `warning: ${this.#path} is mode ${mode.toString(8)} — this machine's\\n` +\n `private key is readable by other users. Fixing to 0600.\\n`,\n );\n await chmod(this.#path, 0o600);\n }\n } catch {\n // A stat failure must not stop a daemon from starting.\n }\n }\n}\n\nfunction isNotFound(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === \"ENOENT\";\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { PublicIdentity } from \"@byollm/protocol\";\nimport { z } from \"zod\";\nimport { normalizeOrigin } from \"./allowlist.js\";\n\n/**\n * One paired server.\n *\n * A daemon may pair with several apps; each pairing is a separate identity\n * with its own token and its own owner. Nothing is shared between them —\n * `owner` from one server means nothing on another\n * ({@link MUSTS.PAIR_ONE_USER}).\n */\nexport const Pairing = z\n .object({\n origin: z.string().min(1),\n runnerId: z.string().min(1),\n /** Bearer token. This file is written 0600 for exactly this reason. */\n token: z.string().min(1),\n /** The app's id for this daemon's owner. */\n owner: z.string().min(1),\n ownerLabel: z.string().optional(),\n /**\n * The site's public keys, pinned at pairing (byollm_009 §5).\n *\n * Pinned rather than fetched: a key re-fetched on each connection is a\n * key an upstream can change, which is the whole thing pinning prevents.\n * The owner can compare `sitePin`'s fingerprint against what the site\n * displays.\n */\n site: PublicIdentity,\n pairedAt: z.number().int().positive(),\n })\n .strict();\nexport type Pairing = z.infer<typeof Pairing>;\n\nconst PairingFile = z\n .object({ version: z.literal(1), pairings: z.array(Pairing) })\n .strict();\n\n/** The daemon's paired servers, on disk. */\nexport class Pairings {\n readonly #path: string;\n #pairings: Pairing[] = [];\n #loaded = false;\n\n constructor(path: string) {\n this.#path = path;\n }\n\n async load(): Promise<void> {\n try {\n const parsed = PairingFile.safeParse(\n JSON.parse(await readFile(this.#path, \"utf8\")),\n );\n this.#pairings = parsed.success ? parsed.data.pairings : [];\n } catch {\n this.#pairings = [];\n }\n this.#loaded = true;\n }\n\n list(): readonly Pairing[] {\n this.#assertLoaded();\n return [...this.#pairings];\n }\n\n get(origin: string): Pairing | undefined {\n this.#assertLoaded();\n const normalized = normalizeOrigin(origin);\n return this.#pairings.find(\n (pairing) => normalizeOrigin(pairing.origin) === normalized,\n );\n }\n\n /** Add or replace the pairing for an origin. Re-pairing supersedes. */\n async put(pairing: Pairing): Promise<void> {\n this.#assertLoaded();\n const normalized = normalizeOrigin(pairing.origin);\n this.#pairings = this.#pairings.filter(\n (existing) => normalizeOrigin(existing.origin) !== normalized,\n );\n this.#pairings.push({ ...pairing, origin: normalized });\n await this.#save();\n }\n\n /** Forget a pairing. Returns whether one was removed. */\n async remove(origin: string): Promise<boolean> {\n this.#assertLoaded();\n const normalized = normalizeOrigin(origin);\n const before = this.#pairings.length;\n this.#pairings = this.#pairings.filter(\n (pairing) => normalizeOrigin(pairing.origin) !== normalized,\n );\n if (this.#pairings.length === before) return false;\n await this.#save();\n return true;\n }\n\n #assertLoaded(): void {\n if (!this.#loaded) throw new Error(\"pairings used before load()\");\n }\n\n async #save(): Promise<void> {\n await mkdir(dirname(this.#path), { recursive: true });\n await writeFile(\n this.#path,\n `${JSON.stringify({ version: 1, pairings: this.#pairings }, null, 2)}\\n`,\n // Tokens live here. Nobody else on a shared machine gets to read them.\n { mode: 0o600 },\n );\n }\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { z } from \"zod\";\n\nconst SpendFile = z\n .object({\n version: z.literal(1),\n /** Per backend key: epoch-ms timestamps and the cents charged. */\n entries: z.record(\n z.string(),\n z.array(\n z.object({ at: z.number().int().positive(), cents: z.number().min(0) }),\n ),\n ),\n })\n .strict();\n\n/**\n * What the owner has spent running other people's work on a metered backend.\n *\n * byollm_007 §4: a widened metered backend must carry a ceiling and stop at\n * it. A ceiling nobody counts against is a comment, so this is the counting.\n *\n * **On accuracy, honestly.** Providers do not return a price, so this\n * estimates from token counts and an owner-supplied rate. It will not match an\n * invoice to the cent. It does not need to: its job is to stop a runaway, and\n * for that a defensible over-estimate is worth more than a precise number\n * arriving too late. The ceiling is a brake, not an accountant.\n */\nexport class SpendLedger {\n readonly #path: string;\n #entries: Record<string, { at: number; cents: number }[]> = {};\n #loaded = false;\n\n constructor(path: string) {\n this.#path = path;\n }\n\n async load(now: number): Promise<void> {\n try {\n const parsed = SpendFile.safeParse(\n JSON.parse(await readFile(this.#path, \"utf8\")),\n );\n this.#entries = parsed.success ? parsed.data.entries : {};\n } catch {\n // A corrupt ledger reads as \"spent nothing\", which would be the unsafe\n // direction — so callers treat a missing ledger as ceiling-reached\n // until it loads cleanly. See `hasReachedCeiling`.\n this.#entries = {};\n }\n this.#prune(now);\n this.#loaded = true;\n }\n\n /** Cents spent on community work for this backend in the last 24 hours. */\n spentTodayCents(backendKey: string, now: number): number {\n this.#assertLoaded();\n const since = now - 86_400_000;\n return (this.#entries[backendKey] ?? [])\n .filter((e) => e.at >= since)\n .reduce((sum, e) => sum + e.cents, 0);\n }\n\n /**\n * Has this backend spent its daily ceiling?\n *\n * A backend with no ceiling reads as reached — not as unlimited. That is\n * the safe direction and it matches the config rule: sharing without a\n * ceiling is refused at load, so reaching this state means something is\n * inconsistent and the brake should be on.\n */\n hasReachedCeiling(\n backendKey: string,\n capCents: number | undefined,\n now: number,\n ): boolean {\n if (capCents === undefined) return true;\n return this.spentTodayCents(backendKey, now) >= capCents;\n }\n\n /** Record an estimated charge for community work. */\n async record(backendKey: string, cents: number, now: number): Promise<void> {\n this.#assertLoaded();\n (this.#entries[backendKey] ??= []).push({ at: now, cents });\n this.#prune(now);\n await mkdir(dirname(this.#path), { recursive: true });\n await writeFile(\n this.#path,\n JSON.stringify({ version: 1, entries: this.#entries }),\n { mode: 0o600 },\n );\n }\n\n /** Everything spent per backend today, for `byollm status`. */\n summary(now: number): Record<string, number> {\n this.#assertLoaded();\n const out: Record<string, number> = {};\n for (const key of Object.keys(this.#entries)) {\n out[key] = this.spentTodayCents(key, now);\n }\n return out;\n }\n\n #assertLoaded(): void {\n if (!this.#loaded) throw new Error(\"spend ledger used before load()\");\n }\n\n /** Anything older than a day can never affect the window again. */\n #prune(now: number): void {\n const cutoff = now - 86_400_000;\n const pruned: Record<string, { at: number; cents: number }[]> = {};\n for (const [key, entries] of Object.entries(this.#entries)) {\n const kept = entries.filter((e) => e.at >= cutoff);\n if (kept.length > 0) pruned[key] = kept;\n }\n this.#entries = pruned;\n }\n}\n\n/**\n * Estimate the cost of a call in cents.\n *\n * Deliberately crude and deliberately generous: characters over four is a\n * rough token count, and the rate is whatever the owner said. Over-estimating\n * trips the brake early, which is the failure everyone prefers.\n */\nexport function estimateCents(\n promptChars: number,\n outputChars: number,\n centsPerMillionTokens: number,\n): number {\n const tokens = (promptChars + outputChars) / 4;\n return (tokens / 1_000_000) * centsPerMillionTokens;\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Where the daemon keeps its state.\n *\n * One directory the owner can `ls`, `cat` and delete. The trust surface is\n * the product (byollm_002), and a trust surface you cannot find is not one.\n */\nexport interface DaemonPaths {\n /** `~/.byollm` — everything below lives here. */\n readonly root: string;\n /** Job routing and backend configuration, owner-authored. */\n readonly config: string;\n /** Paired servers: origin, runner id, token, owner. */\n readonly pairings: string;\n /** The local `named` allowlist — one file, every app. */\n readonly allowlist: string;\n /** Append-only JSONL: every prompt that has run on this machine. */\n readonly ingressLog: string;\n /** Community-job counters, for rate limits and the daily cap. */\n readonly budgets: string;\n /** Estimated money spent running other people's work on metered backends. */\n readonly spend: string;\n /**\n * This machine's device keypairs (byollm_009 §3). The most sensitive file\n * the daemon writes: it is the machine's identity, not a token a server can\n * revoke and reissue.\n */\n readonly keys: string;\n /** Set while the owner has the daemon paused. */\n readonly pauseFlag: string;\n /**\n * Per-job scratch directories. A process-class backend runs with its `cwd`\n * set to an empty one of these and nothing else (byollm_004 §2).\n */\n readonly scratch: string;\n}\n\n/** Resolve the daemon's paths, rooted at `~/.byollm` unless overridden. */\nexport function daemonPaths(root = defaultRoot()): DaemonPaths {\n return {\n root,\n config: join(root, \"config.json\"),\n pairings: join(root, \"pairings.json\"),\n allowlist: join(root, \"allow.json\"),\n ingressLog: join(root, \"ingress.log\"),\n budgets: join(root, \"budgets.json\"),\n spend: join(root, \"spend.json\"),\n keys: join(root, \"keys.json\"),\n pauseFlag: join(root, \"paused\"),\n scratch: join(root, \"scratch\"),\n };\n}\n\n/**\n * `BYOLLM_HOME` exists so the conformance kit and the adversarial suite can\n * run real daemons without touching the developer's own `~/.byollm`.\n */\nexport function defaultRoot(): string {\n return process.env[\"BYOLLM_HOME\"] ?? join(homedir(), \".byollm\");\n}\n","import {\n ENVELOPE_MAX_AGE_MS,\n keyId,\n open,\n publicIdentityOf,\n seal,\n sizeClassCeiling,\n type ClaimedStub,\n type JobPayload,\n type PublicIdentity,\n type SealedEnvelope,\n type StoredKeys,\n REFUSAL_MESSAGES,\n matchAudience,\n type Capability,\n type ClaimedJob,\n type JobOutcome,\n} from \"@byollm/protocol\";\nimport type { Allowlist } from \"./allowlist.js\";\nimport { createBackend, type Backend } from \"./backends/index.js\";\nimport type { Budgets } from \"./budgets.js\";\nimport { ClientError, type ProtocolClient } from \"./client.js\";\nimport { composePrompt } from \"./compose.js\";\nimport type { LoadedConfig, ResolvedRoute } from \"./config.js\";\nimport type { IngressLog } from \"./ingress.js\";\nimport { estimateCents, type SpendLedger } from \"./spend.js\";\n\n/** What the daemon is currently doing, for `byollm status`. */\nexport interface RunnerStatus {\n readonly origin: string;\n readonly owner: string;\n readonly runnerId: string;\n readonly paused: boolean;\n readonly revoked: boolean;\n readonly activeJobs: number;\n readonly capabilities: readonly Capability[];\n /** Set when the last server contact failed — one of the four truths. */\n readonly lastError?: string;\n readonly completed: number;\n readonly refused: number;\n}\n\nexport interface RunnerOptions {\n readonly client: ProtocolClient;\n readonly runnerId: string;\n readonly owner: string;\n readonly daemonVersion: string;\n readonly loaded: LoadedConfig;\n readonly allowlist: Allowlist;\n readonly budgets: Budgets;\n /** Tracks money spent on other people's work, for metered backends. */\n readonly spend: SpendLedger;\n readonly ingress: IngressLog;\n /**\n * How this daemon opens work sealed to it, and what it checks it against.\n *\n * `sitePinned` is the identity taken at pairing (byollm_009 §5). Verifying\n * against it — rather than against anything the envelope claims — is what\n * makes a relay unable to substitute work: it can produce an envelope this\n * machine can open, but not one signed by the site.\n */\n readonly identity?: {\n keys(): Promise<StoredKeys>;\n readonly sitePinned: PublicIdentity;\n };\n /** Heartbeat cadence before jitter. */\n readonly heartbeatMs?: number;\n readonly now?: () => number;\n /** Notified on every state change, so the CLI can render progress. */\n readonly onEvent?: (event: RunnerEvent) => void;\n /** Injectable backend factory, so tests need no real model server. */\n readonly backendFactory?: (route: ResolvedRoute) => Backend;\n}\n\nexport type RunnerEvent =\n | { readonly type: \"heartbeat\"; readonly capabilities: number }\n | { readonly type: \"claimed\"; readonly jobId: string; readonly kind: string }\n | {\n readonly type: \"refused\";\n readonly jobId: string;\n readonly reason: string;\n }\n | {\n readonly type: \"finished\";\n readonly jobId: string;\n readonly outcome: string;\n readonly durationMs: number;\n }\n | { readonly type: \"revoked\" }\n | { readonly type: \"error\"; readonly message: string };\n\nconst DEFAULT_HEARTBEAT_MS = 10_000;\n\n/**\n * The daemon's loop: heartbeat, claim, execute, report.\n *\n * Everything that makes the daemon a *trust anchor* rather than a worker\n * happens in {@link Runner.admit} and {@link Runner.runJob} — the local\n * audience check, the budget check, and the ingress write that precedes\n * execution. The loop itself is deliberately dull.\n */\nexport class Runner {\n readonly #options: RunnerOptions;\n readonly #backends = new Map<string, Backend>();\n /**\n * Jobs in flight, by job id → the grant and how to stop it.\n *\n * The lease id is kept because every lease-scoped call has to name the\n * grant it means: a release that names only the job releases whatever\n * lease exists when it arrives, which for a replayed request is not the\n * one this daemon meant (byollm_009 §4.2, `Lease.id`).\n */\n readonly #active = new Map<\n string,\n { controller: AbortController; leaseId: string }\n >();\n readonly #now: () => number;\n #capabilities: Capability[] = [];\n #paused = false;\n #revoked = false;\n #stopped = false;\n #lastError: string | undefined;\n #completed = 0;\n #refused = 0;\n\n constructor(options: RunnerOptions) {\n this.#options = options;\n this.#now = options.now ?? Date.now;\n }\n\n status(): RunnerStatus {\n return {\n origin: this.#options.client.origin,\n owner: this.#options.owner,\n runnerId: this.#options.runnerId,\n paused: this.#paused,\n revoked: this.#revoked,\n activeJobs: this.#active.size,\n capabilities: [...this.#capabilities],\n ...(this.#lastError === undefined ? {} : { lastError: this.#lastError }),\n completed: this.#completed,\n refused: this.#refused,\n };\n }\n\n pause(): void {\n this.#paused = true;\n }\n\n resume(): void {\n this.#paused = false;\n }\n\n /**\n * Build the capability matrix: owner config intersected with what is\n * actually reachable and healthy right now\n * ({@link MUSTS.CAPABILITY_IS_DETECTED}).\n *\n * A configured route whose backend is down simply does not appear. The\n * daemon then receives no work for it, which is the correct outcome and one\n * the owner can see in `byollm status`.\n */\n async detectCapabilities(): Promise<Capability[]> {\n const capabilities: Capability[] = [];\n\n for (const route of this.#options.loaded.routes) {\n const backend = this.#backendFor(route);\n const health = await backend.health();\n if (!health.healthy) continue;\n\n // If the backend enumerates its models, honour that: advertising a\n // model the server does not have would be advertising a lie.\n if (\n health.models.length > 0 &&\n !modelPresent(health.models, route.model)\n ) {\n continue;\n }\n\n capabilities.push({\n kind: route.kind,\n backendId: route.backendId,\n backendClass: route.backendClass,\n model: route.model,\n offerScope: route.offerScope,\n });\n }\n\n this.#capabilities = capabilities;\n return capabilities;\n }\n\n #backendFor(route: ResolvedRoute): Backend {\n const key = `${route.backendKey}:${route.backendId}`;\n let backend = this.#backends.get(key);\n if (!backend) {\n backend =\n this.#options.backendFactory?.(route) ??\n createBackend(route.backendId, {\n baseUrl: route.baseUrl,\n apiKeyEnv: route.apiKeyEnv,\n });\n this.#backends.set(key, backend);\n }\n return backend;\n }\n\n /**\n * Has this route spent the owner's daily ceiling on other people's work?\n *\n * Only meaningful for `metered` routes; `free` and `subscription` never\n * reach here in a way that matters, because the matcher refuses them for\n * other reasons first ({@link MUSTS.METERED_REQUIRES_CEILING}).\n */\n #spendCeilingReached(route: ResolvedRoute): boolean {\n if (route.cost !== \"metered\") return false;\n return this.#options.spend.hasReachedCeiling(\n route.backendKey,\n route.spendDailyCapCents,\n this.#now(),\n );\n }\n\n #routeFor(kind: string): ResolvedRoute | undefined {\n return this.#options.loaded.routes.find((route) => route.kind === kind);\n }\n\n /**\n * Decide whether this machine will run a claimed job.\n *\n * The server already applied its own version of the audience rules, and\n * that is not what this checks. This is the daemon enforcing against the\n * server: the local `named` allowlist\n * ({@link MUSTS.NAMED_LOCAL_ALLOWLIST}), the subscription self-lock, and\n * the owner's community budgets. A job that fails here is released with\n * reason `refused`, which the server remembers so it is never offered back.\n */\n admit(job: ClaimedStub): { ok: true } | { ok: false; reason: string } {\n const route = this.#routeFor(job.kind);\n if (!route) {\n // An unknown or unrouted kind is refused, never guessed\n // ({@link MUSTS.KIND_TYPED_ONLY}).\n return { ok: false, reason: REFUSAL_MESSAGES[\"no-capability\"] };\n }\n\n const match = matchAudience(\n {\n owner: job.owner,\n audience: job.audience,\n audienceAllow: job.audienceAllow,\n },\n {\n owner: this.#options.owner,\n offerScope: route.offerScope,\n cost: route.cost,\n spend: {\n acknowledged: route.spendAcknowledged,\n ceilingReached: this.#spendCeilingReached(route),\n },\n // The daemon's own list — the whole point of Rev 1 §B.\n locallyAllows: this.#options.allowlist.predicateFor(\n this.#options.client.origin,\n ),\n },\n );\n if (!match.ok) {\n return { ok: false, reason: REFUSAL_MESSAGES[match.refusal] };\n }\n\n if (job.owner !== this.#options.owner) {\n // From the stub's bucket, because admission happens before the payload\n // is fetched. The ceiling is charged rather than a midpoint: refusing\n // slightly too eagerly is the safe direction for someone else's work on\n // the owner's machine.\n const decision = this.#options.budgets.check(\n this.#now(),\n sizeClassCeiling(job.sizeClass),\n );\n if (!decision.ok) return { ok: false, reason: decision.detail };\n }\n\n return { ok: true };\n }\n\n /**\n * Execute one admitted job.\n *\n * Order is load-bearing: the ingress write is awaited *before* the backend\n * is touched ({@link MUSTS.INGRESS_LOGGED_BEFORE_EXECUTION}), so a job that\n * hangs the machine still leaves a record of what it was.\n */\n async runJob(job: ClaimedJob): Promise<JobOutcome> {\n const route = this.#routeFor(job.kind);\n if (!route) {\n return {\n outcome: \"error\",\n code: \"no-capability\",\n message: \"this machine has no route for that job kind\",\n retryable: false,\n };\n }\n\n const controller = new AbortController();\n this.#active.set(job.id, { controller, leaseId: job.lease.id });\n\n const prompt = composePrompt(job);\n const community = job.owner !== this.#options.owner;\n const limits = this.#options.loaded.config;\n\n await this.#options.ingress.recordPrompt({\n at: this.#now(),\n origin: this.#options.client.origin,\n jobId: job.id,\n kind: job.kind,\n audience: job.audience,\n owner: job.owner,\n backendId: route.backendId,\n backendClass: route.backendClass,\n model: route.model,\n prompt,\n });\n\n if (community) await this.#options.budgets.record(this.#now());\n\n try {\n const backend = this.#backendFor(route);\n const result = await backend.execute({\n prompt,\n model: route.model,\n // Community jobs run under the owner's tighter ceiling.\n timeoutMs: community\n ? Math.min(\n limits.community.maxWallClockMs,\n limits.limits.maxWallClockMs,\n )\n : limits.limits.maxWallClockMs,\n maxOutputBytes: community\n ? Math.min(\n limits.community.maxOutputBytes,\n limits.limits.maxOutputBytes,\n )\n : limits.limits.maxOutputBytes,\n signal: controller.signal,\n });\n\n const outcome: JobOutcome = result.ok\n ? { outcome: \"ok\", text: result.text }\n : result.code === \"canceled\"\n ? { outcome: \"canceled\" }\n : {\n outcome: \"error\",\n code: result.code,\n message: result.message,\n retryable: result.retryable,\n };\n\n await this.#options.ingress.recordOutcome({\n at: this.#now(),\n jobId: job.id,\n outcome: outcome.outcome,\n durationMs: result.durationMs,\n outputChars: result.ok ? result.text.length : 0,\n ...(result.ok ? {} : { detail: result.message }),\n });\n\n // Community work on a metered backend spends the owner's money, so it\n // goes on the ledger the ceiling is checked against. Own work is not\n // counted: their machine, their key, their call.\n if (community && route.cost === \"metered\") {\n await this.#options.spend.record(\n route.backendKey,\n estimateCents(\n prompt.length,\n result.ok ? result.text.length : 0,\n route.spendCentsPerMillionTokens,\n ),\n this.#now(),\n );\n }\n\n this.#completed += 1;\n this.#options.onEvent?.({\n type: \"finished\",\n jobId: job.id,\n outcome: outcome.outcome,\n durationMs: result.durationMs,\n });\n return outcome;\n } finally {\n this.#active.delete(job.id);\n }\n }\n\n /** Abort a job's in-flight backend call ({@link MUSTS.CANCEL_HONORED}). */\n cancelJob(jobId: string): void {\n this.#active.get(jobId)?.controller.abort();\n }\n\n /** Abort everything — revocation, or shutdown. */\n cancelAll(): void {\n for (const { controller } of this.#active.values()) controller.abort();\n }\n\n /**\n * Run until stopped.\n *\n * Resumable and idempotent by job id: a daemon that dies mid-job loses\n * nothing, because the server reclaims the lease and offers the job again.\n */\n async run(signal: AbortSignal): Promise<void> {\n const heartbeatMs = this.#options.heartbeatMs ?? DEFAULT_HEARTBEAT_MS;\n\n while (!signal.aborted && !this.#stopped) {\n try {\n await this.tick();\n this.#lastError = undefined;\n } catch (error) {\n this.#lastError =\n error instanceof Error ? error.message : \"unknown error\";\n this.#options.onEvent?.({\n type: \"error\",\n message: this.#lastError,\n });\n if (error instanceof ClientError && error.kind === \"revoked\") {\n this.#revoked = true;\n this.cancelAll();\n this.#options.onEvent?.({ type: \"revoked\" });\n return;\n }\n const backoff =\n error instanceof ClientError && error.retryAfter !== undefined\n ? error.retryAfter * 1000\n : heartbeatMs;\n await sleep(backoff, signal);\n continue;\n }\n // Jitter so a fleet of daemons does not synchronise into a thundering\n // herd against one server.\n await sleep(heartbeatMs * (0.85 + Math.random() * 0.3), signal);\n }\n }\n\n /** One heartbeat-and-claim cycle. Exposed so tests can step deterministically. */\n async tick(): Promise<void> {\n const capabilities = await this.detectCapabilities();\n\n const heartbeat = await this.#options.client.heartbeat({\n runnerId: this.#options.runnerId,\n daemonVersion: this.#options.daemonVersion,\n capabilities,\n activeLeases: [...this.#active.entries()].map(([jobId, held]) => ({\n jobId,\n leaseId: held.leaseId,\n })),\n paused: this.#paused,\n });\n this.#options.onEvent?.({\n type: \"heartbeat\",\n capabilities: capabilities.length,\n });\n\n if (heartbeat.revoked) {\n this.#revoked = true;\n this.cancelAll();\n this.#options.onEvent?.({ type: \"revoked\" });\n this.#stopped = true;\n return;\n }\n\n // A job the server says we lost must be abandoned, not finished\n // ({@link MUSTS.LEASE_HONORED}).\n for (const jobId of heartbeat.lost) this.cancelJob(jobId);\n for (const jobId of heartbeat.cancel) this.cancelJob(jobId);\n\n if (this.#paused || capabilities.length === 0) return;\n\n const free = this.#options.loaded.config.concurrency - this.#active.size;\n if (free <= 0) return;\n\n const { jobs } = await this.#options.client.claim({\n runnerId: this.#options.runnerId,\n capabilities,\n max: free,\n });\n\n // Not awaited: claimed jobs run concurrently up to the owner's limit, and\n // the loop keeps heartbeating so their leases stay alive.\n //\n // The `catch` is load-bearing. Without it, a failure in the background\n // handler — an ingress write that cannot land because the disk is full or\n // the state directory has gone — becomes an unhandled rejection and takes\n // the whole daemon down. The lease lapses instead and the server offers\n // the job again, which is the recovery the protocol is built around.\n for (const job of jobs) {\n void this.#handle(job).catch((error: unknown) => {\n this.#lastError =\n error instanceof Error ? error.message : \"unknown error\";\n this.#options.onEvent?.({ type: \"error\", message: this.#lastError });\n });\n }\n }\n\n async #handle(job: ClaimedStub): Promise<void> {\n this.#options.onEvent?.({\n type: \"claimed\",\n jobId: job.id,\n kind: job.kind,\n });\n\n const admission = this.admit(job);\n if (!admission.ok) {\n this.#refused += 1;\n await this.#options.ingress.recordOutcome({\n at: this.#now(),\n jobId: job.id,\n outcome: \"refused\",\n detail: admission.reason,\n });\n this.#options.onEvent?.({\n type: \"refused\",\n jobId: job.id,\n reason: admission.reason,\n });\n await this.#safely(() =>\n this.#options.client.release({\n runnerId: this.#options.runnerId,\n leases: [{ jobId: job.id, leaseId: job.lease.id }],\n reason: \"refused\",\n }),\n );\n return;\n }\n\n // Only now, after this daemon has decided it will run the work, does the\n // payload arrive (byollm_009 §6). A daemon that declines on its own\n // allowlist never receives the prompt at all — which was not true when\n // the payload rode along with the claim.\n const fetched = await this.#fetchWhenSealed(job);\n if (!fetched) return;\n const payload = await this.#openPayload(job, fetched.envelope);\n\n const route = this.#routeFor(job.kind);\n const outcome = await this.runJob({ ...job, payload });\n\n const envelope = await this.#sealOutcome(job, outcome);\n\n await this.#safely(() =>\n this.#options.client.result({\n runnerId: this.#options.runnerId,\n jobId: job.id,\n envelope,\n disposition: outcome.outcome,\n model: route?.model ?? \"unknown\",\n backendClass: route?.backendClass ?? \"http\",\n durationMs: 0,\n }),\n );\n }\n\n /**\n * Seal a finished outcome back to the site that sent the work.\n *\n * The return leg of {@link ByollmRunner.#openPayload}, and it exists for the\n * same reason: an answer is as sensitive as the prompt that produced it. A\n * relay that is denied one and handed the other has been denied nothing.\n *\n * The signature also does work the payload leg does not need. `RESULT_\n * PROVENANCE` says a result is attributable to a device; until now that\n * rested on the request signature, which covers the request and expires with\n * it. This binds the *outcome itself* to the device's key, so what the app\n * eventually reads carries its own proof of who produced it.\n */\n async #sealOutcome(\n job: ClaimedStub,\n outcome: JobOutcome,\n ): Promise<SealedEnvelope> {\n const identity = this.#options.identity;\n if (!identity) {\n // Unreachable in practice, and the reason is load-bearing: `#openPayload`\n // makes the same check before any work runs, so a keyless daemon fails\n // there — having spent nothing — rather than here, having spent a whole\n // job and lost the answer. Anything that moves the fetch after execution\n // turns this branch into wasted compute.\n throw new Error(\"this daemon has no keys, so it cannot seal a result\");\n }\n const keys = await identity.keys();\n return seal({\n plaintext: JSON.stringify(outcome),\n senderKeys: keys,\n recipientEncryptionPublic: identity.sitePinned.encryption,\n context: {\n jobId: job.id,\n senderKeyId: keyId(publicIdentityOf(keys).identity),\n recipientKeyId: keyId(identity.sitePinned.identity),\n deadlineAt: Date.now() + ENVELOPE_MAX_AGE_MS,\n direction: \"result\",\n },\n });\n }\n\n /**\n * Collect the payload, waiting if the upstream does not have it yet.\n *\n * On the direct plane this always succeeds first time: the site *is* the\n * upstream, so it seals when asked. Through a relay the two are different\n * parties — the site must be told which device claimed before it can seal to\n * it — and `not-ready` is a normal answer for as long as that takes.\n *\n * Discovered by the skeleton relay, which is the reason it exists: the\n * original claim-then-fetch had no wait here, so the first relayed job was\n * claimed, refused with a 409 the daemon treated as a rejection, and\n * abandoned while still holding a perfectly good lease.\n *\n * Bounded, and by the lease rather than by a retry count: waiting past our\n * own lease means racing whoever gets the job next. Returning `null` gives\n * the job up quietly — the upstream's `awaiting-payload` timer will requeue\n * it, and the stub was never lost.\n */\n async #fetchWhenSealed(\n job: ClaimedStub,\n ): Promise<{ envelope: SealedEnvelope } | null> {\n const deadline = Math.min(job.lease.expiresAt, this.#now() + 30_000);\n let delay = 50;\n for (;;) {\n try {\n return await this.#options.client.fetch({\n runnerId: this.#options.runnerId,\n jobId: job.id,\n leaseId: job.lease.id,\n });\n } catch (error) {\n const notReady =\n error instanceof ClientError && error.kind === \"not-ready\";\n if (!notReady) throw error;\n if (this.#now() + delay >= deadline) {\n this.#options.onEvent?.({\n type: \"error\",\n message: `gave up waiting for the payload of ${job.id}`,\n });\n return null;\n }\n await new Promise((resolve) => setTimeout(resolve, delay));\n // Backs off, but stays responsive: a site that is merely slow should\n // not cost the whole lease, and one that is gone is not worth polling.\n delay = Math.min(delay * 2, 1_000);\n }\n }\n }\n\n /**\n * Open work sealed to this machine, or refuse to run it.\n *\n * A failure here is not a job failure to be reported — it is a claim that\n * the work came from the pinned site, which did not hold. Running it anyway\n * would be running whatever an intermediary supplied, on the owner's\n * hardware and their subscription.\n */\n async #openPayload(\n job: ClaimedStub,\n envelope: SealedEnvelope,\n ): Promise<JobPayload> {\n const identity = this.#options.identity;\n if (!identity) {\n throw new Error(\n \"this daemon has no keys, so it cannot open work sealed to it\",\n );\n }\n const keys = await identity.keys();\n const opened = await open({\n envelope,\n recipientKeys: keys,\n senderIdentityPublic: identity.sitePinned.identity,\n expected: {\n jobId: job.id,\n senderKeyId: keyId(identity.sitePinned.identity),\n recipientKeyId: keyId(publicIdentityOf(keys).identity),\n direction: \"payload\",\n },\n });\n if (!opened.ok) {\n throw new Error(\n `refusing job ${job.id}: its payload did not verify as coming from ` +\n `the app this machine paired with (${opened.reason})`,\n );\n }\n return JSON.parse(opened.plaintext) as JobPayload;\n }\n\n /**\n * Report-and-forget.\n *\n * A failed *report* must not crash the loop or re-run the job: the lease\n * will lapse and the server will offer the work again, which is exactly the\n * recovery the protocol is built around.\n */\n async #safely(action: () => Promise<unknown>): Promise<void> {\n try {\n await action();\n } catch (error) {\n this.#lastError =\n error instanceof Error ? error.message : \"unknown error\";\n }\n }\n\n /** Release everything on shutdown, so nothing waits for a lease to lapse. */\n async shutdown(reason: \"shutdown\" | \"pause\"): Promise<void> {\n this.#stopped = true;\n const leases = [...this.#active.entries()].map(([jobId, held]) => ({\n jobId,\n leaseId: held.leaseId,\n }));\n this.cancelAll();\n if (leases.length === 0) return;\n await this.#safely(() =>\n this.#options.client.release({\n runnerId: this.#options.runnerId,\n leases,\n reason,\n }),\n );\n }\n}\n\n/** Case-insensitive model match that tolerates Ollama's `:latest` suffix. */\nfunction modelPresent(models: readonly string[], wanted: string): boolean {\n const target = wanted.toLowerCase();\n return models.some((model) => {\n const id = model.toLowerCase();\n return (\n id === target || id === `${target}:latest` || `${id}:latest` === target\n );\n });\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal.addEventListener(\n \"abort\",\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n });\n}\n","import {\n BACKEND_IDS,\n backendDescriptor,\n type BackendId,\n} from \"@byollm/protocol\";\nimport { ClaudeCliBackend } from \"./claude-cli.js\";\nimport { OpenAiHttpBackend } from \"./openai-http.js\";\nimport type { Backend, BackendInit } from \"./types.js\";\n\n/**\n * Construct a backend instance.\n *\n * The switch is exhaustive over {@link BackendId}, so adding a backend to the\n * protocol registry without implementing it here is a compile error rather\n * than a runtime surprise — and adding one without adversarial rows fails the\n * suite's coverage check.\n */\nexport function createBackend(id: BackendId, init: BackendInit): Backend {\n // Providers are registry entries, not implementations (byollm_007 §3):\n // every HTTP-class id speaks OpenAI-compatible /v1/chat/completions, so they\n // all share one transport and one adversarial corpus. Adding a provider is a\n // line in the registry, not a new class to review.\n if (backendDescriptor(id).class === \"process\") {\n return new ClaudeCliBackend();\n }\n return new OpenAiHttpBackend(init);\n}\n\n/** Every backend the daemon can construct. */\nexport const IMPLEMENTED_BACKEND_IDS: readonly BackendId[] = BACKEND_IDS;\n\nexport { ClaudeCliBackend, childEnv, claudeArgv } from \"./claude-cli.js\";\nexport { OpenAiHttpBackend } from \"./openai-http.js\";\nexport type {\n Backend,\n BackendErrorCode,\n BackendHealth,\n BackendInit,\n BackendRequest,\n BackendResult,\n} from \"./types.js\";\n","import { execFile, spawn } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { delimiter, join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport type { BackendClass, BackendId } from \"@byollm/protocol\";\nimport type {\n Backend,\n BackendHealth,\n BackendRequest,\n BackendResult,\n} from \"./types.js\";\n\n/**\n * The exact argv this backend ever runs, minus the model.\n *\n * A frozen literal, not a builder, so there is no code path that appends to\n * it and no mechanism to pass job-supplied arguments\n * ({@link MUSTS.NO_SHELL_INTERPOLATION}). The adversarial suite asserts that\n * every hostile payload it throws produces exactly this argv.\n *\n * - `--print` — non-interactive, answer and exit.\n * - `--output-format text` — plain text, no envelope to misparse.\n * - `--tools \"\"` — the CLI's own switch for *disabling every built-in tool*.\n * byollm_004 §2 requires the model have no tools; this is the flag that\n * delivers it. Verified against the shipped CLI, not assumed.\n * - `--strict-mcp-config` with an empty `--mcp-config` — no MCP servers, and\n * none inherited from the user's own settings.\n * - `--no-session-persistence` — a job leaves no session behind.\n */\nconst FIXED_ARGV = Object.freeze([\n \"--print\",\n \"--output-format\",\n \"text\",\n \"--tools\",\n \"\",\n \"--strict-mcp-config\",\n \"--mcp-config\",\n '{\"mcpServers\":{}}',\n \"--no-session-persistence\",\n]);\n\n/**\n * Environment variables a `claude` child is allowed to see.\n *\n * Everything else is dropped, so a prompt that says \"read your environment\"\n * finds nothing worth having ({@link MUSTS.STRIPPED_CHILD_ENV}).\n *\n * `HOME` is present and that is a deliberate, documented compromise: the CLI\n * reads its subscription credentials from the user's own config directory, so\n * removing `HOME` would remove the authentication this backend exists to use.\n * The honest statement is in `docs/security.md` — the child can reach the\n * filesystem the user can reach, and what stops it doing anything with that\n * is having no tools, not the environment.\n *\n * `ANTHROPIC_API_KEY` is deliberately **absent**: byollm_002 requires that\n * billing cannot silently move from the subscription to a metered key.\n */\nconst ENV_ALLOWLIST = Object.freeze([\n \"PATH\",\n \"HOME\",\n \"LANG\",\n \"LC_ALL\",\n \"TZ\",\n \"TMPDIR\",\n]);\n\n/**\n * The Windows half of the same compromise `HOME` documents above.\n *\n * The CLI stores its subscription credentials under the user's profile, which\n * on Windows is named by `USERPROFILE` / `APPDATA` rather than `HOME`. Without\n * them the child starts and then cannot authenticate — the backend reports\n * healthy and every job fails, which is a worse failure than not starting.\n *\n * `SystemRoot` and `windir` are here because Windows resolves core DLLs\n * (including the socket stack) through them; a child without them fails in\n * ways that look nothing like a missing variable. `TEMP`/`TMP` are the\n * platform's `TMPDIR`, and `PATHEXT` is how Windows resolves an extensionless\n * command name at all.\n *\n * This widens the allowlist on Windows only. The rule byollm_004 §2 states —\n * the child sees an allowlist, never the daemon's environment — is unchanged.\n */\nconst WINDOWS_ENV_ALLOWLIST = Object.freeze([\n \"USERPROFILE\",\n \"APPDATA\",\n \"LOCALAPPDATA\",\n \"TEMP\",\n \"TMP\",\n \"SystemRoot\",\n \"windir\",\n \"PATHEXT\",\n]);\n\n/** Build the child's environment from the allowlist. */\nexport function childEnv(\n source: NodeJS.ProcessEnv = process.env,\n platform: NodeJS.Platform = process.platform,\n): Record<string, string> {\n const allowed =\n platform === \"win32\"\n ? [...ENV_ALLOWLIST, ...WINDOWS_ENV_ALLOWLIST]\n : ENV_ALLOWLIST;\n\n const env: Record<string, string> = {};\n for (const name of allowed) {\n const value = source[name];\n if (value !== undefined) env[name] = value;\n }\n // Signals to the CLI that it is not attached to a terminal, so it never\n // tries to render interactive UI into a pipe.\n env[\"CI\"] = \"1\";\n return env;\n}\n\n/** The argv this backend would run for a given model. Exported for the suite. */\nexport function claudeArgv(model: string): readonly string[] {\n return Object.freeze([...FIXED_ARGV, \"--model\", model]);\n}\n\n/** What to actually execute, and anything that must precede the CLI's own argv. */\nexport interface ClaudeLaunch {\n readonly command: string;\n readonly prefixArgs: readonly string[];\n}\n\n/**\n * Where the `claude` entry point really is on Windows.\n *\n * npm installs `claude` as `claude.cmd` and `claude.ps1` — there is no `.exe`.\n * Node refuses to spawn a `.cmd` without a shell (hardened after\n * CVE-2024-27980), so `spawn(\"claude\")` fails with ENOENT and this backend can\n * never report healthy on Windows.\n *\n * `shell: true` would fix the symptom and breach\n * {@link MUSTS.NO_SHELL_INTERPOLATION}, so it is not on the table. Instead we\n * find the JavaScript the shim would have run and run it under the Node binary\n * already executing this daemon: no shell, and the CLI's own argv is still the\n * frozen literal above, passed through untouched.\n */\nfunction findWindowsEntry(\n binary: string,\n source: NodeJS.ProcessEnv,\n): string | null {\n const dirs = (source[\"PATH\"] ?? \"\").split(delimiter).filter(Boolean);\n\n for (const dir of dirs) {\n // The npm global layout: the shim sits beside the package it launches.\n const direct = join(\n dir,\n \"node_modules\",\n \"@anthropic-ai\",\n \"claude-code\",\n \"cli.js\",\n );\n if (existsSync(direct)) return direct;\n\n // Otherwise read the shim, which names its target script. Cheap, and it\n // survives layouts we have not seen — pnpm and Volta both differ from npm.\n const shim = join(dir, `${binary}.cmd`);\n if (!existsSync(shim)) continue;\n try {\n const match = /\"?([A-Za-z]:\\\\[^\"\\r\\n]*?\\.js|%~dp0[^\"\\r\\n]*?\\.js)\"?/.exec(\n readFileSync(shim, \"utf8\"),\n );\n if (!match?.[1]) continue;\n const target = match[1].replace(/%~dp0\\\\?/i, `${dir}\\\\`);\n if (existsSync(target)) return target;\n } catch {\n // An unreadable shim is not an error worth failing over; try the next\n // directory and let health() report the honest \"not installed\".\n }\n }\n return null;\n}\n\n/**\n * Resolve what to spawn for the CLI on this platform.\n *\n * Everywhere but Windows this is the identity: the binary name, no prefix. The\n * caller's argv is unchanged on every platform, which is what keeps the\n * adversarial suite's argv assertions meaningful.\n */\nconst launchCache = new Map<string, ClaudeLaunch>();\n\n/** Drop the memo, for tests that change PATH between calls. */\nexport function resetClaudeLaunchCache(): void {\n launchCache.clear();\n}\n\nexport function resolveClaudeLaunch(\n binary = \"claude\",\n platform: NodeJS.Platform = process.platform,\n source: NodeJS.ProcessEnv = process.env,\n): ClaudeLaunch {\n // Memoized because this runs on every `health()` and every `execute()`, and\n // on Windows walks each PATH entry with two `existsSync` calls. At the\n // default concurrency that is a synchronous filesystem crawl on the job\n // dispatch path, blocking the event loop while other jobs are in flight.\n //\n // Safe to cache: the answer is a function of the binary name, the platform\n // and PATH, none of which change meaningfully inside one daemon process. A\n // CLI installed while the daemon runs is picked up on restart — the same\n // thing already true of config.\n const key = `${platform}\\u0000${binary}\\u0000${source[\"PATH\"] ?? \"\"}`;\n const cached = launchCache.get(key);\n if (cached) return cached;\n const resolved = resolveUncached(binary, platform, source);\n launchCache.set(key, resolved);\n return resolved;\n}\n\nfunction resolveUncached(\n binary: string,\n platform: NodeJS.Platform,\n source: NodeJS.ProcessEnv,\n): ClaudeLaunch {\n if (platform !== \"win32\") return { command: binary, prefixArgs: [] };\n\n // A JavaScript entry point runs under this Node, wherever it came from. On\n // Unix a `#!/usr/bin/env node` script is executable and spawns directly;\n // Windows has no shebang, so the same file has to be handed to Node\n // explicitly. The adversarial suite's probe is exactly such a script, which\n // is why that suite could not run on Windows at all.\n if (/\\.[cm]?js$/i.test(binary)) {\n return { command: process.execPath, prefixArgs: [binary] };\n }\n\n // A real executable needs no help.\n if (/[\\\\/]/.test(binary) || /\\.(exe|com|bat|cmd)$/i.test(binary)) {\n return { command: binary, prefixArgs: [] };\n }\n\n const entry = findWindowsEntry(binary, source);\n return entry === null\n ? { command: binary, prefixArgs: [] }\n : { command: process.execPath, prefixArgs: [entry] };\n}\n\n/**\n * The process-class backend: the user's own `claude` CLI, on their own\n * subscription.\n *\n * Subscription-class, so its offer scope is locked to `self`\n * ({@link MUSTS.SUBSCRIPTION_SELF_LOCK}) — one account runs one person's work.\n *\n * Every requirement of byollm_004 §2 applies here and is implemented here:\n * fixed argv, prompt on stdin, stripped environment, empty scratch `cwd`, no\n * inherited descriptors beyond the three std streams, hard timeout, hard\n * output cap.\n */\nexport class ClaudeCliBackend implements Backend {\n readonly id: BackendId = \"claude-cli\";\n readonly class: BackendClass = \"process\";\n readonly #binary: string;\n\n /**\n * @param binary - which executable to run. Defaults to `claude` and is\n * **not reachable from configuration**: {@link createBackend} constructs\n * this with no arguments, and {@link BackendInit} has no field for it. It\n * exists so the adversarial suite can substitute a probe that reports the\n * argv, environment, cwd and stdin it actually received — which is the only\n * way to *prove* byollm_004 §2 rather than assert it.\n */\n constructor(binary = \"claude\") {\n this.#binary = binary;\n }\n\n async health(): Promise<BackendHealth> {\n const version = await new Promise<string | null>((resolve) => {\n // execFile, never exec: no shell is involved even for our own fixed\n // arguments (the eslint rule bans the shell-invoking variants outright).\n const launch = resolveClaudeLaunch(this.#binary);\n execFile(\n launch.command,\n [...launch.prefixArgs, \"--version\"],\n { timeout: 10_000, env: childEnv() },\n (error, stdout) => {\n resolve(error ? null : stdout.trim());\n },\n );\n });\n\n if (version === null) {\n return {\n healthy: false,\n models: [],\n detail:\n \"the `claude` CLI is not installed or not on PATH \" +\n \"(https://claude.com/claude-code)\",\n };\n }\n // The CLI does not enumerate models, and inventing a list would breach\n // \"never advertise what isn't real\". The configured model is the claim,\n // and a wrong one surfaces as `model-not-found` on first use.\n return { healthy: true, models: [] };\n }\n\n async execute(request: BackendRequest): Promise<BackendResult> {\n const started = Date.now();\n // An empty directory of our own making. The child's `cwd` is never the\n // daemon's, never the user's home, and never anything a payload named.\n const scratch = await mkdtemp(join(tmpdir(), \"byollm-job-\"));\n\n try {\n return await this.#spawn(request, scratch, started);\n } finally {\n await rm(scratch, { recursive: true, force: true });\n }\n }\n\n async #spawn(\n request: BackendRequest,\n scratch: string,\n started: number,\n ): Promise<BackendResult> {\n return new Promise<BackendResult>((resolve) => {\n // Check before spawning, not only via the listener below: a job\n // cancelled between the claim and this line arrives with its signal\n // already aborted, and `addEventListener(\"abort\")` never fires for a\n // signal that has already fired. Without this the child would spawn and\n // run to completion after the owner had already said stop.\n if (request.signal.aborted) {\n resolve({\n ok: false,\n code: \"canceled\",\n message: \"the job was canceled before it started\",\n retryable: false,\n durationMs: Date.now() - started,\n });\n return;\n }\n\n // The CLI's own argv is `claudeArgv(model)` on every platform. On Windows\n // `prefixArgs` carries the path to the script Node is being asked to run,\n // which is an argument to Node and not to the model's command line.\n const launch = resolveClaudeLaunch(this.#binary);\n const child = spawn(\n launch.command,\n [...launch.prefixArgs, ...claudeArgv(request.model)],\n {\n cwd: scratch,\n env: childEnv(),\n // Exactly the three std streams. Nothing else is inherited, so the\n // child cannot reach a descriptor the daemon happens to hold open.\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n // No shell, ever. With `shell: false` the argv array is passed to\n // execvp verbatim and metacharacters in it are just bytes.\n shell: false,\n detached: false,\n },\n );\n\n let stdout = \"\";\n let stderr = \"\";\n let outputBytes = 0;\n let settled = false;\n let exited = false;\n let reason: \"timeout\" | \"canceled\" | \"output-too-large\" | null = null;\n\n const finish = (result: BackendResult): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n request.signal.removeEventListener(\"abort\", onAbort);\n resolve(result);\n };\n\n const kill = (why: typeof reason): void => {\n reason = why;\n // SIGTERM first, SIGKILL shortly after: a wedged child must not be\n // able to outlive its budget by ignoring the polite signal.\n //\n // The escalation is gated on `exited`, which we set from the `close`\n // event, and NOT on `child.killed` — that flag means \"a signal was\n // sent\", not \"the process died\", so gating on it would mean the\n // SIGKILL never fires against exactly the child that ignores SIGTERM.\n child.kill(\"SIGTERM\");\n setTimeout(() => {\n if (!exited) child.kill(\"SIGKILL\");\n }, 2_000).unref();\n };\n\n const timer = setTimeout(() => {\n kill(\"timeout\");\n }, request.timeoutMs);\n\n const onAbort = (): void => {\n kill(\"canceled\");\n };\n request.signal.addEventListener(\"abort\", onAbort, { once: true });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n outputBytes += chunk.byteLength;\n if (outputBytes > request.maxOutputBytes) {\n kill(\"output-too-large\");\n return;\n }\n stdout += chunk.toString(\"utf8\");\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n // Bounded independently: a chatty stderr must not exhaust memory\n // either, and it is only ever used for a diagnostic message.\n if (stderr.length < 8_192) stderr += chunk.toString(\"utf8\");\n });\n\n child.on(\"error\", (error: Error) => {\n finish({\n ok: false,\n code: \"backend-unreachable\",\n message: `could not start the claude CLI: ${error.message}`,\n retryable: false,\n durationMs: Date.now() - started,\n });\n });\n\n child.on(\"close\", (code) => {\n exited = true;\n const durationMs = Date.now() - started;\n\n if (reason === \"canceled\") {\n finish({\n ok: false,\n code: \"canceled\",\n message: \"the job was canceled\",\n retryable: false,\n durationMs,\n });\n return;\n }\n if (reason === \"timeout\") {\n finish({\n ok: false,\n code: \"timeout\",\n message: `the model did not answer within ${String(request.timeoutMs)}ms`,\n retryable: true,\n durationMs,\n });\n return;\n }\n if (reason === \"output-too-large\") {\n finish({\n ok: false,\n code: \"output-too-large\",\n message: `the model produced more than ${String(request.maxOutputBytes)} bytes`,\n retryable: false,\n durationMs,\n });\n return;\n }\n if (code !== 0) {\n finish({\n ok: false,\n code: \"backend-error\",\n message:\n stderr.trim() === \"\"\n ? `the claude CLI exited with status ${String(code)}`\n : `the claude CLI failed: ${firstLine(stderr)}`,\n retryable: false,\n durationMs,\n });\n return;\n }\n finish({ ok: true, text: stdout, durationMs });\n });\n\n // The prompt goes here and nowhere else: on stdin, as bytes, after the\n // argv is already fixed. This is the line byollm_004 §2 is about.\n child.stdin.on(\"error\", () => {\n // A child that died before reading stdin surfaces through `close`.\n });\n child.stdin.end(request.prompt, \"utf8\");\n });\n }\n}\n\n/** First line of stderr, for a one-line diagnostic. */\nfunction firstLine(text: string): string {\n return text.trim().split(\"\\n\")[0] ?? \"\";\n}\n","import type { BackendClass, BackendId } from \"@byollm/protocol\";\nimport { checkBaseUrl } from \"../ssrf.js\";\nimport type {\n Backend,\n BackendHealth,\n BackendInit,\n BackendRequest,\n BackendResult,\n} from \"./types.js\";\n\n/**\n * The HTTP-class backend: any server speaking OpenAI-compatible\n * `/v1/chat/completions`.\n *\n * One implementation covers Ollama, `mlx_lm.server`, llama.cpp server and\n * vLLM (byollm_001 Rev 1 §A) — the collapse that puts MLX inference in v1.\n *\n * **Why this is the safest class.** It spawns nothing, so byollm_004 §2's\n * argv, stdin, environment and sandbox requirements do not apply *by\n * construction* rather than by discipline. The prompt travels as a JSON\n * string in a request body; there is no command line for it to escape into\n * because there is no command line.\n *\n * What remains is the destination, and that is nailed down: the base URL\n * comes from owner config, is validated once at load and again here, and\n * redirects are refused so a permitted URL cannot become a forbidden one in\n * flight ({@link MUSTS.HTTP_BASE_URL_SAFE}).\n */\nexport class OpenAiHttpBackend implements Backend {\n readonly id: BackendId = \"openai-http\";\n readonly class: BackendClass = \"http\";\n readonly #baseUrl: URL;\n readonly #apiKeyEnv: string | undefined;\n\n constructor(init: BackendInit) {\n if (init.baseUrl === undefined) {\n throw new Error(\"openai-http backend requires a baseUrl\");\n }\n const check = checkBaseUrl(init.baseUrl);\n if (!check.ok) {\n throw new Error(`refusing base URL: ${check.detail}`);\n }\n this.#baseUrl = check.url;\n this.#apiKeyEnv = init.apiKeyEnv;\n }\n\n /**\n * Build a URL under the configured base.\n *\n * The path is a hardcoded literal from this file — never anything derived\n * from a job — and the result is re-checked against the base's origin so a\n * surprising `baseUrl` (say, one with a `..` path) cannot walk elsewhere.\n */\n #endpoint(path: \"chat/completions\" | \"models\"): URL {\n const base = this.#baseUrl.href.endsWith(\"/\")\n ? this.#baseUrl.href\n : `${this.#baseUrl.href}/`;\n const url = new URL(path, base);\n if (url.origin !== this.#baseUrl.origin) {\n throw new Error(\"computed endpoint left the configured origin\");\n }\n return url;\n }\n\n #headers(): Record<string, string> {\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n };\n if (this.#apiKeyEnv !== undefined) {\n const key = process.env[this.#apiKeyEnv];\n if (key !== undefined && key !== \"\") {\n headers[\"authorization\"] = `Bearer ${key}`;\n }\n }\n return headers;\n }\n\n async health(): Promise<BackendHealth> {\n try {\n const response = await fetch(this.#endpoint(\"models\"), {\n method: \"GET\",\n headers: this.#headers(),\n redirect: \"error\",\n signal: AbortSignal.timeout(5_000),\n });\n if (!response.ok) {\n return {\n healthy: false,\n models: [],\n detail: `model list returned HTTP ${String(response.status)}`,\n };\n }\n const body: unknown = await response.json();\n return { healthy: true, models: extractModelIds(body) };\n } catch (error) {\n return {\n healthy: false,\n models: [],\n detail: describeFetchError(error, this.#baseUrl.origin),\n };\n }\n }\n\n async execute(request: BackendRequest): Promise<BackendResult> {\n const started = Date.now();\n // One timeout governs the call whether it stalls before or during the\n // response body — a server that accepts and then dribbles forever must\n // not be able to wedge the machine.\n const timeout = AbortSignal.timeout(request.timeoutMs);\n const signal = AbortSignal.any([request.signal, timeout]);\n\n try {\n const response = await fetch(this.#endpoint(\"chat/completions\"), {\n method: \"POST\",\n headers: this.#headers(),\n // The payload is a JSON string field. Nothing about it is parsed as\n // configuration, and `model` comes from owner config.\n body: JSON.stringify({\n model: request.model,\n messages: [{ role: \"user\", content: request.prompt }],\n stream: false,\n }),\n redirect: \"error\",\n signal,\n });\n\n if (response.status === 401 || response.status === 403) {\n return this.#fail(\n \"unauthorized\",\n \"the model server rejected our credentials\",\n false,\n started,\n );\n }\n if (response.status === 404) {\n return this.#fail(\n \"model-not-found\",\n `the model server does not know \"${request.model}\"`,\n false,\n started,\n );\n }\n if (!response.ok) {\n return this.#fail(\n \"backend-error\",\n `the model server returned HTTP ${String(response.status)}`,\n response.status >= 500,\n started,\n );\n }\n\n const text = await readCapped(response, request.maxOutputBytes, signal);\n if (text === null) {\n // A hostile or broken local model producing unbounded output must not\n // be able to exhaust memory — byollm_004 §5's zip-bomb row.\n return this.#fail(\n \"output-too-large\",\n `the model produced more than ${String(request.maxOutputBytes)} bytes`,\n false,\n started,\n );\n }\n\n const content = extractContent(text);\n if (content === null) {\n return this.#fail(\n \"backend-error\",\n \"the model server's response was not in OpenAI chat-completion shape\",\n false,\n started,\n );\n }\n return { ok: true, text: content, durationMs: Date.now() - started };\n } catch (error) {\n if (request.signal.aborted) {\n return this.#fail(\"canceled\", \"the job was canceled\", false, started);\n }\n if (isAbort(error)) {\n return this.#fail(\n \"timeout\",\n `the model did not answer within ${String(request.timeoutMs)}ms`,\n true,\n started,\n );\n }\n return this.#fail(\n \"backend-unreachable\",\n describeFetchError(error, this.#baseUrl.origin),\n true,\n started,\n );\n }\n }\n\n #fail(\n code: Exclude<BackendResult & { ok: false }, never>[\"code\"],\n message: string,\n retryable: boolean,\n started: number,\n ): BackendResult {\n return {\n ok: false,\n code,\n message,\n retryable,\n durationMs: Date.now() - started,\n };\n }\n}\n\n/**\n * Read a response body, refusing to buffer past `maxBytes`.\n *\n * `response.text()` would happily allocate whatever the server sends. Reading\n * the stream and stopping at the cap is what makes the ceiling real.\n *\n * @returns the text, or null if the cap was exceeded.\n */\nasync function readCapped(\n response: Response,\n maxBytes: number,\n signal: AbortSignal,\n): Promise<string | null> {\n const body = response.body;\n if (body === null) return \"\";\n\n // `getReader()` is typed as `any` chunks under this lib target; the stream\n // is bytes, and saying so is what lets the cap arithmetic below be checked.\n const reader = (body as ReadableStream<Uint8Array>).getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n for (;;) {\n signal.throwIfAborted();\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel();\n return null;\n }\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n return new TextDecoder().decode(concat(chunks, total));\n}\n\nfunction concat(chunks: readonly Uint8Array[], total: number): Uint8Array {\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return out;\n}\n\n/** Pull the assistant text out of an OpenAI chat-completion response. */\nfunction extractContent(raw: string): string | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const choices = (parsed as { choices?: unknown }).choices;\n if (!Array.isArray(choices) || choices.length === 0) return null;\n const message = (choices[0] as { message?: unknown }).message;\n if (typeof message !== \"object\" || message === null) return null;\n const content = (message as { content?: unknown }).content;\n return typeof content === \"string\" ? content : null;\n}\n\n/** Model ids from an OpenAI `/v1/models` response. */\nfunction extractModelIds(body: unknown): string[] {\n if (typeof body !== \"object\" || body === null) return [];\n const data = (body as { data?: unknown }).data;\n if (!Array.isArray(data)) return [];\n return data\n .map((entry) =>\n typeof entry === \"object\" && entry !== null\n ? (entry as { id?: unknown }).id\n : undefined,\n )\n .filter((id): id is string => typeof id === \"string\");\n}\n\nfunction isAbort(error: unknown): boolean {\n return (\n error instanceof Error &&\n (error.name === \"AbortError\" || error.name === \"TimeoutError\")\n );\n}\n\n/**\n * A reachability failure the owner can act on.\n *\n * Deliberately names the origin and not the underlying error text, which for\n * `fetch` is often a bare \"fetch failed\" that tells nobody anything.\n */\nfunction describeFetchError(error: unknown, origin: string): string {\n const cause =\n error instanceof Error && \"cause\" in error && error.cause instanceof Error\n ? error.cause.message\n : error instanceof Error\n ? error.message\n : \"unknown error\";\n return `could not reach the model server at ${origin} (${cause})`;\n}\n","import type { ClaimedJob } from \"@byollm/protocol\";\n\n/**\n * Reduce a job's payload to the single string a backend receives.\n *\n * This is the narrowest point in the daemon: everything upstream deals in a\n * job, everything downstream deals in text and an owner-chosen model. By\n * construction there is nothing left for a payload to influence.\n *\n * **On `system`.** byollm_004 §2 forbids payload text on a command line, and\n * the `claude` CLI's only system-prompt input is the argv flag\n * `--system-prompt` — so a payload's `system` can never be passed that way.\n * It is folded into the stdin text instead, under a plain delimiter. That\n * costs a little role fidelity on process-class backends and is documented\n * rather than papered over; HTTP-class backends could carry the role natively\n * but use the same composition so a job produces identical text on either\n * class, which is what makes results comparable across runners.\n */\nexport function composePrompt(job: ClaimedJob): string {\n if (job.kind === \"llm.generate\") {\n const payload = job.payload as { prompt: string; system?: string };\n return joinSections([systemSection(payload.system), payload.prompt]);\n }\n\n const payload = job.payload as {\n messages: { role: string; content: string }[];\n system?: string;\n };\n const turns = payload.messages\n .map((message) => `${roleLabel(message.role)}: ${message.content}`)\n .join(\"\\n\\n\");\n return joinSections([systemSection(payload.system), turns]);\n}\n\nfunction systemSection(system: string | undefined): string | undefined {\n if (system === undefined || system.trim() === \"\") return undefined;\n return `System instructions:\\n${system}`;\n}\n\nfunction roleLabel(role: string): string {\n switch (role) {\n case \"assistant\":\n return \"Assistant\";\n case \"system\":\n return \"System\";\n default:\n return \"User\";\n }\n}\n\nfunction joinSections(sections: readonly (string | undefined)[]): string {\n return sections.filter((section) => section !== undefined).join(\"\\n\\n\");\n}\n"],"mappings":"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","names":["PROTOCOL_VERSION","mkdir","readFile","rm","stat","writeFile","dirname","backendDescriptor","resolveCost","mkdir","readFile","writeFile","dirname","z","readFile","z","z","readFile","sleep","mkdir","readFile","writeFile","dirname","z","fingerprint","mkdir","readFile","writeFile","dirname","isNotFound","mkdir","readFile","writeFile","dirname","z","z","readFile","mkdir","dirname","writeFile","mkdir","readFile","writeFile","dirname","z","publicIdentityOf","backendDescriptor","join","platform","platform","join","backendDescriptor","payload","publicIdentityOf","fingerprint","firstLine","mkdir","writeFile","rm","stat","raw","parsed","readFile","backendDescriptor","resolveCost","dirname","PROTOCOL_VERSION"]}
package/dist/index.d.ts CHANGED
@@ -1118,7 +1118,7 @@ declare const BASE_URL_REFUSAL_MESSAGES: Readonly<Record<BaseUrlRefusal, string>
1118
1118
  * define: an app's runner list shows this string, so a stale one is a lie
1119
1119
  * told to every user, and a literal that a test pins cannot drift quietly.
1120
1120
  */
1121
- declare const DAEMON_VERSION = "0.1.0-alpha.7";
1121
+ declare const DAEMON_VERSION = "0.1.0-alpha.8";
1122
1122
  /**
1123
1123
  * Everything needed to reason about one daemon — byollm_010 §5.
1124
1124
  *
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  resolveConfig,
35
35
  runCli,
36
36
  stripControlChars
37
- } from "./chunk-3E2PGDHL.js";
37
+ } from "./chunk-NEV4JDQE.js";
38
38
  export {
39
39
  Allowlist,
40
40
  BASE_URL_REFUSAL_MESSAGES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "byollm",
3
- "version": "0.1.0-alpha.7",
3
+ "version": "0.1.0-alpha.8",
4
4
  "description": "Bring Your Own LLM — run an app's LLM jobs on your own models. ALPHA: under active development, not for production use.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "zod": "^4.4.3",
27
- "@byollm/protocol": "0.1.0-alpha.7"
27
+ "@byollm/protocol": "0.1.0-alpha.8"
28
28
  },
29
29
  "publishConfig": {
30
30
  "access": "public"