@javargasm/opencode-kiro-auth 0.3.1 → 0.5.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
@@ -146,6 +146,31 @@ bun test --watch
146
146
  bun run build
147
147
  ```
148
148
 
149
+ ### Debug logging
150
+
151
+ Structured file logging is **opt-in** via the `KIRO_FILE_LOG` environment
152
+ variable. When enabled, every turn of a conversation is written to
153
+ `/tmp/kiro-logs/session-{id}.log` (full request/response bodies) plus a
154
+ `session-{id}.last-request.json` dump of the most recent request. The id is
155
+ derived from OpenCode's session id, so all turns of one conversation — including
156
+ after a restart (`opencode -s <id>`) — share a single file.
157
+
158
+ It is **off by default** because the logs are verbose and may contain sensitive
159
+ prompt content. Enable it for the current shell:
160
+
161
+ ```bash
162
+ export KIRO_FILE_LOG=1
163
+ ```
164
+
165
+ To keep it always on, add it to your shell profile (macOS uses zsh):
166
+
167
+ ```bash
168
+ echo 'export KIRO_FILE_LOG=1' >> ~/.zshrc && source ~/.zshrc
169
+ ```
170
+
171
+ Accepted truthy values: `1`, `true`, `yes`, `on` (case-insensitive). Rebuild the
172
+ plugin (`bun run build`) and restart OpenCode after changing it.
173
+
149
174
  ### Project Structure
150
175
 
151
176
  ```
@@ -1 +1 @@
1
- {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAgF3D,eAAO,MAAM,GAAG;iBACD,MAAM,SAAS,OAAO;gBACvB,MAAM,SAAS,OAAO;gBACtB,MAAM,SAAS,OAAO;iBACrB,MAAM,SAAS,OAAO;IACnC;4DACwD;;CAEzD,CAAC;AAWF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAa9C"}
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAqF3D,eAAO,MAAM,GAAG;iBACD,MAAM,SAAS,OAAO;gBACvB,MAAM,SAAS,OAAO;gBACtB,MAAM,SAAS,OAAO;iBACrB,MAAM,SAAS,OAAO;IACnC;4DACwD;;CAEzD,CAAC;AAWF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAa9C"}
@@ -50,10 +50,19 @@ export type KiroStreamEvent = {
50
50
  data: {
51
51
  usage: number;
52
52
  };
53
+ } | {
54
+ type: "metadata";
55
+ data: {
56
+ stopReason?: string;
57
+ };
53
58
  };
54
59
  /** Find the matching `}` for the `{` at `start`. Returns -1 if incomplete. */
55
60
  export declare function findJsonEnd(text: string, start: number): number;
56
61
  export declare function parseKiroEventMulti(parsed: Record<string, unknown>): KiroStreamEvent[];
62
+ export declare function detectEventStreamException(buffer: string): {
63
+ type: string;
64
+ message?: string;
65
+ } | null;
57
66
  export declare function parseKiroEvents(buffer: string): {
58
67
  events: KiroStreamEvent[];
59
68
  remaining: string;
@@ -1 +1 @@
1
- {"version":3,"file":"event-parser.d.ts","sourceRoot":"","sources":["../src/event-parser.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GAC7F;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE;QAAE,sBAAsB,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAElD,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA2B/D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,CA4ItF;AAqCD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,GACb;IAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAqElD"}
1
+ {"version":3,"file":"event-parser.d.ts","sourceRoot":"","sources":["../src/event-parser.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GAC7F;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE;QAAE,sBAAsB,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACxE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAExD,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA2B/D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,EAAE,CAmJtF;AAmDD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqB3C;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,GACb;IAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAkFlD"}
@@ -1,47 +1,85 @@
1
- /** Log the full request body sent to Kiro API. */
2
- export declare function logRequest(meta: {
3
- endpoint: string;
4
- model: string;
5
- historyLength: number;
6
- requestBodyChars: number;
7
- attempt: number;
8
- conversationId: string;
9
- }, requestBody: string): void;
10
- /** Log a parsed response event from the Kiro stream. */
11
- export declare function logResponseEvent(event: {
12
- type: string;
13
- data: unknown;
14
- eventSeq: number;
15
- }): void;
16
- /** Log the final response summary when the stream completes. */
17
- export declare function logResponseDone(meta: {
18
- stopReason: string;
19
- emittedToolCalls: number;
20
- usage: unknown;
21
- contentBlocks: number;
22
- model: string;
23
- }): void;
24
- /** Log HTTP error responses from the Kiro API. */
25
- export declare function logHttpError(meta: {
26
- status: number;
27
- statusText: string;
28
- body: string;
29
- endpoint: string;
30
- model: string;
31
- attempt: number;
32
- historyLength: number;
33
- }): void;
34
- /** Log stream-level errors (timeouts, parse errors, etc). */
35
- export declare function logStreamError(meta: {
36
- error: string;
37
- context: string;
38
- model: string;
39
- attempt: number;
40
- }): void;
41
- /** Log caught exceptions from the top-level try/catch. */
42
- export declare function logCaughtError(meta: {
43
- stopReason: string;
44
- errorMessage: string;
45
- model: string;
46
- }): void;
1
+ /** Root directory for ALL Kiro file logs (session logs, debug log, request dumps). */
2
+ export declare const LOG_DIR = "/tmp/kiro-logs";
3
+ /**
4
+ * File logging (the structured `session-{id}.log` files under /tmp/kiro-logs,
5
+ * plus the `.last-request.json` dumps) is OPT-IN via the `KIRO_FILE_LOG` env
6
+ * var. It captures full request/response bodies — invaluable for debugging the
7
+ * Kiro wire protocol, but verbose and potentially containing sensitive prompt
8
+ * content — so it stays OFF unless explicitly enabled.
9
+ *
10
+ * Truthy values: `1`, `true`, `yes`, `on` (case-insensitive). Evaluated on
11
+ * every call so it can be toggled at runtime (and in tests).
12
+ */
13
+ export declare function isFileLoggingEnabled(): boolean;
14
+ /** Ensure LOG_DIR exists. Best-effort and memoized; safe to call on every write. */
15
+ export declare function ensureLogDir(): void;
16
+ /** File path of the session log active in the current async context, if any. */
17
+ export declare function currentSessionLogFile(): string | null;
18
+ /**
19
+ * Bind the given session id to the CURRENT async context (and its
20
+ * continuations). Every subsequent `log.*()` in this request — including those
21
+ * in the detached streamKiro IIFE and the SSE ReadableStream, both created
22
+ * synchronously after this call — routes to `session-{id}.log`. Each request
23
+ * runs in its own async context, so concurrent requests don't interfere.
24
+ * Returns the sanitized id actually used.
25
+ */
26
+ export declare function enterSessionLog(sessionId: string | undefined): string;
27
+ export interface SessionLogger {
28
+ /** Absolute path of the file this logger writes to. */
29
+ readonly file: string;
30
+ /** Sanitized session id used in the filename. */
31
+ readonly sessionId: string;
32
+ /** Log the full request body sent to Kiro API. */
33
+ logRequest(meta: {
34
+ endpoint: string;
35
+ model: string;
36
+ historyLength: number;
37
+ requestBodyChars: number;
38
+ attempt: number;
39
+ conversationId: string;
40
+ }, requestBody: string): void;
41
+ /** Log a parsed response event from the Kiro stream. */
42
+ logResponseEvent(event: {
43
+ type: string;
44
+ data: unknown;
45
+ eventSeq: number;
46
+ }): void;
47
+ /** Log the final response summary when the stream completes. */
48
+ logResponseDone(meta: {
49
+ stopReason: string;
50
+ emittedToolCalls: number;
51
+ usage: unknown;
52
+ contentBlocks: number;
53
+ model: string;
54
+ }): void;
55
+ /** Log HTTP error responses from the Kiro API. */
56
+ logHttpError(meta: {
57
+ status: number;
58
+ statusText: string;
59
+ body: string;
60
+ endpoint: string;
61
+ model: string;
62
+ attempt: number;
63
+ historyLength: number;
64
+ }): void;
65
+ /** Log stream-level errors (timeouts, parse errors, etc). */
66
+ logStreamError(meta: {
67
+ error: string;
68
+ context: string;
69
+ model: string;
70
+ attempt: number;
71
+ }): void;
72
+ /** Log caught exceptions from the top-level try/catch (with full error). */
73
+ logCaughtError(meta: {
74
+ stopReason: string;
75
+ errorMessage: string;
76
+ model: string;
77
+ }, error?: unknown): void;
78
+ }
79
+ /**
80
+ * Create a logger bound to a single session. Pass a stable id (conversation
81
+ * id, client session id, …) so all turns share one file. When no id is given
82
+ * every logger gets its own `session-default.log`.
83
+ */
84
+ export declare function createSessionLogger(sessionId?: string): SessionLogger;
47
85
  //# sourceMappingURL=file-logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-logger.d.ts","sourceRoot":"","sources":["../src/file-logger.ts"],"names":[],"mappings":"AA4CA,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAM5B;AAED,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAOP;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAKP;AAED,kDAAkD;AAClD,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,IAAI,CAKP;AAED,6DAA6D;AAC7D,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,IAAI,CAKP;AAED,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAKP"}
1
+ {"version":3,"file":"file-logger.d.ts","sourceRoot":"","sources":["../src/file-logger.ts"],"names":[],"mappings":"AAaA,sFAAsF;AACtF,eAAO,MAAM,OAAO,mBAAmB,CAAC;AAIxC;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAK9C;AAED,oFAAoF;AACpF,wBAAgB,YAAY,IAAI,IAAI,CAQnC;AA4BD,gFAAgF;AAChF,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAIrE;AAgBD,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,kDAAkD;IAClD,UAAU,CACR,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,gBAAgB,EAAE,MAAM,CAAC;QACzB,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;KACxB,EACD,WAAW,EAAE,MAAM,GAClB,IAAI,CAAC;IAER,wDAAwD;IACxD,gBAAgB,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAEjF,gEAAgE;IAChE,eAAe,CAAC,IAAI,EAAE;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,IAAI,CAAC;IAET,kDAAkD;IAClD,YAAY,CAAC,IAAI,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,EAAE,MAAM,CAAC;KACvB,GAAG,IAAI,CAAC;IAET,6DAA6D;IAC7D,cAAc,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAE/F,4EAA4E;IAC5E,cAAc,CACZ,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EACjE,KAAK,CAAC,EAAE,OAAO,GACd,IAAI,CAAC;CACT;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAkDrE"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,19 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
+ /**
3
+ * Headers injected into every model request so the gateway can tie the Kiro
4
+ * `conversationId` (and its log-file grouping) to OpenCode's STABLE session id.
5
+ *
6
+ * The gateway derives the conversationId from the `x-session-id` header (see
7
+ * `deriveLogSessionId` in server.ts). OpenCode's session id is stable for the
8
+ * life of a conversation AND survives a restart (`opencode -s <id>` resumes the
9
+ * same id), so the conversationId stays constant across turns and restarts —
10
+ * matching the real Kiro CLI. Without this the gateway fell back to an
11
+ * ephemeral header / first-message fingerprint, so the id changed on every
12
+ * restart and the logs scattered across files.
13
+ *
14
+ * Exported for testing. Returns `{}` when no session id is available.
15
+ */
16
+ export declare function kiroSessionHeaders(sessionID: string | undefined): Record<string, string>;
2
17
  export declare const KiroPlugin: Plugin;
3
18
  declare const _default: {
4
19
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,qBAAqB,CAAC;AA0BvE,eAAO,MAAM,UAAU,EAAE,MAqUxB,CAAC;;;;;AAEF,wBAGyB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,qBAAqB,CAAC;AA0BvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIxF;AAED,eAAO,MAAM,UAAU,EAAE,MA+UxB,CAAC;;;;;AAEF,wBAGyB"}