@ze-norm/cli 0.11.3 → 0.11.5

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.
@@ -19,6 +19,9 @@ export declare class ZenormClient {
19
19
  private isLocalBaseUrl;
20
20
  /** True when this client targets a localhost API (dev-bypass eligible). */
21
21
  isLocalDevTarget(): boolean;
22
+ /** True when requests will intentionally ignore stored credentials. */
23
+ isUsingLocalDevBypass(): boolean;
24
+ private shouldBypassAuthForLocalDev;
22
25
  private sendOnce;
23
26
  private request;
24
27
  get<T>(path: string): Promise<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAyBA,kFAAkF;AAClF,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0BD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IAIxB,OAAO,CAAC,aAAa,CAAgB;gBAEzB,IAAI,CAAC,EAAE,gBAAgB;IAKnC,wEAAwE;YAC1D,mBAAmB;IAKjC,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,cAAc;IAStB,2EAA2E;IAC3E,gBAAgB,IAAI,OAAO;YAIb,QAAQ;YAqBR,OAAO;IAqEf,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIzC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;CAG7C"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAyBA,kFAAkF;AAClF,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0BD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IAIxB,OAAO,CAAC,aAAa,CAAgB;gBAEzB,IAAI,CAAC,EAAE,gBAAgB;IAKnC,wEAAwE;YAC1D,mBAAmB;IAMjC,OAAO,CAAC,YAAY;IA0BpB,OAAO,CAAC,cAAc;IAStB,2EAA2E;IAC3E,gBAAgB,IAAI,OAAO;IAI3B,uEAAuE;IACvE,qBAAqB,IAAI,OAAO;IAQhC,OAAO,CAAC,2BAA2B;YAIrB,QAAQ;YAqBR,OAAO;IAqEf,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlD,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIzC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;CAG7C"}
@@ -52,6 +52,8 @@ export class ZenormClient {
52
52
  async resolveRequestToken() {
53
53
  if (this.explicitToken)
54
54
  return this.explicitToken;
55
+ if (this.shouldBypassAuthForLocalDev())
56
+ return null;
55
57
  return resolveValidToken();
56
58
  }
57
59
  buildHeaders(token) {
@@ -91,6 +93,15 @@ export class ZenormClient {
91
93
  isLocalDevTarget() {
92
94
  return this.isLocalBaseUrl();
93
95
  }
96
+ /** True when requests will intentionally ignore stored credentials. */
97
+ isUsingLocalDevBypass() {
98
+ return (this.isLocalBaseUrl() &&
99
+ process.env["ZENORM_LOCAL_DEV_BYPASS_AUTH"] === "true" &&
100
+ !process.env["ZENORM_API_TOKEN"]);
101
+ }
102
+ shouldBypassAuthForLocalDev() {
103
+ return this.isUsingLocalDevBypass();
104
+ }
94
105
  async sendOnce(method, url, token, body) {
95
106
  const init = {
96
107
  method,
@@ -51,4 +51,12 @@ export interface ListTasksResponse {
51
51
  export interface TaskResponse {
52
52
  task: SpecTaskRecord;
53
53
  }
54
+ /**
55
+ * Response from `POST /v1/tasks/claim`. The server atomically claims the oldest
56
+ * ready task for the given repo and flips it to `active`; `task` is `null` when
57
+ * there is no claimable work right now.
58
+ */
59
+ export interface ClaimTaskResponse {
60
+ task: SpecTaskRecord | null;
61
+ }
54
62
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAID,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,cAAc,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAID,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,cAAc,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;CAC7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBlE"}
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBlE"}
@@ -12,7 +12,10 @@ export async function whoamiCommand(_argv) {
12
12
  log.info(`Admin: ${ctx.isAdmin ? "yes" : "no"}`);
13
13
  // Show token expiry from stored credentials (not available for env token)
14
14
  const creds = loadCredentials();
15
- if (creds?.expiresAt) {
15
+ if (client.isUsingLocalDevBypass()) {
16
+ log.dim("Using local development mode.");
17
+ }
18
+ else if (creds?.expiresAt) {
16
19
  log.info(`Expires: ${creds.expiresAt}`);
17
20
  }
18
21
  else if (process.env["ZENORM_API_TOKEN"]) {
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Agent-output renderers for `zenorm work`.
3
+ *
4
+ * Background: `zenorm work` runs each claimed task by spawning a headless coding
5
+ * agent (`claude` / `codex`). Those agents' *interactive* TUIs show a clean,
6
+ * readable transcript (assistant prose + one-line tool calls). Their headless
7
+ * modes do NOT: `claude -p` text mode hides every tool call, and the JSON event
8
+ * streams (`--output-format stream-json`, `codex exec --json`) are raw JSONL —
9
+ * unreadable noise.
10
+ *
11
+ * These renderers consume the JSON event streams and re-emit a compact transcript
12
+ * that mirrors what you'd see in each agent's interactive session — a read-only
13
+ * view of the agent working — while dropping protocol/metadata noise (hooks,
14
+ * init banners, token counts, rate-limit pings, raw tool-result bodies).
15
+ *
16
+ * Pure functions over single events so they can be unit-tested without spawning
17
+ * anything. The caller (`AgentRunner`) feeds newline-delimited stdout chunks to a
18
+ * `LineSplitter` + `renderClaudeEvent` / `renderCodexEvent`.
19
+ */
20
+ /** A single rendered transcript line (no trailing newline). */
21
+ export type RenderedLine = string;
22
+ /**
23
+ * Accumulates raw stdout bytes and yields complete lines. The agent JSON streams
24
+ * are newline-delimited JSON; a chunk may split a line, so we buffer the tail.
25
+ */
26
+ export declare class LineSplitter {
27
+ private buffer;
28
+ /** Push a chunk; returns any newly-completed lines (without the newline). */
29
+ push(chunk: string): string[];
30
+ /** Flush any buffered partial line at end-of-stream. */
31
+ flush(): string[];
32
+ }
33
+ /**
34
+ * Render ONE parsed Claude `--output-format stream-json` event into transcript
35
+ * lines (possibly empty). We render off the *complete* `assistant` events (not
36
+ * the partial `stream_event` deltas) so each block is whole; everything else —
37
+ * `system`/`stream_event`/`rate_limit_event`/`user` tool-result bodies — is
38
+ * dropped as noise. The final `result` event is summarized as a dim footer.
39
+ */
40
+ export declare function renderClaudeEvent(event: unknown): RenderedLine[];
41
+ /**
42
+ * Render ONE parsed Codex `exec --json` event (JSONL) into transcript lines.
43
+ * Codex emits `thread.started` / `turn.started` / `item.*` / `turn.completed` /
44
+ * `error`. We surface assistant messages, command/file-change items, and a dim
45
+ * completion/error footer; thread/turn lifecycle + token metadata are dropped.
46
+ */
47
+ export declare function renderCodexEvent(event: unknown): RenderedLine[];
48
+ /** Per-agent line renderer: parse JSONL safely, then dispatch. */
49
+ export type EventRenderer = (jsonLine: string) => RenderedLine[];
50
+ export declare const claudeRenderer: EventRenderer;
51
+ export declare const codexRenderer: EventRenderer;
52
+ /**
53
+ * The dim footer that closes each agent's transcript. Done turns green with a
54
+ * check; an errored/aborted turn turns red with a cross. `meta` is the trailing
55
+ * detail (turns/duration, or an error message). Kept as a shared helper so the
56
+ * Claude `result` and Codex `turn.completed`/`error` footers render alike.
57
+ *
58
+ * NOTE: the literal words "done"/"error" are asserted by the renderer tests, so
59
+ * keep them as the leading token.
60
+ */
61
+ export declare function transcriptFooter(isError: boolean, meta: string[]): RenderedLine;
62
+ /**
63
+ * Heavy task header printed once when a task starts. The leading rule + blank
64
+ * line give multi-task runs clear visual separation (tasks stop blurring into
65
+ * one another); `index` is the 1-based run counter within this session.
66
+ */
67
+ export declare function taskHeader(shortTaskId: string, title: string, agentName: string, index?: number): string;
68
+ /**
69
+ * The full multi-line splash logo (no surrounding blank lines): the rasterized
70
+ * brand mark on the left (brand-cyan half-blocks), the `ZeNorm` wordmark on the
71
+ * right (3D-extruded, 5-space gutter). The icon stands one row taller than the
72
+ * wordmark (9 vs 8), so the shorter wordmark is vertically centered against it
73
+ * with blank padding. Under NO_COLOR the color escapes collapse to "" (the
74
+ * half-block mark and the wordmark's box outline still draw). Exported so it can
75
+ * be rendered/asserted on its own.
76
+ */
77
+ export declare function splashLogo(): string;
78
+ /**
79
+ * The startup banner for the daemon. Shown once at launch (not just under
80
+ * `--dry-run`) so a real run announces what it's doing instead of sitting
81
+ * silently until the first task lands. Leads with the ZeNorm splash logo, then
82
+ * the run parameters.
83
+ */
84
+ export declare function daemonBanner(opts: {
85
+ agent: string;
86
+ repo: string;
87
+ intervalSeconds: number;
88
+ once: boolean;
89
+ dryRun: boolean;
90
+ }): string;
91
+ /** A spinner-free, dim status line for the daemon's idle/lifecycle states. */
92
+ export declare function statusLine(message: string): string;
93
+ /**
94
+ * The per-task outcome line printed after a task's transcript closes: a bold
95
+ * green check for success or a bold red cross for failure, with the title, id,
96
+ * and wall-clock duration. This is the daemon's own verdict (distinct from the
97
+ * agent's transcript footer) so the run log reads as a sequence of outcomes.
98
+ */
99
+ export declare function taskOutcome(opts: {
100
+ ok: boolean;
101
+ shortTaskId: string;
102
+ title: string;
103
+ durationMs: number;
104
+ }): string;
105
+ /**
106
+ * A loud, framed failure banner for a task that threw. Spells out which task
107
+ * failed, the error, and that it was released back to `todo` so the failure is
108
+ * impossible to miss in a scrolling daemon log (vs. a single dim line).
109
+ */
110
+ export declare function failureBanner(opts: {
111
+ shortTaskId: string;
112
+ title: string;
113
+ error: string;
114
+ }): string;
115
+ /**
116
+ * The session summary printed when the daemon shuts down (Ctrl-C or `--once`
117
+ * exhausted). Closes the run with a rule + a one-line tally so the user sees the
118
+ * total instead of having to count outcome lines by eye.
119
+ */
120
+ export declare function sessionSummary(opts: {
121
+ completed: number;
122
+ failed: number;
123
+ }): string;
124
+ //# sourceMappingURL=work-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-render.d.ts","sourceRoot":"","sources":["../../src/commands/work-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAoBH,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AA2DlC;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAM;IAEpB,6EAA6E;IAC7E,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAQ7B,wDAAwD;IACxD,KAAK,IAAI,MAAM,EAAE;CAMlB;AA+ED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,EAAE,CAkChE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,EAAE,CAoE/D;AAED,kEAAkE;AAClE,MAAM,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,YAAY,EAAE,CAAC;AAuBjE,eAAO,MAAM,cAAc,EAAE,aAA+C,CAAC;AAC7E,eAAO,MAAM,aAAa,EAAE,aAA8C,CAAC;AAE3E;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAI/E;AAMD;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAMR;AA2JD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAenC;AAoBD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,MAAM,CAsBT;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAKT;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,CAMT;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAKT"}