compact-agent 1.27.2 → 1.28.1

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/bin/crowcoder.js CHANGED
@@ -2,10 +2,9 @@
2
2
  // In-process best-effort: override process.emitWarning to drop DEP0040.
3
3
  // Catches the warning when it's emitted late (after this runs), but does NOT
4
4
  // catch warnings fired during Node's ESM bootstrap (before any user code).
5
- // For a fully clean stderr, invoke Crowcoder via:
5
+ // For a fully clean stderr, invoke compact-agent via:
6
6
  // node --no-deprecation bin/crowcoder.js
7
- // NODE_OPTIONS=--no-deprecation crowcoder
8
- // oag chat # already passes --no-deprecation
7
+ // NODE_OPTIONS=--no-deprecation compact-agent
9
8
  (() => {
10
9
  const orig = process.emitWarning;
11
10
  process.emitWarning = function patched(warning, ...rest) {
@@ -16,4 +15,50 @@
16
15
  return orig.call(this, warning, ...rest);
17
16
  };
18
17
  })();
18
+
19
+ // ── --debug [level] flag ───────────────────────────────────
20
+ // Parse here at the entry point so that the env var is set BEFORE
21
+ // any module-level code in dist/index.js reads it. The debug
22
+ // instrumentation in src/debug.ts checks $COMPACT_AGENT_DEBUG at
23
+ // init time; setting it from argv keeps the implementation in one
24
+ // place (env var as single source of truth).
25
+ //
26
+ // Accepted forms:
27
+ // --debug → info
28
+ // --debug=trace → trace
29
+ // --debug trace → trace
30
+ // --debug=on → info (alias)
31
+ // --debug=off → off
32
+ //
33
+ // Invalid levels fall back to 'info' with a one-line stderr notice.
34
+ (() => {
35
+ const argv = process.argv;
36
+ const VALID = new Set(['off', 'info', 'debug', 'trace', 'on']);
37
+ for (let i = 2; i < argv.length; i++) {
38
+ const a = argv[i];
39
+ if (a === '--debug') {
40
+ const next = argv[i + 1];
41
+ if (next && VALID.has(next.toLowerCase())) {
42
+ process.env.COMPACT_AGENT_DEBUG = next.toLowerCase() === 'on' ? 'info' : next.toLowerCase();
43
+ argv.splice(i, 2);
44
+ } else {
45
+ process.env.COMPACT_AGENT_DEBUG = 'info';
46
+ argv.splice(i, 1);
47
+ }
48
+ break;
49
+ }
50
+ if (a && a.startsWith('--debug=')) {
51
+ const lvl = a.slice('--debug='.length).toLowerCase();
52
+ if (VALID.has(lvl)) {
53
+ process.env.COMPACT_AGENT_DEBUG = lvl === 'on' ? 'info' : lvl;
54
+ } else {
55
+ process.stderr.write(`[compact-agent] unknown --debug level "${lvl}"; defaulting to 'info'.\n`);
56
+ process.env.COMPACT_AGENT_DEBUG = 'info';
57
+ }
58
+ argv.splice(i, 1);
59
+ break;
60
+ }
61
+ }
62
+ })();
63
+
19
64
  import('../dist/index.js');
package/bin/ecc-hooks.cjs CHANGED
@@ -19,10 +19,23 @@
19
19
 
20
20
  const checkName = process.argv[2] || '';
21
21
 
22
+ // Parse the tool-input env var. Previously a parse failure silently
23
+ // fell back to `{}`, which makes every per-file check return ok() at
24
+ // its empty-path guard — i.e. a malformed payload was a free bypass.
25
+ // Now: empty/unset is treated as `{}` (legitimate for events that
26
+ // don't carry input, like SessionStart); a NON-empty payload that
27
+ // fails to parse is treated as a security event and the hook
28
+ // blocks. Fail closed > fail open.
29
+ const rawToolInput = process.env.COMPACT_AGENT_TOOL_INPUT || process.env.CROWCODER_TOOL_INPUT || '';
22
30
  let toolInput = {};
23
- try {
24
- toolInput = JSON.parse(process.env.CROWCODER_TOOL_INPUT || '{}');
25
- } catch { /* ignore — leave as {} */ }
31
+ if (rawToolInput.length > 0) {
32
+ try {
33
+ toolInput = JSON.parse(rawToolInput);
34
+ } catch {
35
+ process.stderr.write('[ECC] BLOCKED: tool input env var was not valid JSON.\n');
36
+ process.exit(2);
37
+ }
38
+ }
26
39
 
27
40
  const tool = process.env.CROWCODER_TOOL || '';
28
41
  const cwd = process.env.CROWCODER_CWD || process.cwd();
@@ -73,6 +86,19 @@ const checks = {
73
86
  if (/(^|\s)--no-gpg-sign(\s|$)/.test(cmd)) {
74
87
  return block('`--no-gpg-sign` bypasses signing — ask the user first.');
75
88
  }
89
+ // `git commit -n` is the short form of --no-verify. The previous
90
+ // regex missed it entirely. Scope the check to `git commit`
91
+ // specifically — `-n` in other git subcommands means different
92
+ // things (e.g. `git log -n 5` = limit count, NOT skip hooks).
93
+ if (/\bgit\s+(?:commit|merge|rebase)\b[^|;&]*\s-n(\s|$)/.test(cmd)) {
94
+ return block('`-n` is the short form of `--no-verify` — fix the failing hook instead.');
95
+ }
96
+ // `-c core.hooksPath=/dev/null` (or similar) disables git hooks
97
+ // entirely without using --no-verify. Catches the documented
98
+ // bypass vector even when --no-verify isn't on the command line.
99
+ if (/\bgit\s+-c\s+core\.hooksPath\s*=/i.test(cmd)) {
100
+ return block('`-c core.hooksPath=…` disables git hooks — fix the failure instead.');
101
+ }
76
102
  return ok();
77
103
  },
78
104
 
@@ -207,7 +233,16 @@ const checks = {
207
233
  if (!fs.existsSync(targetPath)) return ok();
208
234
  } catch { /* if statSync fails, fall through to the normal path */ }
209
235
 
210
- const sessionId = process.env.CROWCODER_SESSION_ID || 'unknown';
236
+ // Sanitize sessionId before joining into a path. Without this,
237
+ // a sessionId of e.g. "../../../.ssh/authorized_keys" would let
238
+ // `path.join` traverse out of the state dir, and the subsequent
239
+ // writeFileSync would overwrite arbitrary files with attacker-
240
+ // controllable JSON (the touched-set array, which can include
241
+ // model-controlled file paths). Allow only [A-Za-z0-9_-], length
242
+ // <=64. Anything else falls back to "unknown" — degraded UX
243
+ // (gateguard tracking won't persist), not a security breach.
244
+ const rawSessionId = process.env.COMPACT_AGENT_SESSION_ID || process.env.CROWCODER_SESSION_ID || '';
245
+ const sessionId = /^[A-Za-z0-9_-]{1,64}$/.test(rawSessionId) ? rawSessionId : 'unknown';
211
246
  const stateDir = pathMod.join(os.homedir(), '.compact-agent', 'state', 'gateguard');
212
247
  const stateFile = pathMod.join(stateDir, `${sessionId}.json`);
213
248
 
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Debug instrumentation.
3
+ *
4
+ * Writes NDJSON event records to ~/.compact-agent/debug/<sessionId>.jsonl
5
+ * for offline analysis. Designed so that with `level === 'off'` (the
6
+ * default), every emit() call is a single boolean check + early return —
7
+ * zero file I/O and negligible CPU on the hot path.
8
+ *
9
+ * Levels (each includes everything below it):
10
+ *
11
+ * off — no logging (default; for end users)
12
+ * info — high-signal milestones: session start/end, API request/
13
+ * response summary, tool call summary, hook block, stream
14
+ * loop detection, mode/perm/model change
15
+ * debug — info + per-tool argument previews, per-chunk stream stats,
16
+ * per-keypress trace at REPL, slash command dispatch
17
+ * trace — debug + raw API payloads (truncated), full tool I/O,
18
+ * internal state transitions
19
+ *
20
+ * Toggling:
21
+ *
22
+ * - CLI flag: compact-agent --debug [level]
23
+ * - Env var: COMPACT_AGENT_DEBUG=trace
24
+ * - Slash cmd: /debug on [level] /debug off /debug tail [n]
25
+ *
26
+ * The event log is append-only. Each session gets its own file so
27
+ * concurrent compact-agent instances don't fight over a single sink.
28
+ * Files are subject to the same 24h GC window as the gateguard state.
29
+ *
30
+ * Design notes:
31
+ *
32
+ * - We deliberately don't use console.error or any third-party logger.
33
+ * console.error pollutes the user's REPL view; a third-party logger
34
+ * adds startup time + a transitive dep. Direct fs.appendFileSync to
35
+ * an NDJSON file is the lowest-overhead path that's also trivially
36
+ * consumable by jq / Python / another agent.
37
+ *
38
+ * - We DO accept the cost of synchronous appendFileSync — debug
39
+ * instrumentation is rarely on the hot path of perf-sensitive code,
40
+ * and the cost of one syscall per event (only when level >= info)
41
+ * is dwarfed by the cost of the API call the event describes.
42
+ *
43
+ * - Stack traces are NOT captured automatically. Each emit() takes an
44
+ * explicit `data` object — callers include whatever they need.
45
+ * Auto-traces would balloon the log file for limited extra value.
46
+ */
47
+ export type DebugLevel = 'off' | 'info' | 'debug' | 'trace';
48
+ /**
49
+ * Initialize debug at session start. Resolves level from (in priority order):
50
+ * 1. explicit `level` arg (passed in from --debug flag parsing)
51
+ * 2. $COMPACT_AGENT_DEBUG env var
52
+ * 3. existing state.level (typically 'off')
53
+ *
54
+ * Sets the log file path under ~/.compact-agent/debug/<sessionId>.jsonl
55
+ * but doesn't touch the filesystem until the first emit (lazy create).
56
+ */
57
+ export declare function initDebug(sessionId: string, explicitLevel?: DebugLevel | string): void;
58
+ /**
59
+ * Emit a debug event. The fastest path is the early-return when the
60
+ * configured level is below the event's level — a single integer compare.
61
+ *
62
+ * `data` is shallow-cloned to a JSON-safe form. Functions, BigInts, and
63
+ * circular refs are stripped via the replacer to keep emit cheap and
64
+ * crash-free regardless of what callers throw in.
65
+ */
66
+ export declare function emit(eventLevel: Exclude<DebugLevel, 'off'>, eventName: string, data?: Record<string, unknown>): void;
67
+ /**
68
+ * Public read-only state snapshot for /debug status output.
69
+ */
70
+ export declare function getDebugStatus(): {
71
+ level: DebugLevel;
72
+ logPath: string | null;
73
+ eventCount: number;
74
+ uptimeMs: number;
75
+ };
76
+ /**
77
+ * Change the active debug level at runtime. Called from /debug on/off.
78
+ * If transitioning OFF → non-off, we ensure the log dir exists; if
79
+ * transitioning to OFF we leave the file alone (it's append-only and
80
+ * read by external tools).
81
+ */
82
+ export declare function setDebugLevel(level: DebugLevel): void;
83
+ /**
84
+ * Read the last N events from the current session's log. Used by
85
+ * /debug tail. Returns lines as JSON strings (one per event); the
86
+ * caller can pretty-print or pass through to jq.
87
+ */
88
+ export declare function tailDebug(n: number): string[];
89
+ /**
90
+ * True if any non-off level is active. Use this to gate expensive
91
+ * data preparation that you don't want to run when debug is off:
92
+ *
93
+ * if (isDebugActive()) {
94
+ * emit('debug', 'event-name', { detail: computeExpensiveDetail() });
95
+ * }
96
+ */
97
+ export declare function isDebugActive(): boolean;
package/dist/debug.js ADDED
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Debug instrumentation.
3
+ *
4
+ * Writes NDJSON event records to ~/.compact-agent/debug/<sessionId>.jsonl
5
+ * for offline analysis. Designed so that with `level === 'off'` (the
6
+ * default), every emit() call is a single boolean check + early return —
7
+ * zero file I/O and negligible CPU on the hot path.
8
+ *
9
+ * Levels (each includes everything below it):
10
+ *
11
+ * off — no logging (default; for end users)
12
+ * info — high-signal milestones: session start/end, API request/
13
+ * response summary, tool call summary, hook block, stream
14
+ * loop detection, mode/perm/model change
15
+ * debug — info + per-tool argument previews, per-chunk stream stats,
16
+ * per-keypress trace at REPL, slash command dispatch
17
+ * trace — debug + raw API payloads (truncated), full tool I/O,
18
+ * internal state transitions
19
+ *
20
+ * Toggling:
21
+ *
22
+ * - CLI flag: compact-agent --debug [level]
23
+ * - Env var: COMPACT_AGENT_DEBUG=trace
24
+ * - Slash cmd: /debug on [level] /debug off /debug tail [n]
25
+ *
26
+ * The event log is append-only. Each session gets its own file so
27
+ * concurrent compact-agent instances don't fight over a single sink.
28
+ * Files are subject to the same 24h GC window as the gateguard state.
29
+ *
30
+ * Design notes:
31
+ *
32
+ * - We deliberately don't use console.error or any third-party logger.
33
+ * console.error pollutes the user's REPL view; a third-party logger
34
+ * adds startup time + a transitive dep. Direct fs.appendFileSync to
35
+ * an NDJSON file is the lowest-overhead path that's also trivially
36
+ * consumable by jq / Python / another agent.
37
+ *
38
+ * - We DO accept the cost of synchronous appendFileSync — debug
39
+ * instrumentation is rarely on the hot path of perf-sensitive code,
40
+ * and the cost of one syscall per event (only when level >= info)
41
+ * is dwarfed by the cost of the API call the event describes.
42
+ *
43
+ * - Stack traces are NOT captured automatically. Each emit() takes an
44
+ * explicit `data` object — callers include whatever they need.
45
+ * Auto-traces would balloon the log file for limited extra value.
46
+ */
47
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync } from 'node:fs';
48
+ import { join } from 'node:path';
49
+ import { getHomeStateDir } from './config.js';
50
+ const LEVEL_ORDER = {
51
+ off: 0,
52
+ info: 1,
53
+ debug: 2,
54
+ trace: 3,
55
+ };
56
+ const state = {
57
+ level: 'off',
58
+ sessionId: null,
59
+ logPath: null,
60
+ eventCount: 0,
61
+ startedAt: Date.now(),
62
+ };
63
+ /**
64
+ * Initialize debug at session start. Resolves level from (in priority order):
65
+ * 1. explicit `level` arg (passed in from --debug flag parsing)
66
+ * 2. $COMPACT_AGENT_DEBUG env var
67
+ * 3. existing state.level (typically 'off')
68
+ *
69
+ * Sets the log file path under ~/.compact-agent/debug/<sessionId>.jsonl
70
+ * but doesn't touch the filesystem until the first emit (lazy create).
71
+ */
72
+ export function initDebug(sessionId, explicitLevel) {
73
+ state.sessionId = sessionId;
74
+ const envLevel = process.env.COMPACT_AGENT_DEBUG;
75
+ const requested = (explicitLevel || envLevel || state.level || 'off').toLowerCase();
76
+ state.level = isValidLevel(requested) ? requested : 'off';
77
+ if (state.level !== 'off') {
78
+ const dir = join(getHomeStateDir(), 'debug');
79
+ state.logPath = join(dir, `${sessionId}.jsonl`);
80
+ try {
81
+ mkdirSync(dir, { recursive: true });
82
+ }
83
+ catch { /* if we can't create the dir, emit() will fail-safe */ }
84
+ // GC: drop any debug files older than 24h.
85
+ try {
86
+ const cutoff = Date.now() - 24 * 60 * 60 * 1000;
87
+ for (const name of readdirSync(dir)) {
88
+ const p = join(dir, name);
89
+ try {
90
+ const s = statSync(p);
91
+ if (s.mtimeMs < cutoff)
92
+ unlinkSync(p);
93
+ }
94
+ catch { /* noop */ }
95
+ }
96
+ }
97
+ catch { /* noop */ }
98
+ emit('info', 'debug.init', { level: state.level, sessionId });
99
+ }
100
+ }
101
+ function isValidLevel(s) {
102
+ return s === 'off' || s === 'info' || s === 'debug' || s === 'trace';
103
+ }
104
+ /**
105
+ * Emit a debug event. The fastest path is the early-return when the
106
+ * configured level is below the event's level — a single integer compare.
107
+ *
108
+ * `data` is shallow-cloned to a JSON-safe form. Functions, BigInts, and
109
+ * circular refs are stripped via the replacer to keep emit cheap and
110
+ * crash-free regardless of what callers throw in.
111
+ */
112
+ export function emit(eventLevel, eventName, data) {
113
+ if (LEVEL_ORDER[state.level] < LEVEL_ORDER[eventLevel])
114
+ return;
115
+ if (!state.logPath)
116
+ return;
117
+ const record = {
118
+ t: new Date().toISOString(),
119
+ rel: Date.now() - state.startedAt,
120
+ lvl: eventLevel,
121
+ ev: eventName,
122
+ ...(data ? { data: safeClone(data) } : {}),
123
+ };
124
+ try {
125
+ appendFileSync(state.logPath, JSON.stringify(record) + '\n', 'utf-8');
126
+ state.eventCount++;
127
+ }
128
+ catch {
129
+ // If the log file write fails, we don't want to spam errors into
130
+ // the REPL — silently drop the event. The user can re-enable via
131
+ // /debug if the underlying issue is fixed.
132
+ }
133
+ }
134
+ /**
135
+ * JSON.stringify replacer that prevents crashes on circular refs,
136
+ * BigInt, functions, and overly-large strings. Truncates strings to
137
+ * 8KB so a single huge prompt or tool output doesn't bloat the log.
138
+ */
139
+ function safeClone(input) {
140
+ const seen = new WeakSet();
141
+ return JSON.parse(JSON.stringify(input, (_key, value) => {
142
+ if (typeof value === 'bigint')
143
+ return value.toString() + 'n';
144
+ if (typeof value === 'function')
145
+ return '[function]';
146
+ if (typeof value === 'string' && value.length > 8192) {
147
+ return value.slice(0, 8192) + `…[truncated ${value.length - 8192}b]`;
148
+ }
149
+ if (value && typeof value === 'object') {
150
+ if (seen.has(value))
151
+ return '[circular]';
152
+ seen.add(value);
153
+ }
154
+ return value;
155
+ }));
156
+ }
157
+ /**
158
+ * Public read-only state snapshot for /debug status output.
159
+ */
160
+ export function getDebugStatus() {
161
+ return {
162
+ level: state.level,
163
+ logPath: state.logPath,
164
+ eventCount: state.eventCount,
165
+ uptimeMs: Date.now() - state.startedAt,
166
+ };
167
+ }
168
+ /**
169
+ * Change the active debug level at runtime. Called from /debug on/off.
170
+ * If transitioning OFF → non-off, we ensure the log dir exists; if
171
+ * transitioning to OFF we leave the file alone (it's append-only and
172
+ * read by external tools).
173
+ */
174
+ export function setDebugLevel(level) {
175
+ const old = state.level;
176
+ state.level = level;
177
+ if (level !== 'off' && !state.logPath && state.sessionId) {
178
+ const dir = join(getHomeStateDir(), 'debug');
179
+ state.logPath = join(dir, `${state.sessionId}.jsonl`);
180
+ try {
181
+ mkdirSync(dir, { recursive: true });
182
+ }
183
+ catch { /* noop */ }
184
+ }
185
+ if (level !== 'off' && old !== level) {
186
+ emit('info', 'debug.level-change', { from: old, to: level });
187
+ }
188
+ }
189
+ /**
190
+ * Read the last N events from the current session's log. Used by
191
+ * /debug tail. Returns lines as JSON strings (one per event); the
192
+ * caller can pretty-print or pass through to jq.
193
+ */
194
+ export function tailDebug(n) {
195
+ if (!state.logPath || !existsSync(state.logPath))
196
+ return [];
197
+ try {
198
+ const raw = readFileSync(state.logPath, 'utf-8');
199
+ const lines = raw.split('\n').filter((l) => l.trim().length > 0);
200
+ return lines.slice(-Math.max(1, n));
201
+ }
202
+ catch {
203
+ return [];
204
+ }
205
+ }
206
+ /**
207
+ * True if any non-off level is active. Use this to gate expensive
208
+ * data preparation that you don't want to run when debug is off:
209
+ *
210
+ * if (isDebugActive()) {
211
+ * emit('debug', 'event-name', { detail: computeExpensiveDetail() });
212
+ * }
213
+ */
214
+ export function isDebugActive() {
215
+ return state.level !== 'off';
216
+ }
217
+ //# sourceMappingURL=debug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACjH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAI9C,MAAM,WAAW,GAA+B;IAC9C,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,CAAC;CACT,CAAC;AAUF,MAAM,KAAK,GAAe;IACxB,KAAK,EAAE,KAAK;IACZ,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,CAAC;IACb,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;CACtB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,aAAmC;IAC9E,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACjD,MAAM,SAAS,GAAG,CAAC,aAAa,IAAI,QAAQ,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IACpF,KAAK,CAAC,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;IAE1D,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,OAAO,CAAC,CAAC;QAC7C,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,QAAQ,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC,CAAC,uDAAuD,CAAC,CAAC;QACnE,2CAA2C;QAC3C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;YAChD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBAC1B,IAAI,CAAC;oBACH,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;oBACtB,IAAI,CAAC,CAAC,OAAO,GAAG,MAAM;wBAAE,UAAU,CAAC,CAAC,CAAC,CAAC;gBACxC,CAAC;gBAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QACtB,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,OAAO,CAAC;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,IAAI,CAClB,UAAsC,EACtC,SAAiB,EACjB,IAA8B;IAE9B,IAAI,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,UAAU,CAAC;QAAE,OAAO;IAC/D,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO;IAC3B,MAAM,MAAM,GAAG;QACb,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC3B,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS;QACjC,GAAG,EAAE,UAAU;QACf,EAAE,EAAE,SAAS;QACb,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3C,CAAC;IACF,IAAI,CAAC;QACH,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;QACtE,KAAK,CAAC,UAAU,EAAE,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;QACjE,iEAAiE;QACjE,2CAA2C;IAC7C,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,KAAc;IAC/B,MAAM,IAAI,GAAG,IAAI,OAAO,EAAU,CAAC;IACnC,OAAO,IAAI,CAAC,KAAK,CACf,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACpC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC;QAC7D,IAAI,OAAO,KAAK,KAAK,UAAU;YAAE,OAAO,YAAY,CAAC;QACrD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;YACrD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,eAAe,KAAK,CAAC,MAAM,GAAG,IAAI,IAAI,CAAC;QACvE,CAAC;QACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAe,CAAC;gBAAE,OAAO,YAAY,CAAC;YACnD,IAAI,CAAC,GAAG,CAAC,KAAe,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAM5B,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS;KACvC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC;IACxB,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,IAAI,KAAK,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACzD,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,OAAO,CAAC,CAAC;QAC7C,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,QAAQ,CAAC,CAAC;QACtD,IAAI,CAAC;YAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,KAAK,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,EAAE,oBAAoB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC;AAC/B,CAAC"}