@parall/codex-agent 1.43.0 → 1.45.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.
@@ -0,0 +1,229 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ /**
4
+ * One-shot migration for workspaces last bootstrapped by a pre-protocol-delivery
5
+ * bridge.
6
+ *
7
+ * Those generations (every released bridge up to and including v1.44.0) injected
8
+ * the system prompt by writing `<workspace>/.codex/config.toml`
9
+ * (`developer_instructions`) and marking the workspace trusted in the operator's
10
+ * global codex config. Instructions now ride the app-server's per-thread
11
+ * `developerInstructions` param, so a leftover bridge-authored file would DOUBLE
12
+ * the instructions on any workspace codex still considers trusted.
13
+ *
14
+ * Deleting a file in someone's workspace is the destructive direction, so the
15
+ * gate is fail-closed: we remove ONLY what is provably the retired bridge's own
16
+ * artifact, and preserve (with a warning) everything else. A duplicated prompt
17
+ * is a degraded agent; a deleted operator file is lost work.
18
+ *
19
+ * WHY THIS IS ONE-SHOT AND NOT MERELY IDEMPOTENT. The authorship proof is
20
+ * `.parall/system-prompt.md`, and the bridge REWRITES that file on every boot.
21
+ * So it is legacy-era evidence exactly once: on the first protocol-delivery boot,
22
+ * before anything overwrites it. A gate that merely re-ran each boot would, from
23
+ * boot 2 on, be comparing the legacy config against a prompt THIS bridge wrote —
24
+ * evidence it manufactured itself. That is not hypothetical: prompt assembly is
25
+ * deterministic, so a file the first boot explicitly preserved as "not provably
26
+ * ours" can match on the next boot and be silently deleted, contradicting the
27
+ * warning the operator was just given. Fail-closed has to hold across the whole
28
+ * migration lifecycle, not per function call.
29
+ *
30
+ * Hence a versioned, one-way CLAIM (`.parall/legacy-workspace-config-migration.v1`),
31
+ * created atomically (`wx`) BEFORE any prompt write:
32
+ * - exactly one boot ever wins the claim — it alone may delete;
33
+ * - every later boot (and every concurrent loser) skips, silently, forever;
34
+ * - a claim that cannot be persisted FAILS the boot before the proof is
35
+ * overwritten, so a retry still has real evidence;
36
+ * - a boot that dies mid-migration leaves the claim behind, so the file is
37
+ * preserved forever rather than re-judged against fabricated evidence.
38
+ *
39
+ * The whole module is dead code once no workspace can still hold a pre-#1866
40
+ * artifact — sunset conditions in
41
+ * docs/tech-debt/codex-legacy-workspace-config-shim.md.
42
+ */
43
+ /** Relative location of the retired bridge's workspace config. */
44
+ const LEGACY_CONFIG_RELPATH = ['.codex', 'config.toml'];
45
+ /**
46
+ * The one-way claim. Versioned: a future migration gets its own sentinel rather
47
+ * than reusing (or re-arming) this one.
48
+ */
49
+ const MIGRATION_SENTINEL_RELPATH = ['.parall', 'legacy-workspace-config-migration.v1'];
50
+ export function legacyWorkspaceConfigPath(workspaceDir) {
51
+ return path.join(workspaceDir, ...LEGACY_CONFIG_RELPATH);
52
+ }
53
+ export function migrationSentinelPath(workspaceDir) {
54
+ return path.join(workspaceDir, ...MIGRATION_SENTINEL_RELPATH);
55
+ }
56
+ /**
57
+ * Byte-exact reconstruction of the retired serializer. Verified identical across
58
+ * every released bridge that wrote this file (v1.37.0 … v1.44.0 — the line is
59
+ * byte-for-byte the same in all of them), so a single reconstruction covers the
60
+ * whole legacy fleet. The deletion gate compares raw bytes against this: it must
61
+ * never drift.
62
+ */
63
+ export function legacyWorkspaceConfigToml(prompt) {
64
+ return `developer_instructions = """\n${prompt.replace(/\\/g, '\\\\').replace(/"""/g, '\\"""')}\n"""\n`;
65
+ }
66
+ /**
67
+ * Pure. Decides the fate of the legacy config from filesystem facts alone.
68
+ *
69
+ * The only path to `remove` is: plain regular file + exactly one hard link + a
70
+ * pre-overwrite reference copy exists + raw bytes are EXACTLY the retired
71
+ * serializer's output for that reference prompt. Every other combination
72
+ * preserves — including value-level near-misses (an operator file carrying the
73
+ * same `developer_instructions` value plus a comment would be destroyed together
74
+ * with the comment by a value-level compare).
75
+ */
76
+ export function classifyLegacyWorkspaceConfig(facts) {
77
+ const { entry, rawContent, proof } = facts;
78
+ if (!entry)
79
+ return { action: 'none' };
80
+ if (!entry.isPlainFile)
81
+ return { action: 'preserve', reason: 'not-a-plain-file' };
82
+ if (entry.hardLinks !== 1)
83
+ return { action: 'preserve', reason: 'extra-hard-links' };
84
+ if (proof.kind === 'absent')
85
+ return { action: 'preserve', reason: 'no-authorship-proof' };
86
+ if (proof.kind === 'unreadable') {
87
+ return { action: 'preserve', reason: 'authorship-proof-unreadable' };
88
+ }
89
+ if (rawContent === null)
90
+ return { action: 'preserve', reason: 'config-unreadable' };
91
+ if (rawContent !== legacyWorkspaceConfigToml(proof.prompt)) {
92
+ return { action: 'preserve', reason: 'content-mismatch' };
93
+ }
94
+ return { action: 'remove' };
95
+ }
96
+ const PRESERVE_DETAIL = {
97
+ 'not-a-plain-file': 'it is a symlink or directory, not a plain file the bridge could have written',
98
+ 'extra-hard-links': 'the file has more than one hard link, so another path shares this inode',
99
+ 'no-authorship-proof': 'this workspace has no .parall/system-prompt.md from a previous boot, so nothing here can be proven ours',
100
+ 'authorship-proof-unreadable': 'the .parall/system-prompt.md authorship proof exists but could not be read, so ownership cannot be evaluated',
101
+ 'config-unreadable': 'its own bytes could not be read, so authorship cannot be proven',
102
+ 'content-mismatch': 'its bytes are not what the retired bridge would have written',
103
+ };
104
+ const SENTINEL_BODY = `Parall codex bridge — one-shot workspace migration record (v1)
105
+
106
+ The legacy workspace-config cleanup has been CLAIMED for this workspace. Only the
107
+ boot that created this file was allowed to remove a bridge-authored
108
+ .codex/config.toml, and only under a byte-exact authorship proof.
109
+
110
+ While this file exists the bridge will NEVER auto-remove .codex/config.toml again.
111
+ Deleting this file does not safely re-arm the migration: the evidence it relied on
112
+ (.parall/system-prompt.md as written by a pre-protocol-delivery bridge) has since
113
+ been overwritten by this bridge, so a re-run could mistake a prompt it wrote itself
114
+ for legacy evidence and delete a file that is not ours.
115
+
116
+ If a stale .codex/config.toml is still present, remove it by hand.
117
+ `;
118
+ /**
119
+ * Atomically take the one-way claim. `wx` makes this a single filesystem
120
+ * operation, so concurrent boots cannot both win.
121
+ *
122
+ * THROWS if the claim cannot be persisted (EACCES, EIO, EROFS …). That is
123
+ * deliberate and load-bearing: the caller runs this BEFORE overwriting
124
+ * `.parall/system-prompt.md`, so a boot that cannot record its claim must die
125
+ * with the legacy evidence still intact rather than proceed to manufacture a
126
+ * prompt that a later boot would mistake for that evidence.
127
+ */
128
+ export function claimLegacyWorkspaceConfigMigration(workspaceDir) {
129
+ const sentinel = migrationSentinelPath(workspaceDir);
130
+ // The module owns its own sentinel, directory included — a caller that has not
131
+ // created `.parall` yet must still get a real claim, not an ENOENT throw.
132
+ fs.mkdirSync(path.dirname(sentinel), { recursive: true });
133
+ try {
134
+ fs.writeFileSync(sentinel, SENTINEL_BODY, { flag: 'wx' });
135
+ return 'claimed';
136
+ }
137
+ catch (err) {
138
+ if (err.code === 'EEXIST')
139
+ return 'already-claimed';
140
+ throw err;
141
+ }
142
+ }
143
+ /**
144
+ * The migration lifecycle: claim, then — only if we won the claim — read the
145
+ * proof and clean up.
146
+ *
147
+ * `readProof` is a THUNK, not a value, and that is the whole point. Reading the
148
+ * proof is not free of side effects: an unreadable `.parall/system-prompt.md`
149
+ * warns. Passed as an already-evaluated argument, that warning fires before the
150
+ * claim is even checked — so an already-claimed later boot, or a concurrent
151
+ * loser, would emit a migration warning about a decision it is not making. The
152
+ * thunk makes "only the winner touches the proof" a property of the type rather
153
+ * than of the caller's evaluation order.
154
+ *
155
+ * The caller still owns `.parall/system-prompt.md` and must hand over the
156
+ * PRE-OVERWRITE copy: the winner evaluates the thunk here, before anything
157
+ * writes a new prompt.
158
+ *
159
+ * A boot that does not win the claim returns silently — it must not delete, it
160
+ * must not read, and it must not warn: the winner may be deleting the very file
161
+ * it would warn about, and a stale warning about a file that is already gone is
162
+ * exactly the misleading diagnostic this module exists to avoid.
163
+ */
164
+ export function runLegacyWorkspaceConfigMigration(workspaceDir, readProof, log) {
165
+ if (claimLegacyWorkspaceConfigMigration(workspaceDir) === 'already-claimed')
166
+ return;
167
+ cleanupLegacyWorkspaceConfig(workspaceDir, readProof(), log);
168
+ }
169
+ /**
170
+ * Filesystem execution for the one boot that holds the claim. Reads the facts,
171
+ * asks the classifier, applies the verdict.
172
+ *
173
+ * Never throws: a workspace that cannot be migrated must still boot. Every
174
+ * non-ENOENT problem warns.
175
+ */
176
+ function cleanupLegacyWorkspaceConfig(workspaceDir, proof, log) {
177
+ const configPath = legacyWorkspaceConfigPath(workspaceDir);
178
+ let entry;
179
+ try {
180
+ entry = fs.lstatSync(configPath);
181
+ }
182
+ catch (err) {
183
+ // Only ENOENT means "nothing to clean up". Anything else (EACCES, EIO, …)
184
+ // leaves an unverifiable file behind — surface it rather than silently
185
+ // treating it as absent.
186
+ if (err.code !== 'ENOENT') {
187
+ log?.warn(`could not inspect legacy workspace codex config ${configPath}: ${String(err)}`);
188
+ }
189
+ return;
190
+ }
191
+ const isPlainFile = entry.isFile();
192
+ let rawContent = null;
193
+ if (isPlainFile) {
194
+ try {
195
+ rawContent = fs.readFileSync(configPath, 'utf8');
196
+ }
197
+ catch (err) {
198
+ // Read failure → rawContent stays null → the classifier preserves
199
+ // ('config-unreadable'). Log the cause here; the verdict warning follows.
200
+ log?.warn(`could not read legacy workspace codex config ${configPath}: ${String(err)}`);
201
+ }
202
+ }
203
+ const verdict = classifyLegacyWorkspaceConfig({
204
+ entry: { isPlainFile, hardLinks: entry.nlink },
205
+ rawContent,
206
+ proof,
207
+ });
208
+ if (verdict.action === 'none')
209
+ return;
210
+ if (verdict.action === 'remove') {
211
+ try {
212
+ fs.unlinkSync(configPath);
213
+ }
214
+ catch (err) {
215
+ // ENOENT here means the file went away between our lstat and this unlink
216
+ // — a second bridge booting the same workspace (rapid daemon respawn) got
217
+ // there first. That is exactly the end state we wanted, so it is not a
218
+ // failure: warning "could not remove" about a file that is already gone
219
+ // would send the operator after nothing. Concurrent migrations converge.
220
+ if (err.code === 'ENOENT')
221
+ return;
222
+ log?.warn(`could not remove legacy workspace codex config ${configPath}: ${String(err)}`);
223
+ }
224
+ return;
225
+ }
226
+ log?.warn(`leaving ${configPath} in place — ${PRESERVE_DETAIL[verdict.reason]}, so it is not provably ` +
227
+ "the retired bridge's own artifact. Codex loads it for trusted workspaces IN ADDITION to " +
228
+ 'the platform instructions; remove it manually if it is a stale artifact.');
229
+ }
@@ -0,0 +1,23 @@
1
+ import type { RuntimeEvent } from '@parall/agent-core';
2
+ import { EventMapper } from './event-mapping.js';
3
+ export type TurnEventEnvelope = {
4
+ kind: 'runtime';
5
+ event: RuntimeEvent;
6
+ } | {
7
+ kind: 'turn_end';
8
+ threadId?: string;
9
+ } | {
10
+ kind: 'error';
11
+ message: string;
12
+ };
13
+ /** Per-turn buffered sink backed by an unbounded promise queue. */
14
+ export declare class TurnSink {
15
+ readonly mapper: EventMapper;
16
+ private readonly queue;
17
+ private resolver;
18
+ private closed;
19
+ push(envelope: TurnEventEnvelope): void;
20
+ next(): Promise<TurnEventEnvelope>;
21
+ close(): void;
22
+ }
23
+ //# sourceMappingURL=turn-sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn-sink.d.ts","sourceRoot":"","sources":["../src/turn-sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,mEAAmE;AACnE,qBAAa,QAAQ;IACnB,QAAQ,CAAC,MAAM,cAAqB;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,OAAO,CAAC,QAAQ,CAAqD;IACrE,OAAO,CAAC,MAAM,CAAS;IAEvB,IAAI,CAAC,QAAQ,EAAE,iBAAiB;IAWhC,IAAI,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAelC,KAAK;CAMN"}
@@ -0,0 +1,40 @@
1
+ import { EventMapper } from './event-mapping.js';
2
+ /** Per-turn buffered sink backed by an unbounded promise queue. */
3
+ export class TurnSink {
4
+ mapper = new EventMapper();
5
+ queue = [];
6
+ resolver = null;
7
+ closed = false;
8
+ push(envelope) {
9
+ if (this.closed)
10
+ return;
11
+ if (this.resolver) {
12
+ const r = this.resolver;
13
+ this.resolver = null;
14
+ r(envelope);
15
+ return;
16
+ }
17
+ this.queue.push(envelope);
18
+ }
19
+ next() {
20
+ // Drain any queued envelopes first, even after close(). Otherwise a final
21
+ // error envelope enqueued right before close() (e.g. by
22
+ // handleSubprocessClose) is silently dropped because the consumer would
23
+ // see turn_end before it.
24
+ const pending = this.queue.shift();
25
+ if (pending)
26
+ return Promise.resolve(pending);
27
+ if (this.closed) {
28
+ return Promise.resolve({ kind: 'turn_end' });
29
+ }
30
+ return new Promise((resolve) => {
31
+ this.resolver = resolve;
32
+ });
33
+ }
34
+ close() {
35
+ this.closed = true;
36
+ const r = this.resolver;
37
+ this.resolver = null;
38
+ r?.({ kind: 'turn_end' });
39
+ }
40
+ }
@@ -16,10 +16,10 @@ export declare const CONFIG_LOCK_TIMINGS: {
16
16
  };
17
17
  /**
18
18
  * Advisory cross-process lock serializing `<codexHome>/config.toml`
19
- * read-modify-write. On a local daemon machine every runtime_auth codex
20
- * bridge child shares the operator's CODEX_HOME, and the daemon starts them
21
- * together — without a lock, a whole-file rewrite working from a stale read
22
- * can erase a trust entry another agent appended in between.
19
+ * read-modify-write. Several bridge children can share one CODEX_HOME (an
20
+ * operator-set PRLL_CODEX_HOME reaches every child on the machine), and the
21
+ * daemon starts them together — without a lock, concurrent whole-file
22
+ * rewrites working from stale reads lose updates.
23
23
  *
24
24
  * Queue design (why not wx-create + steal): any scheme that renames or
25
25
  * unlinks the SHARED lock path can, between its staleness check and the
@@ -62,11 +62,12 @@ export declare const CONFIG_LOCK_TIMINGS: {
62
62
  * eviction and the process re-enqueues. On `waitMs` timeout
63
63
  * the mutation proceeds without the lock (warn) — blocking would wedge
64
64
  * bridge startup. The lock coordinates bridge processes only; codex itself
65
- * does not observe it, which is why bridge writes to a shared config are
66
- * additionally kept rare (the trust write is a no-op after the first boot
67
- * per workspace, and runtime_auth agents never write the provider block)
68
- * and whole-file writes are atomic (temp + rename) so codex never reads a
69
- * truncated file.
65
+ * does not observe it, which is why bridge writes to the global config are
66
+ * additionally kept rare the only remaining mutation is the parall
67
+ * provider block (runtime_auth agents, which share the operator's ~/.codex,
68
+ * write nothing at all: platform instructions ride the app-server
69
+ * `developerInstructions` param) — and whole-file writes are atomic
70
+ * (temp + rename) so codex never reads a truncated file.
70
71
  *
71
72
  * Exported for tests.
72
73
  */
@@ -84,19 +85,6 @@ export declare const CONFIG_LOCK_TEST_HOOKS: {
84
85
  beforeTicketPublish?: () => void;
85
86
  beforeTicketEntry?: () => void;
86
87
  };
87
- /**
88
- * Ensure the workspace directory is marked as trusted in the global Codex
89
- * config so that project-level `developer_instructions` are loaded at
90
- * app-server startup.
91
- *
92
- * Uses smol-toml for structured reads (avoids substring false-positives),
93
- * but writes via raw text manipulation (preserves comments and formatting).
94
- * Failures are swallowed (warn-only) so a trust write issue never blocks
95
- * the bridge from starting.
96
- */
97
- export declare function ensureWorkspaceTrusted(codexHome: string, workspaceDir: string, log?: {
98
- warn: (msg: string) => void;
99
- }): void;
100
88
  /**
101
89
  * Returns true when the agent is using the Parall LLM proxy (llm_source=parall)
102
90
  * rather than a BYO custom provider or runtime_auth. Detected by checking
@@ -117,11 +105,21 @@ export declare function isParallProxyMode(env?: NodeJS.ProcessEnv): boolean;
117
105
  *
118
106
  * Provider-managed: overwritten on every boot (env vars are the SSOT).
119
107
  */
108
+ /**
109
+ * Escape a value as a TOML basic (double-quoted) string. Needed for Windows
110
+ * paths (backslashes) in the auth command; harmless hardening everywhere else.
111
+ */
112
+ export declare function tomlBasicString(value: string): string;
113
+ /** Injectable auth-command inputs — production callers pass nothing. */
114
+ export interface ParallProviderAuthOptions {
115
+ platform?: NodeJS.Platform;
116
+ nodeBin?: string;
117
+ }
120
118
  export declare function ensureParallProvider(codexHome: string, apiUrl: string, log?: {
121
119
  warn: (msg: string) => void;
122
- }): void;
123
- export declare function writeCodexSystemPrompt(workspaceDir: string, agentIdentity?: AgentIdentity, capabilityFragments?: string[]): void;
120
+ }, opts?: ParallProviderAuthOptions): void;
121
+ export declare function writeCodexSystemPrompt(workspaceDir: string, agentIdentity?: AgentIdentity, capabilityFragments?: string[]): string;
124
122
  export declare function ensureCodexWorkspace(workspaceDir: string, log?: {
125
123
  warn: (msg: string) => void;
126
- }, agentIdentity?: AgentIdentity, capabilityFragments?: string[]): void;
124
+ }, agentIdentity?: AgentIdentity, capabilityFragments?: string[]): string;
127
125
  //# sourceMappingURL=workspace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB;;;;CAI/B,CAAC;AAUF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GAAG,SAAS,EAChD,EAAE,EAAE,MAAM,IAAI,GACb,IAAI,CAkJN;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE;IACnC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAuJP;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CAEN;AAqGD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAK/E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CAEN;AAoED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,aAAa,EAC7B,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAC7B,IAAI,CAqBN;AAED,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EACrC,aAAa,CAAC,EAAE,aAAa,EAC7B,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAC7B,IAAI,CAQN"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB;;;;CAI/B,CAAC;AAUF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GAAG,SAAS,EAChD,EAAE,EAAE,MAAM,IAAI,GACb,IAAI,CAkJN;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,EAAE;IACnC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAuJP;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAK/E;AAED;;;;;;;;;;;;;GAaG;AACH;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAerD;AAED,wEAAwE;AACxE,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA0BD,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EACrC,IAAI,CAAC,EAAE,yBAAyB,GAC/B,IAAI,CAEN;AAkFD,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,aAAa,EAC7B,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAC7B,MAAM,CAwBR;AAED,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EACrC,aAAa,CAAC,EAAE,aAAa,EAC7B,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAC7B,MAAM,CA+BR"}