@miadi/inquiry-weave 0.7.0 → 0.8.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/README.md CHANGED
@@ -235,3 +235,116 @@ calls (`INQUIRY_WEAVE_ISSUE_LIB` injects a fake issue lib).
235
235
  ---
236
236
  🌸: A loom, not a pen — the weave holds artefact, issue, and episode in relation so none
237
237
  drifts from the others, while the question itself stays yours to ask.
238
+
239
+ ## `resolve` — one chronicle reference, answered
240
+
241
+ ```bash
242
+ inquiry-weave resolve "miadi-chronicle:311/services-inventory"
243
+ ```
244
+
245
+ ```
246
+ écoute factorisation logiciels — the relational software factory
247
+ [room·local] [room·tailnet] [room·public] [wheel·captures]
248
+ [wheel·graph] [wheel·node] [wheel·relations] [file·inventory]
249
+ <miadi-chronicle:311/services-inventory>
250
+ episode 311 · 2026-08-05-episode-311-coute-… · matched by number
251
+ path: /srv/miadi/episodes/…/services-inventory.json
252
+ modality: relational
253
+ ```
254
+
255
+ Turns a `miadi-chronicle:` reference into every door it opens. Contract:
256
+ `rispecs/miadi-chronicle-dsl/SPEC.md` (v1.1) and `SPEC-TERMINAL.md` (v1.2);
257
+ grounding in `foundations/resource-addressing-and-terminal-hypermedia/`.
258
+
259
+ Each bracket is its own OSC 8 hyperlink, and the canonical reference stays
260
+ visible beside them — the OSC 8 specification says a hyperlink "should not be
261
+ the only means of figuring out the target", and there is no way to detect
262
+ whether a terminal supports them. `--raw` drops the escape for clean capture.
263
+
264
+ **The reference is host-free.** `miadi-chronicle:311` is the name; a base is
265
+ chosen at render time. That is ARK's Name Mapping Authority rule — the
266
+ resolver's hostport is identity-inert — and it is why the same reference reads
267
+ correctly from this host, the tailnet, or the public front.
268
+
269
+ | flag | does |
270
+ | --- | --- |
271
+ | `--json` | the full result: `canonical`, `resolution`, `artifact`, `destinations[]`, `open`, `shareable`, `path`, `modality` |
272
+ | `--base local\|internal\|public` | lead with one door. Reorders; never removes one |
273
+ | `--local` | lead with the file on this disk |
274
+ | `--verify` | ask the wheel whether the episode is really on it |
275
+ | `--raw` | no escape sequences |
276
+
277
+ **`--verify` exists because a 200 proves nothing.** The wheel's `/graph`,
278
+ `/nodes` and `/relations` pages are client-routed, and so is forgewright's
279
+ chronicle view: both return 200 for an episode name that does not exist
280
+ (measured `?episode=9999-99-99-episode-000-nope` → 200). Only
281
+ `GET /api/nodes/<id>` discriminates, and that is what `--verify` asks.
282
+
283
+ **Two answers, never collapsed.** `open` is where a human click should land —
284
+ the episode room. `path` is the bytes on this host. An earlier draft returned
285
+ only the file, and clicking it opened a text editor on raw JSON: local-first is
286
+ about data ownership and availability, not about presentation.
287
+
288
+ ### Forms
289
+
290
+ ```
291
+ miadi-chronicle:092/126?view=wheel#scene=river # canonical, rootless
292
+ miadi-chronicle://092/126 # accepted forever, normalized away
293
+ ```
294
+
295
+ `//` is RFC 3986 §3.2's authority marker, so a conformant parser reads the
296
+ first path segment as a host — `new URL("miadi-chronicle://126")` yields host
297
+ `"126"` and an **empty path**. Producers emit rootless; parsers accept both.
298
+
299
+ ### Artifact segments
300
+
301
+ `services-inventory` · `state-machine` · `captures` · `recordings` · `inquiry`
302
+ · `plans`. The last four are served by the medicine wheel and are keyed by
303
+ `episode_path` — the **full folder name**. The episode number is not a key
304
+ there: `?episode_number=320` returns 0 records for an episode whose
305
+ `?episode_path=<folder>` returns 1.
306
+
307
+ ### Fragments
308
+
309
+ `#state=` and `#event=` are spellable; `#transition=`, `#parameter=`,
310
+ `#action=` and `#source=` are not. State names are unique tree-wide (SMDF's
311
+ V002) so they survive structural motion; transitions are addressed positionally
312
+ and a sibling insert silently retargets the reference. Name-keyed fragments are
313
+ durable against structural motion and **fragile against rename** — see
314
+ `SPEC-TERMINAL.md` §4.3a.
315
+
316
+ ## `terminal install` — clickable references in Terminator
317
+
318
+ ```bash
319
+ inquiry-weave terminal install --enable
320
+ ```
321
+
322
+ Writes three files and one config line, each printed:
323
+
324
+ | path | is |
325
+ | --- | --- |
326
+ | `~/.config/terminator/plugins/miadi_chronicle_url_handler.py` | the URL handler |
327
+ | `~/.config/environment.d/50-miadi-chronicle.conf` | systemd user environment |
328
+ | `~/bin/miadi-chronicle-open` | the resolver wrapper a click runs |
329
+ | `enabled_plugins` in the Terminator config | only with `--enable`, after a backup |
330
+
331
+ Then restart Terminator and **Ctrl+click** a `miadi-chronicle:` reference
332
+ anywhere in its output. Plain click needs `link_single_click = True`.
333
+
334
+ `--force` overwrites, `--dry-run` previews, `terminal uninstall` reverses it,
335
+ `terminal show` prints the paths. Running install twice is safe.
336
+
337
+ **Why a plugin when OSC 8 exists.** Terminator has two click paths: an OSC 8
338
+ hyperlink calls `open_url(prepare=False)` and goes straight to `xdg-open`,
339
+ while a regex match calls `prepare=True` — the only path that consults
340
+ `url_handler` plugins. So the plugin covers what OSC 8 structurally cannot: a
341
+ bare `miadi-chronicle:311` in output that knows nothing about miadi — a git
342
+ log, a grep hit, an agent's raw text.
343
+
344
+ **Why the environment drop-in.** A GUI process inherits nothing from your
345
+ shell, so `MIADI_URL_BASE`, `MW_API_URL` and `MIADI_CHRONICLE_ROOT` are absent
346
+ at click time and every click falls back to localhost. `environment.d` is the
347
+ OS's own answer — read by systemd's user-environment generator at session
348
+ start, so every GUI process in the session inherits it. Takes effect at the
349
+ next login; the wrapper carries the same values as a fallback until then.
350
+ Test with `env -i`, which is the real click condition. See `jgwill/Miadi#620`.
@@ -0,0 +1,191 @@
1
+ /**
2
+ * miadi-chronicle URI parsing, artifact registry, and episode resolution.
3
+ *
4
+ * Contract: rispecs/miadi-chronicle-dsl/SPEC.md (v1.1) and SPEC-TERMINAL.md
5
+ * (v1.2). Grounded in foundations/resource-addressing-and-terminal-hypermedia/.
6
+ *
7
+ * This is the app's three pure modules (`app/chronicle/lib/{dsl,resolveRef,
8
+ * inventoryRef}.ts`) brought into a package that already ships built ESM, so
9
+ * one resolver can answer the browser, the HTTP route, and a terminal. It
10
+ * stays pure — no fs, no fetch, no React. The catalog arrives as an argument.
11
+ *
12
+ * Two changes v1.1 does not have, both from the foundations packet:
13
+ *
14
+ * 1. ROOTLESS FORM. `//` is RFC 3986 §3.2's authority marker, so every
15
+ * conformant parser reads the first path segment as a host:
16
+ * new URL("miadi-chronicle://126") → host "126", pathname ""
17
+ * The most common reference has an EMPTY PATH, stock parsers disagree
18
+ * with this file, and SPEC §8's reserved `//root@…/` growth slot is
19
+ * unreachable because episode data already occupies it. Every non-HTTP
20
+ * scheme that survived — did:, urn:, ark:, swh:, tag:, info: — is
21
+ * rootless. So: `miadi-chronicle:092/126` is canonical, `//` is accepted
22
+ * forever on input and normalized away on output.
23
+ *
24
+ * 2. ARTIFACT REGISTRY. v1.1's "registry" was one const string compared by
25
+ * `===` in three places. It is a map now, with `state-machine` as the
26
+ * second entry.
27
+ */
28
+ export declare const MIADI_CHRONICLE_SCHEME = "miadi-chronicle:";
29
+ /** Rendering options folded into the URI query under the reserved prefix. */
30
+ export declare const OPTION_PREFIX = "mc.";
31
+ /**
32
+ * Reserved artifact segments — the registry SPEC §7.1 named itself after.
33
+ * Each key is a name no episode folder can carry (folder names are
34
+ * date-prefixed); each value is the artifact kind the resolver dispatches on.
35
+ */
36
+ export declare const ARTIFACT_SEGMENTS: {
37
+ readonly "services-inventory": "inventory";
38
+ readonly "state-machine": "state-machine";
39
+ readonly captures: "captures";
40
+ readonly recordings: "captures";
41
+ readonly inquiry: "inquiry";
42
+ readonly plans: "plans";
43
+ };
44
+ export type ArtifactKind = (typeof ARTIFACT_SEGMENTS)[keyof typeof ARTIFACT_SEGMENTS];
45
+ /** Kinds served by the medicine wheel rather than by the vessel on disk. */
46
+ export declare const WHEEL_ARTIFACT_KINDS: readonly ["captures", "inquiry", "plans"];
47
+ /** The wheel node id for an episode. The observed format, not the expected one:
48
+ * `chronicle:2026-08-05-episode-311-coute-…-factory`. */
49
+ export declare function wheelNodeId(episodeFolder: string): string;
50
+ export interface ParsedChronicleUri {
51
+ /** The full original URI, exactly as given. */
52
+ uri: string;
53
+ /** Canonical rootless form with `mc.*` options and fragment preserved. */
54
+ canonical: string;
55
+ /** Raw slash-joined path as written, e.g. "092/126" or "311/state-machine". */
56
+ episodePath: string;
57
+ /** Path split into segments, artifact segment included when present. */
58
+ segments: string[];
59
+ /** Segments that address an EPISODE — the artifact segment stripped. */
60
+ episodeSegments: string[];
61
+ /** Which artifact this reference names, or null for a plain episode ref. */
62
+ artifact: ArtifactKind | null;
63
+ /** Query params minus the mc.* rendering options. */
64
+ query: Record<string, string>;
65
+ /** mc.* rendering options, prefix stripped (show, label, highlight, as, …). */
66
+ options: Record<string, string>;
67
+ /** In-episode navigation hint, e.g. "scene=river" or "state=Gathering". */
68
+ fragment?: string;
69
+ }
70
+ export declare function isMiadiChronicleUri(href: string | undefined): boolean;
71
+ /** Parse one URI. Returns null on anything malformed — never throws. */
72
+ export declare function parseMiadiChronicleUri(uri: string): ParsedChronicleUri | null;
73
+ /**
74
+ * Keys a `state-machine` fragment may use.
75
+ *
76
+ * `state` and `event` are name-keyed: SMDF's validation rule V002 forces
77
+ * tree-wide unique state names, and events are keyed by id, so both survive
78
+ * structural motion. Transitions, parameters, actions and event sources are
79
+ * addressed POSITIONALLY (`{state, index}`) — an index shifts the moment a
80
+ * sibling is inserted, and the reference then resolves to the wrong thing
81
+ * without raising anything. Content drift outruns link rot roughly 3:1
82
+ * (Jones et al. 2016, doi:10.1371/journal.pone.0167475) and the silent
83
+ * variant is the damaging one, so a form that cannot be durable is not
84
+ * spellable here.
85
+ *
86
+ * The narrow claim, precisely: a BARE `{state, index}` pair carries no content
87
+ * by which a shifted reference could be re-matched or a mis-resolution
88
+ * detected. Positional addressing can be hardened (Phelps & Wilensky carry
89
+ * node tags alongside the index and resolve by approximate match) — but
90
+ * hardening it here would amount to describing the transition, at which point
91
+ * the index is doing no work. The sanctioned way to address one is therefore
92
+ * by description, from V002-unique names, which inherits their durability:
93
+ * #transition=(from:<State>,on:<Event>,to:<State>)
94
+ * That form EXTENDS this rule rather than breaching it. It is not implemented.
95
+ *
96
+ * Conditional by design: transitions are positional IN SMDF TODAY. OMG XMI
97
+ * gives every model element an `xmi:id`; if SMDF ever mints author-assigned
98
+ * transition ids under the same uniqueness constraint, `#transition=` becomes
99
+ * durable and this rule's own principle would then REQUIRE permitting it.
100
+ */
101
+ export declare const DURABLE_FRAGMENT_KEYS: readonly ["state", "event"];
102
+ /** Positional keys, refused with a reason rather than silently ignored. */
103
+ export declare const POSITIONAL_FRAGMENT_KEYS: readonly ["transition", "parameter", "action", "source"];
104
+ export interface FragmentVerdict {
105
+ key: string;
106
+ value: string;
107
+ durable: boolean;
108
+ reason?: string;
109
+ }
110
+ /**
111
+ * Judge a `key=value` fragment against the durability rule. An unknown key is
112
+ * neither endorsed nor refused — it is passed through, per SPEC §1's rule that
113
+ * unknown parameters are preserved and never fatal.
114
+ */
115
+ export declare function judgeFragment(fragment: string | undefined): FragmentVerdict | null;
116
+ /**
117
+ * Rename is the hole V002 does not cover.
118
+ *
119
+ * V002 gives tree-wide unique state names AT A POINT IN TIME. It says nothing
120
+ * about immutability: under rename, `#state=Foo` fails exactly as a positional
121
+ * reference fails under insertion, and the worse variant — a name reused for a
122
+ * different state — resolves successfully to the wrong element.
123
+ *
124
+ * The policy this package implements is the middle of the three the packet
125
+ * lists: an alias table. A machine MAY carry `former-names`, and a reference
126
+ * to a former name resolves WITH A DEPRECATION SIGNAL rather than failing.
127
+ * That is XPointer's ordered-fallback pattern applied locally, and Memento's
128
+ * idea (reach a prior state) without an archive. Until SMDF carries
129
+ * `former-names`, the honest status is: name-keyed fragments are durable
130
+ * against structural motion and fragile against rename, and this is stated
131
+ * rather than implied.
132
+ */
133
+ export declare const RENAME_POLICY: "alias-table-pending";
134
+ export type MatchedBy = "folder-name" | "number" | "slug" | "date";
135
+ /** The seven fields resolution actually reads. Structurally satisfied by
136
+ * `EpisodeManifestEntry` from the catalog, and by the app's richer view. */
137
+ export interface ResolvableEpisode {
138
+ name: string;
139
+ number?: number;
140
+ slug?: string;
141
+ date?: string;
142
+ title?: string;
143
+ direction?: string;
144
+ theme?: string;
145
+ }
146
+ export interface ResolvedEpisodeRef {
147
+ segment: string;
148
+ resolved: boolean;
149
+ matchedBy?: MatchedBy;
150
+ name?: string;
151
+ number?: number;
152
+ title?: string;
153
+ date?: string;
154
+ direction?: string;
155
+ theme?: string;
156
+ /** App route to the episode room, fragment already attached for targets. */
157
+ route?: string;
158
+ /**
159
+ * Folder names of OTHER episodes the segment also matched. The catalog
160
+ * really does hold duplicate numbers; resolution stays deterministic and
161
+ * the ambiguity is surfaced instead of hidden.
162
+ *
163
+ * Note what this does NOT yet solve: the tie-break is lexicographically
164
+ * first, so backfilling a newly-discovered OLDER episode with a duplicate
165
+ * number silently retargets every existing reference. Non-reassignment is a
166
+ * primary dimension of identifier validity (Kunze et al. 2017); ARK and DOI
167
+ * forbid reassignment outright. Deterministic-at-an-instant is not
168
+ * stable-over-time, and `alternates` reports the ambiguity without fixing it.
169
+ */
170
+ alternates?: string[];
171
+ }
172
+ export interface ChronicleResolution {
173
+ resolved: boolean;
174
+ matchedBy?: MatchedBy;
175
+ target: ResolvedEpisodeRef;
176
+ waypoints: ResolvedEpisodeRef[];
177
+ }
178
+ /**
179
+ * Resolve an already-parsed URI against the catalog.
180
+ *
181
+ * Resolution runs over `episodeSegments`, so an artifact reference resolves
182
+ * its episode exactly as a plain reference does — the reserved segment is
183
+ * stripped before matching, never matched against a folder.
184
+ */
185
+ export declare function resolveChronicleRef(parsed: ParsedChronicleUri, entries: ResolvableEpisode[]): ChronicleResolution;
186
+ /** One-call convenience: raw URI string → resolution, or null if unparseable. */
187
+ export declare function resolveChronicleUri(uri: string, entries: ResolvableEpisode[]): {
188
+ parsed: ParsedChronicleUri;
189
+ resolution: ChronicleResolution;
190
+ } | null;
191
+ //# sourceMappingURL=chronicle-dsl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chronicle-dsl.d.ts","sourceRoot":"","sources":["../src/chronicle-dsl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,327 @@
1
+ /**
2
+ * miadi-chronicle URI parsing, artifact registry, and episode resolution.
3
+ *
4
+ * Contract: rispecs/miadi-chronicle-dsl/SPEC.md (v1.1) and SPEC-TERMINAL.md
5
+ * (v1.2). Grounded in foundations/resource-addressing-and-terminal-hypermedia/.
6
+ *
7
+ * This is the app's three pure modules (`app/chronicle/lib/{dsl,resolveRef,
8
+ * inventoryRef}.ts`) brought into a package that already ships built ESM, so
9
+ * one resolver can answer the browser, the HTTP route, and a terminal. It
10
+ * stays pure — no fs, no fetch, no React. The catalog arrives as an argument.
11
+ *
12
+ * Two changes v1.1 does not have, both from the foundations packet:
13
+ *
14
+ * 1. ROOTLESS FORM. `//` is RFC 3986 §3.2's authority marker, so every
15
+ * conformant parser reads the first path segment as a host:
16
+ * new URL("miadi-chronicle://126") → host "126", pathname ""
17
+ * The most common reference has an EMPTY PATH, stock parsers disagree
18
+ * with this file, and SPEC §8's reserved `//root@…/` growth slot is
19
+ * unreachable because episode data already occupies it. Every non-HTTP
20
+ * scheme that survived — did:, urn:, ark:, swh:, tag:, info: — is
21
+ * rootless. So: `miadi-chronicle:092/126` is canonical, `//` is accepted
22
+ * forever on input and normalized away on output.
23
+ *
24
+ * 2. ARTIFACT REGISTRY. v1.1's "registry" was one const string compared by
25
+ * `===` in three places. It is a map now, with `state-machine` as the
26
+ * second entry.
27
+ */
28
+ export const MIADI_CHRONICLE_SCHEME = "miadi-chronicle:";
29
+ /** Rendering options folded into the URI query under the reserved prefix. */
30
+ export const OPTION_PREFIX = "mc.";
31
+ // Numbered groups: [1]=path [2]=query [3]=fragment.
32
+ //
33
+ // `(?:\/\/)?` is the leniency rule: producers SHOULD emit rootless, parsers
34
+ // MUST accept both. The scheme is case-insensitive per RFC 3986; the path is
35
+ // not.
36
+ //
37
+ // The trailing `\/?` tolerates and normalizes away a trailing slash — RFC 3986
38
+ // reads it as an empty final segment and people type it by reflex; refusing it
39
+ // degraded the reference to raw `{{ }}` braces with nothing explaining why
40
+ // (earned 2026-08-15, episode 103 on the film-media article).
41
+ const URI_RE = /^miadi-chronicle:(?:\/\/)?([A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*)\/?(?:\?([^#]*))?(?:#(.*))?$/i;
42
+ /**
43
+ * Reserved artifact segments — the registry SPEC §7.1 named itself after.
44
+ * Each key is a name no episode folder can carry (folder names are
45
+ * date-prefixed); each value is the artifact kind the resolver dispatches on.
46
+ */
47
+ export const ARTIFACT_SEGMENTS = {
48
+ "services-inventory": "inventory",
49
+ "state-machine": "state-machine",
50
+ // Wheel-backed kinds. These live in the medicine wheel's store rather than
51
+ // in the vessel, and every one of them is keyed by `episode_path` — the full
52
+ // folder name. Measured 2026-08-16: `?episode_number=320` returns 0 records
53
+ // for an episode whose `?episode_path=<folder>` returns 1, because the
54
+ // records carry no `episode_number` field and the filter compares strictly.
55
+ // The number is a nickname; the folder name is the key.
56
+ captures: "captures",
57
+ recordings: "captures", // deprecated alias on the wheel; same records
58
+ inquiry: "inquiry",
59
+ plans: "plans",
60
+ };
61
+ /** `mc.show=` values that name an artifact without using a path segment. */
62
+ const SHOW_TO_KIND = {
63
+ inventory: "inventory",
64
+ "state-machine": "state-machine",
65
+ diagram: "state-machine",
66
+ captures: "captures",
67
+ recordings: "captures",
68
+ inquiry: "inquiry",
69
+ plans: "plans",
70
+ };
71
+ /** Kinds served by the medicine wheel rather than by the vessel on disk. */
72
+ export const WHEEL_ARTIFACT_KINDS = ["captures", "inquiry", "plans"];
73
+ /** The wheel node id for an episode. The observed format, not the expected one:
74
+ * `chronicle:2026-08-05-episode-311-coute-…-factory`. */
75
+ export function wheelNodeId(episodeFolder) {
76
+ return `chronicle:${episodeFolder}`;
77
+ }
78
+ export function isMiadiChronicleUri(href) {
79
+ return typeof href === "string" && /^miadi-chronicle:/i.test(href);
80
+ }
81
+ /** decodeURIComponent that shrugs at malformed escapes ("%zz", trailing "%")
82
+ * instead of throwing — the parse contract is "never throws". */
83
+ function safeDecode(s) {
84
+ try {
85
+ return decodeURIComponent(s);
86
+ }
87
+ catch {
88
+ return s;
89
+ }
90
+ }
91
+ /**
92
+ * The artifact this reference names, by either trigger, or null.
93
+ *
94
+ * Two triggers, deterministic and independent: a reserved segment in the LAST
95
+ * position, or `mc.show=`. The segment wins when both are present and disagree
96
+ * — it is the more explicit of the two.
97
+ *
98
+ * A lone `miadi-chronicle:state-machine` is NOT an artifact reference: with no
99
+ * episode before it there is nothing to resolve the artifact against, so it
100
+ * stays an ordinary (almost certainly unresolved) episode reference rather
101
+ * than becoming a reference to no machine in particular.
102
+ */
103
+ function artifactOf(segments, options) {
104
+ const last = segments[segments.length - 1];
105
+ if (segments.length > 1 && last !== undefined && last in ARTIFACT_SEGMENTS) {
106
+ return ARTIFACT_SEGMENTS[last];
107
+ }
108
+ const show = options.show;
109
+ return (show !== undefined && SHOW_TO_KIND[show]) || null;
110
+ }
111
+ /** Strip a trailing reserved segment; what remains addresses an episode. */
112
+ function episodeSegmentsOf(segments) {
113
+ const last = segments[segments.length - 1];
114
+ if (segments.length > 1 && last !== undefined && last in ARTIFACT_SEGMENTS) {
115
+ return segments.slice(0, -1);
116
+ }
117
+ return segments;
118
+ }
119
+ function buildCanonical(episodePath, query, options, fragment) {
120
+ const params = [];
121
+ for (const [k, v] of Object.entries(query)) {
122
+ params.push(`${encodeURIComponent(k)}=${encodeURIComponent(v)}`);
123
+ }
124
+ for (const [k, v] of Object.entries(options)) {
125
+ params.push(`${OPTION_PREFIX}${encodeURIComponent(k)}=${encodeURIComponent(v)}`);
126
+ }
127
+ const queryPart = params.length > 0 ? `?${params.join("&")}` : "";
128
+ const fragmentPart = fragment ? `#${fragment}` : "";
129
+ return `${MIADI_CHRONICLE_SCHEME}${episodePath}${queryPart}${fragmentPart}`;
130
+ }
131
+ /** Parse one URI. Returns null on anything malformed — never throws. */
132
+ export function parseMiadiChronicleUri(uri) {
133
+ const m = URI_RE.exec(uri.trim());
134
+ if (!m || !m[1])
135
+ return null;
136
+ const query = {};
137
+ const options = {};
138
+ const rawQuery = m[2];
139
+ if (rawQuery) {
140
+ for (const pair of rawQuery.split("&")) {
141
+ if (!pair)
142
+ continue;
143
+ const eq = pair.indexOf("=");
144
+ const key = safeDecode(eq === -1 ? pair : pair.slice(0, eq));
145
+ const value = eq === -1 ? "" : safeDecode(pair.slice(eq + 1));
146
+ if (key.startsWith(OPTION_PREFIX))
147
+ options[key.slice(OPTION_PREFIX.length)] = value;
148
+ else
149
+ query[key] = value;
150
+ }
151
+ }
152
+ const segments = m[1].split("/");
153
+ const fragment = m[3] || undefined;
154
+ return {
155
+ uri: uri.trim(),
156
+ canonical: buildCanonical(m[1], query, options, fragment),
157
+ episodePath: m[1],
158
+ segments,
159
+ episodeSegments: episodeSegmentsOf(segments),
160
+ artifact: artifactOf(segments, options),
161
+ query,
162
+ options,
163
+ fragment,
164
+ };
165
+ }
166
+ // ---------------------------------------------------------------------------
167
+ // Fragment durability (SPEC-TERMINAL §4.3)
168
+ // ---------------------------------------------------------------------------
169
+ /**
170
+ * Keys a `state-machine` fragment may use.
171
+ *
172
+ * `state` and `event` are name-keyed: SMDF's validation rule V002 forces
173
+ * tree-wide unique state names, and events are keyed by id, so both survive
174
+ * structural motion. Transitions, parameters, actions and event sources are
175
+ * addressed POSITIONALLY (`{state, index}`) — an index shifts the moment a
176
+ * sibling is inserted, and the reference then resolves to the wrong thing
177
+ * without raising anything. Content drift outruns link rot roughly 3:1
178
+ * (Jones et al. 2016, doi:10.1371/journal.pone.0167475) and the silent
179
+ * variant is the damaging one, so a form that cannot be durable is not
180
+ * spellable here.
181
+ *
182
+ * The narrow claim, precisely: a BARE `{state, index}` pair carries no content
183
+ * by which a shifted reference could be re-matched or a mis-resolution
184
+ * detected. Positional addressing can be hardened (Phelps & Wilensky carry
185
+ * node tags alongside the index and resolve by approximate match) — but
186
+ * hardening it here would amount to describing the transition, at which point
187
+ * the index is doing no work. The sanctioned way to address one is therefore
188
+ * by description, from V002-unique names, which inherits their durability:
189
+ * #transition=(from:<State>,on:<Event>,to:<State>)
190
+ * That form EXTENDS this rule rather than breaching it. It is not implemented.
191
+ *
192
+ * Conditional by design: transitions are positional IN SMDF TODAY. OMG XMI
193
+ * gives every model element an `xmi:id`; if SMDF ever mints author-assigned
194
+ * transition ids under the same uniqueness constraint, `#transition=` becomes
195
+ * durable and this rule's own principle would then REQUIRE permitting it.
196
+ */
197
+ export const DURABLE_FRAGMENT_KEYS = ["state", "event"];
198
+ /** Positional keys, refused with a reason rather than silently ignored. */
199
+ export const POSITIONAL_FRAGMENT_KEYS = [
200
+ "transition",
201
+ "parameter",
202
+ "action",
203
+ "source",
204
+ ];
205
+ /**
206
+ * Judge a `key=value` fragment against the durability rule. An unknown key is
207
+ * neither endorsed nor refused — it is passed through, per SPEC §1's rule that
208
+ * unknown parameters are preserved and never fatal.
209
+ */
210
+ export function judgeFragment(fragment) {
211
+ if (!fragment)
212
+ return null;
213
+ const eq = fragment.indexOf("=");
214
+ if (eq === -1)
215
+ return { key: fragment, value: "", durable: true };
216
+ const key = fragment.slice(0, eq);
217
+ const value = fragment.slice(eq + 1);
218
+ if (DURABLE_FRAGMENT_KEYS.includes(key)) {
219
+ return { key, value, durable: true };
220
+ }
221
+ if (POSITIONAL_FRAGMENT_KEYS.includes(key)) {
222
+ return {
223
+ key,
224
+ value,
225
+ durable: false,
226
+ reason: `'${key}' is addressed positionally in SMDF, so this reference would ` +
227
+ `resolve to a different element after any sibling insert — silently. ` +
228
+ `Name a state or an event instead.`,
229
+ };
230
+ }
231
+ return { key, value, durable: true };
232
+ }
233
+ /**
234
+ * Rename is the hole V002 does not cover.
235
+ *
236
+ * V002 gives tree-wide unique state names AT A POINT IN TIME. It says nothing
237
+ * about immutability: under rename, `#state=Foo` fails exactly as a positional
238
+ * reference fails under insertion, and the worse variant — a name reused for a
239
+ * different state — resolves successfully to the wrong element.
240
+ *
241
+ * The policy this package implements is the middle of the three the packet
242
+ * lists: an alias table. A machine MAY carry `former-names`, and a reference
243
+ * to a former name resolves WITH A DEPRECATION SIGNAL rather than failing.
244
+ * That is XPointer's ordered-fallback pattern applied locally, and Memento's
245
+ * idea (reach a prior state) without an archive. Until SMDF carries
246
+ * `former-names`, the honest status is: name-keyed fragments are durable
247
+ * against structural motion and fragile against rename, and this is stated
248
+ * rather than implied.
249
+ */
250
+ export const RENAME_POLICY = "alias-table-pending";
251
+ /** Folder-name tail after date and episode-number prefixes: the true slug. */
252
+ function folderSlug(name) {
253
+ return name.replace(/^\d{4}-\d{2}-\d{2}-/, "").replace(/^episode-\d+-*/, "");
254
+ }
255
+ /** Deterministic pick over possibly-multiple matches: lexicographically first
256
+ * folder name (= earliest date), remaining matches surfaced as alternates. */
257
+ function pick(matches, matchedBy) {
258
+ if (matches.length === 0)
259
+ return null;
260
+ const sorted = [...matches].sort((a, b) => a.name.localeCompare(b.name));
261
+ return {
262
+ entry: sorted[0],
263
+ matchedBy,
264
+ alternates: sorted.length > 1 ? sorted.slice(1).map((e) => e.name) : undefined,
265
+ };
266
+ }
267
+ function matchSegment(segment, entries) {
268
+ const exact = entries.find((e) => e.name === segment);
269
+ if (exact)
270
+ return { entry: exact, matchedBy: "folder-name" };
271
+ if (/^\d+$/.test(segment)) {
272
+ const num = parseInt(segment, 10);
273
+ const byNumber = pick(entries.filter((e) => e.number === num), "number");
274
+ if (byNumber)
275
+ return byNumber;
276
+ }
277
+ const bySlug = pick(entries.filter((e) => e.slug === segment || folderSlug(e.name) === segment), "slug");
278
+ if (bySlug)
279
+ return bySlug;
280
+ if (/^\d{4}-\d{2}-\d{2}$/.test(segment)) {
281
+ const byDate = pick(entries.filter((e) => e.date === segment || e.name.startsWith(`${segment}-`)), "date");
282
+ if (byDate)
283
+ return byDate;
284
+ }
285
+ return null;
286
+ }
287
+ function toRef(segment, match, fragment) {
288
+ if (!match)
289
+ return { segment, resolved: false };
290
+ const { entry, matchedBy, alternates } = match;
291
+ const fragmentPart = fragment ? `#${fragment}` : "";
292
+ return {
293
+ segment,
294
+ resolved: true,
295
+ matchedBy,
296
+ name: entry.name,
297
+ number: entry.number,
298
+ title: entry.title,
299
+ date: entry.date,
300
+ direction: entry.direction,
301
+ theme: entry.theme,
302
+ route: `/chronicle/${encodeURIComponent(entry.name)}${fragmentPart}`,
303
+ alternates,
304
+ };
305
+ }
306
+ /**
307
+ * Resolve an already-parsed URI against the catalog.
308
+ *
309
+ * Resolution runs over `episodeSegments`, so an artifact reference resolves
310
+ * its episode exactly as a plain reference does — the reserved segment is
311
+ * stripped before matching, never matched against a folder.
312
+ */
313
+ export function resolveChronicleRef(parsed, entries) {
314
+ const segments = parsed.episodeSegments;
315
+ const targetSegment = segments[segments.length - 1];
316
+ const target = toRef(targetSegment, matchSegment(targetSegment, entries), parsed.fragment);
317
+ const waypoints = segments.slice(0, -1).map((s) => toRef(s, matchSegment(s, entries)));
318
+ return { resolved: target.resolved, matchedBy: target.matchedBy, target, waypoints };
319
+ }
320
+ /** One-call convenience: raw URI string → resolution, or null if unparseable. */
321
+ export function resolveChronicleUri(uri, entries) {
322
+ const parsed = parseMiadiChronicleUri(uri);
323
+ if (!parsed)
324
+ return null;
325
+ return { parsed, resolution: resolveChronicleRef(parsed, entries) };
326
+ }
327
+ //# sourceMappingURL=chronicle-dsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chronicle-dsl.js","sourceRoot":"","sources":["../src/chronicle-dsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,kBAAkB,CAAA;AAExD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAA;AAElC,oDAAoD;AACpD,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,OAAO;AACP,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,2EAA2E;AAC3E,8DAA8D;AAC9D,MAAM,MAAM,GACV,kGAAkG,CAAA;AAEpG;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,oBAAoB,EAAE,WAAW;IACjC,eAAe,EAAE,eAAe;IAChC,2EAA2E;IAC3E,6EAA6E;IAC7E,4EAA4E;IAC5E,uEAAuE;IACvE,4EAA4E;IAC5E,wDAAwD;IACxD,QAAQ,EAAE,UAAU;IACpB,UAAU,EAAE,UAAU,EAAE,8CAA8C;IACtE,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;CACN,CAAA;AAIV,4EAA4E;AAC5E,MAAM,YAAY,GAAiC;IACjD,SAAS,EAAE,WAAW;IACtB,eAAe,EAAE,eAAe;IAChC,OAAO,EAAE,eAAe;IACxB,QAAQ,EAAE,UAAU;IACpB,UAAU,EAAE,UAAU;IACtB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;CACf,CAAA;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAU,CAAA;AAE7E;0DAC0D;AAC1D,MAAM,UAAU,WAAW,CAAC,aAAqB;IAC/C,OAAO,aAAa,aAAa,EAAE,CAAA;AACrC,CAAC;AAuBD,MAAM,UAAU,mBAAmB,CAAC,IAAwB;IAC1D,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpE,CAAC;AAED;kEACkE;AAClE,SAAS,UAAU,CAAC,CAAS;IAC3B,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAA;IACV,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,UAAU,CAAC,QAAkB,EAAE,OAA+B;IACrE,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC1C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,IAAI,iBAAiB,EAAE,CAAC;QAC3E,OAAO,iBAAiB,CAAC,IAAsC,CAAC,CAAA;IAClE,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;IACzB,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAA;AAC3D,CAAC;AAED,4EAA4E;AAC5E,SAAS,iBAAiB,CAAC,QAAkB;IAC3C,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC1C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,IAAI,iBAAiB,EAAE,CAAC;QAC3E,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC9B,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,SAAS,cAAc,CACrB,WAAmB,EACnB,KAA6B,EAC7B,OAA+B,EAC/B,QAAiB;IAEjB,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAClE,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,aAAa,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAClF,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACjE,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACnD,OAAO,GAAG,sBAAsB,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,EAAE,CAAA;AAC7E,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;IACjC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IAE5B,MAAM,KAAK,GAA2B,EAAE,CAAA;IACxC,MAAM,OAAO,GAA2B,EAAE,CAAA;IAC1C,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IACrB,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,IAAI;gBAAE,SAAQ;YACnB,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAC5B,MAAM,GAAG,GAAG,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;YAC5D,MAAM,KAAK,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YAC7D,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAA;;gBAC9E,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACzB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAChC,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAA;IAClC,OAAO;QACL,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;QACf,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC;QACzD,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;QACjB,QAAQ;QACR,eAAe,EAAE,iBAAiB,CAAC,QAAQ,CAAC;QAC5C,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC;QACvC,KAAK;QACL,OAAO;QACP,QAAQ;KACT,CAAA;AACH,CAAC;AAED,8EAA8E;AAC9E,2CAA2C;AAC3C,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAA;AAEhE,2EAA2E;AAC3E,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,YAAY;IACZ,WAAW;IACX,QAAQ;IACR,QAAQ;CACA,CAAA;AASV;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,QAA4B;IACxD,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAA;IAC1B,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAChC,IAAI,EAAE,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IACjE,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;IACpC,IAAK,qBAA2C,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/D,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IACtC,CAAC;IACD,IAAK,wBAA8C,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO;YACL,GAAG;YACH,KAAK;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EACJ,IAAI,GAAG,+DAA+D;gBACtE,sEAAsE;gBACtE,mCAAmC;SACtC,CAAA;IACH,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,qBAA8B,CAAA;AAsD3D,8EAA8E;AAC9E,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAA;AAC9E,CAAC;AAQD;+EAC+E;AAC/E,SAAS,IAAI,CAAC,OAA4B,EAAE,SAAoB;IAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACrC,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IACxE,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;QAChB,SAAS;QACT,UAAU,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KAC/E,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,OAAe,EAAE,OAA4B;IACjE,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAA;IACrD,IAAI,KAAK;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;IAE5D,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;QACjC,MAAM,QAAQ,GAAG,IAAI,CACnB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,EACvC,QAAQ,CACT,CAAA;QACD,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAA;IAC/B,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CACjB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,EAC3E,MAAM,CACP,CAAA;IACD,IAAI,MAAM;QAAE,OAAO,MAAM,CAAA;IAEzB,IAAI,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CACjB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,EAC7E,MAAM,CACP,CAAA;QACD,IAAI,MAAM;YAAE,OAAO,MAAM,CAAA;IAC3B,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,KAAK,CACZ,OAAe,EACf,KAA0B,EAC1B,QAAiB;IAEjB,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAA;IAC/C,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,KAAK,CAAA;IAC9C,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACnD,OAAO;QACL,OAAO;QACP,QAAQ,EAAE,IAAI;QACd,SAAS;QACT,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,KAAK,EAAE,cAAc,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,EAAE;QACpE,UAAU;KACX,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA0B,EAC1B,OAA4B;IAE5B,MAAM,QAAQ,GAAG,MAAM,CAAC,eAAe,CAAA;IACvC,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACnD,MAAM,MAAM,GAAG,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC1F,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACtF,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;AACtF,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,mBAAmB,CACjC,GAAW,EACX,OAA4B;IAE5B,MAAM,MAAM,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAA;IAC1C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;AACrE,CAAC"}