synartesis 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,61 @@
2
2
 
3
3
  What changed, and why it mattered. Dates are release dates.
4
4
 
5
+ ## 0.3.0 — 2026-08-29
6
+
7
+ ### Security
8
+
9
+ - **The journal is no longer world-readable.** To put a file back, what was in
10
+ it has to be kept — so the journal holds the previous contents of everything
11
+ an agent wrote, the arguments of every call, and every reply. SQLite created
12
+ it at whatever the umask allowed, which is `0644` on an ordinary machine: a
13
+ key that happened to be in a file your agent touched was readable by every
14
+ other account. It is now created `0600`, in a directory Synartesis makes
15
+ `0700`, and `0600` is re-applied on every open so a journal written by an
16
+ older version is closed the first time a newer one touches it.
17
+
18
+ A directory that already exists is deliberately left alone: a journal can sit
19
+ beside a policy inside a project, and quietly making your project directory
20
+ `0700` would be the worse surprise. If your `~/.synartesis` predates this
21
+ release, `chmod 700 ~/.synartesis` is worth doing once.
22
+
23
+ ### Added
24
+
25
+ - **`synartesis prune`.** Every write stores the resource as it was, as it
26
+ became, and the call between them, so a journal grows at about four times
27
+ what an agent writes and never shrinks — thirty edits of one 200 kB file came
28
+ to 24 MB, with nothing in the tool or the docs saying so. `prune` deletes
29
+ runs finished more than 30 days ago (`--older-than <days>`, `--dry-run`) and
30
+ then `VACUUM`s, because deleting rows alone leaves a SQLite file exactly as
31
+ large as it was. That 24 MB journal came back to 32 kB.
32
+
33
+ It never touches a run that is still active, or one holding a call that is
34
+ waiting on a person or whose outcome is unknown: age is not an answer to a
35
+ question nobody answered. It names the journal it is about to act on, since
36
+ a journal is found by walking up from where you are standing. Nothing prunes
37
+ on a timer.
38
+ - **`synartesis --version`**, which until now answered `unknown flag
39
+ --version` and exited 2. Also `-V`.
40
+ - **`SECURITY.md`**, with a private reporting route and a plain account of what
41
+ the journal contains.
42
+
43
+ ### Documentation
44
+
45
+ - The README says what the journal holds, what it is chmodded to, how fast it
46
+ grows and how to keep it in hand. None of that was written down anywhere.
47
+
48
+ ## 0.2.4 — 2026-08-25
49
+
50
+ ### Changed
51
+
52
+ - **The toy CRM and the demo agent no longer ship.** They exist to make this
53
+ repo's walkthrough work, and that walkthrough is run from a clone — so
54
+ installing put a fixture server, a demo harness and a policy pointing at a
55
+ binary that is not there onto everyone's disk. `manifests/toy-crm.yaml` goes
56
+ with them for the same reason. 21 files down to 16, 162 kB to 152 kB.
57
+ Nothing a user runs is affected: `synartesis`, `synartesis proxy`, the four
58
+ real policies and the HTTP mode are all untouched.
59
+
5
60
  ## 0.2.3 — 2026-08-22
6
61
 
7
62
  ### Fixed
package/README.md CHANGED
@@ -298,7 +298,7 @@ each manifest below says plainly where that runs out.
298
298
  | [`memory.yaml`](manifests/memory.yaml) | `@modelcontextprotocol/server-memory` | the knowledge graph an agent keeps about you |
299
299
  | [`git.yaml`](manifests/git.yaml) | `mcp-server-git` | a real repository's index and history |
300
300
  | [`github.yaml`](manifests/github.yaml) | `github/github-mcp-server` | issues, pull requests, file contents |
301
- | [`toy-crm.yaml`](manifests/toy-crm.yaml) | the fixture in this repo | the worked example of every class |
301
+ | [`toy-crm.yaml`](manifests/toy-crm.yaml) | the fixture in this repo, not in the published package | the worked example of every class |
302
302
 
303
303
  Every one of those but `github.yaml` was checked against the server actually
304
304
  running. Two demos run the whole loop for real:
@@ -490,6 +490,7 @@ the call simply does not go through.
490
490
  | `undo <runId>` | Reverse a run, newest action first |
491
491
  | `undo <runId> --replan` | Same, but rebuild each undo from the current manifest |
492
492
  | `check` | Load a manifest and verify it against the servers it names |
493
+ | `prune` | Delete runs older than 30 days and reclaim the space |
493
494
  | `close [runId]` | End a run a killed proxy left open. Nothing guesses at this: several proxies can share one journal, so a run left active is indistinguishable from one still being worked on |
494
495
 
495
496
  `--manifest` and `--journal` are found rather than typed. Both are looked for
@@ -502,7 +503,9 @@ that does not exist yet is placed beside the policy, so the proxy that creates
502
503
  it and the CLI that reads it agree without either being told.
503
504
 
504
505
  Other flags: `--dry-run`, `--to <seq>` and `--replan` on `undo`, `--all` on
505
- `approve` and `deny`, `--json` on `list`, `show` and `gates`.
506
+ `approve` and `deny`, `--json` on `list`, `show` and `gates`, `--older-than
507
+ <days>` and `--dry-run` on `prune`. `synartesis --version` prints the version
508
+ and nothing else.
506
509
 
507
510
  Exit codes: `0` succeeded, `1` halted or refused, `2` bad usage or
508
511
  configuration.
@@ -576,6 +579,46 @@ A manifest names commands and Synartesis runs them. Treat one you did not write
576
579
  the way you would treat a shell script from the same source: read it first.
577
580
  There is no sandbox here, and there is not meant to be.
578
581
 
582
+ ### What the journal holds
583
+
584
+ Putting a file back means having kept what was in it, so the journal is not a
585
+ log of what happened. It is a copy of the data: the contents of every resource
586
+ before it was written, the arguments of every call, and what each server sent
587
+ back. A key that was sitting in a file your agent touched is in there in plain
588
+ text. That is not a leak to be closed — it is the thing that makes undo work.
589
+
590
+ So it is treated as private data. The journal is created `0600` and the
591
+ directory Synartesis makes for it `0700`, and `0600` is re-applied every time a
592
+ journal is opened, which closes one written by an older version the first time
593
+ a newer one touches it. A directory that already existed is left alone, because
594
+ a journal can sit beside a policy inside a project and silently making your
595
+ project directory `0700` would be the worse surprise. If your `~/.synartesis`
596
+ predates 0.3.0, `chmod 700 ~/.synartesis` is worth doing once by hand.
597
+
598
+ Nothing is encrypted. Full-disk encryption answers a stolen laptop; file
599
+ permissions answer another account on a machine you share.
600
+
601
+ ### How fast it grows
602
+
603
+ Every write keeps the resource as it was, the resource as it became, and the
604
+ call that did it, so the journal grows at roughly **four times the bytes your
605
+ agent writes** and never shrinks on its own. Thirty edits of one 200 kB file
606
+ came to 24 MB.
607
+
608
+ ```bash
609
+ synartesis prune # runs finished more than 30 days ago
610
+ synartesis prune --older-than 7 --dry-run
611
+ ```
612
+
613
+ It deletes whole runs and then `VACUUM`s, since deleting rows leaves a SQLite
614
+ file exactly the size it was. It will not touch a run that is still active, or
615
+ one holding a call that is waiting on a person or whose outcome is unknown —
616
+ age is not an answer to a question nobody answered. A pruned run cannot be
617
+ undone afterwards, which is the whole of the trade.
618
+
619
+ Nothing prunes on a timer. A tool for undoing things should not discard the
620
+ record of what was done unless it is asked to.
621
+
579
622
  ## Development
580
623
 
581
624
  ```bash
package/SECURITY.md ADDED
@@ -0,0 +1,70 @@
1
+ # Security
2
+
3
+ ## Reporting
4
+
5
+ Report privately through GitHub, using **Security → Report a vulnerability** on
6
+ [the repository](https://github.com/ArhaanDev24/Synartesis/security/advisories/new).
7
+ That opens a draft advisory only you and the maintainer can see.
8
+
9
+ Please do not open a public issue for a vulnerability first. Anything else — a
10
+ crash, a wrong undo, a policy that misclassifies a tool — belongs in the normal
11
+ [issue tracker](https://github.com/ArhaanDev24/Synartesis/issues), and is more
12
+ useful there.
13
+
14
+ Include what you did, what happened, and the output of `synartesis --version`.
15
+
16
+ ## Supported versions
17
+
18
+ The latest published minor. Fixes go out as a new release rather than as
19
+ patches to older ones.
20
+
21
+ | Version | Supported |
22
+ |---|---|
23
+ | 0.3.x | yes |
24
+ | < 0.3 | no |
25
+
26
+ ## What the journal holds, and why it matters
27
+
28
+ Putting a file back means having kept what was in it. So the journal is not a
29
+ log of what happened — it is a copy of the data:
30
+
31
+ - `snapshot_json` — the contents of every resource before it was written
32
+ - `args_json` — the arguments of every call, which for a write is the new
33
+ contents
34
+ - `result_json` — what each server sent back
35
+
36
+ A key that was sitting in a file an agent touched is in the journal in plain
37
+ text, and no amount of care elsewhere changes that: it is what makes undo
38
+ possible.
39
+
40
+ Synartesis therefore creates the journal `0600` and the directory it makes for
41
+ it `0700`, and re-applies `0600` every time a journal is opened, so one written
42
+ by an older version is closed the first time a newer one touches it.
43
+
44
+ Two things it does **not** do, both deliberate:
45
+
46
+ - It does not change the mode of a directory that already exists. A journal can
47
+ sit beside a policy inside a project, and quietly making somebody's project
48
+ directory `0700` would be a worse surprise than the one being prevented. If
49
+ your `~/.synartesis` predates 0.3.0, `chmod 700 ~/.synartesis` is the one
50
+ thing worth doing by hand.
51
+ - It does not encrypt anything. Full-disk encryption is the answer to a stolen
52
+ laptop; file permissions are the answer to another account on a machine you
53
+ share. Neither is Synartesis's to reinvent.
54
+
55
+ `synartesis prune` is how history stops accumulating. Nothing is deleted on a
56
+ timer — a tool for undoing things has no business discarding the record of what
57
+ was done unless asked.
58
+
59
+ ## Scope
60
+
61
+ Synartesis runs the commands a manifest names, with your permissions, and has
62
+ no sandbox. That is the design, and it is why the README says to read a
63
+ manifest you did not write the way you would read a shell script from the same
64
+ source. A manifest that runs something harmful is not a vulnerability in
65
+ Synartesis.
66
+
67
+ Serving over HTTP requires a token of at least 16 characters and binds to
68
+ loopback unless told otherwise. Anything that can reach that port and holds the
69
+ token can write through every server in your policy. Putting it on a network is
70
+ a decision, not a flag.
@@ -172,7 +172,7 @@ var NOTHING_RECORDED_YET = [
172
172
  ];
173
173
 
174
174
  // src/journal/journal.ts
175
- import { existsSync as existsSync2, mkdirSync } from "fs";
175
+ import { chmodSync, existsSync as existsSync2, mkdirSync } from "fs";
176
176
  import { dirname as dirname2 } from "path";
177
177
  import Database from "better-sqlite3";
178
178
  import { z } from "zod";
@@ -308,12 +308,28 @@ function toAction(raw) {
308
308
  ts: row.ts
309
309
  };
310
310
  }
311
+ function restrictToOwner(path) {
312
+ for (const file of [path, `${path}-wal`, `${path}-shm`]) {
313
+ try {
314
+ if (existsSync2(file)) {
315
+ chmodSync(file, 384);
316
+ }
317
+ } catch {
318
+ }
319
+ }
320
+ }
311
321
  function openDatabase(path) {
312
322
  try {
313
323
  const db = new Database(path);
324
+ if (path !== ":memory:") {
325
+ restrictToOwner(path);
326
+ }
314
327
  db.pragma("journal_mode = WAL");
315
328
  db.pragma("foreign_keys = ON");
316
329
  db.pragma("busy_timeout = 5000");
330
+ if (path !== ":memory:") {
331
+ restrictToOwner(path);
332
+ }
317
333
  return db;
318
334
  } catch (error) {
319
335
  const detail = error instanceof Error ? error.message : String(error);
@@ -330,7 +346,7 @@ var SqliteJournal = class {
330
346
  #db;
331
347
  constructor(path) {
332
348
  if (path !== ":memory:") {
333
- mkdirSync(dirname2(path), { recursive: true });
349
+ mkdirSync(dirname2(path), { recursive: true, mode: 448 });
334
350
  }
335
351
  this.#db = openDatabase(path);
336
352
  const existing = z.number().parse(this.#db.pragma("user_version", { simple: true }));
@@ -603,6 +619,61 @@ var SqliteJournal = class {
603
619
  * A failed journal write means the record of what the agent did is
604
620
  * incomplete. It is never swallowed and never merely logged.
605
621
  */
622
+ prunableRuns(before) {
623
+ return this.#run(
624
+ "prunableRuns",
625
+ () => this.#db.prepare(
626
+ // COALESCE, because a run that was closed is dated by when it
627
+ // finished and one that was not is dated by when it began.
628
+ `SELECT r.id, r.label, r.status, COALESCE(r.ended_at, r.started_at) AS at,
629
+ (SELECT COUNT(*) FROM actions a WHERE a.run_id = r.id) AS actions
630
+ FROM runs r
631
+ WHERE r.status != 'active'
632
+ AND COALESCE(r.ended_at, r.started_at) < ?
633
+ AND NOT EXISTS (
634
+ SELECT 1 FROM actions a
635
+ WHERE a.run_id = r.id
636
+ AND a.status IN ('pending','gated','rolling_back'))
637
+ ORDER BY at, r.rowid`
638
+ ).all(before).map(
639
+ (row) => z.object({
640
+ id: z.string(),
641
+ label: z.string().nullable(),
642
+ status: z.enum(["complete", "rolled_back", "partial"]),
643
+ at: z.string(),
644
+ actions: z.number()
645
+ }).parse(row)
646
+ ).map((row) => ({
647
+ id: row.id,
648
+ label: row.label ?? void 0,
649
+ at: row.at,
650
+ status: row.status,
651
+ actions: row.actions
652
+ }))
653
+ );
654
+ }
655
+ deleteRuns(runIds) {
656
+ return this.#run("deleteRuns", () => {
657
+ const remove = this.#db.transaction((ids) => {
658
+ let runs = 0;
659
+ let actions = 0;
660
+ const dropActions = this.#db.prepare("DELETE FROM actions WHERE run_id = ?");
661
+ const dropRun = this.#db.prepare("DELETE FROM runs WHERE id = ?");
662
+ for (const id of ids) {
663
+ actions += dropActions.run(id).changes;
664
+ runs += dropRun.run(id).changes;
665
+ }
666
+ return { runs, actions };
667
+ });
668
+ return remove.immediate(runIds);
669
+ });
670
+ }
671
+ vacuum() {
672
+ this.#run("vacuum", () => {
673
+ this.#db.exec("VACUUM");
674
+ this.#db.pragma("wal_checkpoint(TRUNCATE)");
675
+ });
676
+ }
606
677
  #run(operation, body) {
607
678
  try {
608
679
  return body();
@@ -1408,4 +1479,4 @@ export {
1408
1479
  observeState,
1409
1480
  connectStdioUpstream
1410
1481
  };
1411
- //# sourceMappingURL=chunk-GD6PRYZZ.js.map
1482
+ //# sourceMappingURL=chunk-FIIKQECN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/invocation.ts","../src/locate.ts","../src/style.ts","../src/journal/journal.ts","../src/canonical.ts","../src/journal/schema.ts","../src/manifest/load.ts","../src/manifest/template.ts","../src/manifest/verify.ts","../src/manifest/types.ts","../src/proxy/routing.ts","../src/proxy/upstream.ts","../src/manifest/match.ts","../src/proxy/snapshot.ts"],"sourcesContent":["import { accessSync, constants } from \"node:fs\";\nimport { basename, delimiter, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * How to invoke this CLI, as the reader would have to type it.\n *\n * Printing `synartesis approve ...` is only useful advice if that command\n * exists. Until someone installs it globally it does not, and telling a person\n * to run something that is not there is worse than saying nothing.\n */\nfunction onPath(command: string): boolean {\n const dirs = (process.env[\"PATH\"] ?? \"\").split(delimiter).filter((dir) => dir !== \"\");\n return dirs.some((dir) => {\n try {\n accessSync(join(dir, command), constants.X_OK);\n return true;\n } catch {\n return false;\n }\n });\n}\n\nlet cached: string | undefined;\n\nexport function cliCommand(): string {\n if (cached !== undefined) {\n return cached;\n }\n\n // Installed globally: the shim is a file named for the command itself.\n const invokedAs = process.argv[1];\n if (invokedAs !== undefined && basename(invokedAs) === \"synartesis\") {\n cached = \"synartesis\";\n return cached;\n }\n if (onPath(\"synartesis\")) {\n cached = \"synartesis\";\n return cached;\n }\n\n // Run straight out of a checkout. Spell out what actually works.\n cached = `node ${invokedAs ?? \"dist/cli.js\"}`;\n return cached;\n}\n\n/**\n * The same, worked out from inside the proxy, which lives beside the cli in\n * whatever directory the build put them.\n */\nexport function cliCommandFrom(moduleUrl: string): string {\n if (onPath(\"synartesis\")) {\n return \"synartesis\";\n }\n return `node ${fileURLToPath(new URL(\"cli.js\", moduleUrl))}`;\n}\n\n/**\n * How to start the proxy, as the reader would have to type it.\n *\n * `synartesis proxy` where the cli is reachable: one package and one word is\n * the line people paste into a client config, and it is the same line whether\n * this was installed or is being fetched on the spot. The separate\n * synartesis-proxy binary still exists and is still what an existing config\n * points at; it is simply no longer the shortest way to say it.\n */\nexport function proxyCommand(): string {\n if (onPath(\"synartesis\")) {\n return \"synartesis proxy\";\n }\n if (onPath(\"synartesis-proxy\")) {\n return \"synartesis-proxy\";\n }\n const invokedAs = process.argv[1];\n if (invokedAs !== undefined && invokedAs.endsWith(\"cli.js\")) {\n return `node ${invokedAs} proxy`;\n }\n return `node ${fileURLToPath(new URL(\"cli.js\", import.meta.url))} proxy`;\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\n\n/**\n * Where the policy and the journal are, when nobody said.\n *\n * Typing --manifest and --journal on every command is the friction people\n * actually feel. A policy that belongs to a project sits in it, so both are\n * looked for the way a version control tool looks for its root: from here,\n * upwards, until found.\n *\n * And when there is nothing above you either, there is one home. Most of what\n * anyone guards -- an agent's memory, a notes directory, an account somewhere\n * -- does not belong to a project at all, and making each one its own\n * directory with its own manifest and its own journal is how a home ends up\n * with synartesis-this and synartesis-that in it and no single place that\n * knows what an agent has done.\n */\nexport const MANIFEST_NAME = \"synartesis.yaml\";\nexport const JOURNAL_NAME = \"journal.db\";\nconst NESTED_JOURNAL = join(\".synartesis\", JOURNAL_NAME);\n\n/** Overridable, so a test never has to touch the real one. */\nexport function home(): string {\n return process.env[\"SYNARTESIS_HOME\"] ?? join(homedir(), \".synartesis\");\n}\n\nfunction walkUp(from: string, name: string): string | undefined {\n let dir = resolve(from);\n for (;;) {\n const candidate = join(dir, name);\n if (existsSync(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) {\n return undefined;\n }\n dir = parent;\n }\n}\n\nexport function findManifest(given?: string): string {\n if (given !== undefined) {\n return given;\n }\n return walkUp(process.cwd(), MANIFEST_NAME) ?? join(home(), MANIFEST_NAME);\n}\n\n/**\n * A journal beside the manifest, since that is where a proxy started from that\n * manifest will have been told to put one. Falls back to the nested default so\n * an existing setup keeps working.\n */\nexport function findJournal(given?: string, manifest?: string): string {\n if (given !== undefined) {\n return given;\n }\n\n const near = manifest === undefined ? undefined : dirname(resolve(manifest));\n for (const dir of [near, process.cwd()]) {\n if (dir === undefined) {\n continue;\n }\n for (const name of [JOURNAL_NAME, NESTED_JOURNAL]) {\n const candidate = join(dir, name);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n }\n\n const found = walkUp(process.cwd(), NESTED_JOURNAL) ?? walkUp(process.cwd(), JOURNAL_NAME);\n if (found !== undefined) {\n return found;\n }\n\n // Nothing exists yet. Beside the policy, so the proxy that creates it and the\n // cli that reads it agree without either being told where to look.\n return near === undefined ? join(home(), JOURNAL_NAME) : join(near, JOURNAL_NAME);\n}\n","/**\n * The house style, translated for a terminal.\n *\n * Oxblood and a warm off-white, uppercase letterspaced labels, everything\n * quiet except the one thing that matters. A terminal has no serif and no\n * engraving, so what carries over is the palette, the capitals and the\n * restraint.\n */\nconst ESC = \"\\u001b[\";\nconst ACCENT = `${ESC}38;2;226;134;118m`;\n// Deep oxblood with a warm off-white on it, which holds on a light terminal\n// as well as a dark one.\nconst ON_ACCENT = `${ESC}48;2;94;20;32m${ESC}38;2;246;233;229m`;\nconst BRIGHT = `${ESC}38;2;246;233;229m`;\nconst DIM = `${ESC}2m`;\nconst BOLD = `${ESC}1m`;\nconst RESET = `${ESC}0m`;\n\n/**\n * Colour is for people. Piped output goes to a program that wants the text and\n * not the escape codes, and NO_COLOR is the convention for saying so outright.\n */\nconst enabled =\n process.env[\"NO_COLOR\"] === undefined &&\n process.env[\"TERM\"] !== \"dumb\" &&\n process.stdout.isTTY;\n\nfunction paint(codes: string, text: string): string {\n return enabled ? `${codes}${text}${RESET}` : text;\n}\n\n/**\n * Letterspacing, the one typographic move a terminal can actually make. Only\n * ever applied to the plain ascii labels below, so splitting by code unit is\n * safe here in a way it would not be for arbitrary text.\n */\nexport function spaced(text: string): string {\n return Array.from(text).join(\" \");\n}\n\nexport const style = {\n /** A section label: small, capital, spaced out. */\n label: (text: string): string => paint(ACCENT + DIM, spaced(text.toUpperCase())),\n heading: (text: string): string => paint(BRIGHT + BOLD, text.toUpperCase()),\n accent: (text: string): string => paint(ACCENT, text),\n strong: (text: string): string => paint(BOLD, text),\n quiet: (text: string): string => paint(DIM, text),\n /** Off-white on oxblood, the way the wordmark is set. */\n plate: (text: string): string => paint(ON_ACCENT + BOLD, ` ${text} `),\n};\n\nexport const WORDMARK = spaced(\"SYNARTESIS\");\n\n/**\n * A meander, the Greek fret. A single line that turns back on itself without\n * ever breaking, which is the same idea the name carries and the same idea the\n * product does.\n */\nexport function meander(width: number): string {\n const unit = \"\\u2517\\u2501\\u2513\\u250f\\u2501\\u251b\";\n return unit.repeat(Math.max(1, Math.ceil(width / unit.length))).slice(0, width);\n}\n\n/** A dim fret rule, for separating one region of output from the next. */\nexport function rule(width = 48): string {\n return style.quiet(meander(width));\n}\n\n/**\n * Greek sunartesis, a fastening together. The whole idea in one word: every\n * action is bound to the action that undoes it.\n */\nexport const GREEK = spaced(\"\\u03a3\\u03a5\\u039d\\u0391\\u03a1\\u03a4\\u0397\\u03a3\\u0399\\u03a3\");\nexport const MEANING = \"a fastening together\";\nexport const TAGLINE = \"an undo layer for AI agents\";\n\n/** One compact line, for a process whose real output is something else. */\nexport function mark(): string {\n return `\\n ${style.plate(WORDMARK)} ${style.quiet(MEANING)}\\n\\n`;\n}\n\nexport function banner(): string {\n return [\n \"\",\n ` ${style.plate(WORDMARK)}`,\n ` ${style.accent(meander(24))}`,\n \"\",\n ` ${style.quiet(GREEK)} ${style.quiet(\"\\u00b7\")} ${style.quiet(MEANING)}`,\n \"\",\n ` ${style.accent(spaced(TAGLINE.toUpperCase()))}`,\n ` ${style.quiet(\"Every action is bound to the action that undoes it.\")}`,\n \"\",\n ].join(\"\\n\");\n}\n\n/**\n * What to say when there is no journal yet.\n *\n * The screen and `watch` have always said this; the scriptable commands aborted\n * with \"there is no journal at <path>\" instead, which is true and leads\n * nowhere. Someone who types `synartesis list` before pointing an agent at\n * anything has not made a mistake -- they are early.\n */\nexport const NOTHING_RECORDED_YET = [\n \"One appears the first time an agent calls a tool through the proxy.\",\n \"Point your client at it, then work as usual; this will fill in.\",\n];\n","import { chmodSync, existsSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nimport Database from \"better-sqlite3\";\nimport { z } from \"zod\";\n\nimport { canonical } from \"../canonical.js\";\nimport { JournalError } from \"../errors.js\";\nimport { SCHEMA_SQL, SCHEMA_VERSION } from \"./schema.js\";\n\nexport type RunStatus = \"active\" | \"complete\" | \"rolled_back\" | \"partial\";\n\n/**\n * How a row says its approval was moved onto the action that ran. There is no\n * status for it -- adding one would change the schema, and an older journal\n * cannot be read under a newer schema -- so the row is denied and this is how\n * it is told apart from a person having said no.\n */\nexport const SPENT_APPROVAL = \"approval was used by action\";\n\nexport type ActionStatus =\n | \"pending\"\n | \"gated\"\n /** A person said yes; the agent has not made the call again yet. */\n | \"approved\"\n | \"denied\"\n | \"applied\"\n | \"failed\"\n | \"rolling_back\"\n | \"rolled_back\"\n | \"unrecoverable\";\n\nexport type ActionClass =\n | \"unclassified\"\n | \"readonly\"\n | \"reversible\"\n | \"compensable\"\n | \"irreversible\";\n\nexport interface RunRow {\n readonly id: string;\n readonly label: string | undefined;\n readonly startedAt: string;\n readonly endedAt: string | undefined;\n readonly status: RunStatus;\n}\n\nexport interface ActionRow {\n readonly id: string;\n readonly runId: string;\n readonly seq: number;\n readonly server: string;\n readonly tool: string;\n readonly args: unknown;\n readonly class: ActionClass;\n readonly snapshot: unknown;\n readonly postSnapshot: unknown;\n readonly result: unknown;\n readonly inverse: unknown;\n /** The read that detects drift, resolved at capture time. */\n readonly verify: unknown;\n readonly error: string | undefined;\n readonly idempotencyKey: string;\n readonly status: ActionStatus;\n readonly approvedBy: string | undefined;\n readonly approvedAt: string | undefined;\n readonly ts: string;\n}\n\nexport interface RecordPendingInput {\n readonly runId: string;\n readonly server: string;\n readonly tool: string;\n readonly args: unknown;\n readonly class: ActionClass;\n}\n\nexport interface AppliedOutcome {\n readonly result: unknown;\n /** Fully resolved at capture time (D5); absent when the class has no inverse. */\n readonly inverse?: unknown;\n /** The resolved read used to detect drift later. */\n readonly verify?: unknown;\n /** Post-state for drift detection; absent when the post-read could not run. */\n readonly postSnapshot?: unknown;\n /**\n * A non-fatal problem. `status` says what happened to the call; `error` says\n * what went wrong, and the two are independent: an applied call whose inverse\n * could not be built is both applied and no longer safely reversible.\n */\n readonly warning?: string;\n}\n\nexport interface PendingAction {\n readonly actionId: string;\n readonly seq: number;\n readonly idempotencyKey: string;\n}\n\nconst runSchema = z.object({\n id: z.string(),\n label: z.string().nullable(),\n started_at: z.string(),\n ended_at: z.string().nullable(),\n status: z.enum([\"active\", \"complete\", \"rolled_back\", \"partial\"]),\n});\n\nconst actionSchema = z.object({\n id: z.string(),\n run_id: z.string(),\n seq: z.number(),\n server: z.string(),\n tool: z.string(),\n args_json: z.string(),\n class: z.enum([\"unclassified\", \"readonly\", \"reversible\", \"compensable\", \"irreversible\"]),\n snapshot_json: z.string().nullable(),\n post_snapshot_json: z.string().nullable(),\n result_json: z.string().nullable(),\n inverse_json: z.string().nullable(),\n verify_json: z.string().nullable(),\n error: z.string().nullable(),\n idempotency_key: z.string(),\n status: z.enum([\n \"pending\",\n \"gated\",\n \"approved\",\n \"denied\",\n \"applied\",\n \"failed\",\n \"rolling_back\",\n \"rolled_back\",\n \"unrecoverable\",\n ]),\n approved_by: z.string().nullable(),\n approved_at: z.string().nullable(),\n ts: z.string(),\n});\n\nfunction decode(value: string | null): unknown {\n return value === null ? undefined : (JSON.parse(value) as unknown);\n}\n\nfunction orUndefined(value: string | null): string | undefined {\n return value === null ? undefined : value;\n}\n\nfunction toRun(raw: unknown): RunRow {\n const row = runSchema.parse(raw);\n return {\n id: row.id,\n label: orUndefined(row.label),\n startedAt: row.started_at,\n endedAt: orUndefined(row.ended_at),\n status: row.status,\n };\n}\n\nfunction toAction(raw: unknown): ActionRow {\n const row = actionSchema.parse(raw);\n return {\n id: row.id,\n runId: row.run_id,\n seq: row.seq,\n server: row.server,\n tool: row.tool,\n args: decode(row.args_json),\n class: row.class,\n snapshot: decode(row.snapshot_json),\n postSnapshot: decode(row.post_snapshot_json),\n result: decode(row.result_json),\n inverse: decode(row.inverse_json),\n verify: decode(row.verify_json),\n error: orUndefined(row.error),\n idempotencyKey: row.idempotency_key,\n status: row.status,\n approvedBy: orUndefined(row.approved_by),\n approvedAt: orUndefined(row.approved_at),\n ts: row.ts,\n };\n}\n\nexport interface Journal {\n beginRun(label: string | undefined): string;\n endRun(runId: string, status: RunStatus): void;\n /**\n * Closes a run whose proxy went away without saying so. Only a person can\n * ask for this: several proxies may share one journal, so a run left active\n * is indistinguishable from a run still being worked on, and closing one\n * that is live would make its remaining actions land in a finished run.\n *\n * Returns false when the run is already closed. Ends it at its last action\n * rather than now, since that is when anything last actually happened.\n */\n closeAbandonedRun(runId: string): boolean;\n setRunLabel(runId: string, label: string): void;\n recordPending(input: RecordPendingInput): PendingAction;\n attachSnapshot(actionId: string, snapshot: unknown): void;\n markApplied(actionId: string, outcome: AppliedOutcome): void;\n markFailed(actionId: string, error: string): void;\n markUnknown(actionId: string, error: string): void;\n /**\n * Claims an action for this rollback. Returns false when it was not this\n * call that moved it out of `applied`, which is how two undos running at\n * once are told apart from one resuming after a crash.\n */\n markRollingBack(actionId: string): boolean;\n markRolledBack(actionId: string): void;\n markUnrecoverable(actionId: string, error: string): void;\n markInverseRejected(actionId: string, error: string): void;\n markUnknownInverse(actionId: string, error: string): void;\n /**\n * `why` is kept on the row so the person deciding can see the reason\n * without the proxy running. It goes in `error`, which is already where a\n * row explains the state it is in.\n */\n markGated(actionId: string, why?: string): void;\n /** About to go out: from here on its outcome is genuinely unknown. */\n markInFlight(actionId: string): void;\n /** Returns false when the action is no longer awaiting a decision. */\n approve(actionId: string, by: string): boolean;\n deny(actionId: string, by: string | undefined, reason: string): boolean;\n /**\n * Records a refusal whatever state the row is in. `deny` is conditional\n * because an operator's decision must not overwrite one already settled; the\n * proxy needs the opposite, to record that an action it had approval for was\n * still not carried out.\n */\n settleAsDenied(actionId: string, by: string | undefined, reason: string): void;\n /**\n * Moves an approval granted in an earlier session onto the action that is\n * about to run, and spends the original so it cannot be used twice.\n */\n adoptApproval(actionId: string, granted: ActionRow): void;\n listGated(): readonly ActionRow[];\n /**\n * An approval that was granted but never carried out, for this exact call.\n * A retry after an out-of-band approval reuses that row rather than opening\n * a second one, so the approval sits on the action that actually ran.\n */\n findApproval(query: {\n server: string;\n tool: string;\n args: unknown;\n /** ISO timestamp; approvals older than this are ignored. */\n notBefore: string;\n }): ActionRow | undefined;\n /**\n * A call in this run that is already waiting for a decision. An agent told\n * to try again will often try again before anyone has answered, and a second\n * row for one decision is worse than useless: `approve` then refuses to act\n * without an id, and approving either one leaves its twin waiting for ever.\n */\n findGated(query: {\n runId: string;\n server: string;\n tool: string;\n args: unknown;\n }): ActionRow | undefined;\n getAction(actionId: string): ActionRow | undefined;\n listRuns(): readonly RunRow[];\n getRun(runId: string): RunRow | undefined;\n getActions(runId: string): readonly ActionRow[];\n /** The newest actions across every run, for watching work as it happens. */\n recentActions(limit: number): readonly ActionRow[];\n /**\n * Runs old enough to discard and finished enough that discarding one loses\n * nothing anybody can still act on. Everything still in play is excluded\n * whatever its age: an active run, and any run holding an action that is\n * `pending` (a call went out and nobody knows what it did), `gated` (a\n * person has not decided yet) or `rolling_back` (an inverse may be half\n * applied). Age is not a reason to throw away an unanswered question.\n */\n prunableRuns(before: string): readonly PrunableRun[];\n /** Removes runs and their actions. Returns what actually went. */\n deleteRuns(runIds: readonly string[]): { runs: number; actions: number };\n /**\n * Reclaims the space the deletes freed. Deleting rows leaves a SQLite file\n * exactly as large as it was, so without this a prune frees nothing a user\n * can see. Cannot run inside a transaction.\n */\n vacuum(): void;\n pragma(name: string): unknown;\n close(): void;\n}\n\nexport interface PrunableRun {\n readonly id: string;\n readonly label: string | undefined;\n /** When it last did anything, which is what its age is measured from. */\n readonly at: string;\n readonly status: RunStatus;\n readonly actions: number;\n}\n\n/**\n * A journal is not a log. To put a file back, its previous contents have to be\n * kept, so this database holds a verbatim copy of everything an agent\n * overwrote -- and, in the arguments, everything it wrote. A key that was\n * sitting in a file the agent touched is in here in plain text.\n *\n * SQLite creates its file with whatever the umask allows, which is 0644 on an\n * ordinary machine: readable by every other account, and by anything walking\n * $HOME. This is the ~/.ssh case, and it gets the ~/.ssh answer.\n *\n * On every open rather than only on create, because the journals that most\n * need this are the ones already sitting on disk. Nothing legitimate wants a\n * shared journal: several proxies sharing one are several processes of one\n * person, which 0600 allows.\n */\nfunction restrictToOwner(path: string): void {\n // The sidecars carry the same content. WAL is enabled just after this, so\n // they may not exist yet -- SQLite gives a new one the mode of the database\n // file, and the next open catches any that were made before this ran.\n for (const file of [path, `${path}-wal`, `${path}-shm`]) {\n try {\n if (existsSync(file)) {\n chmodSync(file, 0o600);\n }\n } catch {\n // Windows chmod only moves a read-only bit, and some network mounts\n // refuse it outright. Neither is a reason to stop a working tool: the\n // warning belongs in the docs, not in a crash here.\n }\n }\n}\n\n/**\n * Opening, with the failures named. better-sqlite3 reports \"file is not a\n * database\" and \"unable to open database file\" and leaves out which file it\n * meant, which is unhelpful precisely when the path was the mistake.\n */\nfunction openDatabase(path: string): Database.Database {\n try {\n const db = new Database(path);\n // Before the first pragma, so the window in which the file exists at the\n // umask's mode is as short as it can be made from here.\n if (path !== \":memory:\") {\n restrictToOwner(path);\n }\n // The pragmas, not the constructor: better-sqlite3 opens lazily, so a file\n // that is not a database is only found out on the first read.\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n // WAL lets readers and one writer work at once; a second writer still has\n // to wait its turn, and without this SQLite does not wait at all -- it\n // fails immediately with \"database is locked\". Six agents sharing one\n // journal lost two of their calls that way, which is the arrangement this\n // tool recommends. Writes here are tiny, so the wait is milliseconds; the\n // five seconds is the ceiling before something is genuinely wedged.\n db.pragma(\"busy_timeout = 5000\");\n // Again, because turning WAL on is what creates the sidecars, and they\n // hold the same content as the database they belong to.\n if (path !== \":memory:\") {\n restrictToOwner(path);\n }\n return db;\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n if (detail.includes(\"not a database\")) {\n throw new JournalError(\n \"open\",\n `${path} is not a Synartesis journal. Point --journal at a journal, or at a new file to start one.`,\n );\n }\n throw new JournalError(\"open\", `the journal at ${path} could not be opened: ${detail}`);\n }\n}\n\nclass SqliteJournal implements Journal {\n readonly #db: Database.Database;\n\n constructor(path: string) {\n if (path !== \":memory:\") {\n // 0700 for the same reason the journal is 0600. A umask can only clear\n // bits, never set them, so this is the mode on any ordinary machine.\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n }\n // Opening is the one step a user is most likely to get wrong -- a typo in\n // --journal, a path that is a directory, a file that is something else\n // entirely -- and it was the one step whose errors went out raw, as a bare\n // \"file is not a database\" naming neither the file nor the tool.\n // WAL so a reader (the CLI) never blocks the proxy mid-run.\n this.#db = openDatabase(path);\n\n const existing = z.number().parse(this.#db.pragma(\"user_version\", { simple: true }));\n const populated =\n z\n .object({ count: z.number() })\n .parse(\n this.#db\n .prepare(\"SELECT COUNT(*) AS count FROM sqlite_master WHERE type = 'table' AND name = 'runs'\")\n .get(),\n ).count > 0;\n if (populated && existing !== SCHEMA_VERSION) {\n // Reinterpreting an older journal under a newer schema would risk\n // reading a rollback state that was never written.\n throw new JournalError(\n \"open\",\n `journal at ${path} was written by schema version ${String(existing)}, but this build expects ${String(SCHEMA_VERSION)}. ` +\n `Point --journal at a new file to carry on, and keep this one: everything an agent did is in it. Delete it only once you are sure you do not want that history.`,\n );\n }\n\n this.#db.exec(SCHEMA_SQL);\n this.#db.pragma(`user_version = ${String(SCHEMA_VERSION)}`);\n }\n\n beginRun(label: string | undefined): string {\n const id = crypto.randomUUID();\n this.#run(\"beginRun\", () => {\n this.#db\n .prepare(\"INSERT INTO runs (id, label, started_at, status) VALUES (?, ?, ?, 'active')\")\n .run(id, label ?? null, new Date().toISOString());\n });\n return id;\n }\n\n endRun(runId: string, status: RunStatus): void {\n this.#run(\"endRun\", () => {\n this.#db\n .prepare(\"UPDATE runs SET ended_at = ?, status = ? WHERE id = ?\")\n .run(new Date().toISOString(), status, runId);\n });\n }\n\n closeAbandonedRun(runId: string): boolean {\n return this.#run(\"closeAbandonedRun\", () => {\n const last = z\n .object({ ts: z.string().nullable() })\n .parse(\n this.#db\n .prepare(\"SELECT MAX(ts) AS ts FROM actions WHERE run_id = ?\")\n .get(runId) ?? { ts: null },\n ).ts;\n const result = this.#db\n .prepare(\"UPDATE runs SET ended_at = ?, status = 'complete' WHERE id = ? AND status = 'active'\")\n .run(last ?? new Date().toISOString(), runId);\n return result.changes === 1;\n });\n }\n\n setRunLabel(runId: string, label: string): void {\n this.#run(\"setRunLabel\", () => {\n this.#db.prepare(\"UPDATE runs SET label = ? WHERE id = ?\").run(label, runId);\n });\n }\n\n recordPending(input: RecordPendingInput): PendingAction {\n return this.#run(\"recordPending\", () => {\n const insert = this.#db.transaction((): PendingAction => {\n const next = this.#db\n .prepare(\"SELECT COALESCE(MAX(seq), 0) + 1 AS seq FROM actions WHERE run_id = ?\")\n .get(input.runId);\n const seq = z.object({ seq: z.number() }).parse(next).seq;\n const actionId = crypto.randomUUID();\n // Derived rather than random: a retried rollback must present the same\n // key for the same action, which is the whole point of D7.\n const idempotencyKey = `${input.runId}:${String(seq)}`;\n\n this.#db\n .prepare(\n `INSERT INTO actions\n (id, run_id, seq, server, tool, args_json, class, idempotency_key, status, ts)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?)`,\n )\n .run(\n actionId,\n input.runId,\n seq,\n input.server,\n input.tool,\n JSON.stringify(input.args ?? {}),\n input.class,\n idempotencyKey,\n new Date().toISOString(),\n );\n\n return { actionId, seq, idempotencyKey };\n });\n // immediate, not deferred. This reads the highest seq and then inserts,\n // and SQLite will not upgrade a read lock to a write one while another\n // writer has committed in between -- it returns \"database is locked\"\n // straight away, and busy_timeout does not apply to that case. Taking\n // the write lock up front is what makes the wait actually happen.\n return insert.immediate();\n });\n }\n\n attachSnapshot(actionId: string, snapshot: unknown): void {\n this.#run(\"attachSnapshot\", () => {\n this.#db\n .prepare(\"UPDATE actions SET snapshot_json = ? WHERE id = ?\")\n .run(JSON.stringify(snapshot ?? null), actionId);\n });\n }\n\n markApplied(actionId: string, outcome: AppliedOutcome): void {\n this.#run(\"markApplied\", () => {\n this.#db\n .prepare(\n `UPDATE actions\n SET status = 'applied',\n result_json = ?,\n inverse_json = ?,\n verify_json = ?,\n post_snapshot_json = ?,\n error = ?\n WHERE id = ?`,\n )\n .run(\n JSON.stringify(outcome.result ?? null),\n outcome.inverse === undefined ? null : JSON.stringify(outcome.inverse),\n outcome.verify === undefined ? null : JSON.stringify(outcome.verify),\n outcome.postSnapshot === undefined ? null : JSON.stringify(outcome.postSnapshot),\n outcome.warning ?? null,\n actionId,\n );\n });\n }\n\n markFailed(actionId: string, error: string): void {\n this.#run(\"markFailed\", () => {\n this.#db\n .prepare(\"UPDATE actions SET status = 'failed', error = ? WHERE id = ?\")\n .run(error, actionId);\n });\n }\n\n /**\n * The call was interrupted, so whether the upstream applied it is genuinely\n * unknown. The row deliberately stays `pending`: recording it as failed\n * would assert something we cannot know, and section 3.1 wants exactly this\n * case surfaced rather than resolved by guesswork.\n */\n markUnknown(actionId: string, error: string): void {\n this.#run(\"markUnknown\", () => {\n this.#db\n .prepare(\"UPDATE actions SET status = 'pending', error = ? WHERE id = ?\")\n .run(error, actionId);\n });\n }\n\n markRollingBack(actionId: string): boolean {\n return this.#run(\"markRollingBack\", () => {\n // Conditional, so the transition is a claim rather than an announcement.\n // Two rollbacks of one run both read the action as applied and both sent\n // its inverse; for a compensating call rather than a restore, that is a\n // second real change to the world.\n const result = this.#db\n .prepare(\"UPDATE actions SET status = 'rolling_back' WHERE id = ? AND status = 'applied'\")\n .run(actionId);\n return result.changes === 1;\n });\n }\n\n markRolledBack(actionId: string): void {\n this.#run(\"markRolledBack\", () => {\n this.#db.prepare(\"UPDATE actions SET status = 'rolled_back' WHERE id = ?\").run(actionId);\n });\n }\n\n /**\n * The upstream processed the inverse and refused it, so nothing was applied\n * and the action still needs undoing. Distinct from `unrecoverable`, which\n * means a human has to look: a refused inverse may simply be a server that\n * was briefly unwell, and rollback is expected to be retried (D7).\n */\n markInverseRejected(actionId: string, error: string): void {\n this.#run(\"markInverseRejected\", () => {\n this.#db\n .prepare(\"UPDATE actions SET status = 'applied', error = ? WHERE id = ?\")\n .run(error, actionId);\n });\n }\n\n /**\n * The inverse may or may not have reached the upstream. The row stays in\n * `rolling_back` so the next attempt knows to resolve it by reading the\n * current state rather than assuming either way.\n */\n markUnknownInverse(actionId: string, error: string): void {\n this.#run(\"markUnknownInverse\", () => {\n this.#db\n .prepare(\"UPDATE actions SET status = 'rolling_back', error = ? WHERE id = ?\")\n .run(error, actionId);\n });\n }\n\n markGated(actionId: string, why?: string): void {\n this.#run(\"markGated\", () => {\n this.#db\n .prepare(\"UPDATE actions SET status = 'gated', error = ? WHERE id = ?\")\n .run(why ?? null, actionId);\n });\n }\n\n markInFlight(actionId: string): void {\n this.#run(\"markInFlight\", () => {\n this.#db.prepare(\"UPDATE actions SET status = 'pending' WHERE id = ?\").run(actionId);\n });\n }\n\n /**\n * Conditional on the row still being gated, so a decision made at the same\n * moment as a timeout resolves one way rather than both.\n */\n approve(actionId: string, by: string): boolean {\n return this.#run(\"approve\", () => {\n const result = this.#db\n .prepare(\n `UPDATE actions SET status = 'approved', approved_by = ?, approved_at = ?, error = NULL\n WHERE id = ? AND status = 'gated'`,\n )\n .run(by, new Date().toISOString(), actionId);\n return result.changes === 1;\n });\n }\n\n deny(actionId: string, by: string | undefined, reason: string): boolean {\n return this.#run(\"deny\", () => {\n const result = this.#db\n .prepare(\n `UPDATE actions SET status = 'denied', approved_by = ?, approved_at = ?, error = ?\n WHERE id = ? AND status = 'gated'`,\n )\n .run(by ?? null, new Date().toISOString(), reason, actionId);\n return result.changes === 1;\n });\n }\n\n settleAsDenied(actionId: string, by: string | undefined, reason: string): void {\n this.#run(\"settleAsDenied\", () => {\n this.#db\n .prepare(\n \"UPDATE actions SET status = 'denied', approved_by = ?, approved_at = ?, error = ? WHERE id = ?\",\n )\n .run(by ?? null, new Date().toISOString(), reason, actionId);\n });\n }\n\n adoptApproval(actionId: string, granted: ActionRow): void {\n this.#run(\"adoptApproval\", () => {\n // Also immediate: adopting an approval reads one row and writes two.\n const move = this.#db.transaction((): void => {\n this.#db\n .prepare(\"UPDATE actions SET approved_by = ?, approved_at = ? WHERE id = ?\")\n .run(granted.approvedBy ?? null, granted.approvedAt ?? null, actionId);\n this.#db\n .prepare(\"UPDATE actions SET status = 'denied', error = ? WHERE id = ?\")\n .run(`${SPENT_APPROVAL} ${actionId}`, granted.id);\n });\n move.immediate();\n });\n }\n\n listGated(): readonly ActionRow[] {\n return this.#run(\"listGated\", () =>\n this.#db.prepare(\"SELECT * FROM actions WHERE status = 'gated' ORDER BY ts\").all().map(toAction),\n );\n }\n\n findApproval(query: {\n server: string;\n tool: string;\n args: unknown;\n notBefore: string;\n }): ActionRow | undefined {\n return this.#run(\"findApproval\", () => {\n // Not scoped to one run: people restart their client, and an approval\n // stranded in a dead session is the same as no approval at all. Bounded\n // by time and by being single use instead, so a decision made this\n // morning cannot silently authorise the same call tomorrow.\n const rows = this.#db\n .prepare(\n `SELECT * FROM actions\n WHERE server = ? AND tool = ?\n AND status = 'approved'\n AND approved_at >= ?\n ORDER BY approved_at DESC`,\n )\n .all(query.server, query.tool, query.notBefore)\n .map(toAction);\n // Matched on meaning rather than on spelling: an agent that re-emits the\n // same arguments in a different key order is making the same call, and\n // sending a person back to approve what they just approved would teach\n // them to stop reading what they are approving.\n const wanted = canonical(query.args ?? {});\n return rows.find((row) => canonical(row.args) === wanted);\n });\n }\n\n findGated(query: {\n runId: string;\n server: string;\n tool: string;\n args: unknown;\n }): ActionRow | undefined {\n return this.#run(\"findGated\", () => {\n // Scoped to the run, unlike an approval: a gated row belongs to the run\n // that raised it, and adopting one from a dead session would hang the\n // decision on an action that undoing this run would never reach.\n const rows = this.#db\n .prepare(\n `SELECT * FROM actions\n WHERE run_id = ? AND server = ? AND tool = ? AND status = 'gated'\n ORDER BY seq`,\n )\n .all(query.runId, query.server, query.tool)\n .map(toAction);\n const wanted = canonical(query.args ?? {});\n return rows.find((row) => canonical(row.args) === wanted);\n });\n }\n\n getAction(actionId: string): ActionRow | undefined {\n return this.#run(\"getAction\", () => {\n const raw = this.#db.prepare(\"SELECT * FROM actions WHERE id = ?\").get(actionId);\n return raw === undefined ? undefined : toAction(raw);\n });\n }\n\n markUnrecoverable(actionId: string, error: string): void {\n this.#run(\"markUnrecoverable\", () => {\n this.#db\n .prepare(\"UPDATE actions SET status = 'unrecoverable', error = ? WHERE id = ?\")\n .run(error, actionId);\n });\n }\n\n listRuns(): readonly RunRow[] {\n return this.#run(\"listRuns\", () =>\n // Insertion order as the tiebreak, not the id. Two runs that start in\n // the same millisecond have equal timestamps, and a uuid orders them at\n // random -- which decides which one `show` and `undo` mean by \"the most\n // recent\", so the answer has to come from when they were written rather\n // than from what they happen to be called.\n this.#db.prepare(\"SELECT * FROM runs ORDER BY started_at, rowid\").all().map(toRun),\n );\n }\n\n getRun(runId: string): RunRow | undefined {\n return this.#run(\"getRun\", () => {\n const raw = this.#db.prepare(\"SELECT * FROM runs WHERE id = ?\").get(runId);\n return raw === undefined ? undefined : toRun(raw);\n });\n }\n\n getActions(runId: string): readonly ActionRow[] {\n return this.#run(\"getActions\", () =>\n this.#db\n .prepare(\"SELECT * FROM actions WHERE run_id = ? ORDER BY seq\")\n .all(runId)\n .map(toAction),\n );\n }\n\n recentActions(limit: number): readonly ActionRow[] {\n return this.#run(\"recentActions\", () =>\n this.#db\n .prepare(\"SELECT * FROM actions ORDER BY ts DESC, seq DESC LIMIT ?\")\n .all(limit)\n .map(toAction)\n .reverse(),\n );\n }\n\n pragma(name: string): unknown {\n return this.#db.pragma(name, { simple: true });\n }\n\n close(): void {\n this.#db.close();\n }\n\n /**\n * A failed journal write means the record of what the agent did is\n * incomplete. It is never swallowed and never merely logged.\n */\n prunableRuns(before: string): readonly PrunableRun[] {\n return this.#run(\"prunableRuns\", () =>\n this.#db\n .prepare(\n // COALESCE, because a run that was closed is dated by when it\n // finished and one that was not is dated by when it began.\n `SELECT r.id, r.label, r.status, COALESCE(r.ended_at, r.started_at) AS at,\n (SELECT COUNT(*) FROM actions a WHERE a.run_id = r.id) AS actions\n FROM runs r\n WHERE r.status != 'active'\n AND COALESCE(r.ended_at, r.started_at) < ?\n AND NOT EXISTS (\n SELECT 1 FROM actions a\n WHERE a.run_id = r.id\n AND a.status IN ('pending','gated','rolling_back'))\n ORDER BY at, r.rowid`,\n )\n .all(before)\n .map((row) =>\n z\n .object({\n id: z.string(),\n label: z.string().nullable(),\n status: z.enum([\"complete\", \"rolled_back\", \"partial\"]),\n at: z.string(),\n actions: z.number(),\n })\n .parse(row),\n )\n .map((row) => ({\n id: row.id,\n label: row.label ?? undefined,\n at: row.at,\n status: row.status,\n actions: row.actions,\n })),\n );\n }\n\n deleteRuns(runIds: readonly string[]): { runs: number; actions: number } {\n return this.#run(\"deleteRuns\", () => {\n const remove = this.#db.transaction((ids: readonly string[]) => {\n let runs = 0;\n let actions = 0;\n const dropActions = this.#db.prepare(\"DELETE FROM actions WHERE run_id = ?\");\n const dropRun = this.#db.prepare(\"DELETE FROM runs WHERE id = ?\");\n for (const id of ids) {\n // Actions first: they carry the foreign key onto the run, so the\n // other order is rejected rather than cascading.\n actions += dropActions.run(id).changes;\n runs += dropRun.run(id).changes;\n }\n return { runs, actions };\n });\n // immediate, for the same reason recordPending is: this reads before it\n // writes, and a deferred transaction cannot take the write lock later.\n return remove.immediate(runIds);\n });\n }\n\n vacuum(): void {\n this.#run(\"vacuum\", () => {\n this.#db.exec(\"VACUUM\");\n // And then fold the log back in. In WAL mode the rebuilt database is\n // written to the write-ahead log, so until this runs the file on disk is\n // exactly the size it was and the prune appears to have freed nothing --\n // which, to anyone looking at df, is the same as not working.\n this.#db.pragma(\"wal_checkpoint(TRUNCATE)\");\n });\n }\n\n #run<T>(operation: string, body: () => T): T {\n try {\n return body();\n } catch (error: unknown) {\n throw new JournalError(operation, error);\n }\n }\n}\n\nexport interface OpenOptions {\n /**\n * Refuse to create the file. Reading commands should say a journal is not\n * there rather than conjure an empty one and report that nothing happened,\n * which looks identical to a real answer and leaves a stray file behind.\n */\n readonly mustExist?: boolean;\n}\n\nexport function openJournal(path: string, options: OpenOptions = {}): Journal {\n if (options.mustExist === true && path !== \":memory:\" && !existsSync(path)) {\n throw new JournalError(\"open\", `there is no journal at ${path}`);\n }\n return new SqliteJournal(path);\n}\n\n/**\n * A row denied because its approval was spent on the call that actually ran is\n * not a refusal, and `watch` reported one as \"denied\" moments after the person\n * had said yes and the call had gone through.\n */\nexport function labelFor(action: ActionRow): string {\n return action.status === \"denied\" && (action.error ?? \"\").startsWith(SPENT_APPROVAL)\n ? \"used\"\n : action.status;\n}\n\nexport function wasRefused(action: ActionRow): boolean {\n return action.status === \"unrecoverable\" || labelFor(action) === \"denied\";\n}\n","/**\n * A stable text form of a json value.\n *\n * Key order carries no meaning in json, and nothing obliges an agent to\n * serialise the same arguments the same way twice. Anywhere two values are\n * compared for sameness -- state against recorded state, a retried call\n * against the approval that was granted for it -- the comparison has to be on\n * meaning rather than on spelling.\n */\nexport function canonical(value: unknown): string {\n if (value === undefined) {\n return \"undefined\";\n }\n if (value === null || typeof value !== \"object\") {\n return JSON.stringify(value);\n }\n if (Array.isArray(value)) {\n return `[${value.map(canonical).join(\",\")}]`;\n }\n const entries = Object.entries(value)\n .filter(([, item]) => item !== undefined)\n .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`).join(\",\")}}`;\n}\n","/**\n * Schema version is stored in SQLite's user_version.\n *\n * Version 2 adds `rolling_back`, written before an inverse is sent. On resume,\n * a row still in that state means the inverse may already have been applied,\n * which is the difference between a correct resume and a double-application.\n * It also adds `verify_json`, the read used to detect drift, resolved to\n * literal arguments at capture time for the same reason the inverse is (D5):\n * the manifest may have been edited by the time anyone rolls back.\n *\n * Version 3 adds `approved`: granted by a person but not yet carried out.\n * That was `pending` at first, which also means a call went out and its\n * outcome is unknown. Undo has to halt on the second and step past the first,\n * so they cannot share a name.\n *\n * There is no migration path yet, and inventing one before anything needs\n * migrating would mean shipping untested machinery. An older journal is\n * refused with instructions instead of being silently reinterpreted.\n */\nexport const SCHEMA_VERSION = 3;\n\nexport const SCHEMA_SQL = `\nCREATE TABLE IF NOT EXISTS runs (\n id TEXT PRIMARY KEY,\n label TEXT,\n started_at TEXT NOT NULL,\n ended_at TEXT,\n status TEXT NOT NULL CHECK (status IN ('active','complete','rolled_back','partial'))\n);\n\nCREATE TABLE IF NOT EXISTS actions (\n id TEXT PRIMARY KEY,\n run_id TEXT NOT NULL REFERENCES runs(id),\n seq INTEGER NOT NULL,\n server TEXT NOT NULL,\n tool TEXT NOT NULL,\n args_json TEXT NOT NULL,\n class TEXT NOT NULL,\n snapshot_json TEXT,\n post_snapshot_json TEXT,\n result_json TEXT,\n inverse_json TEXT,\n verify_json TEXT,\n error TEXT,\n idempotency_key TEXT NOT NULL UNIQUE,\n status TEXT NOT NULL CHECK (status IN\n ('pending','gated','approved','denied','applied','failed',\n 'rolling_back','rolled_back','unrecoverable')),\n approved_by TEXT,\n approved_at TEXT,\n ts TEXT NOT NULL,\n UNIQUE(run_id, seq)\n);\n\nCREATE INDEX IF NOT EXISTS actions_by_run ON actions(run_id, seq);\n`;\n","import { readFileSync } from \"node:fs\";\n\nimport { LineCounter, isNode, parseDocument, type Document } from \"yaml\";\nimport { z } from \"zod\";\n\nimport { ManifestError, describe as describeCause, type SourceLocation } from \"../errors.js\";\nimport { referencesIn } from \"./template.js\";\nimport type { CallTemplate, Manifest, TemplateValue, ToolPolicy } from \"./types.js\";\n\nconst templateValue: z.ZodType<TemplateValue> = z.lazy(() =>\n z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.null(),\n z.array(templateValue),\n z.record(z.string(), templateValue),\n ]),\n);\n\nconst callTemplate = z.strictObject({\n tool: z.string().min(1),\n args: z.record(z.string(), templateValue).default({}),\n absent_when: z\n .union([z.string().min(1), z.array(z.string().min(1)).min(1)])\n .optional(),\n});\n\nconst toolPolicy = z.strictObject({\n match: z.string().min(1),\n class: z.enum([\"readonly\", \"reversible\", \"compensable\", \"irreversible\"]),\n gate: z.enum([\"always\", \"on_write\", \"never\"]).optional(),\n snapshot: callTemplate.optional(),\n inverse: callTemplate.optional(),\n});\n\nconst serverSpec = z.strictObject({\n command: z.string().min(1),\n args: z.array(z.string()).default([]),\n env: z.record(z.string(), z.string()).optional(),\n});\n\nconst manifestSchema = z.strictObject({\n version: z.literal(1),\n servers: z.record(z.string(), serverSpec),\n tools: z.array(toolPolicy).default([]),\n});\n\ntype Path = readonly (string | number)[];\n\nclass Source {\n constructor(\n private readonly doc: Document.Parsed,\n private readonly lines: LineCounter,\n private readonly file: string,\n ) {}\n\n /** Narrows to the deepest node that still exists, so a location is always given. */\n locate(path: Path): SourceLocation {\n for (let depth = path.length; depth >= 0; depth -= 1) {\n const node: unknown =\n depth === 0 ? this.doc.contents : this.doc.getIn(path.slice(0, depth), true);\n const range = isNode(node) ? node.range : undefined;\n if (range != null) {\n const position = this.lines.linePos(range[0]);\n return { file: this.file, line: position.line, column: position.col };\n }\n }\n return { file: this.file, line: 1, column: 1 };\n }\n\n fail(path: Path, message: string): never {\n throw new ManifestError(message, this.locate(path));\n }\n}\n\n/**\n * `${VAR}` in a server's environment, taken from the shell the proxy was\n * started from.\n *\n * This is how a token stays out of a file that gets committed, which is what\n * the shipped manifests tell people to do. Without expansion the server\n * receives the reference itself and fails with an authentication error that\n * says nothing about the cause. A variable that is not set is refused at load\n * time rather than passed on empty, for the same reason: never start with a\n * policy that cannot work.\n */\nconst REFERENCE = /\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g;\n\nfunction expandEnvironment(\n source: Source,\n path: Path,\n env: Readonly<Record<string, string>>,\n): Record<string, string> {\n const expanded: Record<string, string> = {};\n for (const [key, value] of Object.entries(env)) {\n expanded[key] = value.replace(REFERENCE, (whole, name: string) => {\n const found = process.env[name];\n if (found === undefined) {\n source.fail(\n [...path, \"env\", key],\n `${whole} is not set in this environment; export ${name} before starting, or write the value here`,\n );\n }\n return found;\n });\n }\n return expanded;\n}\n\nfunction serverSegment(pattern: string): string {\n const dot = pattern.indexOf(\".\");\n return dot === -1 ? \"\" : pattern.slice(0, dot);\n}\n\nfunction matchesAnyServer(segment: string, servers: readonly string[]): boolean {\n if (!segment.includes(\"*\")) {\n return servers.includes(segment);\n }\n const source = segment\n .split(\"*\")\n .map((literal) => literal.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"))\n .join(\"[^.]*\");\n const test = new RegExp(`^${source}$`);\n return servers.some((name) => test.test(name));\n}\n\nfunction checkCall(\n source: Source,\n path: Path,\n call: CallTemplate,\n servers: readonly string[],\n allowed: readonly string[],\n): void {\n const segment = serverSegment(call.tool);\n if (segment === \"\" || call.tool.endsWith(\".\")) {\n source.fail([...path, \"tool\"], `${call.tool} must be qualified as server.tool`);\n }\n if (segment.includes(\"*\")) {\n source.fail([...path, \"tool\"], `${call.tool} must name one server, not a pattern`);\n }\n if (!servers.includes(segment)) {\n source.fail([...path, \"tool\"], `${call.tool} names server ${segment}, which is not declared`);\n }\n\n for (const reference of referencesIn(call.args)) {\n // Matches `$ns.field`, `$ns[0]` and a bare `$ns`, so a whole-value or\n // subscripted reference is checked rather than silently treated as `$.`\n // and failing at run time.\n const namespace = /^\\$(\\w*)(?:[.[]|$)/.exec(reference)?.[1] ?? \"\";\n const label = namespace === \"\" ? \"$.\" : `$${namespace}.`;\n if (!allowed.includes(label)) {\n source.fail(\n [...path, \"args\"],\n `${reference} uses ${label}, which is not available here; allowed: ${allowed.join(\", \")}`,\n );\n }\n }\n}\n\n/**\n * Cross-field rules the shape alone cannot express. These are the difference\n * between a manifest that parses and a policy that can actually be executed,\n * and every one of them fails startup rather than surfacing mid-run.\n */\nfunction validate(source: Source, manifest: Manifest): void {\n const servers = Object.keys(manifest.servers);\n if (servers.length === 0) {\n source.fail([\"servers\"], \"at least one server must be declared\");\n }\n\n const seen = new Map<string, number>();\n manifest.tools.forEach((policy, index) => {\n const path: Path = [\"tools\", index];\n const previous = seen.get(policy.match);\n if (previous !== undefined) {\n source.fail(\n [...path, \"match\"],\n `duplicate match pattern ${policy.match}; it is already declared at tools[${String(previous)}]`,\n );\n }\n seen.set(policy.match, index);\n\n const segment = serverSegment(policy.match);\n if (segment === \"\") {\n source.fail([...path, \"match\"], `${policy.match} must be qualified as server.tool`);\n }\n if (!matchesAnyServer(segment, servers)) {\n source.fail(\n [...path, \"match\"],\n `${policy.match} names server ${segment}, which is not declared`,\n );\n }\n\n const needsInverse = policy.class === \"reversible\" || policy.class === \"compensable\";\n if (needsInverse && policy.inverse === undefined) {\n source.fail(path, `a ${policy.class} tool must declare an inverse`);\n }\n if (!needsInverse && policy.inverse !== undefined) {\n source.fail([...path, \"inverse\"], `a ${policy.class} tool must not declare an inverse`);\n }\n // A snapshot is required only when the inverse actually depends on one.\n // Some actions are reversible from their arguments alone: the inverse of\n // moving a file from A to B is moving it from B to A, and no pre-read\n // could tell you anything the arguments do not already say.\n const needsSnapshot =\n policy.inverse !== undefined &&\n referencesIn(policy.inverse.args).some(\n (reference) => reference === \"$snapshot\" || reference.startsWith(\"$snapshot.\"),\n );\n if (policy.class === \"reversible\" && needsSnapshot && policy.snapshot === undefined) {\n // Without a pre-read such a reversible action is silently irreversible.\n source.fail(path, \"this inverse reads $snapshot, so a snapshot must be declared\");\n }\n if (policy.class === \"readonly\" && policy.snapshot !== undefined) {\n source.fail([...path, \"snapshot\"], \"a readonly tool must not declare a snapshot\");\n }\n\n if (policy.snapshot !== undefined) {\n // The snapshot runs before the forward call, so neither the result nor a\n // snapshot exists yet.\n checkCall(source, [...path, \"snapshot\"], policy.snapshot, servers, [\"$.\"]);\n }\n if (policy.inverse !== undefined) {\n const allowed = [\"$.\", \"$result.\"];\n if (policy.snapshot !== undefined) {\n allowed.push(\"$snapshot.\");\n }\n checkCall(source, [...path, \"inverse\"], policy.inverse, servers, allowed);\n }\n });\n}\n\nfunction withGate(policy: z.infer<typeof toolPolicy>): ToolPolicy {\n // D4: irreversible is gated unless the manifest deliberately says otherwise.\n // `absent_when` in the file, absentWhen in the type: the one place a name is\n // translated, so a single string and a list read the same way afterwards.\n const toCall = (call: {\n tool: string;\n args: Record<string, TemplateValue>;\n absent_when?: string | string[] | undefined;\n }): CallTemplate => ({\n tool: call.tool,\n args: call.args,\n ...(call.absent_when === undefined\n ? {}\n : {\n absentWhen:\n typeof call.absent_when === \"string\" ? [call.absent_when] : [...call.absent_when],\n }),\n });\n\n const gate = policy.gate ?? (policy.class === \"irreversible\" ? \"always\" : \"never\");\n return {\n match: policy.match,\n class: policy.class,\n gate,\n ...(policy.snapshot === undefined ? {} : { snapshot: toCall(policy.snapshot) }),\n ...(policy.inverse === undefined ? {} : { inverse: toCall(policy.inverse) }),\n };\n}\n\nexport function parseManifest(text: string, file: string): Manifest {\n const lines = new LineCounter();\n const doc = parseDocument(text, { lineCounter: lines });\n\n const syntaxError = doc.errors[0];\n if (syntaxError !== undefined) {\n const position = lines.linePos(syntaxError.pos[0]);\n throw new ManifestError(syntaxError.message, {\n file,\n line: position.line,\n column: position.col,\n });\n }\n\n const source = new Source(doc, lines, file);\n const parsed = manifestSchema.safeParse(doc.toJS());\n if (!parsed.success) {\n const issue = parsed.error.issues[0];\n if (issue === undefined) {\n throw new ManifestError(\"manifest failed validation\", source.locate([]));\n }\n const path = issue.path.filter(\n (segment): segment is string | number => typeof segment !== \"symbol\",\n );\n const where = path.length === 0 ? \"\" : `${path.join(\".\")}: `;\n throw new ManifestError(`${where}${issue.message}`, source.locate(path));\n }\n\n const manifest: Manifest = {\n version: parsed.data.version,\n servers: Object.fromEntries(\n Object.entries(parsed.data.servers).map(([name, spec]) => [\n name,\n {\n command: spec.command,\n args: spec.args,\n ...(spec.env === undefined\n ? {}\n : { env: expandEnvironment(source, [\"servers\", name], spec.env) }),\n },\n ]),\n ),\n tools: parsed.data.tools.map(withGate),\n };\n validate(source, manifest);\n return manifest;\n}\n\n/** Node reports a missing file with code ENOENT and no type to narrow on. */\nfunction isMissing(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\nexport function loadManifest(path: string): Manifest {\n let text: string;\n try {\n text = readFileSync(path, \"utf8\");\n } catch (error: unknown) {\n // A policy that is simply not there yet is the commonest way this fails,\n // and it has an answer. Saying only \"ENOENT\" leaves someone who has not\n // run init with no idea that init is the thing that writes this file.\n if (isMissing(error)) {\n throw new ManifestError(\n `there is no policy at ${path}. Write one with: synartesis init <name> -- <the server's command>`,\n );\n }\n throw new ManifestError(`cannot read manifest at ${path}: ${describeCause(error)}`);\n }\n return parseManifest(text, path);\n}\n","import { ManifestError } from \"../errors.js\";\nimport type { TemplateValue } from \"./types.js\";\n\nexport interface TemplateContext {\n readonly args: unknown;\n readonly snapshot?: unknown;\n readonly result?: unknown;\n}\n\nconst NAMESPACES = [\"snapshot\", \"result\"] as const;\n\ninterface Reference {\n readonly namespace: \"args\" | \"snapshot\" | \"result\";\n readonly path: string;\n}\n\n/**\n * Three namespaces and dotted paths, nothing else. Spec 3.2 is explicit that\n * the manifest must not become a language: the moment it grows expressions,\n * it stops being writable in fifteen minutes by someone who has never seen it.\n */\nfunction parseReference(raw: string): Reference | undefined {\n if (!raw.startsWith(\"$\")) {\n return undefined;\n }\n // A bare namespace means the whole value. Writing a file back needs the\n // entire captured contents, which is not a field of anything.\n if (raw === \"$\") {\n return { namespace: \"args\", path: \"\" };\n }\n // A namespace may be followed by a dot or straight by a subscript. Servers\n // that answer with a bare list are common -- the memory server's\n // create_entities returns the entities it actually created -- and\n // $result[].name is the only safe thing for its inverse to name.\n if (raw.startsWith(\"$.\") || raw.startsWith(\"$[\")) {\n return { namespace: \"args\", path: raw.slice(raw[1] === \".\" ? 2 : 1) };\n }\n for (const namespace of NAMESPACES) {\n if (raw === `$${namespace}`) {\n return { namespace, path: \"\" };\n }\n const head = `$${namespace}`;\n const after = raw.startsWith(head) ? raw.slice(head.length) : undefined;\n if (after !== undefined && (after.startsWith(\".\") || after.startsWith(\"[\"))) {\n return { namespace, path: after.startsWith(\".\") ? after.slice(1) : after };\n }\n }\n throw new ManifestError(\n `unknown interpolation namespace in ${raw}; expected $., $snapshot. or $result.`,\n );\n}\n\ntype Segment =\n | { readonly kind: \"key\"; readonly key: string }\n | { readonly kind: \"index\"; readonly index: number }\n /** `[]`: apply the rest of the path to every element. */\n | { readonly kind: \"each\" };\n\n/** Splits `items[1].id` and `labels[].name` into their steps. */\nfunction segments(path: string, reference: string): Segment[] {\n const parts: Segment[] = [];\n for (const chunk of path.split(\".\")) {\n const match = /^([^[\\]]*)((?:\\[\\d*\\])*)$/.exec(chunk);\n if (match === null) {\n throw new ManifestError(`malformed path in ${reference}`);\n }\n const [, head = \"\", brackets = \"\"] = match;\n if (head !== \"\") {\n parts.push({ kind: \"key\", key: head });\n }\n for (const bracket of brackets.matchAll(/\\[(\\d*)\\]/g)) {\n const index = bracket[1] ?? \"\";\n parts.push(index === \"\" ? { kind: \"each\" } : { kind: \"index\", index: Number(index) });\n }\n }\n if (parts.length === 0) {\n throw new ManifestError(`empty path in ${reference}`);\n }\n return parts;\n}\n\nfunction walk(current: unknown, parts: readonly Segment[], at: number, reference: string): unknown {\n const segment = parts[at];\n if (segment === undefined) {\n return current;\n }\n if (current === null || current === undefined) {\n throw new ManifestError(`${reference} is unresolvable: nothing to read from`);\n }\n\n switch (segment.kind) {\n case \"each\": {\n if (!Array.isArray(current)) {\n throw new ManifestError(`${reference} is unresolvable: [] needs a list to walk`);\n }\n // Projection, not a transform. It reads the same field from each element\n // and nothing more, which is what an API that returns objects and\n // accepts names needs, and is still only a path.\n return current.map((item) => walk(item, parts, at + 1, reference));\n }\n case \"index\": {\n if (!Array.isArray(current) || segment.index >= current.length) {\n throw new ManifestError(\n `${reference} is unresolvable: index ${String(segment.index)} is absent`,\n );\n }\n return walk(current[segment.index], parts, at + 1, reference);\n }\n case \"key\": {\n if (typeof current !== \"object\" || !(segment.key in current)) {\n throw new ManifestError(`${reference} is unresolvable: ${segment.key} is absent`);\n }\n const next: unknown = Object.getOwnPropertyDescriptor(current, segment.key)?.value;\n return walk(next, parts, at + 1, reference);\n }\n }\n}\n\nfunction read(root: unknown, path: string, reference: string): unknown {\n return walk(root, segments(path, reference), 0, reference);\n}\n\n/**\n * A reference appearing inside a larger string, such as a commit message that\n * names the path it is reverting. Only the dotted forms are recognised here: a\n * bare `$result` in the middle of a sentence is far more likely to be prose\n * than an interpolation.\n */\nconst EMBEDDED =\n /\\$(?:snapshot|result)?\\.[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*|\\[\\d*\\])*/g;\n\nconst ESCAPE = \"\\u0000synartesis-dollar\\u0000\";\n\nfunction stringify(value: unknown): string {\n return typeof value === \"string\" ? value : JSON.stringify(value);\n}\n\nfunction resolveString(raw: string, context: TemplateContext): unknown {\n // A string that is nothing but a reference keeps the referenced value's\n // type. Anything else is text with references substituted into it, which is\n // what people write without being told they can.\n const whole = raw.startsWith(\"$$\") ? undefined : parseReference(raw);\n if (whole !== undefined) {\n return readNamespace(whole, raw, context);\n }\n\n const escaped = raw.split(\"$$\").join(ESCAPE);\n const substituted = escaped.replace(EMBEDDED, (token) => {\n const reference = parseReference(token);\n if (reference === undefined) {\n return token;\n }\n return stringify(readNamespace(reference, token, context));\n });\n return substituted.split(ESCAPE).join(\"$\");\n}\n\nfunction readNamespace(reference: Reference, raw: string, context: TemplateContext): unknown {\n const root = context[reference.namespace];\n if (root === undefined) {\n throw new ManifestError(\n `${raw} refers to ${reference.namespace}, which is not available at this point`,\n );\n }\n return reference.path === \"\" ? root : read(root, reference.path, raw);\n}\n\n/** Array.isArray widens a readonly union to any[]; this keeps the element type. */\nfunction isTemplateArray(value: TemplateValue): value is readonly TemplateValue[] {\n return Array.isArray(value);\n}\n\nexport function resolveTemplate(template: TemplateValue, context: TemplateContext): unknown {\n if (typeof template === \"string\") {\n return resolveString(template, context);\n }\n if (isTemplateArray(template)) {\n return template.map((item) => resolveTemplate(item, context));\n }\n if (template !== null && typeof template === \"object\") {\n return Object.fromEntries(\n Object.entries(template).map(([key, value]) => [key, resolveTemplate(value, context)]),\n );\n }\n return template;\n}\n\n/** Every reference a template contains, used for load-time validation. */\nexport function referencesIn(template: TemplateValue): string[] {\n if (typeof template === \"string\") {\n if (template.startsWith(\"$$\")) {\n return [];\n }\n if (parseReference(template) !== undefined) {\n return [template];\n }\n // Embedded references are validated too, so a namespace that is not\n // available at that point is reported when the manifest loads rather than\n // silently producing the wrong text at run time.\n return template.split(\"$$\").join(ESCAPE).match(EMBEDDED) ?? [];\n }\n if (isTemplateArray(template)) {\n return template.flatMap(referencesIn);\n }\n if (template !== null && typeof template === \"object\") {\n return Object.values(template).flatMap(referencesIn);\n }\n return [];\n}\n","import { z } from \"zod\";\n\nimport { ManifestError } from \"../errors.js\";\nimport type { Upstream } from \"../proxy/upstream.js\";\nimport { splitQualified, type Manifest } from \"./types.js\";\n\nconst listSchema = z.looseObject({\n tools: z.array(z.looseObject({ name: z.string() })),\n nextCursor: z.string().optional(),\n});\n\nasync function toolNames(upstream: Upstream): Promise<Set<string>> {\n const names = new Set<string>();\n let cursor: string | undefined;\n do {\n const page = listSchema.parse(\n await upstream.client.request(\n { method: \"tools/list\", params: cursor === undefined ? {} : { cursor } },\n z.looseObject({}),\n ),\n );\n for (const tool of page.tools) {\n names.add(tool.name);\n }\n cursor = page.nextCursor;\n } while (cursor !== undefined);\n return names;\n}\n\n/**\n * Checks that every tool a policy calls actually exists on the server it names.\n *\n * This cannot be done when the manifest is parsed, because it needs the servers\n * running. It matters because a mistyped snapshot tool is otherwise\n * indistinguishable at run time from the resource simply not being there: both\n * come back as a tool-level error. Catching it at startup keeps that inference\n * safe, and keeps a broken policy from ever serving a request.\n */\nexport async function verifyAgainstServers(\n upstreams: readonly Upstream[],\n manifest: Manifest,\n): Promise<void> {\n const available = new Map<string, Set<string>>();\n for (const upstream of upstreams) {\n available.set(upstream.name, await toolNames(upstream));\n }\n\n const problems: string[] = [];\n const check = (qualified: string, role: string, match: string): void => {\n const target = splitQualified(qualified);\n if (target === undefined) {\n return;\n }\n const names = available.get(target.server);\n if (names === undefined) {\n problems.push(`${match}: its ${role} names server ${target.server}, which is not connected`);\n return;\n }\n if (!names.has(target.tool)) {\n problems.push(\n `${match}: its ${role} calls ${qualified}, which ${target.server} does not expose`,\n );\n }\n };\n\n for (const policy of manifest.tools) {\n if (policy.snapshot !== undefined) {\n check(policy.snapshot.tool, \"snapshot\", policy.match);\n }\n if (policy.inverse !== undefined) {\n check(policy.inverse.tool, \"inverse\", policy.match);\n }\n }\n\n if (problems.length > 0) {\n throw new ManifestError(`the manifest calls tools that do not exist:\\n ${problems.join(\"\\n \")}`);\n }\n}\n","/** The four behaviours from spec 1.4. */\nexport type ToolClass = \"readonly\" | \"reversible\" | \"compensable\" | \"irreversible\";\n\n/**\n * `on_write` is a heuristic for tools whose destructiveness cannot be decided\n * statically, such as a raw SQL runner. The heuristic itself lands with the\n * gate in Phase 5; the manifest only has to carry the intent.\n */\nexport type GateMode = \"always\" | \"on_write\" | \"never\";\n\nexport interface ServerSpec {\n readonly command: string;\n readonly args: readonly string[];\n readonly env?: Readonly<Record<string, string>>;\n}\n\nexport type TemplateValue =\n | string\n | number\n | boolean\n | null\n | readonly TemplateValue[]\n | { readonly [key: string]: TemplateValue };\n\nexport interface CallTemplate {\n /** Qualified as `server.tool`. */\n readonly tool: string;\n readonly args: Readonly<Record<string, TemplateValue>>;\n /**\n * What this server says when the thing is not there, as substrings of its\n * error text. Only meaningful on a snapshot.\n *\n * Without it every failed pre-read has to be read as absence, because the\n * protocol gives no way to tell the two apart -- which means a resource that\n * exists and could not be read is offered for approval as a creation. With\n * it, anything that is not one of these is a failed snapshot and the write\n * is refused outright.\n */\n readonly absentWhen?: readonly string[];\n}\n\nexport interface ToolPolicy {\n readonly match: string;\n readonly class: ToolClass;\n readonly gate: GateMode;\n readonly snapshot?: CallTemplate;\n readonly inverse?: CallTemplate;\n}\n\nexport interface Manifest {\n readonly version: 1;\n readonly servers: Readonly<Record<string, ServerSpec>>;\n readonly tools: readonly ToolPolicy[];\n}\n\n/** Qualified name used everywhere policy is looked up. */\nexport function qualify(server: string, tool: string): string {\n return `${server}.${tool}`;\n}\n\nexport interface QualifiedName {\n readonly server: string;\n readonly tool: string;\n}\n\n/** Splits on the first dot only; tool names may contain further dots. */\nexport function splitQualified(qualified: string): QualifiedName | undefined {\n const dot = qualified.indexOf(\".\");\n if (dot <= 0 || dot === qualified.length - 1) {\n return undefined;\n }\n return { server: qualified.slice(0, dot), tool: qualified.slice(dot + 1) };\n}\n","import { ManifestError } from \"../errors.js\";\nimport type { Manifest } from \"../manifest/types.js\";\nimport type { Upstream } from \"./upstream.js\";\n\n/**\n * A dot cannot be used to namespace tool names: many MCP clients constrain\n * tool names to [A-Za-z0-9_-], and a name the client rejects is a tool the\n * agent cannot call at all.\n */\nexport const SEPARATOR = \"__\";\n\nexport interface Route {\n readonly upstream: Upstream;\n /** The name as the upstream knows it, with any prefix removed. */\n readonly tool: string;\n}\n\nexport interface Router {\n readonly prefixed: boolean;\n readonly upstreams: readonly Upstream[];\n expose(server: string, name: string): string;\n route(exposed: string): Route | undefined;\n byName(server: string): Upstream | undefined;\n}\n\nexport function createRouter(upstreams: readonly Upstream[], manifest: Manifest): Router {\n if (upstreams.length === 0) {\n throw new ManifestError(\"no upstream servers were connected\");\n }\n\n for (const upstream of upstreams) {\n if (!(upstream.name in manifest.servers)) {\n throw new ManifestError(\n `upstream ${upstream.name} is connected but not declared in the manifest`,\n );\n }\n if (upstream.name.includes(SEPARATOR) || upstream.name.includes(\".\")) {\n throw new ManifestError(\n `server name ${upstream.name} may not contain \".\" or \"${SEPARATOR}\"; both are reserved for qualifying tool names`,\n );\n }\n }\n\n const byName = new Map(upstreams.map((upstream) => [upstream.name, upstream]));\n if (byName.size !== upstreams.length) {\n throw new ManifestError(\"two upstreams were connected under the same name\");\n }\n\n // With one server there is nothing to disambiguate, so names pass through\n // untouched and the proxy stays invisible. Adding a second server is an\n // explicit edit to the manifest, so the rename that comes with it is not a\n // surprise; what would be surprising is a name whose meaning depends on\n // which other servers happen to be configured beside it.\n const prefixed = upstreams.length > 1;\n\n // Longest first so that servers named `a` and `a_b` cannot both claim the\n // same exposed name.\n const keys = [...byName.keys()].sort((a, b) => b.length - a.length);\n\n return {\n prefixed,\n upstreams,\n expose(server: string, name: string): string {\n return prefixed ? `${server}${SEPARATOR}${name}` : name;\n },\n route(exposed: string): Route | undefined {\n if (!prefixed) {\n const only = upstreams[0];\n if (only === undefined) {\n return undefined;\n }\n // The qualified name works here too. Guarding one server advertises\n // `write_file` and guarding two advertises `fs__write_file`, so a name\n // written down against one setup was rejected by the other -- and in\n // this direction it was not even rejected: any unknown name routed to\n // the only server, missed the policy written for `fs.write_file`, and\n // was held for a human to approve as something that could not be\n // undone. A read, held for approval, because it was spelled the way\n // the other setup spells it.\n //\n // Only this server's own name is unwrapped; a tool whose real name\n // begins with it would be written `fs.fs__write_file` in the manifest.\n const prefix = `${only.name}${SEPARATOR}`;\n return exposed.startsWith(prefix)\n ? { upstream: only, tool: exposed.slice(prefix.length) }\n : { upstream: only, tool: exposed };\n }\n for (const key of keys) {\n const prefix = `${key}${SEPARATOR}`;\n if (exposed.startsWith(prefix)) {\n const upstream = byName.get(key);\n if (upstream !== undefined) {\n return { upstream, tool: exposed.slice(prefix.length) };\n }\n }\n }\n return undefined;\n },\n byName(server: string): Upstream | undefined {\n return byName.get(server);\n },\n };\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\n\nimport { UpstreamError } from \"../errors.js\";\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport interface UpstreamSpec {\n /** Key the manifest uses to qualify this server's tools, e.g. `crm`. */\n readonly name: string;\n readonly command: string;\n readonly args?: readonly string[];\n readonly env?: Readonly<Record<string, string>>;\n /**\n * Where the server's own stderr goes. The proxy inherits it, so a server\n * that fails to boot says why in the client's logs. The CLI captures it, so\n * that reason can be repeated back in the error rather than shown as a\n * banner: a report for a person should not be interleaved with a server's\n * own logging, but it must not throw away the one line that explains the\n * failure either.\n */\n readonly stderr?: \"inherit\" | \"ignore\" | \"capture\";\n}\n\nexport interface Upstream {\n readonly name: string;\n readonly client: Client;\n /**\n * Start the server again after its transport has died. A single oversized\n * response is enough to close a stdio connection, and without this the\n * proxy stayed connected to nothing for the rest of the session: every call\n * after it failed with \"Not connected\", whatever it was.\n *\n * Absent on an upstream that was not spawned from a command, which has\n * nothing to respawn.\n */\n reconnect?(): Promise<void>;\n close(): Promise<void>;\n}\n\nexport const PROXY_CLIENT_INFO = { name: \"synartesis-proxy\", version: \"0.0.0\" } as const;\n\n/**\n * Whatever a stream has buffered, without asserting it into a shape. The sdk\n * types stderr as Stream, which has no read(); what it hands back is a\n * Readable, and a wrong guess here would be a crash while reporting a crash.\n */\nfunction bufferedText(stream: unknown): string {\n if (typeof stream !== \"object\" || stream === null || !(\"read\" in stream)) {\n return \"\";\n }\n const read: unknown = stream.read;\n if (typeof read !== \"function\") {\n return \"\";\n }\n const chunk: unknown = read.call(stream);\n if (typeof chunk === \"string\") {\n return chunk;\n }\n return Buffer.isBuffer(chunk) ? chunk.toString(\"utf8\") : \"\";\n}\n\n/** The tail of what a server said, tidied for repeating back in one error. */\nfunction lastWords(text: string): string | undefined {\n const lines = text\n .split(\"\\n\")\n .map((line) => line.trimEnd())\n .filter((line) => line.trim() !== \"\");\n const kept = lines.slice(-4).join(\"; \");\n return kept === \"\" ? undefined : kept;\n}\n\nexport async function connectStdioUpstream(spec: UpstreamSpec): Promise<Upstream> {\n const started = await start(spec);\n let current = started;\n return {\n name: spec.name,\n get client(): Client {\n return current.client;\n },\n async reconnect(): Promise<void> {\n // Best effort: the old one is already broken, and failing to close a\n // broken thing must not stop the new one being made.\n await current.client.close().catch(() => undefined);\n current = await start(spec);\n },\n close: async (): Promise<void> => {\n await current.client.close();\n },\n };\n}\n\nasync function start(spec: UpstreamSpec): Promise<{ client: Client }> {\n const wanted = spec.stderr ?? \"inherit\";\n const transport = new StdioClientTransport({\n command: spec.command,\n args: [...(spec.args ?? [])],\n ...(spec.env === undefined ? {} : { env: { ...spec.env } }),\n // \"pipe\" is what the sdk calls it; captured here so a failure can quote it.\n stderr: wanted === \"capture\" ? \"pipe\" : wanted,\n });\n\n const client = new Client({ ...PROXY_CLIENT_INFO });\n let said = \"\";\n try {\n await client.connect(transport);\n } catch (error: unknown) {\n // Read after the failure: the stream is only attached once the child is\n // spawned, and by the time connect rejects the server has already spoken.\n said = bufferedText(transport.stderr);\n const reason = lastWords(said);\n throw new UpstreamError(\n spec.name,\n \"connect\",\n reason === undefined ? error : `${describeError(error)} — the server said: ${reason}`,\n );\n }\n\n return { client };\n}\n","import type { Manifest, ToolPolicy } from \"./types.js\";\n\nexport interface PolicyMatch {\n readonly policy: ToolPolicy;\n /** False when the fail-closed default was synthesised instead of matched. */\n readonly matched: boolean;\n}\n\nexport interface PolicyResolver {\n resolve(qualifiedName: string): PolicyMatch;\n}\n\n/** `*` stands for any run of characters that is not a dot. */\nfunction toRegExp(pattern: string): RegExp {\n const source = pattern\n .split(\"*\")\n .map((literal) => literal.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"))\n .join(\"[^.]*\");\n return new RegExp(`^${source}$`);\n}\n\nfunction literalLength(pattern: string): number {\n return pattern.length - pattern.split(\"*\").length + 1;\n}\n\ninterface CompiledPolicy {\n readonly policy: ToolPolicy;\n readonly test: RegExp;\n readonly specificity: number;\n readonly wildcards: number;\n}\n\n/**\n * D4. An unrecognised tool is irreversible and gated. A silent passthrough on\n * an unknown destructive tool is worse than having no product at all.\n */\nfunction failClosed(qualifiedName: string): ToolPolicy {\n return { match: qualifiedName, class: \"irreversible\", gate: \"always\" };\n}\n\nexport function createPolicyResolver(manifest: Manifest): PolicyResolver {\n const compiled: CompiledPolicy[] = manifest.tools\n .map((policy) => ({\n policy,\n test: toRegExp(policy.match),\n specificity: literalLength(policy.match),\n wildcards: policy.match.split(\"*\").length - 1,\n }))\n // Longest literal wins, ties broken by fewer wildcards. Ordering is a\n // property of the patterns, never of the order they were written in.\n .sort((a, b) => b.specificity - a.specificity || a.wildcards - b.wildcards);\n\n const cache = new Map<string, PolicyMatch>();\n\n return {\n resolve(qualifiedName: string): PolicyMatch {\n const cached = cache.get(qualifiedName);\n if (cached !== undefined) {\n return cached;\n }\n const hit = compiled.find((candidate) => candidate.test.test(qualifiedName));\n const match: PolicyMatch =\n hit === undefined\n ? { policy: failClosed(qualifiedName), matched: false }\n : { policy: hit.policy, matched: true };\n cache.set(qualifiedName, match);\n return match;\n },\n };\n}\n","import { z } from \"zod\";\n\nimport { ManifestError, SnapshotError, describe } from \"../errors.js\";\nimport { resolveTemplate, type TemplateContext } from \"../manifest/template.js\";\nimport { splitQualified, type CallTemplate } from \"../manifest/types.js\";\nimport type { Router } from \"./routing.js\";\n\n/**\n * What a read saw. Absence is a real state, not a failure: after a successful\n * delete the record is gone, and that is precisely the post-state Phase 4 has\n * to compare against.\n */\nexport type StateObservation = { readonly present: true; readonly value: unknown } | { readonly present: false };\n\n/** A fully resolved call, carrying literal values only (D5). */\nexport interface InversePlan {\n readonly server: string;\n readonly tool: string;\n readonly args: Record<string, unknown>;\n}\n\nconst ToolResult = z.looseObject({\n isError: z.boolean().default(false),\n content: z.array(z.looseObject({ type: z.string() })).default([]),\n});\n\n/**\n * The message an upstream sent when it refused a call, or undefined when it\n * did not refuse.\n *\n * A tool-level error arrives as an ordinary successful response carrying\n * `isError`, so nothing on the forward path notices it unless it looks. It\n * means the server received the call, understood it, and did not do it, which\n * is the same reading `runRead` gives a refused pre-read and `executeInverse`\n * gives a refused inverse.\n */\nexport function refusal(result: unknown): string | undefined {\n const parsed = ToolResult.safeParse(result);\n if (!parsed.success || !parsed.data.isError) {\n return undefined;\n }\n const said = parsed.data.content\n .map((block) => (typeof block[\"text\"] === \"string\" ? block[\"text\"] : \"\"))\n .filter((text) => text !== \"\")\n .join(\" \");\n return said === \"\" ? JSON.stringify(result) : said;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * The logical value a tool returned, rather than its MCP envelope. Manifests\n * say `$snapshot.plan`, not `$snapshot.content[0].text`, so the envelope has to\n * be unwrapped before interpolation sees it.\n */\nexport function toPayload(result: unknown): unknown {\n if (!isRecord(result)) {\n return result;\n }\n const structured = result[\"structuredContent\"];\n if (structured !== undefined) {\n return structured;\n }\n const content = result[\"content\"];\n if (Array.isArray(content) && content.length === 1) {\n const block: unknown = content[0];\n if (isRecord(block) && block[\"type\"] === \"text\" && typeof block[\"text\"] === \"string\") {\n const text = block[\"text\"];\n try {\n return JSON.parse(text) as unknown;\n } catch {\n // Not every server returns json. The raw text is still the payload.\n return text;\n }\n }\n }\n return result;\n}\n\nfunction resolveArgs(call: CallTemplate, context: TemplateContext): Record<string, unknown> {\n const resolved = resolveTemplate(call.args, context);\n if (!isRecord(resolved)) {\n throw new ManifestError(`${call.tool} resolved to arguments that are not an object`);\n }\n return resolved;\n}\n\n/**\n * Resolves the inverse while the run is still in progress (D5). At rollback\n * time the upstream may have drifted and the old value may no longer be\n * readable anywhere.\n */\nexport function planInverse(call: CallTemplate, context: TemplateContext): InversePlan {\n const target = splitQualified(call.tool);\n if (target === undefined) {\n throw new ManifestError(`inverse tool ${call.tool} is not qualified as server.tool`);\n }\n return { server: target.server, tool: target.tool, args: resolveArgs(call, context) };\n}\n\n/** The snapshot read with its arguments already reduced to literals. */\nexport interface ResolvedRead {\n readonly server: string;\n readonly tool: string;\n readonly args: Record<string, unknown>;\n /** What this server's error says when the thing is simply not there. */\n readonly absentWhen?: readonly string[];\n}\n\n/**\n * Resolves a declared pre-read against the current context. Stored on the\n * action so that drift can be checked later without consulting a manifest\n * that may have been edited in the meantime.\n */\nexport function planRead(call: CallTemplate, context: TemplateContext): ResolvedRead {\n const target = splitQualified(call.tool);\n if (target === undefined) {\n throw new SnapshotError(call.tool, \"the snapshot tool is not qualified as server.tool\");\n }\n try {\n return {\n server: target.server,\n tool: target.tool,\n args: resolveArgs(call, context),\n ...(call.absentWhen === undefined ? {} : { absentWhen: call.absentWhen }),\n };\n } catch (error: unknown) {\n throw new SnapshotError(call.tool, describe(error), { cause: error });\n }\n}\n\n/**\n * Runs a resolved pre-read. Deliberately not journalled: this is the proxy's\n * own traffic, and recording it would bury the actions an operator needs.\n */\n/**\n * Whether an error says the connection is gone rather than that the call was\n * refused. Matched on the message because the sdk reports both of these as\n * plain errors with no code to tell them apart.\n */\nexport function isDisconnected(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return message.includes(\"Not connected\") || message.includes(\"Connection closed\");\n}\n\n/**\n * Whether the call may already have arrived. The sdk says \"Not connected\" when\n * there was no transport to write to, which means it was never sent; it says\n * \"Connection closed\" when the transport went while a reply was still owed,\n * which says nothing at all about whether the far end acted on it.\n */\nexport function mayHaveArrived(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return message.includes(\"Connection closed\");\n}\n\nexport async function runRead(\n router: Router,\n read: ResolvedRead,\n signal: AbortSignal,\n): Promise<unknown> {\n const label = `${read.server}.${read.tool}`;\n const upstream = router.byName(read.server);\n if (upstream === undefined) {\n throw new SnapshotError(label, `server ${read.server} is not connected`);\n }\n const { tool, args } = read;\n\n const ask = (): Promise<unknown> =>\n upstream.client.request(\n { method: \"tools/call\", params: { name: tool, arguments: args } },\n z.looseObject({}),\n { signal },\n );\n\n let raw: unknown;\n try {\n raw = await ask();\n } catch (error: unknown) {\n // A single oversized response closes a stdio connection, and every call\n // after it -- reads, writes, anything -- then failed with \"Not connected\"\n // for the rest of the session: one large file bricked the run. Reading is\n // safe to do again, so the server is started back up and asked once more.\n if (!isDisconnected(error) || upstream.reconnect === undefined) {\n throw new SnapshotError(label, describe(error), { cause: error });\n }\n try {\n await upstream.reconnect();\n raw = await ask();\n } catch (retry: unknown) {\n // The second attempt can kill the connection the same way the first did\n // -- the response is still too large -- so leave a live one behind. The\n // call that caused it fails either way; the rest of the session should\n // not have to.\n if (isDisconnected(retry)) {\n await upstream.reconnect().catch(() => undefined);\n }\n // Twice, the same way, on a fresh connection: the request is fine and\n // the reply is what cannot be carried. Saying so is the difference\n // between a diagnosis and a shrug, because nothing else about\n // \"Connection closed\" points at the size of a file.\n const twice = isDisconnected(error) && isDisconnected(retry);\n throw new SnapshotError(\n label,\n twice\n ? `the connection to ${read.server} closed while reading, and again on a fresh one. ` +\n `A reply too large to carry does this: if the resource is more than a few megabytes, ` +\n `it cannot be snapshotted, and a write that cannot be snapshotted is refused rather than risked.`\n : `${describe(error)} (the connection to ${read.server} was restarted and the read failed again: ${describe(retry)})`,\n { cause: retry },\n );\n }\n }\n\n const parsed = ToolResult.safeParse(raw);\n if (parsed.success && parsed.data.isError) {\n // A tool-level error is a failed read either way: whatever the write is\n // about to overwrite, we did not capture it. What it means is the\n // question. Where the policy says what absence looks like on this server,\n // anything else is a failure and the write is refused rather than offered\n // for approval as a creation. Where it says nothing, every error has to be\n // read as absence, because the protocol gives no way to tell.\n const said = JSON.stringify(raw);\n const absent =\n read.absentWhen === undefined ||\n read.absentWhen.some((phrase) => said.toLowerCase().includes(phrase.toLowerCase()));\n throw new SnapshotError(label, `the read reported an error: ${said}`, { absent });\n }\n return toPayload(raw);\n}\n\n/**\n * The post-write read. Unlike the pre-read, a tool-level error here is\n * meaningful rather than fatal: the same read with the same arguments\n * succeeded moments earlier, so an error now says the resource is gone, which\n * is exactly what a delete is supposed to produce. Transport and protocol\n * failures still throw, because those say nothing about the resource.\n */\nexport async function observeState(\n router: Router,\n read: ResolvedRead,\n signal: AbortSignal,\n): Promise<StateObservation> {\n try {\n return { present: true, value: await runRead(router, read, signal) };\n } catch (error: unknown) {\n if (error instanceof SnapshotError && error.absent) {\n return { present: false };\n }\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,YAAY,iBAAiB;AACtC,SAAS,UAAU,WAAW,YAAY;AAC1C,SAAS,qBAAqB;AAS9B,SAAS,OAAO,SAA0B;AACxC,QAAM,QAAQ,QAAQ,IAAI,MAAM,KAAK,IAAI,MAAM,SAAS,EAAE,OAAO,CAAC,QAAQ,QAAQ,EAAE;AACpF,SAAO,KAAK,KAAK,CAAC,QAAQ;AACxB,QAAI;AACF,iBAAW,KAAK,KAAK,OAAO,GAAG,UAAU,IAAI;AAC7C,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACH;AAEA,IAAI;AAEG,SAAS,aAAqB;AACnC,MAAI,WAAW,QAAW;AACxB,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,QAAQ,KAAK,CAAC;AAChC,MAAI,cAAc,UAAa,SAAS,SAAS,MAAM,cAAc;AACnE,aAAS;AACT,WAAO;AAAA,EACT;AACA,MAAI,OAAO,YAAY,GAAG;AACxB,aAAS;AACT,WAAO;AAAA,EACT;AAGA,WAAS,QAAQ,aAAa,aAAa;AAC3C,SAAO;AACT;AAMO,SAAS,eAAe,WAA2B;AACxD,MAAI,OAAO,YAAY,GAAG;AACxB,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,cAAc,IAAI,IAAI,UAAU,SAAS,CAAC,CAAC;AAC5D;AAWO,SAAS,eAAuB;AACrC,MAAI,OAAO,YAAY,GAAG;AACxB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,kBAAkB,GAAG;AAC9B,WAAO;AAAA,EACT;AACA,QAAM,YAAY,QAAQ,KAAK,CAAC;AAChC,MAAI,cAAc,UAAa,UAAU,SAAS,QAAQ,GAAG;AAC3D,WAAO,QAAQ,SAAS;AAAA,EAC1B;AACA,SAAO,QAAQ,cAAc,IAAI,IAAI,UAAU,YAAY,GAAG,CAAC,CAAC;AAClE;;;AC9EA,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,SAAS,QAAAA,OAAM,eAAe;AAiBhC,IAAM,gBAAgB;AACtB,IAAM,eAAe;AAC5B,IAAM,iBAAiBA,MAAK,eAAe,YAAY;AAGhD,SAAS,OAAe;AAC7B,SAAO,QAAQ,IAAI,iBAAiB,KAAKA,MAAK,QAAQ,GAAG,aAAa;AACxE;AAEA,SAAS,OAAO,MAAc,MAAkC;AAC9D,MAAI,MAAM,QAAQ,IAAI;AACtB,aAAS;AACP,UAAM,YAAYA,MAAK,KAAK,IAAI;AAChC,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO;AAAA,IACT;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,KAAK;AAClB,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AAEO,SAAS,aAAa,OAAwB;AACnD,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,SAAO,OAAO,QAAQ,IAAI,GAAG,aAAa,KAAKA,MAAK,KAAK,GAAG,aAAa;AAC3E;AAOO,SAAS,YAAY,OAAgB,UAA2B;AACrE,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,aAAa,SAAY,SAAY,QAAQ,QAAQ,QAAQ,CAAC;AAC3E,aAAW,OAAO,CAAC,MAAM,QAAQ,IAAI,CAAC,GAAG;AACvC,QAAI,QAAQ,QAAW;AACrB;AAAA,IACF;AACA,eAAW,QAAQ,CAAC,cAAc,cAAc,GAAG;AACjD,YAAM,YAAYA,MAAK,KAAK,IAAI;AAChC,UAAI,WAAW,SAAS,GAAG;AACzB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,OAAO,QAAQ,IAAI,GAAG,cAAc,KAAK,OAAO,QAAQ,IAAI,GAAG,YAAY;AACzF,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AAIA,SAAO,SAAS,SAAYA,MAAK,KAAK,GAAG,YAAY,IAAIA,MAAK,MAAM,YAAY;AAClF;;;ACzEA,IAAM,MAAM;AACZ,IAAM,SAAS,GAAG,GAAG;AAGrB,IAAM,YAAY,GAAG,GAAG,iBAAiB,GAAG;AAC5C,IAAM,SAAS,GAAG,GAAG;AACrB,IAAM,MAAM,GAAG,GAAG;AAClB,IAAM,OAAO,GAAG,GAAG;AACnB,IAAM,QAAQ,GAAG,GAAG;AAMpB,IAAM,UACJ,QAAQ,IAAI,UAAU,MAAM,UAC5B,QAAQ,IAAI,MAAM,MAAM,UACxB,QAAQ,OAAO;AAEjB,SAAS,MAAM,OAAe,MAAsB;AAClD,SAAO,UAAU,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,KAAK;AAC/C;AAOO,SAAS,OAAO,MAAsB;AAC3C,SAAO,MAAM,KAAK,IAAI,EAAE,KAAK,GAAG;AAClC;AAEO,IAAM,QAAQ;AAAA;AAAA,EAEnB,OAAO,CAAC,SAAyB,MAAM,SAAS,KAAK,OAAO,KAAK,YAAY,CAAC,CAAC;AAAA,EAC/E,SAAS,CAAC,SAAyB,MAAM,SAAS,MAAM,KAAK,YAAY,CAAC;AAAA,EAC1E,QAAQ,CAAC,SAAyB,MAAM,QAAQ,IAAI;AAAA,EACpD,QAAQ,CAAC,SAAyB,MAAM,MAAM,IAAI;AAAA,EAClD,OAAO,CAAC,SAAyB,MAAM,KAAK,IAAI;AAAA;AAAA,EAEhD,OAAO,CAAC,SAAyB,MAAM,YAAY,MAAM,IAAI,IAAI,GAAG;AACtE;AAEO,IAAM,WAAW,OAAO,YAAY;AAOpC,SAAS,QAAQ,OAAuB;AAC7C,QAAM,OAAO;AACb,SAAO,KAAK,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK;AAChF;AAGO,SAAS,KAAK,QAAQ,IAAY;AACvC,SAAO,MAAM,MAAM,QAAQ,KAAK,CAAC;AACnC;AAMO,IAAM,QAAQ,OAAO,8DAA8D;AACnF,IAAM,UAAU;AAChB,IAAM,UAAU;AAGhB,SAAS,OAAe;AAC7B,SAAO;AAAA,IAAO,MAAM,MAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,OAAO,CAAC;AAAA;AAAA;AAC9D;AAEO,SAAS,SAAiB;AAC/B,SAAO;AAAA,IACL;AAAA,IACA,KAAK,MAAM,MAAM,QAAQ,CAAC;AAAA,IAC1B,KAAK,MAAM,OAAO,QAAQ,EAAE,CAAC,CAAC;AAAA,IAC9B;AAAA,IACA,KAAK,MAAM,MAAM,KAAK,CAAC,KAAK,MAAM,MAAM,MAAQ,CAAC,KAAK,MAAM,MAAM,OAAO,CAAC;AAAA,IAC1E;AAAA,IACA,KAAK,MAAM,OAAO,OAAO,QAAQ,YAAY,CAAC,CAAC,CAAC;AAAA,IAChD,KAAK,MAAM,MAAM,qDAAqD,CAAC;AAAA,IACvE;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAUO,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AACF;;;AC1GA,SAAS,WAAW,cAAAC,aAAY,iBAAiB;AACjD,SAAS,WAAAC,gBAAe;AAExB,OAAO,cAAc;AACrB,SAAS,SAAS;;;ACKX,SAAS,UAAU,OAAwB;AAChD,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,IAAI,MAAM,IAAI,SAAS,EAAE,KAAK,GAAG,CAAC;AAAA,EAC3C;AACA,QAAM,UAAU,OAAO,QAAQ,KAAK,EACjC,OAAO,CAAC,CAAC,EAAE,IAAI,MAAM,SAAS,MAAS,EACvC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAE;AAClD,SAAO,IAAI,QAAQ,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,GAAG,KAAK,UAAU,GAAG,CAAC,IAAI,UAAU,IAAI,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AAChG;;;ACJO,IAAM,iBAAiB;AAEvB,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AFHnB,IAAM,iBAAiB;AAiF9B,IAAM,YAAY,EAAE,OAAO;AAAA,EACzB,IAAI,EAAE,OAAO;AAAA,EACb,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,YAAY,EAAE,OAAO;AAAA,EACrB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,QAAQ,EAAE,KAAK,CAAC,UAAU,YAAY,eAAe,SAAS,CAAC;AACjE,CAAC;AAED,IAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,IAAI,EAAE,OAAO;AAAA,EACb,QAAQ,EAAE,OAAO;AAAA,EACjB,KAAK,EAAE,OAAO;AAAA,EACd,QAAQ,EAAE,OAAO;AAAA,EACjB,MAAM,EAAE,OAAO;AAAA,EACf,WAAW,EAAE,OAAO;AAAA,EACpB,OAAO,EAAE,KAAK,CAAC,gBAAgB,YAAY,cAAc,eAAe,cAAc,CAAC;AAAA,EACvF,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,oBAAoB,EAAE,OAAO,EAAE,SAAS;AAAA,EACxC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,iBAAiB,EAAE,OAAO;AAAA,EAC1B,QAAQ,EAAE,KAAK;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,IAAI,EAAE,OAAO;AACf,CAAC;AAED,SAAS,OAAO,OAA+B;AAC7C,SAAO,UAAU,OAAO,SAAa,KAAK,MAAM,KAAK;AACvD;AAEA,SAAS,YAAY,OAA0C;AAC7D,SAAO,UAAU,OAAO,SAAY;AACtC;AAEA,SAAS,MAAM,KAAsB;AACnC,QAAM,MAAM,UAAU,MAAM,GAAG;AAC/B,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,OAAO,YAAY,IAAI,KAAK;AAAA,IAC5B,WAAW,IAAI;AAAA,IACf,SAAS,YAAY,IAAI,QAAQ;AAAA,IACjC,QAAQ,IAAI;AAAA,EACd;AACF;AAEA,SAAS,SAAS,KAAyB;AACzC,QAAM,MAAM,aAAa,MAAM,GAAG;AAClC,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,OAAO,IAAI;AAAA,IACX,KAAK,IAAI;AAAA,IACT,QAAQ,IAAI;AAAA,IACZ,MAAM,IAAI;AAAA,IACV,MAAM,OAAO,IAAI,SAAS;AAAA,IAC1B,OAAO,IAAI;AAAA,IACX,UAAU,OAAO,IAAI,aAAa;AAAA,IAClC,cAAc,OAAO,IAAI,kBAAkB;AAAA,IAC3C,QAAQ,OAAO,IAAI,WAAW;AAAA,IAC9B,SAAS,OAAO,IAAI,YAAY;AAAA,IAChC,QAAQ,OAAO,IAAI,WAAW;AAAA,IAC9B,OAAO,YAAY,IAAI,KAAK;AAAA,IAC5B,gBAAgB,IAAI;AAAA,IACpB,QAAQ,IAAI;AAAA,IACZ,YAAY,YAAY,IAAI,WAAW;AAAA,IACvC,YAAY,YAAY,IAAI,WAAW;AAAA,IACvC,IAAI,IAAI;AAAA,EACV;AACF;AAkIA,SAAS,gBAAgB,MAAoB;AAI3C,aAAW,QAAQ,CAAC,MAAM,GAAG,IAAI,QAAQ,GAAG,IAAI,MAAM,GAAG;AACvD,QAAI;AACF,UAAIC,YAAW,IAAI,GAAG;AACpB,kBAAU,MAAM,GAAK;AAAA,MACvB;AAAA,IACF,QAAQ;AAAA,IAIR;AAAA,EACF;AACF;AAOA,SAAS,aAAa,MAAiC;AACrD,MAAI;AACF,UAAM,KAAK,IAAI,SAAS,IAAI;AAG5B,QAAI,SAAS,YAAY;AACvB,sBAAgB,IAAI;AAAA,IACtB;AAGA,OAAG,OAAO,oBAAoB;AAC9B,OAAG,OAAO,mBAAmB;AAO7B,OAAG,OAAO,qBAAqB;AAG/B,QAAI,SAAS,YAAY;AACvB,sBAAgB,IAAI;AAAA,IACtB;AACA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,QAAI,OAAO,SAAS,gBAAgB,GAAG;AACrC,YAAM,IAAI;AAAA,QACR;AAAA,QACA,GAAG,IAAI;AAAA,MACT;AAAA,IACF;AACA,UAAM,IAAI,aAAa,QAAQ,kBAAkB,IAAI,yBAAyB,MAAM,EAAE;AAAA,EACxF;AACF;AAEA,IAAM,gBAAN,MAAuC;AAAA,EAC5B;AAAA,EAET,YAAY,MAAc;AACxB,QAAI,SAAS,YAAY;AAGvB,gBAAUC,SAAQ,IAAI,GAAG,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAAA,IAC3D;AAMA,SAAK,MAAM,aAAa,IAAI;AAE5B,UAAM,WAAW,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,OAAO,gBAAgB,EAAE,QAAQ,KAAK,CAAC,CAAC;AACnF,UAAM,YACJ,EACG,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAC5B;AAAA,MACC,KAAK,IACF,QAAQ,oFAAoF,EAC5F,IAAI;AAAA,IACT,EAAE,QAAQ;AACd,QAAI,aAAa,aAAa,gBAAgB;AAG5C,YAAM,IAAI;AAAA,QACR;AAAA,QACA,cAAc,IAAI,kCAAkC,OAAO,QAAQ,CAAC,4BAA4B,OAAO,cAAc,CAAC;AAAA,MAExH;AAAA,IACF;AAEA,SAAK,IAAI,KAAK,UAAU;AACxB,SAAK,IAAI,OAAO,kBAAkB,OAAO,cAAc,CAAC,EAAE;AAAA,EAC5D;AAAA,EAEA,SAAS,OAAmC;AAC1C,UAAM,KAAK,OAAO,WAAW;AAC7B,SAAK,KAAK,YAAY,MAAM;AAC1B,WAAK,IACF,QAAQ,6EAA6E,EACrF,IAAI,IAAI,SAAS,OAAM,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,IACpD,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,OAAe,QAAyB;AAC7C,SAAK,KAAK,UAAU,MAAM;AACxB,WAAK,IACF,QAAQ,uDAAuD,EAC/D,KAAI,oBAAI,KAAK,GAAE,YAAY,GAAG,QAAQ,KAAK;AAAA,IAChD,CAAC;AAAA,EACH;AAAA,EAEA,kBAAkB,OAAwB;AACxC,WAAO,KAAK,KAAK,qBAAqB,MAAM;AAC1C,YAAM,OAAO,EACV,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EACpC;AAAA,QACC,KAAK,IACF,QAAQ,oDAAoD,EAC5D,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK;AAAA,MAC9B,EAAE;AACJ,YAAM,SAAS,KAAK,IACjB,QAAQ,sFAAsF,EAC9F,IAAI,SAAQ,oBAAI,KAAK,GAAE,YAAY,GAAG,KAAK;AAC9C,aAAO,OAAO,YAAY;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,OAAe,OAAqB;AAC9C,SAAK,KAAK,eAAe,MAAM;AAC7B,WAAK,IAAI,QAAQ,wCAAwC,EAAE,IAAI,OAAO,KAAK;AAAA,IAC7E,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,OAA0C;AACtD,WAAO,KAAK,KAAK,iBAAiB,MAAM;AACtC,YAAM,SAAS,KAAK,IAAI,YAAY,MAAqB;AACvD,cAAM,OAAO,KAAK,IACf,QAAQ,uEAAuE,EAC/E,IAAI,MAAM,KAAK;AAClB,cAAM,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,IAAI,EAAE;AACtD,cAAM,WAAW,OAAO,WAAW;AAGnC,cAAM,iBAAiB,GAAG,MAAM,KAAK,IAAI,OAAO,GAAG,CAAC;AAEpD,aAAK,IACF;AAAA,UACC;AAAA;AAAA;AAAA,QAGF,EACC;AAAA,UACC;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,MAAM;AAAA,UACN,MAAM;AAAA,UACN,KAAK,UAAU,MAAM,QAAQ,CAAC,CAAC;AAAA,UAC/B,MAAM;AAAA,UACN;AAAA,WACA,oBAAI,KAAK,GAAE,YAAY;AAAA,QACzB;AAEF,eAAO,EAAE,UAAU,KAAK,eAAe;AAAA,MACzC,CAAC;AAMD,aAAO,OAAO,UAAU;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEA,eAAe,UAAkB,UAAyB;AACxD,SAAK,KAAK,kBAAkB,MAAM;AAChC,WAAK,IACF,QAAQ,mDAAmD,EAC3D,IAAI,KAAK,UAAU,YAAY,IAAI,GAAG,QAAQ;AAAA,IACnD,CAAC;AAAA,EACH;AAAA,EAEA,YAAY,UAAkB,SAA+B;AAC3D,SAAK,KAAK,eAAe,MAAM;AAC7B,WAAK,IACF;AAAA,QACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQF,EACC;AAAA,QACC,KAAK,UAAU,QAAQ,UAAU,IAAI;AAAA,QACrC,QAAQ,YAAY,SAAY,OAAO,KAAK,UAAU,QAAQ,OAAO;AAAA,QACrE,QAAQ,WAAW,SAAY,OAAO,KAAK,UAAU,QAAQ,MAAM;AAAA,QACnE,QAAQ,iBAAiB,SAAY,OAAO,KAAK,UAAU,QAAQ,YAAY;AAAA,QAC/E,QAAQ,WAAW;AAAA,QACnB;AAAA,MACF;AAAA,IACJ,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,UAAkB,OAAqB;AAChD,SAAK,KAAK,cAAc,MAAM;AAC5B,WAAK,IACF,QAAQ,8DAA8D,EACtE,IAAI,OAAO,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,UAAkB,OAAqB;AACjD,SAAK,KAAK,eAAe,MAAM;AAC7B,WAAK,IACF,QAAQ,+DAA+D,EACvE,IAAI,OAAO,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,gBAAgB,UAA2B;AACzC,WAAO,KAAK,KAAK,mBAAmB,MAAM;AAKxC,YAAM,SAAS,KAAK,IACjB,QAAQ,gFAAgF,EACxF,IAAI,QAAQ;AACf,aAAO,OAAO,YAAY;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,eAAe,UAAwB;AACrC,SAAK,KAAK,kBAAkB,MAAM;AAChC,WAAK,IAAI,QAAQ,wDAAwD,EAAE,IAAI,QAAQ;AAAA,IACzF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,oBAAoB,UAAkB,OAAqB;AACzD,SAAK,KAAK,uBAAuB,MAAM;AACrC,WAAK,IACF,QAAQ,+DAA+D,EACvE,IAAI,OAAO,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,UAAkB,OAAqB;AACxD,SAAK,KAAK,sBAAsB,MAAM;AACpC,WAAK,IACF,QAAQ,oEAAoE,EAC5E,IAAI,OAAO,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,UAAkB,KAAoB;AAC9C,SAAK,KAAK,aAAa,MAAM;AAC3B,WAAK,IACF,QAAQ,6DAA6D,EACrE,IAAI,OAAO,MAAM,QAAQ;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,UAAwB;AACnC,SAAK,KAAK,gBAAgB,MAAM;AAC9B,WAAK,IAAI,QAAQ,oDAAoD,EAAE,IAAI,QAAQ;AAAA,IACrF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,UAAkB,IAAqB;AAC7C,WAAO,KAAK,KAAK,WAAW,MAAM;AAChC,YAAM,SAAS,KAAK,IACjB;AAAA,QACC;AAAA;AAAA,MAEF,EACC,IAAI,KAAI,oBAAI,KAAK,GAAE,YAAY,GAAG,QAAQ;AAC7C,aAAO,OAAO,YAAY;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,KAAK,UAAkB,IAAwB,QAAyB;AACtE,WAAO,KAAK,KAAK,QAAQ,MAAM;AAC7B,YAAM,SAAS,KAAK,IACjB;AAAA,QACC;AAAA;AAAA,MAEF,EACC,IAAI,MAAM,OAAM,oBAAI,KAAK,GAAE,YAAY,GAAG,QAAQ,QAAQ;AAC7D,aAAO,OAAO,YAAY;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA,EAEA,eAAe,UAAkB,IAAwB,QAAsB;AAC7E,SAAK,KAAK,kBAAkB,MAAM;AAChC,WAAK,IACF;AAAA,QACC;AAAA,MACF,EACC,IAAI,MAAM,OAAM,oBAAI,KAAK,GAAE,YAAY,GAAG,QAAQ,QAAQ;AAAA,IAC/D,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,UAAkB,SAA0B;AACxD,SAAK,KAAK,iBAAiB,MAAM;AAE/B,YAAM,OAAO,KAAK,IAAI,YAAY,MAAY;AAC5C,aAAK,IACF,QAAQ,kEAAkE,EAC1E,IAAI,QAAQ,cAAc,MAAM,QAAQ,cAAc,MAAM,QAAQ;AACvE,aAAK,IACF,QAAQ,8DAA8D,EACtE,IAAI,GAAG,cAAc,IAAI,QAAQ,IAAI,QAAQ,EAAE;AAAA,MACpD,CAAC;AACD,WAAK,UAAU;AAAA,IACjB,CAAC;AAAA,EACH;AAAA,EAEA,YAAkC;AAChC,WAAO,KAAK;AAAA,MAAK;AAAA,MAAa,MAC5B,KAAK,IAAI,QAAQ,0DAA0D,EAAE,IAAI,EAAE,IAAI,QAAQ;AAAA,IACjG;AAAA,EACF;AAAA,EAEA,aAAa,OAKa;AACxB,WAAO,KAAK,KAAK,gBAAgB,MAAM;AAKrC,YAAM,OAAO,KAAK,IACf;AAAA,QACC;AAAA;AAAA;AAAA;AAAA;AAAA,MAKF,EACC,IAAI,MAAM,QAAQ,MAAM,MAAM,MAAM,SAAS,EAC7C,IAAI,QAAQ;AAKf,YAAM,SAAS,UAAU,MAAM,QAAQ,CAAC,CAAC;AACzC,aAAO,KAAK,KAAK,CAAC,QAAQ,UAAU,IAAI,IAAI,MAAM,MAAM;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,OAKgB;AACxB,WAAO,KAAK,KAAK,aAAa,MAAM;AAIlC,YAAM,OAAO,KAAK,IACf;AAAA,QACC;AAAA;AAAA;AAAA,MAGF,EACC,IAAI,MAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,EACzC,IAAI,QAAQ;AACf,YAAM,SAAS,UAAU,MAAM,QAAQ,CAAC,CAAC;AACzC,aAAO,KAAK,KAAK,CAAC,QAAQ,UAAU,IAAI,IAAI,MAAM,MAAM;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,UAAyC;AACjD,WAAO,KAAK,KAAK,aAAa,MAAM;AAClC,YAAM,MAAM,KAAK,IAAI,QAAQ,oCAAoC,EAAE,IAAI,QAAQ;AAC/E,aAAO,QAAQ,SAAY,SAAY,SAAS,GAAG;AAAA,IACrD,CAAC;AAAA,EACH;AAAA,EAEA,kBAAkB,UAAkB,OAAqB;AACvD,SAAK,KAAK,qBAAqB,MAAM;AACnC,WAAK,IACF,QAAQ,qEAAqE,EAC7E,IAAI,OAAO,QAAQ;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,WAA8B;AAC5B,WAAO,KAAK;AAAA,MAAK;AAAA,MAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAM3B,KAAK,IAAI,QAAQ,+CAA+C,EAAE,IAAI,EAAE,IAAI,KAAK;AAAA;AAAA,IACnF;AAAA,EACF;AAAA,EAEA,OAAO,OAAmC;AACxC,WAAO,KAAK,KAAK,UAAU,MAAM;AAC/B,YAAM,MAAM,KAAK,IAAI,QAAQ,iCAAiC,EAAE,IAAI,KAAK;AACzE,aAAO,QAAQ,SAAY,SAAY,MAAM,GAAG;AAAA,IAClD,CAAC;AAAA,EACH;AAAA,EAEA,WAAW,OAAqC;AAC9C,WAAO,KAAK;AAAA,MAAK;AAAA,MAAc,MAC7B,KAAK,IACF,QAAQ,qDAAqD,EAC7D,IAAI,KAAK,EACT,IAAI,QAAQ;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,cAAc,OAAqC;AACjD,WAAO,KAAK;AAAA,MAAK;AAAA,MAAiB,MAChC,KAAK,IACF,QAAQ,0DAA0D,EAClE,IAAI,KAAK,EACT,IAAI,QAAQ,EACZ,QAAQ;AAAA,IACb;AAAA,EACF;AAAA,EAEA,OAAO,MAAuB;AAC5B,WAAO,KAAK,IAAI,OAAO,MAAM,EAAE,QAAQ,KAAK,CAAC;AAAA,EAC/C;AAAA,EAEA,QAAc;AACZ,SAAK,IAAI,MAAM;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,QAAwC;AACnD,WAAO,KAAK;AAAA,MAAK;AAAA,MAAgB,MAC/B,KAAK,IACF;AAAA;AAAA;AAAA,QAGC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUF,EACC,IAAI,MAAM,EACV;AAAA,QAAI,CAAC,QACJ,EACG,OAAO;AAAA,UACN,IAAI,EAAE,OAAO;AAAA,UACb,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,UAC3B,QAAQ,EAAE,KAAK,CAAC,YAAY,eAAe,SAAS,CAAC;AAAA,UACrD,IAAI,EAAE,OAAO;AAAA,UACb,SAAS,EAAE,OAAO;AAAA,QACpB,CAAC,EACA,MAAM,GAAG;AAAA,MACd,EACC,IAAI,CAAC,SAAS;AAAA,QACb,IAAI,IAAI;AAAA,QACR,OAAO,IAAI,SAAS;AAAA,QACpB,IAAI,IAAI;AAAA,QACR,QAAQ,IAAI;AAAA,QACZ,SAAS,IAAI;AAAA,MACf,EAAE;AAAA,IACN;AAAA,EACF;AAAA,EAEA,WAAW,QAA8D;AACvE,WAAO,KAAK,KAAK,cAAc,MAAM;AACnC,YAAM,SAAS,KAAK,IAAI,YAAY,CAAC,QAA2B;AAC9D,YAAI,OAAO;AACX,YAAI,UAAU;AACd,cAAM,cAAc,KAAK,IAAI,QAAQ,sCAAsC;AAC3E,cAAM,UAAU,KAAK,IAAI,QAAQ,+BAA+B;AAChE,mBAAW,MAAM,KAAK;AAGpB,qBAAW,YAAY,IAAI,EAAE,EAAE;AAC/B,kBAAQ,QAAQ,IAAI,EAAE,EAAE;AAAA,QAC1B;AACA,eAAO,EAAE,MAAM,QAAQ;AAAA,MACzB,CAAC;AAGD,aAAO,OAAO,UAAU,MAAM;AAAA,IAChC,CAAC;AAAA,EACH;AAAA,EAEA,SAAe;AACb,SAAK,KAAK,UAAU,MAAM;AACxB,WAAK,IAAI,KAAK,QAAQ;AAKtB,WAAK,IAAI,OAAO,0BAA0B;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEA,KAAQ,WAAmB,MAAkB;AAC3C,QAAI;AACF,aAAO,KAAK;AAAA,IACd,SAAS,OAAgB;AACvB,YAAM,IAAI,aAAa,WAAW,KAAK;AAAA,IACzC;AAAA,EACF;AACF;AAWO,SAAS,YAAY,MAAc,UAAuB,CAAC,GAAY;AAC5E,MAAI,QAAQ,cAAc,QAAQ,SAAS,cAAc,CAACD,YAAW,IAAI,GAAG;AAC1E,UAAM,IAAI,aAAa,QAAQ,0BAA0B,IAAI,EAAE;AAAA,EACjE;AACA,SAAO,IAAI,cAAc,IAAI;AAC/B;AAOO,SAAS,SAAS,QAA2B;AAClD,SAAO,OAAO,WAAW,aAAa,OAAO,SAAS,IAAI,WAAW,cAAc,IAC/E,SACA,OAAO;AACb;AAEO,SAAS,WAAW,QAA4B;AACrD,SAAO,OAAO,WAAW,mBAAmB,SAAS,MAAM,MAAM;AACnE;;;AGv3BA,SAAS,oBAAoB;AAE7B,SAAS,aAAa,QAAQ,qBAAoC;AAClE,SAAS,KAAAE,UAAS;;;ACMlB,IAAM,aAAa,CAAC,YAAY,QAAQ;AAYxC,SAAS,eAAe,KAAoC;AAC1D,MAAI,CAAC,IAAI,WAAW,GAAG,GAAG;AACxB,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,KAAK;AACf,WAAO,EAAE,WAAW,QAAQ,MAAM,GAAG;AAAA,EACvC;AAKA,MAAI,IAAI,WAAW,IAAI,KAAK,IAAI,WAAW,IAAI,GAAG;AAChD,WAAO,EAAE,WAAW,QAAQ,MAAM,IAAI,MAAM,IAAI,CAAC,MAAM,MAAM,IAAI,CAAC,EAAE;AAAA,EACtE;AACA,aAAW,aAAa,YAAY;AAClC,QAAI,QAAQ,IAAI,SAAS,IAAI;AAC3B,aAAO,EAAE,WAAW,MAAM,GAAG;AAAA,IAC/B;AACA,UAAM,OAAO,IAAI,SAAS;AAC1B,UAAM,QAAQ,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI;AAC9D,QAAI,UAAU,WAAc,MAAM,WAAW,GAAG,KAAK,MAAM,WAAW,GAAG,IAAI;AAC3E,aAAO,EAAE,WAAW,MAAM,MAAM,WAAW,GAAG,IAAI,MAAM,MAAM,CAAC,IAAI,MAAM;AAAA,IAC3E;AAAA,EACF;AACA,QAAM,IAAI;AAAA,IACR,sCAAsC,GAAG;AAAA,EAC3C;AACF;AASA,SAAS,SAAS,MAAc,WAA8B;AAC5D,QAAM,QAAmB,CAAC;AAC1B,aAAW,SAAS,KAAK,MAAM,GAAG,GAAG;AACnC,UAAM,QAAQ,4BAA4B,KAAK,KAAK;AACpD,QAAI,UAAU,MAAM;AAClB,YAAM,IAAI,cAAc,qBAAqB,SAAS,EAAE;AAAA,IAC1D;AACA,UAAM,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,IAAI;AACrC,QAAI,SAAS,IAAI;AACf,YAAM,KAAK,EAAE,MAAM,OAAO,KAAK,KAAK,CAAC;AAAA,IACvC;AACA,eAAW,WAAW,SAAS,SAAS,YAAY,GAAG;AACrD,YAAM,QAAQ,QAAQ,CAAC,KAAK;AAC5B,YAAM,KAAK,UAAU,KAAK,EAAE,MAAM,OAAO,IAAI,EAAE,MAAM,SAAS,OAAO,OAAO,KAAK,EAAE,CAAC;AAAA,IACtF;AAAA,EACF;AACA,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,cAAc,iBAAiB,SAAS,EAAE;AAAA,EACtD;AACA,SAAO;AACT;AAEA,SAAS,KAAK,SAAkB,OAA2B,IAAY,WAA4B;AACjG,QAAM,UAAU,MAAM,EAAE;AACxB,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,EACT;AACA,MAAI,YAAY,QAAQ,YAAY,QAAW;AAC7C,UAAM,IAAI,cAAc,GAAG,SAAS,wCAAwC;AAAA,EAC9E;AAEA,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK,QAAQ;AACX,UAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,cAAM,IAAI,cAAc,GAAG,SAAS,2CAA2C;AAAA,MACjF;AAIA,aAAO,QAAQ,IAAI,CAAC,SAAS,KAAK,MAAM,OAAO,KAAK,GAAG,SAAS,CAAC;AAAA,IACnE;AAAA,IACA,KAAK,SAAS;AACZ,UAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,SAAS,QAAQ,QAAQ;AAC9D,cAAM,IAAI;AAAA,UACR,GAAG,SAAS,2BAA2B,OAAO,QAAQ,KAAK,CAAC;AAAA,QAC9D;AAAA,MACF;AACA,aAAO,KAAK,QAAQ,QAAQ,KAAK,GAAG,OAAO,KAAK,GAAG,SAAS;AAAA,IAC9D;AAAA,IACA,KAAK,OAAO;AACV,UAAI,OAAO,YAAY,YAAY,EAAE,QAAQ,OAAO,UAAU;AAC5D,cAAM,IAAI,cAAc,GAAG,SAAS,qBAAqB,QAAQ,GAAG,YAAY;AAAA,MAClF;AACA,YAAM,OAAgB,OAAO,yBAAyB,SAAS,QAAQ,GAAG,GAAG;AAC7E,aAAO,KAAK,MAAM,OAAO,KAAK,GAAG,SAAS;AAAA,IAC5C;AAAA,EACF;AACF;AAEA,SAAS,KAAK,MAAe,MAAc,WAA4B;AACrE,SAAO,KAAK,MAAM,SAAS,MAAM,SAAS,GAAG,GAAG,SAAS;AAC3D;AAQA,IAAM,WACJ;AAEF,IAAM,SAAS;AAEf,SAAS,UAAU,OAAwB;AACzC,SAAO,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;AACjE;AAEA,SAAS,cAAc,KAAa,SAAmC;AAIrE,QAAM,QAAQ,IAAI,WAAW,IAAI,IAAI,SAAY,eAAe,GAAG;AACnE,MAAI,UAAU,QAAW;AACvB,WAAO,cAAc,OAAO,KAAK,OAAO;AAAA,EAC1C;AAEA,QAAM,UAAU,IAAI,MAAM,IAAI,EAAE,KAAK,MAAM;AAC3C,QAAM,cAAc,QAAQ,QAAQ,UAAU,CAAC,UAAU;AACvD,UAAM,YAAY,eAAe,KAAK;AACtC,QAAI,cAAc,QAAW;AAC3B,aAAO;AAAA,IACT;AACA,WAAO,UAAU,cAAc,WAAW,OAAO,OAAO,CAAC;AAAA,EAC3D,CAAC;AACD,SAAO,YAAY,MAAM,MAAM,EAAE,KAAK,GAAG;AAC3C;AAEA,SAAS,cAAc,WAAsB,KAAa,SAAmC;AAC3F,QAAM,OAAO,QAAQ,UAAU,SAAS;AACxC,MAAI,SAAS,QAAW;AACtB,UAAM,IAAI;AAAA,MACR,GAAG,GAAG,cAAc,UAAU,SAAS;AAAA,IACzC;AAAA,EACF;AACA,SAAO,UAAU,SAAS,KAAK,OAAO,KAAK,MAAM,UAAU,MAAM,GAAG;AACtE;AAGA,SAAS,gBAAgB,OAAyD;AAChF,SAAO,MAAM,QAAQ,KAAK;AAC5B;AAEO,SAAS,gBAAgB,UAAyB,SAAmC;AAC1F,MAAI,OAAO,aAAa,UAAU;AAChC,WAAO,cAAc,UAAU,OAAO;AAAA,EACxC;AACA,MAAI,gBAAgB,QAAQ,GAAG;AAC7B,WAAO,SAAS,IAAI,CAAC,SAAS,gBAAgB,MAAM,OAAO,CAAC;AAAA,EAC9D;AACA,MAAI,aAAa,QAAQ,OAAO,aAAa,UAAU;AACrD,WAAO,OAAO;AAAA,MACZ,OAAO,QAAQ,QAAQ,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,gBAAgB,OAAO,OAAO,CAAC,CAAC;AAAA,IACvF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,aAAa,UAAmC;AAC9D,MAAI,OAAO,aAAa,UAAU;AAChC,QAAI,SAAS,WAAW,IAAI,GAAG;AAC7B,aAAO,CAAC;AAAA,IACV;AACA,QAAI,eAAe,QAAQ,MAAM,QAAW;AAC1C,aAAO,CAAC,QAAQ;AAAA,IAClB;AAIA,WAAO,SAAS,MAAM,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,EAC/D;AACA,MAAI,gBAAgB,QAAQ,GAAG;AAC7B,WAAO,SAAS,QAAQ,YAAY;AAAA,EACtC;AACA,MAAI,aAAa,QAAQ,OAAO,aAAa,UAAU;AACrD,WAAO,OAAO,OAAO,QAAQ,EAAE,QAAQ,YAAY;AAAA,EACrD;AACA,SAAO,CAAC;AACV;;;ADvMA,IAAM,gBAA0CC,GAAE;AAAA,EAAK,MACrDA,GAAE,MAAM;AAAA,IACNA,GAAE,OAAO;AAAA,IACTA,GAAE,OAAO;AAAA,IACTA,GAAE,QAAQ;AAAA,IACVA,GAAE,KAAK;AAAA,IACPA,GAAE,MAAM,aAAa;AAAA,IACrBA,GAAE,OAAOA,GAAE,OAAO,GAAG,aAAa;AAAA,EACpC,CAAC;AACH;AAEA,IAAM,eAAeA,GAAE,aAAa;AAAA,EAClC,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,MAAMA,GAAE,OAAOA,GAAE,OAAO,GAAG,aAAa,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpD,aAAaA,GACV,MAAM,CAACA,GAAE,OAAO,EAAE,IAAI,CAAC,GAAGA,GAAE,MAAMA,GAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAC5D,SAAS;AACd,CAAC;AAED,IAAM,aAAaA,GAAE,aAAa;AAAA,EAChC,OAAOA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,OAAOA,GAAE,KAAK,CAAC,YAAY,cAAc,eAAe,cAAc,CAAC;AAAA,EACvE,MAAMA,GAAE,KAAK,CAAC,UAAU,YAAY,OAAO,CAAC,EAAE,SAAS;AAAA,EACvD,UAAU,aAAa,SAAS;AAAA,EAChC,SAAS,aAAa,SAAS;AACjC,CAAC;AAED,IAAM,aAAaA,GAAE,aAAa;AAAA,EAChC,SAASA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,MAAMA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpC,KAAKA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,OAAO,CAAC,EAAE,SAAS;AACjD,CAAC;AAED,IAAM,iBAAiBA,GAAE,aAAa;AAAA,EACpC,SAASA,GAAE,QAAQ,CAAC;AAAA,EACpB,SAASA,GAAE,OAAOA,GAAE,OAAO,GAAG,UAAU;AAAA,EACxC,OAAOA,GAAE,MAAM,UAAU,EAAE,QAAQ,CAAC,CAAC;AACvC,CAAC;AAID,IAAM,SAAN,MAAa;AAAA,EACX,YACmB,KACA,OACA,MACjB;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAHgB;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAInB,OAAO,MAA4B;AACjC,aAAS,QAAQ,KAAK,QAAQ,SAAS,GAAG,SAAS,GAAG;AACpD,YAAM,OACJ,UAAU,IAAI,KAAK,IAAI,WAAW,KAAK,IAAI,MAAM,KAAK,MAAM,GAAG,KAAK,GAAG,IAAI;AAC7E,YAAM,QAAQ,OAAO,IAAI,IAAI,KAAK,QAAQ;AAC1C,UAAI,SAAS,MAAM;AACjB,cAAM,WAAW,KAAK,MAAM,QAAQ,MAAM,CAAC,CAAC;AAC5C,eAAO,EAAE,MAAM,KAAK,MAAM,MAAM,SAAS,MAAM,QAAQ,SAAS,IAAI;AAAA,MACtE;AAAA,IACF;AACA,WAAO,EAAE,MAAM,KAAK,MAAM,MAAM,GAAG,QAAQ,EAAE;AAAA,EAC/C;AAAA,EAEA,KAAK,MAAY,SAAwB;AACvC,UAAM,IAAI,cAAc,SAAS,KAAK,OAAO,IAAI,CAAC;AAAA,EACpD;AACF;AAaA,IAAM,YAAY;AAElB,SAAS,kBACP,QACA,MACA,KACwB;AACxB,QAAM,WAAmC,CAAC;AAC1C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,aAAS,GAAG,IAAI,MAAM,QAAQ,WAAW,CAAC,OAAO,SAAiB;AAChE,YAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,UAAI,UAAU,QAAW;AACvB,eAAO;AAAA,UACL,CAAC,GAAG,MAAM,OAAO,GAAG;AAAA,UACpB,GAAG,KAAK,2CAA2C,IAAI;AAAA,QACzD;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,SAAS,cAAc,SAAyB;AAC9C,QAAM,MAAM,QAAQ,QAAQ,GAAG;AAC/B,SAAO,QAAQ,KAAK,KAAK,QAAQ,MAAM,GAAG,GAAG;AAC/C;AAEA,SAAS,iBAAiB,SAAiB,SAAqC;AAC9E,MAAI,CAAC,QAAQ,SAAS,GAAG,GAAG;AAC1B,WAAO,QAAQ,SAAS,OAAO;AAAA,EACjC;AACA,QAAM,SAAS,QACZ,MAAM,GAAG,EACT,IAAI,CAAC,YAAY,QAAQ,QAAQ,uBAAuB,MAAM,CAAC,EAC/D,KAAK,OAAO;AACf,QAAM,OAAO,IAAI,OAAO,IAAI,MAAM,GAAG;AACrC,SAAO,QAAQ,KAAK,CAAC,SAAS,KAAK,KAAK,IAAI,CAAC;AAC/C;AAEA,SAAS,UACP,QACA,MACA,MACA,SACA,SACM;AACN,QAAM,UAAU,cAAc,KAAK,IAAI;AACvC,MAAI,YAAY,MAAM,KAAK,KAAK,SAAS,GAAG,GAAG;AAC7C,WAAO,KAAK,CAAC,GAAG,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,mCAAmC;AAAA,EAChF;AACA,MAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,WAAO,KAAK,CAAC,GAAG,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,sCAAsC;AAAA,EACnF;AACA,MAAI,CAAC,QAAQ,SAAS,OAAO,GAAG;AAC9B,WAAO,KAAK,CAAC,GAAG,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,iBAAiB,OAAO,yBAAyB;AAAA,EAC9F;AAEA,aAAW,aAAa,aAAa,KAAK,IAAI,GAAG;AAI/C,UAAM,YAAY,qBAAqB,KAAK,SAAS,IAAI,CAAC,KAAK;AAC/D,UAAM,QAAQ,cAAc,KAAK,OAAO,IAAI,SAAS;AACrD,QAAI,CAAC,QAAQ,SAAS,KAAK,GAAG;AAC5B,aAAO;AAAA,QACL,CAAC,GAAG,MAAM,MAAM;AAAA,QAChB,GAAG,SAAS,SAAS,KAAK,2CAA2C,QAAQ,KAAK,IAAI,CAAC;AAAA,MACzF;AAAA,IACF;AAAA,EACF;AACF;AAOA,SAAS,SAAS,QAAgB,UAA0B;AAC1D,QAAM,UAAU,OAAO,KAAK,SAAS,OAAO;AAC5C,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,KAAK,CAAC,SAAS,GAAG,sCAAsC;AAAA,EACjE;AAEA,QAAM,OAAO,oBAAI,IAAoB;AACrC,WAAS,MAAM,QAAQ,CAAC,QAAQ,UAAU;AACxC,UAAM,OAAa,CAAC,SAAS,KAAK;AAClC,UAAM,WAAW,KAAK,IAAI,OAAO,KAAK;AACtC,QAAI,aAAa,QAAW;AAC1B,aAAO;AAAA,QACL,CAAC,GAAG,MAAM,OAAO;AAAA,QACjB,2BAA2B,OAAO,KAAK,qCAAqC,OAAO,QAAQ,CAAC;AAAA,MAC9F;AAAA,IACF;AACA,SAAK,IAAI,OAAO,OAAO,KAAK;AAE5B,UAAM,UAAU,cAAc,OAAO,KAAK;AAC1C,QAAI,YAAY,IAAI;AAClB,aAAO,KAAK,CAAC,GAAG,MAAM,OAAO,GAAG,GAAG,OAAO,KAAK,mCAAmC;AAAA,IACpF;AACA,QAAI,CAAC,iBAAiB,SAAS,OAAO,GAAG;AACvC,aAAO;AAAA,QACL,CAAC,GAAG,MAAM,OAAO;AAAA,QACjB,GAAG,OAAO,KAAK,iBAAiB,OAAO;AAAA,MACzC;AAAA,IACF;AAEA,UAAM,eAAe,OAAO,UAAU,gBAAgB,OAAO,UAAU;AACvE,QAAI,gBAAgB,OAAO,YAAY,QAAW;AAChD,aAAO,KAAK,MAAM,KAAK,OAAO,KAAK,+BAA+B;AAAA,IACpE;AACA,QAAI,CAAC,gBAAgB,OAAO,YAAY,QAAW;AACjD,aAAO,KAAK,CAAC,GAAG,MAAM,SAAS,GAAG,KAAK,OAAO,KAAK,mCAAmC;AAAA,IACxF;AAKA,UAAM,gBACJ,OAAO,YAAY,UACnB,aAAa,OAAO,QAAQ,IAAI,EAAE;AAAA,MAChC,CAAC,cAAc,cAAc,eAAe,UAAU,WAAW,YAAY;AAAA,IAC/E;AACF,QAAI,OAAO,UAAU,gBAAgB,iBAAiB,OAAO,aAAa,QAAW;AAEnF,aAAO,KAAK,MAAM,8DAA8D;AAAA,IAClF;AACA,QAAI,OAAO,UAAU,cAAc,OAAO,aAAa,QAAW;AAChE,aAAO,KAAK,CAAC,GAAG,MAAM,UAAU,GAAG,6CAA6C;AAAA,IAClF;AAEA,QAAI,OAAO,aAAa,QAAW;AAGjC,gBAAU,QAAQ,CAAC,GAAG,MAAM,UAAU,GAAG,OAAO,UAAU,SAAS,CAAC,IAAI,CAAC;AAAA,IAC3E;AACA,QAAI,OAAO,YAAY,QAAW;AAChC,YAAM,UAAU,CAAC,MAAM,UAAU;AACjC,UAAI,OAAO,aAAa,QAAW;AACjC,gBAAQ,KAAK,YAAY;AAAA,MAC3B;AACA,gBAAU,QAAQ,CAAC,GAAG,MAAM,SAAS,GAAG,OAAO,SAAS,SAAS,OAAO;AAAA,IAC1E;AAAA,EACF,CAAC;AACH;AAEA,SAAS,SAAS,QAAgD;AAIhE,QAAM,SAAS,CAAC,UAIK;AAAA,IACnB,MAAM,KAAK;AAAA,IACX,MAAM,KAAK;AAAA,IACX,GAAI,KAAK,gBAAgB,SACrB,CAAC,IACD;AAAA,MACE,YACE,OAAO,KAAK,gBAAgB,WAAW,CAAC,KAAK,WAAW,IAAI,CAAC,GAAG,KAAK,WAAW;AAAA,IACpF;AAAA,EACN;AAEA,QAAM,OAAO,OAAO,SAAS,OAAO,UAAU,iBAAiB,WAAW;AAC1E,SAAO;AAAA,IACL,OAAO,OAAO;AAAA,IACd,OAAO,OAAO;AAAA,IACd;AAAA,IACA,GAAI,OAAO,aAAa,SAAY,CAAC,IAAI,EAAE,UAAU,OAAO,OAAO,QAAQ,EAAE;AAAA,IAC7E,GAAI,OAAO,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,OAAO,OAAO,OAAO,EAAE;AAAA,EAC5E;AACF;AAEO,SAAS,cAAc,MAAc,MAAwB;AAClE,QAAM,QAAQ,IAAI,YAAY;AAC9B,QAAM,MAAM,cAAc,MAAM,EAAE,aAAa,MAAM,CAAC;AAEtD,QAAM,cAAc,IAAI,OAAO,CAAC;AAChC,MAAI,gBAAgB,QAAW;AAC7B,UAAM,WAAW,MAAM,QAAQ,YAAY,IAAI,CAAC,CAAC;AACjD,UAAM,IAAI,cAAc,YAAY,SAAS;AAAA,MAC3C;AAAA,MACA,MAAM,SAAS;AAAA,MACf,QAAQ,SAAS;AAAA,IACnB,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,IAAI,OAAO,KAAK,OAAO,IAAI;AAC1C,QAAM,SAAS,eAAe,UAAU,IAAI,KAAK,CAAC;AAClD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,QAAQ,OAAO,MAAM,OAAO,CAAC;AACnC,QAAI,UAAU,QAAW;AACvB,YAAM,IAAI,cAAc,8BAA8B,OAAO,OAAO,CAAC,CAAC,CAAC;AAAA,IACzE;AACA,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB,CAAC,YAAwC,OAAO,YAAY;AAAA,IAC9D;AACA,UAAM,QAAQ,KAAK,WAAW,IAAI,KAAK,GAAG,KAAK,KAAK,GAAG,CAAC;AACxD,UAAM,IAAI,cAAc,GAAG,KAAK,GAAG,MAAM,OAAO,IAAI,OAAO,OAAO,IAAI,CAAC;AAAA,EACzE;AAEA,QAAM,WAAqB;AAAA,IACzB,SAAS,OAAO,KAAK;AAAA,IACrB,SAAS,OAAO;AAAA,MACd,OAAO,QAAQ,OAAO,KAAK,OAAO,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM;AAAA,QACxD;AAAA,QACA;AAAA,UACE,SAAS,KAAK;AAAA,UACd,MAAM,KAAK;AAAA,UACX,GAAI,KAAK,QAAQ,SACb,CAAC,IACD,EAAE,KAAK,kBAAkB,QAAQ,CAAC,WAAW,IAAI,GAAG,KAAK,GAAG,EAAE;AAAA,QACpE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,OAAO,OAAO,KAAK,MAAM,IAAI,QAAQ;AAAA,EACvC;AACA,WAAS,QAAQ,QAAQ;AACzB,SAAO;AACT;AAGA,SAAS,UAAU,OAAyB;AAC1C,SACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACT,MAA6B,SAAS;AAE3C;AAEO,SAAS,aAAa,MAAwB;AACnD,MAAI;AACJ,MAAI;AACF,WAAO,aAAa,MAAM,MAAM;AAAA,EAClC,SAAS,OAAgB;AAIvB,QAAI,UAAU,KAAK,GAAG;AACpB,YAAM,IAAI;AAAA,QACR,yBAAyB,IAAI;AAAA,MAC/B;AAAA,IACF;AACA,UAAM,IAAI,cAAc,2BAA2B,IAAI,KAAK,SAAc,KAAK,CAAC,EAAE;AAAA,EACpF;AACA,SAAO,cAAc,MAAM,IAAI;AACjC;;;AEhVA,SAAS,KAAAC,UAAS;;;ACwDX,SAAS,QAAQ,QAAgB,MAAsB;AAC5D,SAAO,GAAG,MAAM,IAAI,IAAI;AAC1B;AAQO,SAAS,eAAe,WAA8C;AAC3E,QAAM,MAAM,UAAU,QAAQ,GAAG;AACjC,MAAI,OAAO,KAAK,QAAQ,UAAU,SAAS,GAAG;AAC5C,WAAO;AAAA,EACT;AACA,SAAO,EAAE,QAAQ,UAAU,MAAM,GAAG,GAAG,GAAG,MAAM,UAAU,MAAM,MAAM,CAAC,EAAE;AAC3E;;;ADlEA,IAAM,aAAaC,GAAE,YAAY;AAAA,EAC/B,OAAOA,GAAE,MAAMA,GAAE,YAAY,EAAE,MAAMA,GAAE,OAAO,EAAE,CAAC,CAAC;AAAA,EAClD,YAAYA,GAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AAED,eAAe,UAAU,UAA0C;AACjE,QAAM,QAAQ,oBAAI,IAAY;AAC9B,MAAI;AACJ,KAAG;AACD,UAAM,OAAO,WAAW;AAAA,MACtB,MAAM,SAAS,OAAO;AAAA,QACpB,EAAE,QAAQ,cAAc,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,OAAO,EAAE;AAAA,QACvEA,GAAE,YAAY,CAAC,CAAC;AAAA,MAClB;AAAA,IACF;AACA,eAAW,QAAQ,KAAK,OAAO;AAC7B,YAAM,IAAI,KAAK,IAAI;AAAA,IACrB;AACA,aAAS,KAAK;AAAA,EAChB,SAAS,WAAW;AACpB,SAAO;AACT;AAWA,eAAsB,qBACpB,WACA,UACe;AACf,QAAM,YAAY,oBAAI,IAAyB;AAC/C,aAAW,YAAY,WAAW;AAChC,cAAU,IAAI,SAAS,MAAM,MAAM,UAAU,QAAQ,CAAC;AAAA,EACxD;AAEA,QAAM,WAAqB,CAAC;AAC5B,QAAM,QAAQ,CAAC,WAAmB,MAAc,UAAwB;AACtE,UAAM,SAAS,eAAe,SAAS;AACvC,QAAI,WAAW,QAAW;AACxB;AAAA,IACF;AACA,UAAM,QAAQ,UAAU,IAAI,OAAO,MAAM;AACzC,QAAI,UAAU,QAAW;AACvB,eAAS,KAAK,GAAG,KAAK,SAAS,IAAI,iBAAiB,OAAO,MAAM,0BAA0B;AAC3F;AAAA,IACF;AACA,QAAI,CAAC,MAAM,IAAI,OAAO,IAAI,GAAG;AAC3B,eAAS;AAAA,QACP,GAAG,KAAK,SAAS,IAAI,UAAU,SAAS,WAAW,OAAO,MAAM;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AAEA,aAAW,UAAU,SAAS,OAAO;AACnC,QAAI,OAAO,aAAa,QAAW;AACjC,YAAM,OAAO,SAAS,MAAM,YAAY,OAAO,KAAK;AAAA,IACtD;AACA,QAAI,OAAO,YAAY,QAAW;AAChC,YAAM,OAAO,QAAQ,MAAM,WAAW,OAAO,KAAK;AAAA,IACpD;AAAA,EACF;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,IAAI,cAAc;AAAA,IAAkD,SAAS,KAAK,MAAM,CAAC,EAAE;AAAA,EACnG;AACF;;;AEpEO,IAAM,YAAY;AAgBlB,SAAS,aAAa,WAAgC,UAA4B;AACvF,MAAI,UAAU,WAAW,GAAG;AAC1B,UAAM,IAAI,cAAc,oCAAoC;AAAA,EAC9D;AAEA,aAAW,YAAY,WAAW;AAChC,QAAI,EAAE,SAAS,QAAQ,SAAS,UAAU;AACxC,YAAM,IAAI;AAAA,QACR,YAAY,SAAS,IAAI;AAAA,MAC3B;AAAA,IACF;AACA,QAAI,SAAS,KAAK,SAAS,SAAS,KAAK,SAAS,KAAK,SAAS,GAAG,GAAG;AACpE,YAAM,IAAI;AAAA,QACR,eAAe,SAAS,IAAI,4BAA4B,SAAS;AAAA,MACnE;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,IAAI,IAAI,UAAU,IAAI,CAAC,aAAa,CAAC,SAAS,MAAM,QAAQ,CAAC,CAAC;AAC7E,MAAI,OAAO,SAAS,UAAU,QAAQ;AACpC,UAAM,IAAI,cAAc,kDAAkD;AAAA,EAC5E;AAOA,QAAM,WAAW,UAAU,SAAS;AAIpC,QAAM,OAAO,CAAC,GAAG,OAAO,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAElE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,QAAgB,MAAsB;AAC3C,aAAO,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,KAAK;AAAA,IACrD;AAAA,IACA,MAAM,SAAoC;AACxC,UAAI,CAAC,UAAU;AACb,cAAM,OAAO,UAAU,CAAC;AACxB,YAAI,SAAS,QAAW;AACtB,iBAAO;AAAA,QACT;AAYA,cAAM,SAAS,GAAG,KAAK,IAAI,GAAG,SAAS;AACvC,eAAO,QAAQ,WAAW,MAAM,IAC5B,EAAE,UAAU,MAAM,MAAM,QAAQ,MAAM,OAAO,MAAM,EAAE,IACrD,EAAE,UAAU,MAAM,MAAM,QAAQ;AAAA,MACtC;AACA,iBAAW,OAAO,MAAM;AACtB,cAAM,SAAS,GAAG,GAAG,GAAG,SAAS;AACjC,YAAI,QAAQ,WAAW,MAAM,GAAG;AAC9B,gBAAM,WAAW,OAAO,IAAI,GAAG;AAC/B,cAAI,aAAa,QAAW;AAC1B,mBAAO,EAAE,UAAU,MAAM,QAAQ,MAAM,OAAO,MAAM,EAAE;AAAA,UACxD;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,OAAO,QAAsC;AAC3C,aAAO,OAAO,IAAI,MAAM;AAAA,IAC1B;AAAA,EACF;AACF;;;ACtGA,SAAS,cAAc;AACvB,SAAS,4BAA4B;AAIrC,SAAS,cAAc,OAAwB;AAC7C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAmCO,IAAM,oBAAoB,EAAE,MAAM,oBAAoB,SAAS,QAAQ;AAO9E,SAAS,aAAa,QAAyB;AAC7C,MAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,EAAE,UAAU,SAAS;AACxE,WAAO;AAAA,EACT;AACA,QAAMC,QAAgB,OAAO;AAC7B,MAAI,OAAOA,UAAS,YAAY;AAC9B,WAAO;AAAA,EACT;AACA,QAAM,QAAiBA,MAAK,KAAK,MAAM;AACvC,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,OAAO,SAAS,KAAK,IAAI,MAAM,SAAS,MAAM,IAAI;AAC3D;AAGA,SAAS,UAAU,MAAkC;AACnD,QAAM,QAAQ,KACX,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC,EAC5B,OAAO,CAAC,SAAS,KAAK,KAAK,MAAM,EAAE;AACtC,QAAM,OAAO,MAAM,MAAM,EAAE,EAAE,KAAK,IAAI;AACtC,SAAO,SAAS,KAAK,SAAY;AACnC;AAEA,eAAsB,qBAAqB,MAAuC;AAChF,QAAM,UAAU,MAAM,MAAM,IAAI;AAChC,MAAI,UAAU;AACd,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,IAAI,SAAiB;AACnB,aAAO,QAAQ;AAAA,IACjB;AAAA,IACA,MAAM,YAA2B;AAG/B,YAAM,QAAQ,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AAClD,gBAAU,MAAM,MAAM,IAAI;AAAA,IAC5B;AAAA,IACA,OAAO,YAA2B;AAChC,YAAM,QAAQ,OAAO,MAAM;AAAA,IAC7B;AAAA,EACF;AACF;AAEA,eAAe,MAAM,MAAiD;AACpE,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,YAAY,IAAI,qBAAqB;AAAA,IACzC,SAAS,KAAK;AAAA,IACd,MAAM,CAAC,GAAI,KAAK,QAAQ,CAAC,CAAE;AAAA,IAC3B,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,EAAE;AAAA;AAAA,IAEzD,QAAQ,WAAW,YAAY,SAAS;AAAA,EAC1C,CAAC;AAED,QAAM,SAAS,IAAI,OAAO,EAAE,GAAG,kBAAkB,CAAC;AAClD,MAAI,OAAO;AACX,MAAI;AACF,UAAM,OAAO,QAAQ,SAAS;AAAA,EAChC,SAAS,OAAgB;AAGvB,WAAO,aAAa,UAAU,MAAM;AACpC,UAAM,SAAS,UAAU,IAAI;AAC7B,UAAM,IAAI;AAAA,MACR,KAAK;AAAA,MACL;AAAA,MACA,WAAW,SAAY,QAAQ,GAAG,cAAc,KAAK,CAAC,4BAAuB,MAAM;AAAA,IACrF;AAAA,EACF;AAEA,SAAO,EAAE,OAAO;AAClB;;;AC5GA,SAAS,SAAS,SAAyB;AACzC,QAAM,SAAS,QACZ,MAAM,GAAG,EACT,IAAI,CAAC,YAAY,QAAQ,QAAQ,uBAAuB,MAAM,CAAC,EAC/D,KAAK,OAAO;AACf,SAAO,IAAI,OAAO,IAAI,MAAM,GAAG;AACjC;AAEA,SAAS,cAAc,SAAyB;AAC9C,SAAO,QAAQ,SAAS,QAAQ,MAAM,GAAG,EAAE,SAAS;AACtD;AAaA,SAAS,WAAW,eAAmC;AACrD,SAAO,EAAE,OAAO,eAAe,OAAO,gBAAgB,MAAM,SAAS;AACvE;AAEO,SAAS,qBAAqB,UAAoC;AACvE,QAAM,WAA6B,SAAS,MACzC,IAAI,CAAC,YAAY;AAAA,IAChB;AAAA,IACA,MAAM,SAAS,OAAO,KAAK;AAAA,IAC3B,aAAa,cAAc,OAAO,KAAK;AAAA,IACvC,WAAW,OAAO,MAAM,MAAM,GAAG,EAAE,SAAS;AAAA,EAC9C,EAAE,EAGD,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS;AAE5E,QAAM,QAAQ,oBAAI,IAAyB;AAE3C,SAAO;AAAA,IACL,QAAQ,eAAoC;AAC1C,YAAMC,UAAS,MAAM,IAAI,aAAa;AACtC,UAAIA,YAAW,QAAW;AACxB,eAAOA;AAAA,MACT;AACA,YAAM,MAAM,SAAS,KAAK,CAAC,cAAc,UAAU,KAAK,KAAK,aAAa,CAAC;AAC3E,YAAM,QACJ,QAAQ,SACJ,EAAE,QAAQ,WAAW,aAAa,GAAG,SAAS,MAAM,IACpD,EAAE,QAAQ,IAAI,QAAQ,SAAS,KAAK;AAC1C,YAAM,IAAI,eAAe,KAAK;AAC9B,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACrEA,SAAS,KAAAC,UAAS;AAqBlB,IAAM,aAAaC,GAAE,YAAY;AAAA,EAC/B,SAASA,GAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EAClC,SAASA,GAAE,MAAMA,GAAE,YAAY,EAAE,MAAMA,GAAE,OAAO,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAClE,CAAC;AAYM,SAAS,QAAQ,QAAqC;AAC3D,QAAM,SAAS,WAAW,UAAU,MAAM;AAC1C,MAAI,CAAC,OAAO,WAAW,CAAC,OAAO,KAAK,SAAS;AAC3C,WAAO;AAAA,EACT;AACA,QAAM,OAAO,OAAO,KAAK,QACtB,IAAI,CAAC,UAAW,OAAO,MAAM,MAAM,MAAM,WAAW,MAAM,MAAM,IAAI,EAAG,EACvE,OAAO,CAAC,SAAS,SAAS,EAAE,EAC5B,KAAK,GAAG;AACX,SAAO,SAAS,KAAK,KAAK,UAAU,MAAM,IAAI;AAChD;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAOO,SAAS,UAAU,QAA0B;AAClD,MAAI,CAAC,SAAS,MAAM,GAAG;AACrB,WAAO;AAAA,EACT;AACA,QAAM,aAAa,OAAO,mBAAmB;AAC7C,MAAI,eAAe,QAAW;AAC5B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAAG;AAClD,UAAM,QAAiB,QAAQ,CAAC;AAChC,QAAI,SAAS,KAAK,KAAK,MAAM,MAAM,MAAM,UAAU,OAAO,MAAM,MAAM,MAAM,UAAU;AACpF,YAAM,OAAO,MAAM,MAAM;AACzB,UAAI;AACF,eAAO,KAAK,MAAM,IAAI;AAAA,MACxB,QAAQ;AAEN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,MAAoB,SAAmD;AAC1F,QAAM,WAAW,gBAAgB,KAAK,MAAM,OAAO;AACnD,MAAI,CAAC,SAAS,QAAQ,GAAG;AACvB,UAAM,IAAI,cAAc,GAAG,KAAK,IAAI,+CAA+C;AAAA,EACrF;AACA,SAAO;AACT;AAOO,SAAS,YAAY,MAAoB,SAAuC;AACrF,QAAM,SAAS,eAAe,KAAK,IAAI;AACvC,MAAI,WAAW,QAAW;AACxB,UAAM,IAAI,cAAc,gBAAgB,KAAK,IAAI,kCAAkC;AAAA,EACrF;AACA,SAAO,EAAE,QAAQ,OAAO,QAAQ,MAAM,OAAO,MAAM,MAAM,YAAY,MAAM,OAAO,EAAE;AACtF;AAgBO,SAAS,SAAS,MAAoB,SAAwC;AACnF,QAAM,SAAS,eAAe,KAAK,IAAI;AACvC,MAAI,WAAW,QAAW;AACxB,UAAM,IAAI,cAAc,KAAK,MAAM,mDAAmD;AAAA,EACxF;AACA,MAAI;AACF,WAAO;AAAA,MACL,QAAQ,OAAO;AAAA,MACf,MAAM,OAAO;AAAA,MACb,MAAM,YAAY,MAAM,OAAO;AAAA,MAC/B,GAAI,KAAK,eAAe,SAAY,CAAC,IAAI,EAAE,YAAY,KAAK,WAAW;AAAA,IACzE;AAAA,EACF,SAAS,OAAgB;AACvB,UAAM,IAAI,cAAc,KAAK,MAAM,SAAS,KAAK,GAAG,EAAE,OAAO,MAAM,CAAC;AAAA,EACtE;AACF;AAWO,SAAS,eAAe,OAAyB;AACtD,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,SAAO,QAAQ,SAAS,eAAe,KAAK,QAAQ,SAAS,mBAAmB;AAClF;AAQO,SAAS,eAAe,OAAyB;AACtD,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,SAAO,QAAQ,SAAS,mBAAmB;AAC7C;AAEA,eAAsB,QACpB,QACAC,OACA,QACkB;AAClB,QAAM,QAAQ,GAAGA,MAAK,MAAM,IAAIA,MAAK,IAAI;AACzC,QAAM,WAAW,OAAO,OAAOA,MAAK,MAAM;AAC1C,MAAI,aAAa,QAAW;AAC1B,UAAM,IAAI,cAAc,OAAO,UAAUA,MAAK,MAAM,mBAAmB;AAAA,EACzE;AACA,QAAM,EAAE,MAAM,KAAK,IAAIA;AAEvB,QAAM,MAAM,MACV,SAAS,OAAO;AAAA,IACd,EAAE,QAAQ,cAAc,QAAQ,EAAE,MAAM,MAAM,WAAW,KAAK,EAAE;AAAA,IAChED,GAAE,YAAY,CAAC,CAAC;AAAA,IAChB,EAAE,OAAO;AAAA,EACX;AAEF,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,IAAI;AAAA,EAClB,SAAS,OAAgB;AAKvB,QAAI,CAAC,eAAe,KAAK,KAAK,SAAS,cAAc,QAAW;AAC9D,YAAM,IAAI,cAAc,OAAO,SAAS,KAAK,GAAG,EAAE,OAAO,MAAM,CAAC;AAAA,IAClE;AACA,QAAI;AACF,YAAM,SAAS,UAAU;AACzB,YAAM,MAAM,IAAI;AAAA,IAClB,SAAS,OAAgB;AAKvB,UAAI,eAAe,KAAK,GAAG;AACzB,cAAM,SAAS,UAAU,EAAE,MAAM,MAAM,MAAS;AAAA,MAClD;AAKA,YAAM,QAAQ,eAAe,KAAK,KAAK,eAAe,KAAK;AAC3D,YAAM,IAAI;AAAA,QACR;AAAA,QACA,QACI,qBAAqBC,MAAK,MAAM,yOAGhC,GAAG,SAAS,KAAK,CAAC,uBAAuBA,MAAK,MAAM,6CAA6C,SAAS,KAAK,CAAC;AAAA,QACpH,EAAE,OAAO,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,WAAW,UAAU,GAAG;AACvC,MAAI,OAAO,WAAW,OAAO,KAAK,SAAS;AAOzC,UAAM,OAAO,KAAK,UAAU,GAAG;AAC/B,UAAM,SACJA,MAAK,eAAe,UACpBA,MAAK,WAAW,KAAK,CAAC,WAAW,KAAK,YAAY,EAAE,SAAS,OAAO,YAAY,CAAC,CAAC;AACpF,UAAM,IAAI,cAAc,OAAO,+BAA+B,IAAI,IAAI,EAAE,OAAO,CAAC;AAAA,EAClF;AACA,SAAO,UAAU,GAAG;AACtB;AASA,eAAsB,aACpB,QACAA,OACA,QAC2B;AAC3B,MAAI;AACF,WAAO,EAAE,SAAS,MAAM,OAAO,MAAM,QAAQ,QAAQA,OAAM,MAAM,EAAE;AAAA,EACrE,SAAS,OAAgB;AACvB,QAAI,iBAAiB,iBAAiB,MAAM,QAAQ;AAClD,aAAO,EAAE,SAAS,MAAM;AAAA,IAC1B;AACA,UAAM;AAAA,EACR;AACF;","names":["join","existsSync","dirname","existsSync","dirname","z","z","z","z","read","cached","z","z","read"]}