litmus-cli 1.0.14 → 1.0.17

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.
@@ -1,11 +1,24 @@
1
1
  import { readFile, writeFile, mkdir } from "fs/promises";
2
2
  import { existsSync } from "fs";
3
3
  import path from "path";
4
+ /**
5
+ * Calculate the effective deadline timestamp (ms) from config.
6
+ * Returns null if no deadline or time limit is configured.
7
+ *
8
+ * NOTE: This logic is duplicated in watcher.cjs (which is CommonJS and
9
+ * cannot import this module). Keep both in sync.
10
+ */
11
+ export function getEffectiveDeadline(config) {
12
+ const candidates = [
13
+ config.deadline ? new Date(config.deadline).getTime() : Infinity,
14
+ config.startedAt && config.timeLimit
15
+ ? new Date(config.startedAt).getTime() + config.timeLimit * 60000
16
+ : Infinity,
17
+ ].filter(t => t !== Infinity);
18
+ return candidates.length > 0 ? Math.min(...candidates) : null;
19
+ }
4
20
  const CONFIG_DIR = ".litmus";
5
21
  const CONFIG_FILE = "config.json";
6
- export function getConfigPath(projectRoot) {
7
- return path.join(projectRoot, CONFIG_DIR, CONFIG_FILE);
8
- }
9
22
  export async function writeConfig(projectRoot, config) {
10
23
  const configDir = path.join(projectRoot, CONFIG_DIR);
11
24
  await mkdir(configDir, { recursive: true });
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AAC/B,OAAO,IAAI,MAAM,MAAM,CAAA;AAevB,MAAM,UAAU,GAAG,SAAS,CAAA;AAC5B,MAAM,WAAW,GAAG,aAAa,CAAA;AAEjC,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,WAAW,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,WAAmB,EACnB,MAAoB;IAEpB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAA;IACpD,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IACpD,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IACvB,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,CAAC,CAAA;QAC1D,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,OAAO,GAAG,CAAA;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAK;QACzB,GAAG,GAAG,MAAM,CAAA;IACd,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEvB,6DAA6D;IAC7D,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,CAAC,CAAA;QAC1D,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;YAC9C,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAA;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CACb,0GAA0G,CAC3G,CAAA;YACH,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAK,CAAC,0BAA0B;QACpD,GAAG,GAAG,MAAM,CAAA;IACd,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Litmus AI prompt logger.
4
+ * Universal hook script invoked by Claude Code, GitHub Copilot CLI, and OpenAI Codex CLI.
5
+ *
6
+ * Usage:
7
+ * node hook-logger.cjs <tool>
8
+ *
9
+ * Each tool pipes JSON on stdin when a user submits a prompt:
10
+ * - Claude Code (UserPromptSubmit): stdin JSON with session_id, prompt content
11
+ * - Copilot CLI (userPromptSubmitted): { timestamp, cwd, prompt }
12
+ * - Codex CLI: experimental hooks support (format TBD)
13
+ *
14
+ * Normalizes to: { ts, type: "ai_prompt", tool, prompt, sessionId? }
15
+ * Appends to .litmus/activity.jsonl — the same file the watcher uses,
16
+ * so prompts flow through the existing analysis pipeline.
17
+ * Also uploads the event to the server (fire-and-forget) for real-time backup.
18
+ */
19
+
20
+ const fs = require("fs")
21
+ const path = require("path")
22
+ const https = require("https")
23
+ const http = require("http")
24
+
25
+ // Keep under the server's MAX_EVENT_SIZE (2048 bytes) after JSON serialization.
26
+ // ~1800 chars of prompt + ~150 bytes of wrapper fields + JSON escaping = safely under 2KB.
27
+ const MAX_PROMPT_LENGTH = 1800
28
+
29
+ const tool = process.argv[2] || "unknown"
30
+
31
+ // Find the .litmus directory — walk up from cwd
32
+ function findLitmusDir() {
33
+ let dir = process.cwd()
34
+ for (let i = 0; i < 10; i++) {
35
+ const candidate = path.join(dir, ".litmus")
36
+ if (fs.existsSync(candidate)) return candidate
37
+ const parent = path.dirname(dir)
38
+ if (parent === dir) break
39
+ dir = parent
40
+ }
41
+ return null
42
+ }
43
+
44
+ // Read config.json for server upload credentials
45
+ function readConfig(litmusDir) {
46
+ try {
47
+ const configPath = path.join(litmusDir, "config.json")
48
+ return JSON.parse(fs.readFileSync(configPath, "utf8"))
49
+ } catch {
50
+ return null
51
+ }
52
+ }
53
+
54
+ // Fire-and-forget upload to /cli/activity.
55
+ // Uses socket.unref() so Node exits immediately without waiting for the response —
56
+ // the OS TCP stack still flushes the outbound data after our process exits.
57
+ function uploadEvent(config, event) {
58
+ if (!config || !config.token || !config.backendUrl) return
59
+
60
+ const body = JSON.stringify({ events: [event] })
61
+ const url = new URL(
62
+ `${config.backendUrl}/cli/activity?token=${encodeURIComponent(config.token)}`
63
+ )
64
+ const reqFn = url.protocol === "https:" ? https.request : http.request
65
+
66
+ const req = reqFn(url, {
67
+ method: "POST",
68
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(body) },
69
+ timeout: 5000,
70
+ })
71
+ req.on("error", () => {}) // Swallow — fire-and-forget
72
+ req.on("timeout", () => { req.destroy() })
73
+ req.on("socket", (socket) => { socket.unref() }) // Don't keep process alive for response
74
+ req.end(body)
75
+ }
76
+
77
+ function readStdin() {
78
+ return new Promise((resolve) => {
79
+ let resolved = false
80
+ const chunks = []
81
+ process.stdin.setEncoding("utf8")
82
+ process.stdin.on("data", (chunk) => chunks.push(chunk))
83
+ process.stdin.on("end", () => {
84
+ if (!resolved) { resolved = true; resolve(chunks.join("")) }
85
+ })
86
+ // Safety timeout — stdin should arrive immediately from hook runners.
87
+ // Keep this short to avoid blocking the AI tool.
88
+ setTimeout(() => {
89
+ if (!resolved) { resolved = true; resolve(chunks.join("")) }
90
+ }, 300)
91
+ })
92
+ }
93
+
94
+ function extractPrompt(input, toolName) {
95
+ try {
96
+ const data = JSON.parse(input)
97
+
98
+ switch (toolName) {
99
+ case "claude": {
100
+ // Claude Code UserPromptSubmit: prompt may be in message.content or content field
101
+ const prompt = data.user_message
102
+ || data.prompt
103
+ || (data.message && data.message.content)
104
+ || null
105
+ return {
106
+ prompt: typeof prompt === "string" ? prompt : JSON.stringify(prompt),
107
+ sessionId: data.session_id || null,
108
+ }
109
+ }
110
+ case "copilot": {
111
+ // Copilot CLI userPromptSubmitted: { timestamp, cwd, prompt }
112
+ return {
113
+ prompt: data.prompt || null,
114
+ sessionId: null,
115
+ }
116
+ }
117
+ case "codex": {
118
+ // Codex CLI: experimental, extract what we can
119
+ const prompt = data.prompt
120
+ || data.user_message
121
+ || (data.message && data.message.content)
122
+ || null
123
+ return {
124
+ prompt: typeof prompt === "string" ? prompt : JSON.stringify(prompt),
125
+ sessionId: data.thread_id || null,
126
+ }
127
+ }
128
+ default: {
129
+ // Best-effort: look for common field names
130
+ const prompt = data.prompt || data.user_message || data.content || null
131
+ return {
132
+ prompt: typeof prompt === "string" ? prompt : JSON.stringify(prompt),
133
+ sessionId: data.session_id || null,
134
+ }
135
+ }
136
+ }
137
+ } catch {
138
+ return { prompt: null, sessionId: null }
139
+ }
140
+ }
141
+
142
+ async function main() {
143
+ const litmusDir = findLitmusDir()
144
+ if (!litmusDir) return // Not in a Litmus assessment — silently exit
145
+
146
+ const raw = await readStdin()
147
+ if (!raw.trim()) return
148
+
149
+ const { prompt, sessionId } = extractPrompt(raw, tool)
150
+ if (!prompt) return
151
+
152
+ const truncated = prompt.length > MAX_PROMPT_LENGTH
153
+ ? prompt.slice(0, MAX_PROMPT_LENGTH) + "...[truncated]"
154
+ : prompt
155
+
156
+ const event = {
157
+ ts: new Date().toISOString(),
158
+ type: "ai_prompt",
159
+ tool,
160
+ prompt: truncated,
161
+ }
162
+ if (sessionId) event.sessionId = sessionId
163
+
164
+ // 1. Append to activity.jsonl (for submission ZIP)
165
+ const logPath = path.join(litmusDir, "activity.jsonl")
166
+ try {
167
+ fs.appendFileSync(logPath, JSON.stringify(event) + "\n")
168
+ } catch {
169
+ // Non-critical
170
+ }
171
+
172
+ // 2. Upload to server (fire-and-forget, for real-time backup)
173
+ const config = readConfig(litmusDir)
174
+ uploadEvent(config, event)
175
+
176
+ // No explicit process.exit() — the event loop drains naturally.
177
+ // The HTTP socket is unref'd so it won't keep the process alive.
178
+ }
179
+
180
+ main().catch(() => process.exit(0))
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Start the file watcher in the background.
3
- * Spawns an inline Node script as a detached process; logs file events to
3
+ * Spawns watcher.cjs as a detached process; logs file events to
4
4
  * <projectDir>/.litmus/activity.jsonl for later inclusion in the submission ZIP.
5
5
  */
6
6
  export declare function startTracker(projectDir: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AAuBA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CA2BrD"}
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAyCrD"}
@@ -1,27 +1,21 @@
1
1
  import { spawn } from "child_process";
2
- import { mkdirSync, openSync, writeFileSync } from "fs";
2
+ import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from "fs";
3
3
  import path from "path";
4
- const WATCHER_SCRIPT = `
5
- const fs = require("fs");
6
- const path = require("path");
7
- const args = process.argv.slice(-2);
8
- const projectDir = args[0];
9
- const activityLogPath = args[1];
10
- if (!projectDir || !activityLogPath) { process.stderr.write("[watcher] missing args: " + JSON.stringify(process.argv) + "\\n"); process.exit(1); }
11
- if (!fs.existsSync(projectDir)) { process.stderr.write("[watcher] dir not found: " + projectDir + "\\n"); process.exit(1); }
12
- fs.mkdirSync(path.dirname(activityLogPath), { recursive: true });
13
- const log = fs.createWriteStream(activityLogPath, { flags: "a" });
14
- const IGNORED = [/[\\/]\\./,/node_modules/,/__pycache__/,/\\.pyc$/,/\\.class$/,/[\\/]venv[\\/]/,/[\\/]\\.venv[\\/]/];
15
- function shouldIgnore(p) { return IGNORED.some(r => r.test(p)); }
16
- function write(type, rel) { log.write(JSON.stringify({ ts: new Date().toISOString(), type, path: rel }) + "\\n"); }
17
- process.on("uncaughtException", (err) => { process.stderr.write("[watcher] crash: " + err + "\\n"); process.exit(1); });
18
- const w = fs.watch(projectDir, { recursive: true }, (ev, f) => { if (f && !shouldIgnore(f)) write(ev, f); });
19
- w.on("error", (err) => { process.stderr.write("[watcher] watch error: " + err + "\\n"); });
20
- process.stderr.write("[watcher] running, watching " + projectDir + "\\n");
21
- `;
4
+ import { fileURLToPath } from "url";
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ function isProcessAlive(pid) {
8
+ try {
9
+ process.kill(pid, 0); // Signal 0 = check if process exists
10
+ return true;
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
22
16
  /**
23
17
  * Start the file watcher in the background.
24
- * Spawns an inline Node script as a detached process; logs file events to
18
+ * Spawns watcher.cjs as a detached process; logs file events to
25
19
  * <projectDir>/.litmus/activity.jsonl for later inclusion in the submission ZIP.
26
20
  */
27
21
  export function startTracker(projectDir) {
@@ -35,8 +29,22 @@ export function startTracker(projectDir) {
35
29
  catch {
36
30
  // Non-critical
37
31
  }
32
+ // Check if a watcher is already running
33
+ if (existsSync(pidFile)) {
34
+ try {
35
+ const existingPid = parseInt(readFileSync(pidFile, "utf8").trim(), 10);
36
+ if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
37
+ return; // Watcher already running
38
+ }
39
+ }
40
+ catch {
41
+ // PID file unreadable — proceed to spawn a new watcher
42
+ }
43
+ }
38
44
  const errFd = openSync(errLog, "a");
39
- const child = spawn(process.execPath, ["-e", WATCHER_SCRIPT, "--", projectDir, activityLog], {
45
+ const watcherPath = path.join(__dirname, "watcher.cjs");
46
+ const cliBinPath = path.join(__dirname, "..", "index.js");
47
+ const child = spawn(process.execPath, [watcherPath, projectDir, activityLog, cliBinPath], {
40
48
  detached: true,
41
49
  stdio: ["ignore", "ignore", errFd],
42
50
  });
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AACvD,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;CAiBtB,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACnD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IAElD,IAAI,CAAC;QACH,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAEnC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE;QAC3F,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC;KACnC,CAAC,CAAA;IAEF,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,IAAI,CAAC;YACH,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/lib/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AACjF,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AAEnC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACjD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;AAE1C,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA,CAAC,qCAAqC;QAC1D,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACnD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IAElD,IAAI,CAAC;QACH,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;IAED,wCAAwC;IACxC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;YACtE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;gBACvD,OAAM,CAAC,0BAA0B;YACnC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,CAAA;IAEzD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE;QACxF,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC;KACnC,CAAC,CAAA;IAEF,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,KAAK,CAAC,KAAK,EAAE,CAAA;QACb,IAAI,CAAC;YACH,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;AACH,CAAC"}