aibroker 0.2.6 → 0.6.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.
Files changed (170) hide show
  1. package/README.md +164 -4
  2. package/dist/adapters/iterm/core.d.ts +2 -0
  3. package/dist/adapters/iterm/core.d.ts.map +1 -1
  4. package/dist/adapters/iterm/core.js +13 -5
  5. package/dist/adapters/iterm/core.js.map +1 -1
  6. package/dist/adapters/iterm/iterm2-api.d.ts +20 -0
  7. package/dist/adapters/iterm/iterm2-api.d.ts.map +1 -0
  8. package/dist/adapters/iterm/iterm2-api.js +244 -0
  9. package/dist/adapters/iterm/iterm2-api.js.map +1 -0
  10. package/dist/adapters/iterm/sessions.d.ts.map +1 -1
  11. package/dist/adapters/iterm/sessions.js +3 -2
  12. package/dist/adapters/iterm/sessions.js.map +1 -1
  13. package/dist/adapters/kokoro/media.d.ts +2 -1
  14. package/dist/adapters/kokoro/media.d.ts.map +1 -1
  15. package/dist/adapters/kokoro/media.js +53 -5
  16. package/dist/adapters/kokoro/media.js.map +1 -1
  17. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-56).d.ts +49 -0
  18. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-56).d.ts.map +1 -0
  19. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-56).js +632 -0
  20. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-56).js.map +1 -0
  21. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-13-59).js +632 -0
  22. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-36).d.ts +49 -0
  23. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-36).d.ts.map +1 -0
  24. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-36).js +614 -0
  25. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-36).js.map +1 -0
  26. package/dist/adapters/pailot/gateway (SFConflict mnott 2026-03-06-21-15-46).js +614 -0
  27. package/dist/adapters/pailot/gateway.d.ts +48 -0
  28. package/dist/adapters/pailot/gateway.d.ts (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  29. package/dist/adapters/pailot/gateway.d.ts (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  30. package/dist/adapters/pailot/gateway.d.ts.map +1 -0
  31. package/dist/adapters/pailot/gateway.js +828 -0
  32. package/dist/adapters/pailot/gateway.js (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  33. package/dist/adapters/pailot/gateway.js (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  34. package/dist/adapters/pailot/gateway.js.map +1 -0
  35. package/dist/backend/api.d.ts +5 -1
  36. package/dist/backend/api.d.ts.map +1 -1
  37. package/dist/backend/api.js +74 -3
  38. package/dist/backend/api.js.map +1 -1
  39. package/dist/core/hybrid.d.ts +7 -0
  40. package/dist/core/hybrid.d.ts.map +1 -1
  41. package/dist/core/hybrid.js +33 -0
  42. package/dist/core/hybrid.js.map +1 -1
  43. package/dist/core/state.d.ts +3 -0
  44. package/dist/core/state.d.ts.map +1 -1
  45. package/dist/core/state.js +4 -0
  46. package/dist/core/state.js.map +1 -1
  47. package/dist/core/status-cache.d.ts +51 -0
  48. package/dist/core/status-cache.d.ts.map +1 -0
  49. package/dist/core/status-cache.js +62 -0
  50. package/dist/core/status-cache.js.map +1 -0
  51. package/dist/daemon/adapter-registry (SFConflict mnott 2026-03-06-21-15-36).d.ts +63 -0
  52. package/dist/daemon/adapter-registry (SFConflict mnott 2026-03-06-21-15-36).d.ts.map +1 -0
  53. package/dist/daemon/adapter-registry (SFConflict mnott 2026-03-06-21-15-36).js +229 -0
  54. package/dist/daemon/adapter-registry (SFConflict mnott 2026-03-06-21-15-36).js.map +1 -0
  55. package/dist/daemon/adapter-registry.d.ts +63 -0
  56. package/dist/daemon/adapter-registry.d.ts.map +1 -0
  57. package/dist/daemon/adapter-registry.js +240 -0
  58. package/dist/daemon/adapter-registry.js.map +1 -0
  59. package/dist/daemon/cli.d.ts +14 -0
  60. package/dist/daemon/cli.d.ts.map +1 -0
  61. package/dist/daemon/cli.js +150 -0
  62. package/dist/daemon/cli.js.map +1 -0
  63. package/dist/daemon/command-context.d.ts +24 -0
  64. package/dist/daemon/command-context.d.ts.map +1 -0
  65. package/dist/daemon/command-context.js +13 -0
  66. package/dist/daemon/command-context.js.map +1 -0
  67. package/dist/daemon/commands.d.ts +22 -0
  68. package/dist/daemon/commands.d.ts.map +1 -0
  69. package/dist/daemon/commands.js +632 -0
  70. package/dist/daemon/commands.js.map +1 -0
  71. package/dist/daemon/core-handlers.d.ts +24 -0
  72. package/dist/daemon/core-handlers.d.ts.map +1 -0
  73. package/dist/daemon/core-handlers.js +640 -0
  74. package/dist/daemon/core-handlers.js.map +1 -0
  75. package/dist/daemon/create-adapter.d.ts +22 -0
  76. package/dist/daemon/create-adapter.d.ts.map +1 -0
  77. package/dist/daemon/create-adapter.js +153 -0
  78. package/dist/daemon/create-adapter.js.map +1 -0
  79. package/dist/daemon/image-gen.d.ts +28 -0
  80. package/dist/daemon/image-gen.d.ts.map +1 -0
  81. package/dist/daemon/image-gen.js +97 -0
  82. package/dist/daemon/image-gen.js.map +1 -0
  83. package/dist/daemon/index.d.ts +12 -0
  84. package/dist/daemon/index.d.ts.map +1 -0
  85. package/dist/daemon/index.js +184 -0
  86. package/dist/daemon/index.js.map +1 -0
  87. package/dist/daemon/pai-projects.d.ts +68 -0
  88. package/dist/daemon/pai-projects.d.ts.map +1 -0
  89. package/dist/daemon/pai-projects.js +174 -0
  90. package/dist/daemon/pai-projects.js.map +1 -0
  91. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-56).d.ts +12 -0
  92. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-56).d.ts.map +1 -0
  93. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-56).js +252 -0
  94. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-56).js.map +1 -0
  95. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-13-59).js +252 -0
  96. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).d.ts +12 -0
  97. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).d.ts.map +1 -0
  98. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).js +240 -0
  99. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).js.map +1 -0
  100. package/dist/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-46).js +240 -0
  101. package/dist/daemon/screenshot.d.ts +12 -0
  102. package/dist/daemon/screenshot.d.ts (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  103. package/dist/daemon/screenshot.d.ts (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  104. package/dist/daemon/screenshot.d.ts.map +1 -0
  105. package/dist/daemon/screenshot.js +252 -0
  106. package/dist/daemon/screenshot.js (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  107. package/dist/daemon/screenshot.js (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  108. package/dist/daemon/screenshot.js.map +1 -0
  109. package/dist/daemon/session-content.d.ts +27 -0
  110. package/dist/daemon/session-content.d.ts.map +1 -0
  111. package/dist/daemon/session-content.js +76 -0
  112. package/dist/daemon/session-content.js.map +1 -0
  113. package/dist/daemon/vision.d.ts +46 -0
  114. package/dist/daemon/vision.d.ts.map +1 -0
  115. package/dist/daemon/vision.js +176 -0
  116. package/dist/daemon/vision.js.map +1 -0
  117. package/dist/index.d.ts +16 -2
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +12 -1
  120. package/dist/index.js.map +1 -1
  121. package/dist/ipc/client.d.ts +4 -1
  122. package/dist/ipc/client.d.ts.map +1 -1
  123. package/dist/ipc/client.js +10 -1
  124. package/dist/ipc/client.js.map +1 -1
  125. package/dist/ipc/validate.d.ts +52 -0
  126. package/dist/ipc/validate.d.ts.map +1 -0
  127. package/dist/ipc/validate.js +129 -0
  128. package/dist/ipc/validate.js.map +1 -0
  129. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-56).d.ts +23 -0
  130. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-56).d.ts.map +1 -0
  131. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-56).js +595 -0
  132. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-56).js.map +1 -0
  133. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-13-59).js +595 -0
  134. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-36).d.ts +23 -0
  135. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-36).d.ts.map +1 -0
  136. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-36).js +592 -0
  137. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-36).js.map +1 -0
  138. package/dist/mcp/index (SFConflict mnott 2026-03-06-21-15-46).js +592 -0
  139. package/dist/mcp/index.d.ts +23 -0
  140. package/dist/mcp/index.d.ts.map +1 -0
  141. package/dist/mcp/index.js +660 -0
  142. package/dist/mcp/index.js (SFConflict mnott 2026-03-06-21-13-59).map +1 -0
  143. package/dist/mcp/index.js (SFConflict mnott 2026-03-06-21-15-46).map +1 -0
  144. package/dist/mcp/index.js.map +1 -0
  145. package/dist/types/adapter.d.ts +41 -0
  146. package/dist/types/adapter.d.ts.map +1 -0
  147. package/dist/types/adapter.js +2 -0
  148. package/dist/types/adapter.js.map +1 -0
  149. package/dist/types/backend.d.ts +29 -1
  150. package/dist/types/backend.d.ts.map +1 -1
  151. package/dist/types/broker.d.ts +47 -0
  152. package/dist/types/broker.d.ts.map +1 -0
  153. package/dist/types/broker.js +21 -0
  154. package/dist/types/broker.js.map +1 -0
  155. package/dist/types/index.d.ts +2 -0
  156. package/dist/types/index.d.ts.map +1 -1
  157. package/dist/types/index.js +2 -0
  158. package/dist/types/index.js.map +1 -1
  159. package/package.json +12 -2
  160. package/templates/adapter/ONBOARDING_PROMPT.md +309 -0
  161. package/templates/adapter/README.md.tmpl +81 -0
  162. package/templates/adapter/package.json.tmpl +23 -0
  163. package/templates/adapter/src/watcher/cli.ts.tmpl +12 -0
  164. package/templates/adapter/src/watcher/commands.ts.tmpl +44 -0
  165. package/templates/adapter/src/watcher/connection.ts.tmpl +59 -0
  166. package/templates/adapter/src/watcher/index.ts.tmpl +201 -0
  167. package/templates/adapter/src/watcher/ipc-server.ts.tmpl +250 -0
  168. package/templates/adapter/src/watcher/send.ts.tmpl +62 -0
  169. package/templates/adapter/src/watcher/state.ts.tmpl +39 -0
  170. package/templates/adapter/tsconfig.json.tmpl +14 -0
@@ -0,0 +1,252 @@
1
+ /**
2
+ * daemon/screenshot.ts — Screenshot capture for the AIBroker hub.
3
+ *
4
+ * Captures the iTerm2 window containing the active session and sends
5
+ * it back through the CommandContext reply channel. Handles screen-lock
6
+ * detection with text fallback.
7
+ *
8
+ * Extracted from Whazaa's screenshot.ts — now transport-agnostic.
9
+ */
10
+ import { readFileSync, unlinkSync } from "node:fs";
11
+ import { tmpdir } from "node:os";
12
+ import { join } from "node:path";
13
+ import { spawnSync, execSync } from "node:child_process";
14
+ import { runAppleScript, stripItermPrefix, } from "../adapters/iterm/core.js";
15
+ import { listClaudeSessions } from "../adapters/iterm/sessions.js";
16
+ import { log } from "../core/log.js";
17
+ import { activeClientId, activeItermSessionId, setActiveItermSessionId, sessionRegistry, } from "../core/state.js";
18
+ import { broadcastImage, broadcastText } from "../adapters/pailot/gateway.js";
19
+ let lastScreenshotContent = null;
20
+ function getActiveSessionContent() {
21
+ const activeEntry = activeClientId ? sessionRegistry.get(activeClientId) : undefined;
22
+ const itermId = stripItermPrefix((activeItermSessionId || undefined) ?? activeEntry?.itermSessionId);
23
+ if (!itermId)
24
+ return null;
25
+ const result = spawnSync("osascript", [], {
26
+ input: `tell application "iTerm2"
27
+ repeat with w in windows
28
+ repeat with t in tabs of w
29
+ repeat with s in sessions of t
30
+ if id of s is "${itermId}" then
31
+ return contents of s
32
+ end if
33
+ end repeat
34
+ end repeat
35
+ end repeat
36
+ return ""
37
+ end tell`,
38
+ stdio: ["pipe", "pipe", "pipe"],
39
+ timeout: 10_000,
40
+ });
41
+ if (result.status !== 0 || result.signal)
42
+ return null;
43
+ const stdout = result.stdout?.toString().trim() ?? "";
44
+ return stdout || null;
45
+ }
46
+ async function handleTextScreenshot(ctx) {
47
+ try {
48
+ const candidates = [];
49
+ const activeEntry = activeClientId ? sessionRegistry.get(activeClientId) : undefined;
50
+ const primaryId = stripItermPrefix((activeItermSessionId || undefined) ?? activeEntry?.itermSessionId);
51
+ if (primaryId)
52
+ candidates.push({ id: primaryId, source: "active" });
53
+ const registryEntries = [...sessionRegistry.values()]
54
+ .sort((a, b) => b.registeredAt - a.registeredAt);
55
+ for (const entry of registryEntries) {
56
+ const rid = stripItermPrefix(entry.itermSessionId);
57
+ if (rid && !candidates.some((c) => c.id === rid)) {
58
+ candidates.push({ id: rid, source: `registry:${entry.name}` });
59
+ }
60
+ }
61
+ if (candidates.length === 0) {
62
+ await ctx.reply("Screen is locked and no iTerm2 session found — cannot capture.");
63
+ return;
64
+ }
65
+ for (const candidate of candidates) {
66
+ const script = `tell application "iTerm2"
67
+ repeat with w in windows
68
+ repeat with t in tabs of w
69
+ repeat with s in sessions of t
70
+ if id of s is "${candidate.id}" then
71
+ return contents of s
72
+ end if
73
+ end repeat
74
+ end repeat
75
+ end repeat
76
+ return "::NOT_FOUND::"
77
+ end tell`;
78
+ const result = spawnSync("osascript", [], {
79
+ input: script,
80
+ stdio: ["pipe", "pipe", "pipe"],
81
+ timeout: 10_000,
82
+ });
83
+ const stdout = result.stdout?.toString().trim() ?? "";
84
+ if (result.signal === "SIGTERM" || result.status !== 0 || stdout === "::NOT_FOUND::" || stdout === "")
85
+ continue;
86
+ lastScreenshotContent = stdout;
87
+ // Send to PAILot (skip if the request came from PAILot — ctx.reply handles it)
88
+ if (ctx.source !== "pailot") {
89
+ const cleaned = stdout
90
+ .split("\n")
91
+ .filter((line) => !/^[─━═┄┈╌╍┅┉]{3,}\s*$/.test(line.trim()))
92
+ .filter((line) => line.trim() !== "")
93
+ .slice(-50)
94
+ .join("\n");
95
+ broadcastText(`Terminal capture (screen locked):\n\n${cleaned}`);
96
+ }
97
+ // Send to originating adapter
98
+ const maxLen = 4000;
99
+ const trimmed = stdout.length > maxLen ? "...\n" + stdout.slice(-maxLen) : stdout;
100
+ await ctx.reply(`*Terminal capture (screen locked):*\n\n\`\`\`\n${trimmed}\n\`\`\``);
101
+ return;
102
+ }
103
+ await ctx.reply(`Screen is locked — tried ${candidates.length} session(s) but none returned buffer content.`);
104
+ }
105
+ catch (err) {
106
+ const msg = err instanceof Error ? err.message : String(err);
107
+ log(`/ss: text capture error — ${msg}`);
108
+ await ctx.reply(`Screen is locked — text capture failed: ${msg}`);
109
+ }
110
+ }
111
+ export async function handleScreenshot(ctx) {
112
+ // Check if content is unchanged
113
+ const currentContent = getActiveSessionContent();
114
+ if (currentContent && lastScreenshotContent) {
115
+ const tail = (s) => s.split("\n").slice(-100).join("\n").trim();
116
+ if (tail(currentContent) === tail(lastScreenshotContent)) {
117
+ const lines = currentContent
118
+ .split("\n")
119
+ .filter((l) => !/^[─━═┄┈╌╍┅┉]{3,}\s*$/.test(l.trim()))
120
+ .filter((l) => l.trim() !== "")
121
+ .slice(-30)
122
+ .join("\n");
123
+ if (lines) {
124
+ if (ctx.source !== "pailot")
125
+ broadcastText(lines);
126
+ await ctx.reply(`*Terminal (unchanged):*\n\n\`\`\`\n${lines}\n\`\`\``);
127
+ log("/ss: content unchanged, sent tail as text");
128
+ return;
129
+ }
130
+ }
131
+ }
132
+ lastScreenshotContent = currentContent;
133
+ // Check screen lock
134
+ try {
135
+ const lockCheck = spawnSync("sh", ["-c", "ioreg -n Root -d1 -a | grep -c CGSSessionScreenIsLocked"], { timeout: 5_000, encoding: "utf8" });
136
+ if (parseInt((lockCheck.stdout ?? "0").trim(), 10) > 0) {
137
+ log("/ss: screen is locked — falling back to terminal text capture");
138
+ await handleTextScreenshot(ctx);
139
+ return;
140
+ }
141
+ }
142
+ catch { /* proceed */ }
143
+ await ctx.reply("Capturing screenshot...");
144
+ const filePath = join(tmpdir(), `aibroker-screenshot-${Date.now()}.png`);
145
+ try {
146
+ // Resolve the window
147
+ let windowId;
148
+ const activeEntry = activeClientId ? sessionRegistry.get(activeClientId) : undefined;
149
+ let itermSessionId = stripItermPrefix((activeItermSessionId || undefined) ?? activeEntry?.itermSessionId);
150
+ if (!itermSessionId) {
151
+ const registryEntries = [...sessionRegistry.values()]
152
+ .sort((a, b) => b.registeredAt - a.registeredAt);
153
+ const newest = registryEntries.find(e => e.itermSessionId);
154
+ if (newest?.itermSessionId) {
155
+ itermSessionId = stripItermPrefix(newest.itermSessionId);
156
+ setActiveItermSessionId(itermSessionId);
157
+ }
158
+ }
159
+ if (!itermSessionId) {
160
+ const liveSessions = listClaudeSessions();
161
+ if (liveSessions.length > 0) {
162
+ itermSessionId = liveSessions[0].id;
163
+ setActiveItermSessionId(liveSessions[0].id);
164
+ }
165
+ }
166
+ if (itermSessionId) {
167
+ const findAndRaiseScript = `tell application "iTerm2"
168
+ repeat with w in windows
169
+ set tabCount to count of tabs of w
170
+ repeat with tabIdx from 1 to tabCount
171
+ set t to tab tabIdx of w
172
+ repeat with s in sessions of t
173
+ if id of s is "${itermSessionId}" then
174
+ select t
175
+ set index of w to 1
176
+ activate
177
+ return (id of w as text)
178
+ end if
179
+ end repeat
180
+ end repeat
181
+ end repeat
182
+ return ""
183
+ end tell`;
184
+ const findResult = runAppleScript(findAndRaiseScript);
185
+ if (findResult && findResult !== "") {
186
+ windowId = findResult.trim();
187
+ }
188
+ else {
189
+ runAppleScript('tell application "iTerm2" to activate');
190
+ const fb = runAppleScript(`tell application "iTerm2"\n set w to window 1\n activate\n return (id of w as text)\nend tell`) ?? "";
191
+ windowId = fb.trim();
192
+ }
193
+ }
194
+ else {
195
+ runAppleScript('tell application "iTerm2" to activate');
196
+ const fb = runAppleScript(`tell application "iTerm2"\n set w to window 1\n activate\n return (id of w as text)\nend tell`) ?? "";
197
+ windowId = fb.trim();
198
+ }
199
+ if (!windowId) {
200
+ await ctx.reply("Error: Could not get iTerm2 window ID.");
201
+ return;
202
+ }
203
+ await new Promise((r) => setTimeout(r, 1500));
204
+ const boundsScript = `tell application "iTerm2"
205
+ repeat with w in windows
206
+ if (id of w as text) is "${windowId}" then
207
+ set wBounds to bounds of w
208
+ set wx to item 1 of wBounds
209
+ set wy to item 2 of wBounds
210
+ set wx2 to item 3 of wBounds
211
+ set wy2 to item 4 of wBounds
212
+ return (wx as text) & "," & (wy as text) & "," & ((wx2 - wx) as text) & "," & ((wy2 - wy) as text)
213
+ end if
214
+ end repeat
215
+ return ""
216
+ end tell`;
217
+ const boundsResult = runAppleScript(boundsScript) ?? "";
218
+ const bounds = boundsResult.trim();
219
+ if (!bounds || !bounds.includes(",")) {
220
+ throw new Error("Could not get window bounds from iTerm2");
221
+ }
222
+ log(`/ss: capturing screen region ${bounds} (iTerm2 window ${windowId})`);
223
+ execSync(`/usr/sbin/screencapture -x -R ${bounds} "${filePath}"`, { timeout: 15_000 });
224
+ const buffer = readFileSync(filePath);
225
+ // Send to PAILot WebSocket clients (skip if request came from PAILot)
226
+ if (ctx.source !== "pailot")
227
+ broadcastImage(buffer, "Screenshot");
228
+ // Send to originating adapter
229
+ await ctx.replyImage(buffer, "Screenshot");
230
+ log("/ss: screenshot sent");
231
+ }
232
+ catch (err) {
233
+ const msg = err instanceof Error ? err.message : String(err);
234
+ log(`/ss: screencapture failed — ${msg}`);
235
+ // If screencapture failed (e.g. screen locked but ioreg didn't detect it,
236
+ // or "could not create image from rect"), fall back to text mode
237
+ log("/ss: falling back to terminal text capture");
238
+ try {
239
+ unlinkSync(filePath);
240
+ }
241
+ catch { /* ignore */ }
242
+ await handleTextScreenshot(ctx);
243
+ return;
244
+ }
245
+ finally {
246
+ try {
247
+ unlinkSync(filePath);
248
+ }
249
+ catch { /* ignore */ }
250
+ }
251
+ }
252
+ //# sourceMappingURL=screenshot.js.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * daemon/screenshot.ts — Screenshot capture for the AIBroker hub.
3
+ *
4
+ * Captures the iTerm2 window containing the active session and sends
5
+ * it back through the CommandContext reply channel. Handles screen-lock
6
+ * detection with text fallback.
7
+ *
8
+ * Extracted from Whazaa's screenshot.ts — now transport-agnostic.
9
+ */
10
+ import type { CommandContext } from "./command-context.js";
11
+ export declare function handleScreenshot(ctx: CommandContext): Promise<void>;
12
+ //# sourceMappingURL=screenshot%20(SFConflict%20mnott%202026-03-06-21-15-36).d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot (SFConflict mnott 2026-03-06-21-15-36).d.ts","sourceRoot":"","sources":["../../src/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAyG3D,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA6IzE"}
@@ -0,0 +1,240 @@
1
+ /**
2
+ * daemon/screenshot.ts — Screenshot capture for the AIBroker hub.
3
+ *
4
+ * Captures the iTerm2 window containing the active session and sends
5
+ * it back through the CommandContext reply channel. Handles screen-lock
6
+ * detection with text fallback.
7
+ *
8
+ * Extracted from Whazaa's screenshot.ts — now transport-agnostic.
9
+ */
10
+ import { readFileSync, unlinkSync } from "node:fs";
11
+ import { tmpdir } from "node:os";
12
+ import { join } from "node:path";
13
+ import { spawnSync, execSync } from "node:child_process";
14
+ import { runAppleScript, stripItermPrefix, } from "../adapters/iterm/core.js";
15
+ import { listClaudeSessions } from "../adapters/iterm/sessions.js";
16
+ import { log } from "../core/log.js";
17
+ import { activeClientId, activeItermSessionId, setActiveItermSessionId, sessionRegistry, } from "../core/state.js";
18
+ import { broadcastImage, broadcastText } from "../adapters/pailot/gateway.js";
19
+ let lastScreenshotContent = null;
20
+ function getActiveSessionContent() {
21
+ const activeEntry = activeClientId ? sessionRegistry.get(activeClientId) : undefined;
22
+ const itermId = stripItermPrefix((activeItermSessionId || undefined) ?? activeEntry?.itermSessionId);
23
+ if (!itermId)
24
+ return null;
25
+ const result = spawnSync("osascript", [], {
26
+ input: `tell application "iTerm2"
27
+ repeat with w in windows
28
+ repeat with t in tabs of w
29
+ repeat with s in sessions of t
30
+ if id of s is "${itermId}" then
31
+ return contents of s
32
+ end if
33
+ end repeat
34
+ end repeat
35
+ end repeat
36
+ return ""
37
+ end tell`,
38
+ stdio: ["pipe", "pipe", "pipe"],
39
+ timeout: 10_000,
40
+ });
41
+ if (result.status !== 0 || result.signal)
42
+ return null;
43
+ const stdout = result.stdout?.toString().trim() ?? "";
44
+ return stdout || null;
45
+ }
46
+ async function handleTextScreenshot(ctx) {
47
+ try {
48
+ const candidates = [];
49
+ const activeEntry = activeClientId ? sessionRegistry.get(activeClientId) : undefined;
50
+ const primaryId = stripItermPrefix((activeItermSessionId || undefined) ?? activeEntry?.itermSessionId);
51
+ if (primaryId)
52
+ candidates.push({ id: primaryId, source: "active" });
53
+ const registryEntries = [...sessionRegistry.values()]
54
+ .sort((a, b) => b.registeredAt - a.registeredAt);
55
+ for (const entry of registryEntries) {
56
+ const rid = stripItermPrefix(entry.itermSessionId);
57
+ if (rid && !candidates.some((c) => c.id === rid)) {
58
+ candidates.push({ id: rid, source: `registry:${entry.name}` });
59
+ }
60
+ }
61
+ if (candidates.length === 0) {
62
+ await ctx.reply("Screen is locked and no iTerm2 session found — cannot capture.");
63
+ return;
64
+ }
65
+ for (const candidate of candidates) {
66
+ const script = `tell application "iTerm2"
67
+ repeat with w in windows
68
+ repeat with t in tabs of w
69
+ repeat with s in sessions of t
70
+ if id of s is "${candidate.id}" then
71
+ return contents of s
72
+ end if
73
+ end repeat
74
+ end repeat
75
+ end repeat
76
+ return "::NOT_FOUND::"
77
+ end tell`;
78
+ const result = spawnSync("osascript", [], {
79
+ input: script,
80
+ stdio: ["pipe", "pipe", "pipe"],
81
+ timeout: 10_000,
82
+ });
83
+ const stdout = result.stdout?.toString().trim() ?? "";
84
+ if (result.signal === "SIGTERM" || result.status !== 0 || stdout === "::NOT_FOUND::" || stdout === "")
85
+ continue;
86
+ lastScreenshotContent = stdout;
87
+ // Send to PAILot
88
+ const cleaned = stdout
89
+ .split("\n")
90
+ .filter((line) => !/^[─━═┄┈╌╍┅┉]{3,}\s*$/.test(line.trim()))
91
+ .filter((line) => line.trim() !== "")
92
+ .slice(-50)
93
+ .join("\n");
94
+ broadcastText(`Terminal capture (screen locked):\n\n${cleaned}`);
95
+ // Send to originating adapter
96
+ const maxLen = 4000;
97
+ const trimmed = stdout.length > maxLen ? "...\n" + stdout.slice(-maxLen) : stdout;
98
+ await ctx.reply(`*Terminal capture (screen locked):*\n\n\`\`\`\n${trimmed}\n\`\`\``);
99
+ return;
100
+ }
101
+ await ctx.reply(`Screen is locked — tried ${candidates.length} session(s) but none returned buffer content.`);
102
+ }
103
+ catch (err) {
104
+ const msg = err instanceof Error ? err.message : String(err);
105
+ log(`/ss: text capture error — ${msg}`);
106
+ await ctx.reply(`Screen is locked — text capture failed: ${msg}`);
107
+ }
108
+ }
109
+ export async function handleScreenshot(ctx) {
110
+ // Check if content is unchanged
111
+ const currentContent = getActiveSessionContent();
112
+ if (currentContent && lastScreenshotContent) {
113
+ const tail = (s) => s.split("\n").slice(-100).join("\n").trim();
114
+ if (tail(currentContent) === tail(lastScreenshotContent)) {
115
+ const lines = currentContent
116
+ .split("\n")
117
+ .filter((l) => !/^[─━═┄┈╌╍┅┉]{3,}\s*$/.test(l.trim()))
118
+ .filter((l) => l.trim() !== "")
119
+ .slice(-30)
120
+ .join("\n");
121
+ if (lines) {
122
+ broadcastText(lines);
123
+ await ctx.reply(`*Terminal (unchanged):*\n\n\`\`\`\n${lines}\n\`\`\``);
124
+ log("/ss: content unchanged, sent tail as text");
125
+ return;
126
+ }
127
+ }
128
+ }
129
+ lastScreenshotContent = currentContent;
130
+ // Check screen lock
131
+ try {
132
+ const lockCheck = spawnSync("sh", ["-c", "ioreg -n Root -d1 -a | grep -c CGSSessionScreenIsLocked"], { timeout: 5_000, encoding: "utf8" });
133
+ if (parseInt((lockCheck.stdout ?? "0").trim(), 10) > 0) {
134
+ log("/ss: screen is locked — falling back to terminal text capture");
135
+ await handleTextScreenshot(ctx);
136
+ return;
137
+ }
138
+ }
139
+ catch { /* proceed */ }
140
+ await ctx.reply("Capturing screenshot...");
141
+ const filePath = join(tmpdir(), `aibroker-screenshot-${Date.now()}.png`);
142
+ try {
143
+ // Resolve the window
144
+ let windowId;
145
+ const activeEntry = activeClientId ? sessionRegistry.get(activeClientId) : undefined;
146
+ let itermSessionId = stripItermPrefix((activeItermSessionId || undefined) ?? activeEntry?.itermSessionId);
147
+ if (!itermSessionId) {
148
+ const registryEntries = [...sessionRegistry.values()]
149
+ .sort((a, b) => b.registeredAt - a.registeredAt);
150
+ const newest = registryEntries.find(e => e.itermSessionId);
151
+ if (newest?.itermSessionId) {
152
+ itermSessionId = stripItermPrefix(newest.itermSessionId);
153
+ setActiveItermSessionId(itermSessionId);
154
+ }
155
+ }
156
+ if (!itermSessionId) {
157
+ const liveSessions = listClaudeSessions();
158
+ if (liveSessions.length > 0) {
159
+ itermSessionId = liveSessions[0].id;
160
+ setActiveItermSessionId(liveSessions[0].id);
161
+ }
162
+ }
163
+ if (itermSessionId) {
164
+ const findAndRaiseScript = `tell application "iTerm2"
165
+ repeat with w in windows
166
+ set tabCount to count of tabs of w
167
+ repeat with tabIdx from 1 to tabCount
168
+ set t to tab tabIdx of w
169
+ repeat with s in sessions of t
170
+ if id of s is "${itermSessionId}" then
171
+ select t
172
+ set index of w to 1
173
+ activate
174
+ return (id of w as text)
175
+ end if
176
+ end repeat
177
+ end repeat
178
+ end repeat
179
+ return ""
180
+ end tell`;
181
+ const findResult = runAppleScript(findAndRaiseScript);
182
+ if (findResult && findResult !== "") {
183
+ windowId = findResult.trim();
184
+ }
185
+ else {
186
+ runAppleScript('tell application "iTerm2" to activate');
187
+ const fb = runAppleScript(`tell application "iTerm2"\n set w to window 1\n activate\n return (id of w as text)\nend tell`) ?? "";
188
+ windowId = fb.trim();
189
+ }
190
+ }
191
+ else {
192
+ runAppleScript('tell application "iTerm2" to activate');
193
+ const fb = runAppleScript(`tell application "iTerm2"\n set w to window 1\n activate\n return (id of w as text)\nend tell`) ?? "";
194
+ windowId = fb.trim();
195
+ }
196
+ if (!windowId) {
197
+ await ctx.reply("Error: Could not get iTerm2 window ID.");
198
+ return;
199
+ }
200
+ await new Promise((r) => setTimeout(r, 1500));
201
+ const boundsScript = `tell application "iTerm2"
202
+ repeat with w in windows
203
+ if (id of w as text) is "${windowId}" then
204
+ set wBounds to bounds of w
205
+ set wx to item 1 of wBounds
206
+ set wy to item 2 of wBounds
207
+ set wx2 to item 3 of wBounds
208
+ set wy2 to item 4 of wBounds
209
+ return (wx as text) & "," & (wy as text) & "," & ((wx2 - wx) as text) & "," & ((wy2 - wy) as text)
210
+ end if
211
+ end repeat
212
+ return ""
213
+ end tell`;
214
+ const boundsResult = runAppleScript(boundsScript) ?? "";
215
+ const bounds = boundsResult.trim();
216
+ if (!bounds || !bounds.includes(",")) {
217
+ throw new Error("Could not get window bounds from iTerm2");
218
+ }
219
+ log(`/ss: capturing screen region ${bounds} (iTerm2 window ${windowId})`);
220
+ execSync(`/usr/sbin/screencapture -x -R ${bounds} "${filePath}"`, { timeout: 15_000 });
221
+ const buffer = readFileSync(filePath);
222
+ // Send to PAILot WebSocket clients
223
+ broadcastImage(buffer, "Screenshot");
224
+ // Send to originating adapter
225
+ await ctx.replyImage(buffer, "Screenshot");
226
+ log("/ss: screenshot sent");
227
+ }
228
+ catch (err) {
229
+ const msg = err instanceof Error ? err.message : String(err);
230
+ log(`/ss: error — ${msg}`);
231
+ await ctx.reply(`Error taking screenshot: ${msg}`);
232
+ }
233
+ finally {
234
+ try {
235
+ unlinkSync(filePath);
236
+ }
237
+ catch { /* ignore */ }
238
+ }
239
+ }
240
+ //# sourceMappingURL=screenshot%20(SFConflict%20mnott%202026-03-06-21-15-36).js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot (SFConflict mnott 2026-03-06-21-15-36).js","sourceRoot":"","sources":["../../src/daemon/screenshot (SFConflict mnott 2026-03-06-21-15-36).ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EACL,cAAc,EACd,gBAAgB,GAEjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG9E,IAAI,qBAAqB,GAAkB,IAAI,CAAC;AAEhD,SAAS,uBAAuB;IAC9B,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACrF,MAAM,OAAO,GAAG,gBAAgB,CAC9B,CAAC,oBAAoB,IAAI,SAAS,CAAC,IAAI,WAAW,EAAE,cAAc,CACnE,CAAC;IACF,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,EAAE,EAAE,EAAE;QACxC,KAAK,EAAE;;;;yBAIc,OAAO;;;;;;;SAOvB;QACL,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;QAC/B,OAAO,EAAE,MAAM;KAChB,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACtD,OAAO,MAAM,IAAI,IAAI,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,GAAmB;IACrD,IAAI,CAAC;QACH,MAAM,UAAU,GAA0C,EAAE,CAAC;QAC7D,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrF,MAAM,SAAS,GAAG,gBAAgB,CAChC,CAAC,oBAAoB,IAAI,SAAS,CAAC,IAAI,WAAW,EAAE,cAAc,CACnE,CAAC;QACF,IAAI,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEpE,MAAM,eAAe,GAAG,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC;aAClD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;QACnD,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,gBAAgB,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YACnD,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC;gBACjD,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACjE,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,GAAG,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;YAClF,OAAO;QACT,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG;;;;yBAII,SAAS,CAAC,EAAE;;;;;;;SAO5B,CAAC;YAEJ,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,EAAE,EAAE,EAAE;gBACxC,KAAK,EAAE,MAAM;gBACb,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;gBAC/B,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;YACtD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,eAAe,IAAI,MAAM,KAAK,EAAE;gBAAE,SAAS;YAEhH,qBAAqB,GAAG,MAAM,CAAC;YAE/B,iBAAiB;YACjB,MAAM,OAAO,GAAG,MAAM;iBACnB,KAAK,CAAC,IAAI,CAAC;iBACX,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;iBACnE,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;iBAC5C,KAAK,CAAC,CAAC,EAAE,CAAC;iBACV,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,aAAa,CAAC,wCAAwC,OAAO,EAAE,CAAC,CAAC;YAEjE,8BAA8B;YAC9B,MAAM,MAAM,GAAG,IAAI,CAAC;YACpB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAClF,MAAM,GAAG,CAAC,KAAK,CAAC,kDAAkD,OAAO,UAAU,CAAC,CAAC;YACrF,OAAO;QACT,CAAC;QAED,MAAM,GAAG,CAAC,KAAK,CAAC,4BAA4B,UAAU,CAAC,MAAM,+CAA+C,CAAC,CAAC;IAChH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,GAAG,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;QACxC,MAAM,GAAG,CAAC,KAAK,CAAC,2CAA2C,GAAG,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAmB;IACxD,gCAAgC;IAChC,MAAM,cAAc,GAAG,uBAAuB,EAAE,CAAC;IACjD,IAAI,cAAc,IAAI,qBAAqB,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACxE,IAAI,IAAI,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC;YACzD,MAAM,KAAK,GAAG,cAAc;iBACzB,KAAK,CAAC,IAAI,CAAC;iBACX,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;iBAC7D,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;iBACtC,KAAK,CAAC,CAAC,EAAE,CAAC;iBACV,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,IAAI,KAAK,EAAE,CAAC;gBACV,aAAa,CAAC,KAAK,CAAC,CAAC;gBACrB,MAAM,GAAG,CAAC,KAAK,CAAC,sCAAsC,KAAK,UAAU,CAAC,CAAC;gBACvE,GAAG,CAAC,2CAA2C,CAAC,CAAC;gBACjD,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;IACD,qBAAqB,GAAG,cAAc,CAAC;IAEvC,oBAAoB;IACpB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,SAAS,CACzB,IAAI,EACJ,CAAC,IAAI,EAAE,yDAAyD,CAAC,EACjE,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CACrC,CAAC;QACF,IAAI,QAAQ,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,+DAA+D,CAAC,CAAC;YACrE,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;YAChC,OAAO;QACT,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC;IAEzB,MAAM,GAAG,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAEzE,IAAI,CAAC;QACH,qBAAqB;QACrB,IAAI,QAAgB,CAAC;QACrB,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrF,IAAI,cAAc,GAAG,gBAAgB,CAAC,CAAC,oBAAoB,IAAI,SAAS,CAAC,IAAI,WAAW,EAAE,cAAc,CAAC,CAAC;QAE1G,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,eAAe,GAAG,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC;iBAClD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;YACnD,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;YAC3D,IAAI,MAAM,EAAE,cAAc,EAAE,CAAC;gBAC3B,cAAc,GAAG,gBAAgB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;gBACzD,uBAAuB,CAAC,cAAe,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;YAC1C,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,cAAc,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QAED,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,kBAAkB,GAAG;;;;;;yBAMR,cAAc;;;;;;;;;;SAU9B,CAAC;YACJ,MAAM,UAAU,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAC;YACtD,IAAI,UAAU,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;gBACpC,QAAQ,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,uCAAuC,CAAC,CAAC;gBACxD,MAAM,EAAE,GAAG,cAAc,CAAC,kGAAkG,CAAC,IAAI,EAAE,CAAC;gBACpI,QAAQ,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,uCAAuC,CAAC,CAAC;YACxD,MAAM,EAAE,GAAG,cAAc,CAAC,kGAAkG,CAAC,IAAI,EAAE,CAAC;YACpI,QAAQ,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,GAAG,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QAED,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAE9C,MAAM,YAAY,GAAG;;+BAEM,QAAQ;;;;;;;;;;SAU9B,CAAC;QACN,MAAM,YAAY,GAAG,cAAc,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QAED,GAAG,CAAC,gCAAgC,MAAM,mBAAmB,QAAQ,GAAG,CAAC,CAAC;QAC1E,QAAQ,CAAC,iCAAiC,MAAM,KAAK,QAAQ,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAEvF,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QAEtC,mCAAmC;QACnC,cAAc,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAErC,8BAA8B;QAC9B,MAAM,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAE3C,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,GAAG,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC;QAC3B,MAAM,GAAG,CAAC,KAAK,CAAC,4BAA4B,GAAG,EAAE,CAAC,CAAC;IACrD,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}