@bragi-gmbh/codebus 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/bin/codebus.js +2 -0
  2. package/dist/binding-guard.js +97 -0
  3. package/dist/binding-guard.js.map +1 -0
  4. package/dist/client.js +94 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/commands/ack.js +47 -0
  7. package/dist/commands/ack.js.map +1 -0
  8. package/dist/commands/archive.js +21 -0
  9. package/dist/commands/archive.js.map +1 -0
  10. package/dist/commands/as.js +299 -0
  11. package/dist/commands/as.js.map +1 -0
  12. package/dist/commands/ask.js +189 -0
  13. package/dist/commands/ask.js.map +1 -0
  14. package/dist/commands/auth.js +33 -0
  15. package/dist/commands/auth.js.map +1 -0
  16. package/dist/commands/checkin.js +235 -0
  17. package/dist/commands/checkin.js.map +1 -0
  18. package/dist/commands/decision.js +52 -0
  19. package/dist/commands/decision.js.map +1 -0
  20. package/dist/commands/digest.js +117 -0
  21. package/dist/commands/digest.js.map +1 -0
  22. package/dist/commands/doctor.js +106 -0
  23. package/dist/commands/doctor.js.map +1 -0
  24. package/dist/commands/factory.js +191 -0
  25. package/dist/commands/factory.js.map +1 -0
  26. package/dist/commands/github-login.js +205 -0
  27. package/dist/commands/github-login.js.map +1 -0
  28. package/dist/commands/graph.js +88 -0
  29. package/dist/commands/graph.js.map +1 -0
  30. package/dist/commands/health.js +34 -0
  31. package/dist/commands/health.js.map +1 -0
  32. package/dist/commands/inbox.js +83 -0
  33. package/dist/commands/inbox.js.map +1 -0
  34. package/dist/commands/ingest.js +553 -0
  35. package/dist/commands/ingest.js.map +1 -0
  36. package/dist/commands/init.js +97 -0
  37. package/dist/commands/init.js.map +1 -0
  38. package/dist/commands/install.js +520 -0
  39. package/dist/commands/install.js.map +1 -0
  40. package/dist/commands/invite.js +152 -0
  41. package/dist/commands/invite.js.map +1 -0
  42. package/dist/commands/jira.js +237 -0
  43. package/dist/commands/jira.js.map +1 -0
  44. package/dist/commands/join.js +96 -0
  45. package/dist/commands/join.js.map +1 -0
  46. package/dist/commands/links.js +66 -0
  47. package/dist/commands/links.js.map +1 -0
  48. package/dist/commands/login.js +84 -0
  49. package/dist/commands/login.js.map +1 -0
  50. package/dist/commands/morning.js +121 -0
  51. package/dist/commands/morning.js.map +1 -0
  52. package/dist/commands/next.js +66 -0
  53. package/dist/commands/next.js.map +1 -0
  54. package/dist/commands/onboarding.js +109 -0
  55. package/dist/commands/onboarding.js.map +1 -0
  56. package/dist/commands/pack.js +276 -0
  57. package/dist/commands/pack.js.map +1 -0
  58. package/dist/commands/plan-gh.js +425 -0
  59. package/dist/commands/plan-gh.js.map +1 -0
  60. package/dist/commands/plan.js +465 -0
  61. package/dist/commands/plan.js.map +1 -0
  62. package/dist/commands/pr.js +88 -0
  63. package/dist/commands/pr.js.map +1 -0
  64. package/dist/commands/question.js +142 -0
  65. package/dist/commands/question.js.map +1 -0
  66. package/dist/commands/read.js +84 -0
  67. package/dist/commands/read.js.map +1 -0
  68. package/dist/commands/refs.js +357 -0
  69. package/dist/commands/refs.js.map +1 -0
  70. package/dist/commands/reply.js +38 -0
  71. package/dist/commands/reply.js.map +1 -0
  72. package/dist/commands/repo.js +1198 -0
  73. package/dist/commands/repo.js.map +1 -0
  74. package/dist/commands/report.js +41 -0
  75. package/dist/commands/report.js.map +1 -0
  76. package/dist/commands/resolve-refs.js +21 -0
  77. package/dist/commands/resolve-refs.js.map +1 -0
  78. package/dist/commands/resolve.js +93 -0
  79. package/dist/commands/resolve.js.map +1 -0
  80. package/dist/commands/send.js +168 -0
  81. package/dist/commands/send.js.map +1 -0
  82. package/dist/commands/sent.js +22 -0
  83. package/dist/commands/sent.js.map +1 -0
  84. package/dist/commands/session.js +426 -0
  85. package/dist/commands/session.js.map +1 -0
  86. package/dist/commands/statusline.js +43 -0
  87. package/dist/commands/statusline.js.map +1 -0
  88. package/dist/commands/task.js +140 -0
  89. package/dist/commands/task.js.map +1 -0
  90. package/dist/commands/tick.js +233 -0
  91. package/dist/commands/tick.js.map +1 -0
  92. package/dist/commands/upgrade.js +76 -0
  93. package/dist/commands/upgrade.js.map +1 -0
  94. package/dist/commands/watch.js +169 -0
  95. package/dist/commands/watch.js.map +1 -0
  96. package/dist/commands/whoami.js +27 -0
  97. package/dist/commands/whoami.js.map +1 -0
  98. package/dist/config.js +103 -0
  99. package/dist/config.js.map +1 -0
  100. package/dist/directives.js +102 -0
  101. package/dist/directives.js.map +1 -0
  102. package/dist/errors.js +110 -0
  103. package/dist/errors.js.map +1 -0
  104. package/dist/git-hooks.js +116 -0
  105. package/dist/git-hooks.js.map +1 -0
  106. package/dist/graph-bootstrap.js +95 -0
  107. package/dist/graph-bootstrap.js.map +1 -0
  108. package/dist/graph-remote.js +889 -0
  109. package/dist/graph-remote.js.map +1 -0
  110. package/dist/graph.js +335 -0
  111. package/dist/graph.js.map +1 -0
  112. package/dist/index.js +154 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/kit/graph-publish.mjs +400 -0
  115. package/dist/mail-latency.js +120 -0
  116. package/dist/mail-latency.js.map +1 -0
  117. package/dist/mcp-registry.js +859 -0
  118. package/dist/mcp-registry.js.map +1 -0
  119. package/dist/mcp.js +193 -0
  120. package/dist/mcp.js.map +1 -0
  121. package/dist/output.js +12 -0
  122. package/dist/output.js.map +1 -0
  123. package/dist/positioning.js +21 -0
  124. package/dist/positioning.js.map +1 -0
  125. package/dist/rolestore.js +89 -0
  126. package/dist/rolestore.js.map +1 -0
  127. package/dist/session.js +49 -0
  128. package/dist/session.js.map +1 -0
  129. package/dist/sessionstore.js +736 -0
  130. package/dist/sessionstore.js.map +1 -0
  131. package/dist/version-check.js +97 -0
  132. package/dist/version-check.js.map +1 -0
  133. package/package.json +47 -0
@@ -0,0 +1,553 @@
1
+ /**
2
+ * ingest.ts — S3: Knowledge sources index (delta scan, index-not-mirror)
3
+ *
4
+ * `codebus ingest connect [--repo <slug>] [--dry-run]`
5
+ * Delta-scans .md/doc files changed since last_indexed_sha, computes
6
+ * content-hash, upserts knowledge_sources rows.
7
+ * Rename (R) → new row with prev_source_id=old, old tombstoned.
8
+ * Delete (D) → tombstone.
9
+ * Refuses to run on non-main branches.
10
+ * Best-effort secret-scan: skips files matching known secret patterns.
11
+ * Repo resolution (Known Defect #5 fix, docs/plans/repo-intelligence.md
12
+ * A4): `--repo` wins if given (hard error if that slug isn't connected in
13
+ * this workspace); otherwise this checkout's `origin` remote is matched
14
+ * against `repos.remote_url`. No more silent `"default"`-slug auto-create
15
+ * — an unrecognized/unmatched repo is now a hard, actionable error naming
16
+ * `codebus repo connect`.
17
+ *
18
+ * `codebus ingest status`
19
+ * Shows counts + staleness vs HEAD (reuses checkStaleness). Same repo
20
+ * resolution as `connect`, but degrades to an "unknown" staleness note
21
+ * instead of throwing — status is read-only and informational.
22
+ *
23
+ * Primitives reused: repos (0014), checkStaleness (graph.ts), client/config.
24
+ */
25
+ import { createHash } from "node:crypto";
26
+ import { execSync, execFileSync } from "node:child_process";
27
+ import { readFileSync, existsSync } from "node:fs";
28
+ import { join } from "node:path";
29
+ import { resolveConfig } from "../config.js";
30
+ import { makeCtx, workspaceId } from "../client.js";
31
+ import { CodebusError } from "../errors.js";
32
+ import { checkStaleness, loadGraphSnapshot } from "../graph.js";
33
+ import { parseOwnerRepo, redactUrlUserinfo } from "./plan-gh.js";
34
+ // ── Secret-scan regex pack ─────────────────────────────────────────────────
35
+ /**
36
+ * Best-effort secret-scan patterns.
37
+ * Files matching ANY pattern are skipped (never recorded).
38
+ */
39
+ export const SECRET_PATTERNS = [
40
+ /AKIA[0-9A-Z]{16}/, // AWS access key
41
+ /-----BEGIN (RSA |EC |OPENSSH |DSA )?PRIVATE KEY/, // PEM private key
42
+ /\bsk-[A-Za-z0-9]{20,}/, // OpenAI sk-
43
+ /\bghp_[A-Za-z0-9]{36,}/, // GitHub personal access token
44
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}/, // Slack tokens
45
+ /password\s*=\s*['"][^'"]{4,}/i, // password= assignment
46
+ /secret\s*=\s*['"][^'"]{4,}/i, // secret= assignment
47
+ /[A-Za-z0-9+/]{40,}={0,2}/, // high-entropy base64 (≥40 chars)
48
+ ];
49
+ /**
50
+ * Returns true if the file body contains a suspected secret.
51
+ * Reads at most 64 KB to keep it fast.
52
+ */
53
+ export function containsSecret(body) {
54
+ for (const pat of SECRET_PATTERNS) {
55
+ if (pat.test(body))
56
+ return true;
57
+ }
58
+ return false;
59
+ }
60
+ // ── Doc extension filter ───────────────────────────────────────────────────
61
+ const DOC_EXTENSIONS = [".md", ".mdx", ".rst", ".txt", ".adoc", ".adr"];
62
+ export function isDocFile(filePath) {
63
+ const lower = filePath.toLowerCase();
64
+ return DOC_EXTENSIONS.some((ext) => lower.endsWith(ext));
65
+ }
66
+ /** Classify a file path into knowledge_sources.kind */
67
+ export function classifyKind(filePath) {
68
+ const lower = filePath.toLowerCase();
69
+ if (lower.endsWith(".adr") || lower.includes("/adr/") || lower.includes("/adrs/"))
70
+ return "adr";
71
+ if (lower.endsWith(".md") || lower.endsWith(".mdx"))
72
+ return "md";
73
+ return "doc";
74
+ }
75
+ /**
76
+ * Parse `git diff --name-status --find-renames` output into FileChange records.
77
+ * Lines look like:
78
+ * A\tdocs/new.md
79
+ * M\tdocs/old.md
80
+ * D\tdocs/gone.md
81
+ * R100\tdocs/old.md\tdocs/new.md
82
+ */
83
+ export function parseNameStatus(output) {
84
+ const changes = [];
85
+ for (const line of output.split("\n")) {
86
+ const trimmed = line.trim();
87
+ if (!trimmed)
88
+ continue;
89
+ const parts = trimmed.split("\t");
90
+ const status = parts[0];
91
+ if (status.startsWith("R")) {
92
+ const oldPath = parts[1];
93
+ const newPath = parts[2];
94
+ if (oldPath && newPath) {
95
+ changes.push({ kind: "R", path: newPath, oldPath });
96
+ }
97
+ }
98
+ else if (status === "A" || status === "M") {
99
+ const path = parts[1];
100
+ if (path)
101
+ changes.push({ kind: status, path });
102
+ }
103
+ else if (status === "D") {
104
+ const path = parts[1];
105
+ if (path)
106
+ changes.push({ kind: "D", path });
107
+ }
108
+ }
109
+ return changes;
110
+ }
111
+ // ── Gitignore / .codebusignore helper ─────────────────────────────────────
112
+ /**
113
+ * Read ignore patterns from .gitignore and .codebusignore (if present).
114
+ * Returns a list of path prefixes/patterns to skip.
115
+ */
116
+ export function readIgnorePatterns(repoRoot) {
117
+ const patterns = [];
118
+ for (const fname of [".gitignore", ".codebusignore"]) {
119
+ const p = join(repoRoot, fname);
120
+ if (existsSync(p)) {
121
+ const lines = readFileSync(p, "utf-8").split("\n");
122
+ for (const line of lines) {
123
+ const trimmed = line.trim();
124
+ if (trimmed && !trimmed.startsWith("#")) {
125
+ patterns.push(trimmed);
126
+ }
127
+ }
128
+ }
129
+ }
130
+ return patterns;
131
+ }
132
+ /**
133
+ * Returns true if the given file path matches any of the ignore patterns.
134
+ * Simple prefix/substring match (not full glob).
135
+ */
136
+ export function isIgnored(filePath, patterns) {
137
+ for (const pat of patterns) {
138
+ const stripped = pat.replace(/^\//, "").replace(/\/$/, "");
139
+ if (filePath === stripped || filePath.startsWith(stripped + "/") || filePath.includes("/" + stripped + "/")) {
140
+ return true;
141
+ }
142
+ }
143
+ return false;
144
+ }
145
+ // ── Repo detection ─────────────────────────────────────────────────────────
146
+ /**
147
+ * Get the current git branch.
148
+ */
149
+ export function getCurrentBranch(repoRoot) {
150
+ try {
151
+ return execSync("git rev-parse --abbrev-ref HEAD", { cwd: repoRoot, encoding: "utf-8" }).trim();
152
+ }
153
+ catch {
154
+ throw new CodebusError("not a git repository or git is not available");
155
+ }
156
+ }
157
+ /**
158
+ * Get HEAD commit sha.
159
+ */
160
+ export function getHeadSha(repoRoot) {
161
+ try {
162
+ return execSync("git rev-parse HEAD", { cwd: repoRoot, encoding: "utf-8" }).trim();
163
+ }
164
+ catch {
165
+ throw new CodebusError("failed to get HEAD sha");
166
+ }
167
+ }
168
+ /**
169
+ * Get changed files between two shas (or all tracked files at HEAD if fromSha is null).
170
+ *
171
+ * When fromSha is null (initial scan), uses `git ls-tree -r --name-only HEAD` to list
172
+ * all tracked files, then formats them as "A\tpath" lines to be parsed by parseNameStatus.
173
+ * This avoids the root-commit edge case with diff-tree.
174
+ */
175
+ export function getDiffNameStatus(repoRoot, fromSha, toSha) {
176
+ try {
177
+ if (fromSha) {
178
+ return execFileSync("git", ["diff", `${fromSha}..${toSha}`, "--name-status", "--find-renames"], {
179
+ cwd: repoRoot, encoding: "utf-8",
180
+ });
181
+ }
182
+ else {
183
+ // No prior sha — list ALL tracked files at HEAD as "A\tpath" lines
184
+ const files = execFileSync("git", ["ls-tree", "-r", "--name-only", toSha], {
185
+ cwd: repoRoot, encoding: "utf-8",
186
+ });
187
+ return files
188
+ .split("\n")
189
+ .filter(Boolean)
190
+ .map((f) => `A\t${f}`)
191
+ .join("\n");
192
+ }
193
+ }
194
+ catch {
195
+ return "";
196
+ }
197
+ }
198
+ /**
199
+ * Compute SHA-256 hex digest of file body.
200
+ */
201
+ export function computeContentHash(body) {
202
+ return createHash("sha256").update(body, "utf-8").digest("hex");
203
+ }
204
+ /**
205
+ * `git remote get-url origin`, or null if there is no such remote / this
206
+ * isn't a git checkout at all. Deliberately swallows every failure — the
207
+ * caller treats "no remote" the same as "couldn't tell", never a crash.
208
+ */
209
+ export function getGitRemoteUrl(repoRoot) {
210
+ try {
211
+ const url = execFileSync("git", ["remote", "get-url", "origin"], { cwd: repoRoot, encoding: "utf-8" }).trim();
212
+ return url || null;
213
+ }
214
+ catch {
215
+ return null;
216
+ }
217
+ }
218
+ export async function resolveConnectedRepo(ctx, ws, opts) {
219
+ const repoRoot = opts.repoRoot ?? process.cwd();
220
+ if (opts.repo) {
221
+ // Round-20 review finding (CONFIRMED, PR #55 comment 3827670905): this
222
+ // used to be a bare `.eq("slug", opts.repo)` lookup — it neither
223
+ // rejected a retired row nor followed `retired_into`, so
224
+ // `--repo <loser-dup-slug>` (a stale bookmark/CI config surviving a
225
+ // `collapse_duplicate_repo_group` collapse — the loser's OWN row is
226
+ // never deleted, only renamed to `-dup-<n>` and retired) resolved to
227
+ // the retired loser's id, and every subsequent `knowledge_sources`
228
+ // upsert/tombstone in this ingest run wrote against a repo_id that is
229
+ // dead for every graph query RPC and dropped by `repo list`. This is
230
+ // the client-side sibling of the round-17 `graph_resolve_repo_id` fix
231
+ // (0070_repo_connect.sql) — reused here via RPC (the SAME resolver
232
+ // graph-remote.ts's `matchRepoByRemote`-adjacent callers already use,
233
+ // `security invoker`+`grant ... to authenticated`, so this CLI's own
234
+ // session can call it directly) rather than re-implementing the
235
+ // bounded-loop-with-cycle-guard client-side: one fewer place for that
236
+ // chain-walk to drift out of sync with the SQL original.
237
+ const { data: repoId, error: rpcError } = await ctx.supabase.rpc("graph_resolve_repo_id", {
238
+ p_caller: "codebus-ingest",
239
+ p_repo_slug: opts.repo,
240
+ p_workspace_slug: ctx.workspaceSlug,
241
+ });
242
+ if (rpcError || !repoId) {
243
+ throw new CodebusError(`unknown repo '${opts.repo}' in this workspace — run \`codebus repo connect <github-url> --slug ${opts.repo}\` first, or check --repo.`);
244
+ }
245
+ // graph_resolve_repo_id returns only the (already retired_into-
246
+ // resolved) canonical id — one follow-up lookup for its CURRENT slug,
247
+ // both to satisfy ResolvedRepo's contract and to detect (for the
248
+ // redirect note below) whether opts.repo actually named a retired row.
249
+ const { data: canonical, error: canonicalError } = await ctx.supabase
250
+ .from("repos").select("id, slug").eq("id", repoId).single();
251
+ if (canonicalError || !canonical) {
252
+ throw new CodebusError(canonicalError?.message ?? `repo ${repoId} resolved but its row could not be re-read`);
253
+ }
254
+ return { id: canonical.id, slug: canonical.slug, requestedSlug: opts.repo };
255
+ }
256
+ const remoteUrl = getGitRemoteUrl(repoRoot);
257
+ if (!remoteUrl) {
258
+ throw new CodebusError("could not determine which repo this is: no --repo given and this checkout has no 'origin' git remote. " +
259
+ "Pass --repo <slug>, or run this from a checkout with an 'origin' remote, or `codebus repo connect <github-url>` first.");
260
+ }
261
+ const ownerRepo = parseOwnerRepo(remoteUrl);
262
+ if (!ownerRepo) {
263
+ // Round-19 review finding (CONFIRMED, credential-leakage theme — Luna
264
+ // PR #55 review, comment 3826839023): remoteUrl is THIS checkout's own
265
+ // 'origin' — fully attacker/environment-controlled, and a git remote
266
+ // legally embeds HTTP Basic-style userinfo (`https://token@github.com/
267
+ // ...`). Echoing it raw here wrote that credential straight to stderr
268
+ // (and any CI log capturing it) the instant the URL failed to parse.
269
+ throw new CodebusError(`could not parse a github.com owner/repo from this checkout's 'origin' remote (${redactUrlUserinfo(remoteUrl)}). ` +
270
+ "Pass --repo <slug>, or `codebus repo connect <github-url>` first.");
271
+ }
272
+ const { data: rows, error } = await ctx.supabase.from("repos").select("id, slug, remote_url").eq("workspace_id", ws);
273
+ if (error)
274
+ throw new CodebusError(error.message);
275
+ const matches = (rows ?? []).filter((r) => r.remote_url && parseOwnerRepo(r.remote_url) === ownerRepo);
276
+ if (matches.length === 0) {
277
+ // Same finding — the suggested `codebus repo connect <remote>` command
278
+ // must never repeat a credential-bearing URL either (doubly bad: it
279
+ // leaks it here AND encourages pasting it into shell history verbatim
280
+ // if the operator copies the suggestion literally).
281
+ throw new CodebusError(`no repo connected in this workspace matches origin remote '${ownerRepo}'. ` +
282
+ `Run \`codebus repo connect ${redactUrlUserinfo(remoteUrl)}\` first, or pass --repo <slug>.`);
283
+ }
284
+ if (matches.length > 1) {
285
+ throw new CodebusError(`origin remote '${ownerRepo}' matches more than one connected repo in this workspace ` +
286
+ `(${matches.map((m) => m.slug).join(", ")}) — pass --repo <slug> to disambiguate.`);
287
+ }
288
+ return { id: matches[0].id, slug: matches[0].slug };
289
+ }
290
+ /**
291
+ * Core ingest logic. Delta-scans .md/doc files and upserts knowledge_sources.
292
+ * Exported for unit testing and MCP reuse.
293
+ */
294
+ export async function ingestConnectCore(ctx, opts = {}) {
295
+ const repoRoot = opts.repoRoot ?? process.cwd();
296
+ const ws = await workspaceId(ctx);
297
+ // Refuse non-main branches
298
+ const branch = getCurrentBranch(repoRoot);
299
+ if (branch !== "main" && branch !== "master") {
300
+ throw new CodebusError(`ingest connect only runs on main/master (current branch: ${branch}). ` +
301
+ "Switch to main or use --force to override (not implemented in MVP).");
302
+ }
303
+ const headSha = getHeadSha(repoRoot);
304
+ const ignorePatterns = readIgnorePatterns(repoRoot);
305
+ // Resolve repo row — Known Defect #5 fix: no more "default"-slug
306
+ // auto-create footgun. resolveConnectedRepo throws a hard, actionable
307
+ // error for an unknown --repo or an unmatched origin remote; there is no
308
+ // longer a dry-run special case that pretends a fabricated repo exists.
309
+ let repoId;
310
+ let lastIndexedSha = null;
311
+ const repoRow = await resolveConnectedRepo(ctx, ws, { repo: opts.repo, repoRoot });
312
+ repoId = repoRow.id;
313
+ const redirectedFrom = repoRow.requestedSlug && repoRow.requestedSlug !== repoRow.slug
314
+ ? { requestedSlug: repoRow.requestedSlug, canonicalSlug: repoRow.slug }
315
+ : undefined;
316
+ // Get most recent last_indexed_sha for this repo
317
+ const { data: latestKs } = await ctx.supabase
318
+ .from("knowledge_sources")
319
+ .select("last_indexed_sha")
320
+ .eq("workspace_id", ws)
321
+ .eq("repo_id", repoId)
322
+ .eq("status", "active")
323
+ .order("created_at", { ascending: false })
324
+ .limit(1)
325
+ .maybeSingle();
326
+ if (latestKs?.last_indexed_sha) {
327
+ lastIndexedSha = latestKs.last_indexed_sha;
328
+ }
329
+ // Check if nothing changed (HEAD == lastIndexedSha)
330
+ if (lastIndexedSha && lastIndexedSha === headSha) {
331
+ return { upserted: 0, tombstoned: 0, skippedSecret: 0, skippedIgnore: 0, headSha, dryRun: !!opts.dryRun, redirectedFrom };
332
+ }
333
+ // Get changed files
334
+ const diffOutput = getDiffNameStatus(repoRoot, lastIndexedSha, headSha);
335
+ const allChanges = parseNameStatus(diffOutput);
336
+ // Filter to doc files only
337
+ const docChanges = allChanges.filter((c) => isDocFile(c.path));
338
+ let upserted = 0;
339
+ let tombstoned = 0;
340
+ let skippedSecret = 0;
341
+ let skippedIgnore = 0;
342
+ for (const change of docChanges) {
343
+ // Check ignore patterns
344
+ if (isIgnored(change.path, ignorePatterns) || (change.oldPath && isIgnored(change.oldPath, ignorePatterns))) {
345
+ skippedIgnore++;
346
+ continue;
347
+ }
348
+ if (change.kind === "D") {
349
+ // Tombstone: mark all active rows for this path as tombstoned
350
+ if (!opts.dryRun) {
351
+ await ctx.supabase
352
+ .from("knowledge_sources")
353
+ .update({ status: "tombstoned", updated_at: new Date().toISOString() })
354
+ .eq("workspace_id", ws)
355
+ .eq("repo_id", repoId)
356
+ .eq("path", change.path)
357
+ .eq("status", "active");
358
+ }
359
+ tombstoned++;
360
+ continue;
361
+ }
362
+ if (change.kind === "R" && change.oldPath) {
363
+ // Rename: tombstone old, insert new with prev_source_id
364
+ const absNewPath = join(repoRoot, change.path);
365
+ let body = "";
366
+ try {
367
+ body = readFileSync(absNewPath, "utf-8");
368
+ }
369
+ catch {
370
+ // File missing — skip
371
+ continue;
372
+ }
373
+ if (isIgnored(change.path, ignorePatterns)) {
374
+ skippedIgnore++;
375
+ continue;
376
+ }
377
+ if (containsSecret(body)) {
378
+ skippedSecret++;
379
+ continue;
380
+ }
381
+ const contentHash = computeContentHash(body);
382
+ const kind = classifyKind(change.path);
383
+ if (!opts.dryRun) {
384
+ // Find old row to get its id
385
+ const { data: oldRow } = await ctx.supabase
386
+ .from("knowledge_sources")
387
+ .select("id")
388
+ .eq("workspace_id", ws)
389
+ .eq("repo_id", repoId)
390
+ .eq("path", change.oldPath)
391
+ .eq("status", "active")
392
+ .maybeSingle();
393
+ const oldId = oldRow?.id ?? null;
394
+ // Insert new row
395
+ await ctx.supabase.from("knowledge_sources").insert({
396
+ workspace_id: ws,
397
+ repo_id: repoId,
398
+ path: change.path,
399
+ commit_sha: headSha,
400
+ content_hash: contentHash,
401
+ kind,
402
+ status: "active",
403
+ prev_source_id: oldId,
404
+ last_indexed_sha: headSha,
405
+ });
406
+ // Tombstone old
407
+ if (oldId) {
408
+ await ctx.supabase
409
+ .from("knowledge_sources")
410
+ .update({ status: "tombstoned", updated_at: new Date().toISOString() })
411
+ .eq("id", oldId);
412
+ tombstoned++;
413
+ }
414
+ }
415
+ upserted++;
416
+ continue;
417
+ }
418
+ // A or M: read file, scan for secrets, upsert
419
+ const absPath = join(repoRoot, change.path);
420
+ let body = "";
421
+ try {
422
+ body = readFileSync(absPath, "utf-8");
423
+ }
424
+ catch {
425
+ // File missing (e.g., unstaged deletion)
426
+ continue;
427
+ }
428
+ if (containsSecret(body)) {
429
+ skippedSecret++;
430
+ continue;
431
+ }
432
+ const contentHash = computeContentHash(body);
433
+ const kind = classifyKind(change.path);
434
+ if (!opts.dryRun) {
435
+ await ctx.supabase.from("knowledge_sources").upsert({
436
+ workspace_id: ws,
437
+ repo_id: repoId,
438
+ path: change.path,
439
+ commit_sha: headSha,
440
+ content_hash: contentHash,
441
+ kind,
442
+ status: "active",
443
+ last_indexed_sha: headSha,
444
+ updated_at: new Date().toISOString(),
445
+ }, { onConflict: "workspace_id,repo_id,path,content_hash", ignoreDuplicates: true });
446
+ }
447
+ upserted++;
448
+ }
449
+ return { upserted, tombstoned, skippedSecret, skippedIgnore, headSha, dryRun: !!opts.dryRun, redirectedFrom };
450
+ }
451
+ export async function ingestStatusCore(ctx, opts = {}) {
452
+ const ws = await workspaceId(ctx);
453
+ const repoRoot = opts.repoRoot ?? process.cwd();
454
+ // Known Defect #5 fix: same resolution as ingestConnectCore (no more
455
+ // "default"-slug guess) — but `status` is read-only and informational, so
456
+ // an unresolved repo degrades to the existing soft "unknown" shape rather
457
+ // than throwing.
458
+ let repoRow;
459
+ try {
460
+ repoRow = await resolveConnectedRepo(ctx, ws, { repo: opts.repo, repoRoot });
461
+ }
462
+ catch (e) {
463
+ return {
464
+ activeCount: 0,
465
+ tombstonedCount: 0,
466
+ staleness: { isStale: false, isDirty: false, unknown: true, note: e instanceof Error ? e.message : "no repo row found" },
467
+ };
468
+ }
469
+ const redirectedFrom = repoRow.requestedSlug && repoRow.requestedSlug !== repoRow.slug
470
+ ? { requestedSlug: repoRow.requestedSlug, canonicalSlug: repoRow.slug }
471
+ : undefined;
472
+ const { data: rows } = await ctx.supabase
473
+ .from("knowledge_sources")
474
+ .select("status")
475
+ .eq("workspace_id", ws)
476
+ .eq("repo_id", repoRow.id);
477
+ const activeCount = (rows ?? []).filter((r) => r.status === "active").length;
478
+ const tombstonedCount = (rows ?? []).filter((r) => r.status === "tombstoned").length;
479
+ // Staleness: load snapshot if available, else use a lightweight git check
480
+ const snapshot = loadGraphSnapshot(repoRoot);
481
+ let staleness;
482
+ if (snapshot) {
483
+ staleness = await checkStaleness(snapshot, repoRoot);
484
+ }
485
+ else {
486
+ staleness = { isStale: false, isDirty: false, unknown: true, note: "no graph snapshot" };
487
+ }
488
+ return { activeCount, tombstonedCount, staleness, redirectedFrom };
489
+ }
490
+ // ── Output rendering ────────────────────────────────────────────────────
491
+ //
492
+ // Extracted from the two `.action()` closures below (round-20 review,
493
+ // PR #55 comment 3827670905) into their own exported, pure functions of an
494
+ // already-resolved result — the SAME split repo.ts's printConnectResult
495
+ // uses, and for the same reason: it gives the redirect note below a direct
496
+ // unit test (spy on console.log) rather than requiring a full CLI
497
+ // subprocess/integration run just to see one extra printed line.
498
+ /** Shared by both printers below: the same "(--repo 'X' is retired —
499
+ * resolved to canonical slug 'Y')" note printConnectResult (repo.ts)
500
+ * renders for the analogous requestedSlug/slug divergence on `repo
501
+ * connect`. Only ever set when --repo named a retired `-dup-<n>` slug
502
+ * that resolveConnectedRepo (via graph_resolve_repo_id) redirected to a
503
+ * DIFFERENT, canonical repo — every write `ingest connect` just made, or
504
+ * every count `ingest status` just read, is against that canonical
505
+ * repo_id, not the one literally typed, so the operator needs to see it
506
+ * to avoid re-running against the stale slug. */
507
+ function printRedirectNote(redirectedFrom) {
508
+ if (redirectedFrom) {
509
+ console.log(`(--repo '${redirectedFrom.requestedSlug}' is retired — resolved to canonical slug '${redirectedFrom.canonicalSlug}')`);
510
+ }
511
+ }
512
+ export function printIngestConnectResult(result, json) {
513
+ if (json) {
514
+ console.log(JSON.stringify(result, null, 2));
515
+ return;
516
+ }
517
+ const dryTag = result.dryRun ? " [dry-run]" : "";
518
+ console.log(`ingest connect${dryTag}: +${result.upserted} upserted, -${result.tombstoned} tombstoned, ${result.skippedSecret} secret-skipped, ${result.skippedIgnore} ignore-skipped (HEAD ${result.headSha.slice(0, 7)})`);
519
+ printRedirectNote(result.redirectedFrom);
520
+ }
521
+ export function printIngestStatusResult(result, json) {
522
+ if (json) {
523
+ console.log(JSON.stringify(result, null, 2));
524
+ return;
525
+ }
526
+ const staleNote = result.staleness.unknown
527
+ ? " (staleness unknown)"
528
+ : result.staleness.isStale
529
+ ? ` (stale: ${result.staleness.note ?? ""})`
530
+ : " (fresh)";
531
+ console.log(`knowledge_sources: ${result.activeCount} active, ${result.tombstonedCount} tombstoned${staleNote}`);
532
+ printRedirectNote(result.redirectedFrom);
533
+ }
534
+ // ── CLI commands ────────────────────────────────────────────────────────────
535
+ export function registerIngest(program, g) {
536
+ const ingest = program.command("ingest");
537
+ g(ingest.command("connect"))
538
+ .option("--repo <slug>", "repo slug (default: auto-detect from this checkout's origin remote)")
539
+ .option("--dry-run", "scan without writing to DB")
540
+ .action(async (o) => {
541
+ const ctx = await makeCtx(resolveConfig(o));
542
+ const result = await ingestConnectCore(ctx, { repo: o.repo, dryRun: !!o.dryRun });
543
+ printIngestConnectResult(result, !!o.json);
544
+ });
545
+ g(ingest.command("status"))
546
+ .option("--repo <slug>", "repo slug (default: auto-detect from this checkout's origin remote)")
547
+ .action(async (o) => {
548
+ const ctx = await makeCtx(resolveConfig(o));
549
+ const result = await ingestStatusCore(ctx, { repo: o.repo });
550
+ printIngestStatusResult(result, !!o.json);
551
+ });
552
+ }
553
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/commands/ingest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAuB,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,aAAa,EAAa,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAO,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjE,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAa;IACvC,kBAAkB,EAA2B,iBAAiB;IAC9D,iDAAiD,EAAI,kBAAkB;IACvE,uBAAuB,EAAsB,aAAa;IAC1D,wBAAwB,EAAqB,+BAA+B;IAC5E,gCAAgC,EAAa,eAAe;IAC5D,+BAA+B,EAAc,uBAAuB;IACpE,6BAA6B,EAAgB,qBAAqB;IAClE,0BAA0B,EAAmB,kCAAkC;CAChF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QAClC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAE9E,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAExE,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAChG,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACjE,OAAO,KAAK,CAAC;AACf,CAAC;AAYD;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;aAAM,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAmB,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;aAAM,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,6EAA6E;AAE7E;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,CAAC,YAAY,EAAE,gBAAgB,CAAC,EAAE,CAAC;QACrD,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAChC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACnD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5B,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,QAAkB;IAC5D,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,QAAQ,GAAG,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,GAAG,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC;YAC5G,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAE9E;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,iCAAiC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClG,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,YAAY,CAAC,8CAA8C,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,oBAAoB,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,YAAY,CAAC,wBAAwB,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,OAAsB,EAAE,KAAa;IACvF,IAAI,CAAC;QACH,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,OAAO,KAAK,KAAK,EAAE,EAAE,eAAe,EAAE,gBAAgB,CAAC,EAAE;gBAC9F,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;aACjC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,mEAAmE;YACnE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE;gBACzE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO;aACjC,CAAC,CAAC;YACH,OAAO,KAAK;iBACT,KAAK,CAAC,IAAI,CAAC;iBACX,MAAM,CAAC,OAAO,CAAC;iBACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;iBACrB,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9G,OAAO,GAAG,IAAI,IAAI,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AA6BD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,GAAQ,EAAE,EAAU,EAAE,IAA0C;IAEhE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEhD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,uEAAuE;QACvE,iEAAiE;QACjE,yDAAyD;QACzD,oEAAoE;QACpE,oEAAoE;QACpE,qEAAqE;QACrE,mEAAmE;QACnE,sEAAsE;QACtE,qEAAqE;QACrE,sEAAsE;QACtE,mEAAmE;QACnE,sEAAsE;QACtE,qEAAqE;QACrE,gEAAgE;QAChE,sEAAsE;QACtE,yDAAyD;QACzD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,uBAAuB,EAAE;YACxF,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,IAAI,CAAC,IAAI;YACtB,gBAAgB,EAAE,GAAG,CAAC,aAAa;SACpC,CAAC,CAAC;QACH,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,YAAY,CACpB,iBAAiB,IAAI,CAAC,IAAI,wEAAwE,IAAI,CAAC,IAAI,4BAA4B,CACxI,CAAC;QACJ,CAAC;QACD,gEAAgE;QAChE,sEAAsE;QACtE,iEAAiE;QACjE,uEAAuE;QACvE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ;aAClE,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;QAC9D,IAAI,cAAc,IAAI,CAAC,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,YAAY,CAAC,cAAc,EAAE,OAAO,IAAI,QAAQ,MAAM,4CAA4C,CAAC,CAAC;QAChH,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAC9E,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,YAAY,CACpB,wGAAwG;YACxG,wHAAwH,CACzH,CAAC;IACJ,CAAC;IACD,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,sEAAsE;QACtE,uEAAuE;QACvE,qEAAqE;QACrE,uEAAuE;QACvE,sEAAsE;QACtE,qEAAqE;QACrE,MAAM,IAAI,YAAY,CACpB,iFAAiF,iBAAiB,CAAC,SAAS,CAAC,KAAK;YAClH,mEAAmE,CACpE,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACrH,IAAI,KAAK;QAAE,MAAM,IAAI,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,SAAS,CAAC,CAAC;IAEvG,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,uEAAuE;QACvE,oEAAoE;QACpE,sEAAsE;QACtE,oDAAoD;QACpD,MAAM,IAAI,YAAY,CACpB,8DAA8D,SAAS,KAAK;YAC5E,8BAA8B,iBAAiB,CAAC,SAAS,CAAC,kCAAkC,CAC7F,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,YAAY,CACpB,kBAAkB,SAAS,2DAA2D;YACtF,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,yCAAyC,CACnF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACtD,CAAC;AA2BD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAQ,EACR,OAA0B,EAAE;IAE5B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAChD,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IAElC,2BAA2B;IAC3B,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7C,MAAM,IAAI,YAAY,CACpB,4DAA4D,MAAM,KAAK;YACvE,qEAAqE,CACtE,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,cAAc,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAEpD,iEAAiE;IACjE,sEAAsE;IACtE,yEAAyE;IACzE,wEAAwE;IACxE,IAAI,MAAc,CAAC;IACnB,IAAI,cAAc,GAAkB,IAAI,CAAC;IAEzC,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnF,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IACpB,MAAM,cAAc,GAClB,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,KAAK,OAAO,CAAC,IAAI;QAC7D,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,CAAC,IAAI,EAAE;QACvE,CAAC,CAAC,SAAS,CAAC;IAEhB,iDAAiD;IACjD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ;SAC1C,IAAI,CAAC,mBAAmB,CAAC;SACzB,MAAM,CAAC,kBAAkB,CAAC;SAC1B,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC;SACtB,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;SACrB,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;SACtB,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;SACzC,KAAK,CAAC,CAAC,CAAC;SACR,WAAW,EAAE,CAAC;IAEjB,IAAI,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAC/B,cAAc,GAAG,QAAQ,CAAC,gBAAgB,CAAC;IAC7C,CAAC;IAED,oDAAoD;IACpD,IAAI,cAAc,IAAI,cAAc,KAAK,OAAO,EAAE,CAAC;QACjD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IAC5H,CAAC;IAED,oBAAoB;IACpB,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAE/C,2BAA2B;IAC3B,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAE/D,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;QAChC,wBAAwB;QACxB,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAC5G,aAAa,EAAE,CAAC;YAChB,SAAS;QACX,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;YACxB,8DAA8D;YAC9D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,MAAM,GAAG,CAAC,QAAQ;qBACf,IAAI,CAAC,mBAAmB,CAAC;qBACzB,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;qBACtE,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC;qBACtB,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;qBACrB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC;qBACvB,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC5B,CAAC;YACD,UAAU,EAAE,CAAC;YACb,SAAS;QACX,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC1C,wDAAwD;YACxD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,IAAI,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC3C,CAAC;YAAC,MAAM,CAAC;gBACP,sBAAsB;gBACtB,SAAS;YACX,CAAC;YAED,IAAI,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC;gBAC3C,aAAa,EAAE,CAAC;gBAChB,SAAS;YACX,CAAC;YAED,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzB,aAAa,EAAE,CAAC;gBAChB,SAAS;YACX,CAAC;YAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC7C,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAEvC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,6BAA6B;gBAC7B,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ;qBACxC,IAAI,CAAC,mBAAmB,CAAC;qBACzB,MAAM,CAAC,IAAI,CAAC;qBACZ,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC;qBACtB,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;qBACrB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC;qBAC1B,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;qBACtB,WAAW,EAAE,CAAC;gBAEjB,MAAM,KAAK,GAAG,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC;gBAEjC,iBAAiB;gBACjB,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC;oBAClD,YAAY,EAAE,EAAE;oBAChB,OAAO,EAAE,MAAM;oBACf,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,UAAU,EAAE,OAAO;oBACnB,YAAY,EAAE,WAAW;oBACzB,IAAI;oBACJ,MAAM,EAAE,QAAQ;oBAChB,cAAc,EAAE,KAAK;oBACrB,gBAAgB,EAAE,OAAO;iBAC1B,CAAC,CAAC;gBAEH,gBAAgB;gBAChB,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,GAAG,CAAC,QAAQ;yBACf,IAAI,CAAC,mBAAmB,CAAC;yBACzB,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;yBACtE,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;oBACnB,UAAU,EAAE,CAAC;gBACf,CAAC;YACH,CAAC;YACD,QAAQ,EAAE,CAAC;YACX,SAAS;QACX,CAAC;QAED,8CAA8C;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,CAAC;YACH,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,yCAAyC;YACzC,SAAS;QACX,CAAC;QAED,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,aAAa,EAAE,CAAC;YAChB,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEvC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,CACjD;gBACE,YAAY,EAAE,EAAE;gBAChB,OAAO,EAAE,MAAM;gBACf,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,UAAU,EAAE,OAAO;gBACnB,YAAY,EAAE,WAAW;gBACzB,IAAI;gBACJ,MAAM,EAAE,QAAQ;gBAChB,gBAAgB,EAAE,OAAO;gBACzB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACrC,EACD,EAAE,UAAU,EAAE,wCAAwC,EAAE,gBAAgB,EAAE,IAAI,EAAE,CACjF,CAAC;QACJ,CAAC;QACD,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;AAChH,CAAC;AAeD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAQ,EACR,OAA6C,EAAE;IAE/C,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEhD,qEAAqE;IACrE,0EAA0E;IAC1E,0EAA0E;IAC1E,iBAAiB;IACjB,IAAI,OAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,EAAE;SACzH,CAAC;IACJ,CAAC;IACD,MAAM,cAAc,GAClB,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,aAAa,KAAK,OAAO,CAAC,IAAI;QAC7D,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,CAAC,IAAI,EAAE;QACvE,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ;SACtC,IAAI,CAAC,mBAAmB,CAAC;SACzB,MAAM,CAAC,QAAQ,CAAC;SAChB,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC;SACtB,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAE7B,MAAM,WAAW,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IAC7E,MAAM,eAAe,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,MAAM,CAAC;IAErF,0EAA0E;IAC1E,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,SAA0C,CAAC;IAC/C,IAAI,QAAQ,EAAE,CAAC;QACb,SAAS,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,SAAS,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;IAC3F,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;AACrE,CAAC;AAED,2EAA2E;AAC3E,EAAE;AACF,sEAAsE;AACtE,2EAA2E;AAC3E,wEAAwE;AACxE,2EAA2E;AAC3E,kEAAkE;AAClE,iEAAiE;AAEjE;;;;;;;;kDAQkD;AAClD,SAAS,iBAAiB,CAAC,cAAiE;IAC1F,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,YAAY,cAAc,CAAC,aAAa,8CAA8C,cAAc,CAAC,aAAa,IAAI,CAAC,CAAC;IACtI,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAoB,EAAE,IAAa;IAC1E,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,MAAM,MAAM,CAAC,QAAQ,eAAe,MAAM,CAAC,UAAU,gBAAgB,MAAM,CAAC,aAAa,oBAAoB,MAAM,CAAC,aAAa,yBAAyB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAC5N,iBAAiB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAA0B,EAAE,IAAa;IAC/E,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO;QACxC,CAAC,CAAC,sBAAsB;QACxB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO;YACxB,CAAC,CAAC,YAAY,MAAM,CAAC,SAAS,CAAC,IAAI,IAAI,EAAE,GAAG;YAC5C,CAAC,CAAC,UAAU,CAAC;IACjB,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,WAAW,YAAY,MAAM,CAAC,eAAe,cAAc,SAAS,EAAE,CAAC,CAAC;IACjH,iBAAiB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AAC3C,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,cAAc,CAAC,OAAgB,EAAE,CAA0B;IACzE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEzC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;SACzB,MAAM,CAAC,eAAe,EAAE,qEAAqE,CAAC;SAC9F,MAAM,CAAC,WAAW,EAAE,4BAA4B,CAAC;SACjD,MAAM,CAAC,KAAK,EAAE,CAAkD,EAAE,EAAE;QACnE,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAClF,wBAAwB,CAAC,MAAM,EAAE,CAAC,CAAE,CAAwB,CAAC,IAAI,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEL,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;SACxB,MAAM,CAAC,eAAe,EAAE,qEAAqE,CAAC;SAC9F,MAAM,CAAC,KAAK,EAAE,CAAgC,EAAE,EAAE;QACjD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,uBAAuB,CAAC,MAAM,EAAE,CAAC,CAAE,CAAwB,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACP,CAAC"}