@clauderecallhq/cli 0.12.5 → 0.61.3

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 (218) hide show
  1. package/LICENSE +37 -17
  2. package/README.md +110 -22
  3. package/dist/cli.js +1641 -353
  4. package/dist/daemon/entrypoint.js +1872 -54
  5. package/dist/mcp-server.js +930 -0
  6. package/dist/share/fonts/Inter-Bold.woff +0 -0
  7. package/dist/share/fonts/Inter-Regular.woff +0 -0
  8. package/dist/share/fonts/JetBrainsMono-Regular.woff +0 -0
  9. package/dist/web/assets/_brand-Bw9uSB4O.js +1 -0
  10. package/dist/web/assets/captureNode-9CVj9vYC.js +2 -0
  11. package/dist/web/assets/card-a-minimal-ujNERzX7.js +1 -0
  12. package/dist/web/assets/card-b-terminal-DpJ_tVpg.js +1 -0
  13. package/dist/web/assets/card-c-gradient-CZXVGuNd.js +1 -0
  14. package/dist/web/assets/card-d-dashboard-CHKD-PnB.js +1 -0
  15. package/dist/web/assets/dist-CWaokT35.js +56 -0
  16. package/dist/web/assets/index-B-HrjaDy.css +1 -0
  17. package/dist/web/assets/index-BZYcD76T.js +633 -0
  18. package/dist/web/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
  19. package/dist/web/assets/patterns-BPeZb9N0.js +1 -0
  20. package/dist/web/assets/stats-BSwqSiFU.js +1 -0
  21. package/dist/web/assets/thread-D2AXyhOx.js +1 -0
  22. package/dist/web/index.html +8 -2
  23. package/package.json +58 -18
  24. package/scripts/postinstall.mjs +38 -0
  25. package/dist/cli.js.map +0 -1
  26. package/dist/commands/activate.js +0 -69
  27. package/dist/commands/activate.js.map +0 -1
  28. package/dist/commands/audit-secrets.js +0 -103
  29. package/dist/commands/audit-secrets.js.map +0 -1
  30. package/dist/commands/blame.js +0 -35
  31. package/dist/commands/blame.js.map +0 -1
  32. package/dist/commands/config-verification.js +0 -18
  33. package/dist/commands/config-verification.js.map +0 -1
  34. package/dist/commands/context.js +0 -144
  35. package/dist/commands/context.js.map +0 -1
  36. package/dist/commands/correlate.js +0 -70
  37. package/dist/commands/correlate.js.map +0 -1
  38. package/dist/commands/digest.js +0 -78
  39. package/dist/commands/digest.js.map +0 -1
  40. package/dist/commands/health.js +0 -62
  41. package/dist/commands/health.js.map +0 -1
  42. package/dist/commands/index.js +0 -247
  43. package/dist/commands/index.js.map +0 -1
  44. package/dist/commands/install-extension.js +0 -138
  45. package/dist/commands/install-extension.js.map +0 -1
  46. package/dist/commands/license.js +0 -39
  47. package/dist/commands/license.js.map +0 -1
  48. package/dist/commands/list.js +0 -47
  49. package/dist/commands/list.js.map +0 -1
  50. package/dist/commands/mcp.js +0 -29
  51. package/dist/commands/mcp.js.map +0 -1
  52. package/dist/commands/open.js +0 -28
  53. package/dist/commands/open.js.map +0 -1
  54. package/dist/commands/paste.js +0 -154
  55. package/dist/commands/paste.js.map +0 -1
  56. package/dist/commands/projects.js +0 -36
  57. package/dist/commands/projects.js.map +0 -1
  58. package/dist/commands/search.js +0 -67
  59. package/dist/commands/search.js.map +0 -1
  60. package/dist/commands/semantic.js +0 -173
  61. package/dist/commands/semantic.js.map +0 -1
  62. package/dist/commands/show.js +0 -121
  63. package/dist/commands/show.js.map +0 -1
  64. package/dist/commands/start.js +0 -47
  65. package/dist/commands/start.js.map +0 -1
  66. package/dist/commands/stats.js +0 -133
  67. package/dist/commands/stats.js.map +0 -1
  68. package/dist/commands/status.js +0 -45
  69. package/dist/commands/status.js.map +0 -1
  70. package/dist/commands/stop.js +0 -29
  71. package/dist/commands/stop.js.map +0 -1
  72. package/dist/commands/thread.js +0 -396
  73. package/dist/commands/thread.js.map +0 -1
  74. package/dist/context/formatter.js +0 -103
  75. package/dist/context/formatter.js.map +0 -1
  76. package/dist/daemon/auto-tag-config.js +0 -103
  77. package/dist/daemon/auto-tag-config.js.map +0 -1
  78. package/dist/daemon/auto-tag-config.test.js +0 -72
  79. package/dist/daemon/auto-tag-config.test.js.map +0 -1
  80. package/dist/daemon/auto-title-config.js +0 -70
  81. package/dist/daemon/auto-title-config.js.map +0 -1
  82. package/dist/daemon/bulk-title-jobs.js +0 -170
  83. package/dist/daemon/bulk-title-jobs.js.map +0 -1
  84. package/dist/daemon/correlator.js +0 -320
  85. package/dist/daemon/correlator.js.map +0 -1
  86. package/dist/daemon/discover.js +0 -316
  87. package/dist/daemon/discover.js.map +0 -1
  88. package/dist/daemon/editor-detection.js +0 -186
  89. package/dist/daemon/editor-detection.js.map +0 -1
  90. package/dist/daemon/entrypoint.js.map +0 -1
  91. package/dist/daemon/git-correlator.js +0 -256
  92. package/dist/daemon/git-correlator.js.map +0 -1
  93. package/dist/daemon/mcp-installer.js +0 -108
  94. package/dist/daemon/mcp-installer.js.map +0 -1
  95. package/dist/daemon/onboarding-state.js +0 -140
  96. package/dist/daemon/onboarding-state.js.map +0 -1
  97. package/dist/daemon/pidfile.js +0 -57
  98. package/dist/daemon/pidfile.js.map +0 -1
  99. package/dist/daemon/ports.js +0 -48
  100. package/dist/daemon/ports.js.map +0 -1
  101. package/dist/daemon/scanProgressRegistry.js +0 -62
  102. package/dist/daemon/scanProgressRegistry.js.map +0 -1
  103. package/dist/daemon/server.js +0 -2010
  104. package/dist/daemon/server.js.map +0 -1
  105. package/dist/daemon/tag-scanner/anthropic-client.js +0 -40
  106. package/dist/daemon/tag-scanner/anthropic-client.js.map +0 -1
  107. package/dist/daemon/tag-scanner/autopilot.js +0 -131
  108. package/dist/daemon/tag-scanner/autopilot.js.map +0 -1
  109. package/dist/daemon/tag-scanner/claude-cli-driver.js +0 -250
  110. package/dist/daemon/tag-scanner/claude-cli-driver.js.map +0 -1
  111. package/dist/daemon/tag-scanner/orchestrator.js +0 -88
  112. package/dist/daemon/tag-scanner/orchestrator.js.map +0 -1
  113. package/dist/daemon/tag-scanner/prompt.js +0 -46
  114. package/dist/daemon/tag-scanner/prompt.js.map +0 -1
  115. package/dist/daemon/tag-scanner/prompt.test.js +0 -48
  116. package/dist/daemon/tag-scanner/prompt.test.js.map +0 -1
  117. package/dist/daemon/tag-scanner/scan-state.js +0 -49
  118. package/dist/daemon/tag-scanner/scan-state.js.map +0 -1
  119. package/dist/daemon/tag-scanner/session-fetcher.js +0 -82
  120. package/dist/daemon/tag-scanner/session-fetcher.js.map +0 -1
  121. package/dist/daemon/tag-scanner/session-fetcher.test.js +0 -34
  122. package/dist/daemon/tag-scanner/session-fetcher.test.js.map +0 -1
  123. package/dist/daemon/tag-scanner/validator.js +0 -50
  124. package/dist/daemon/tag-scanner/validator.js.map +0 -1
  125. package/dist/daemon/tag-scanner/validator.test.js +0 -41
  126. package/dist/daemon/tag-scanner/validator.test.js.map +0 -1
  127. package/dist/daemon/terminal-registry.js +0 -443
  128. package/dist/daemon/terminal-registry.js.map +0 -1
  129. package/dist/daemon/ui.js +0 -64
  130. package/dist/daemon/ui.js.map +0 -1
  131. package/dist/daemon/watcher.js +0 -256
  132. package/dist/daemon/watcher.js.map +0 -1
  133. package/dist/db/client.js +0 -22
  134. package/dist/db/client.js.map +0 -1
  135. package/dist/db/schema.js +0 -496
  136. package/dist/db/schema.js.map +0 -1
  137. package/dist/license/api-base.js +0 -13
  138. package/dist/license/api-base.js.map +0 -1
  139. package/dist/license/manager.js +0 -43
  140. package/dist/license/manager.js.map +0 -1
  141. package/dist/license/public-key.js +0 -19
  142. package/dist/license/public-key.js.map +0 -1
  143. package/dist/license/storage.js +0 -27
  144. package/dist/license/storage.js.map +0 -1
  145. package/dist/license/verify.js +0 -23
  146. package/dist/license/verify.js.map +0 -1
  147. package/dist/mcp/audit.js +0 -126
  148. package/dist/mcp/audit.js.map +0 -1
  149. package/dist/mcp/prompts.js +0 -180
  150. package/dist/mcp/prompts.js.map +0 -1
  151. package/dist/mcp/server.js +0 -502
  152. package/dist/mcp/server.js.map +0 -1
  153. package/dist/mcp/thread-tools.js +0 -363
  154. package/dist/mcp/thread-tools.js.map +0 -1
  155. package/dist/mcp/write-tools.js +0 -239
  156. package/dist/mcp/write-tools.js.map +0 -1
  157. package/dist/parser/jsonl.js +0 -150
  158. package/dist/parser/jsonl.js.map +0 -1
  159. package/dist/semantic/chunker.js +0 -47
  160. package/dist/semantic/chunker.js.map +0 -1
  161. package/dist/semantic/config.js +0 -74
  162. package/dist/semantic/config.js.map +0 -1
  163. package/dist/semantic/embedder.js +0 -54
  164. package/dist/semantic/embedder.js.map +0 -1
  165. package/dist/semantic/fusion.js +0 -38
  166. package/dist/semantic/fusion.js.map +0 -1
  167. package/dist/semantic/model-download.js +0 -69
  168. package/dist/semantic/model-download.js.map +0 -1
  169. package/dist/semantic/pipeline.js +0 -375
  170. package/dist/semantic/pipeline.js.map +0 -1
  171. package/dist/semantic/query.js +0 -42
  172. package/dist/semantic/query.js.map +0 -1
  173. package/dist/semantic/worker.js +0 -78
  174. package/dist/semantic/worker.js.map +0 -1
  175. package/dist/stats/backfill.js +0 -151
  176. package/dist/stats/backfill.js.map +0 -1
  177. package/dist/stats/health.js +0 -102
  178. package/dist/stats/health.js.map +0 -1
  179. package/dist/stats/query.js +0 -385
  180. package/dist/stats/query.js.map +0 -1
  181. package/dist/utils/aliases.js +0 -107
  182. package/dist/utils/aliases.js.map +0 -1
  183. package/dist/utils/autoCollections.js +0 -635
  184. package/dist/utils/autoCollections.js.map +0 -1
  185. package/dist/utils/autoTitle.js +0 -348
  186. package/dist/utils/autoTitle.js.map +0 -1
  187. package/dist/utils/collections.js +0 -446
  188. package/dist/utils/collections.js.map +0 -1
  189. package/dist/utils/format.js +0 -46
  190. package/dist/utils/format.js.map +0 -1
  191. package/dist/utils/notes.js +0 -270
  192. package/dist/utils/notes.js.map +0 -1
  193. package/dist/utils/paths.js +0 -50
  194. package/dist/utils/paths.js.map +0 -1
  195. package/dist/utils/pricing.js +0 -257
  196. package/dist/utils/pricing.js.map +0 -1
  197. package/dist/utils/secret-scanner.js +0 -166
  198. package/dist/utils/secret-scanner.js.map +0 -1
  199. package/dist/utils/sessionLabel.js +0 -64
  200. package/dist/utils/sessionLabel.js.map +0 -1
  201. package/dist/utils/tags.js +0 -97
  202. package/dist/utils/tags.js.map +0 -1
  203. package/dist/utils/thread-context.js +0 -129
  204. package/dist/utils/thread-context.js.map +0 -1
  205. package/dist/utils/threadFilter.js +0 -18
  206. package/dist/utils/threadFilter.js.map +0 -1
  207. package/dist/utils/threads-titler.js +0 -298
  208. package/dist/utils/threads-titler.js.map +0 -1
  209. package/dist/utils/threads.js +0 -383
  210. package/dist/utils/threads.js.map +0 -1
  211. package/dist/utils/usage.js +0 -76
  212. package/dist/utils/usage.js.map +0 -1
  213. package/dist/verification/compute.js +0 -88
  214. package/dist/verification/compute.js.map +0 -1
  215. package/dist/verification/config.js +0 -34
  216. package/dist/verification/config.js.map +0 -1
  217. package/dist/web/assets/index-CIr6J4Fw.js +0 -1201
  218. package/dist/web/assets/index-Ctc8g9Jw.css +0 -1
@@ -1,348 +0,0 @@
1
- import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { getDb } from '../db/client.js';
4
- import { RECALL_HOME, ensureRecallHome } from './paths.js';
5
- import { getThreadContextForSession, } from './thread-context.js';
6
- /**
7
- * v0.14b (T5) — derived session titles.
8
- *
9
- * Two tiers, same append-only "never lose data" guarantees as aliases/notes:
10
- *
11
- * 1. `deriveHeuristicTitle(firstUserMessage)` — pure, sync. Stripped of
12
- * code fences / inline backticks / URLs, whitespace normalised, first
13
- * sentence if it fits, else a 60-char slice. Called from the indexer on
14
- * every session insert.
15
- *
16
- * 2. `deriveAgentTitle(sessionId)` — shells out to the user's
17
- * local `claude` CLI (same plumbing as auto-tag) with a summarisation
18
- * prompt over the first 20 user messages. Opt-in via the ✨ Generate
19
- * title button in the transcript header.
20
- *
21
- * Durability — three layers, identical to the alias module:
22
- *
23
- * 1. SQLite: `auto_title`, `auto_title_source`, `auto_title_generated_at`.
24
- * 2. SQLite history column: `auto_title_history` (JSON array of prior
25
- * values; every replacement pushes a row, we never lose one).
26
- * 3. Plain-text mirror: `$RECALL_HOME/titles/<sessionId>.txt` — grep-able,
27
- * recoverable from disk even if the SQLite file is wiped.
28
- *
29
- * Demotion protection: a `source='heuristic'` write is a no-op if the existing
30
- * row is `source='agent'`. Rationale — the indexer fires heuristic on every
31
- * reindex of a session file; without this guard, every reindex of an agent-
32
- * titled session would clobber the user's explicit ✨ Generate choice.
33
- *
34
- * Fallback chain (consumers): `alias → auto_title → first_user_message →
35
- * id.slice(0,8)`. Manual alias always wins.
36
- */
37
- export const TITLES_DIR = join(RECALL_HOME, 'titles');
38
- const HEURISTIC_SENTENCE_MAX = 80;
39
- const HEURISTIC_SLICE_MAX = 60;
40
- const AGENT_TITLE_MAX = 50;
41
- // We sample the conversation as `head + tail` rather than just the first N
42
- // messages so the title reflects BOTH initial intent AND current direction.
43
- // Sessions where the user pasted off-topic context first (logs, errors from
44
- // another session) used to produce wildly off-topic titles; with a tail
45
- // included, the model sees what the conversation actually became.
46
- const AGENT_HEAD_LIMIT = 5;
47
- const AGENT_TAIL_LIMIT = 15;
48
- const AGENT_PER_MESSAGE_CHAR_LIMIT = 500;
49
- function parseHistory(raw) {
50
- if (!raw)
51
- return [];
52
- try {
53
- const parsed = JSON.parse(raw);
54
- if (Array.isArray(parsed)) {
55
- return parsed.filter((e) => !!e &&
56
- typeof e === 'object' &&
57
- typeof e.title === 'string' &&
58
- typeof e.replaced_at === 'string');
59
- }
60
- }
61
- catch {
62
- /* fall through */
63
- }
64
- return [];
65
- }
66
- /**
67
- * Clean up a first-user-message into a ≤80-char title.
68
- * Deterministic and synchronous — runs on every indexer insert.
69
- */
70
- export function deriveHeuristicTitle(msg) {
71
- if (!msg)
72
- return null;
73
- let t = msg;
74
- // Strip fenced code blocks, then inline code. Order matters — triple
75
- // backticks would otherwise match as nested inline pairs.
76
- t = t.replace(/```[\s\S]*?```/g, ' ');
77
- t = t.replace(/`[^`]+`/g, ' ');
78
- // Replace URLs with a short placeholder so "see https://…foo?x=y" doesn't
79
- // dominate a title.
80
- t = t.replace(/https?:\/\/\S+/g, '[url]');
81
- t = t.replace(/\s+/g, ' ').trim();
82
- if (!t)
83
- return null;
84
- const firstSentence = t.match(/^[^.!?\n]{8,}?[.!?]/)?.[0]?.trim();
85
- const cut = firstSentence && firstSentence.length <= HEURISTIC_SENTENCE_MAX
86
- ? firstSentence
87
- : t.slice(0, HEURISTIC_SLICE_MAX);
88
- const out = cut.trim();
89
- return out || null;
90
- }
91
- /**
92
- * Build the prompt that `deriveAgentTitle` sends to the local `claude` CLI.
93
- * Exported so unit tests can assert on the constructed text without invoking
94
- * the subprocess.
95
- *
96
- * Bucket 2: when the session belongs to a thread, a "Thread context" preamble
97
- * is prepended with the parent + sibling display titles so the model can mint
98
- * a hierarchy-aware title (for example "Phase A: API design"). Sessions in
99
- * zero threads get the existing single-session prompt verbatim. Thread-context
100
- * resolution is wrapped in try/catch so that any DB hiccup never blocks title
101
- * generation: we log and fall back to the no-context prompt.
102
- */
103
- export function buildAgentTitlePrompt(sessionId) {
104
- const db = getDb();
105
- // Two queries to avoid loading every message into Node when sessions have
106
- // thousands. Head = first N chronologically; tail = last M. Dedupe by rowid
107
- // so short sessions (<head+tail) don't double-count, then re-sort
108
- // chronologically before sending to the model.
109
- const head = db
110
- .prepare(`SELECT rowid AS rid, content_text
111
- FROM messages
112
- WHERE session_id = ? AND role = 'user' AND is_sidechain = 0
113
- AND content_text IS NOT NULL AND content_text != ''
114
- ORDER BY COALESCE(timestamp, ''), rowid ASC
115
- LIMIT ?`)
116
- .all(sessionId, AGENT_HEAD_LIMIT);
117
- const tail = db
118
- .prepare(`SELECT rowid AS rid, content_text
119
- FROM messages
120
- WHERE session_id = ? AND role = 'user' AND is_sidechain = 0
121
- AND content_text IS NOT NULL AND content_text != ''
122
- ORDER BY COALESCE(timestamp, '') DESC, rowid DESC
123
- LIMIT ?`)
124
- .all(sessionId, AGENT_TAIL_LIMIT);
125
- const byRid = new Map();
126
- for (const r of head)
127
- byRid.set(r.rid, r.content_text);
128
- for (const r of tail)
129
- byRid.set(r.rid, r.content_text);
130
- if (byRid.size === 0) {
131
- throw new Error('no user messages available to summarise');
132
- }
133
- const rows = Array.from(byRid.entries())
134
- .sort((a, b) => a[0] - b[0])
135
- .map(([, content_text]) => ({ content_text }));
136
- // Mark the conversational gap so the model knows it's seeing a sample,
137
- // not a continuous stream. Only insert the marker when both head and tail
138
- // were saturated AND there's at least one message between them not in the
139
- // sample (i.e. byRid.size === HEAD + TAIL with no overlap).
140
- const hasGap = head.length === AGENT_HEAD_LIMIT &&
141
- tail.length === AGENT_TAIL_LIMIT &&
142
- byRid.size === AGENT_HEAD_LIMIT + AGENT_TAIL_LIMIT;
143
- const body = rows
144
- .map((r, i) => {
145
- const content = (r.content_text ?? '').slice(0, AGENT_PER_MESSAGE_CHAR_LIMIT);
146
- if (hasGap && i === AGENT_HEAD_LIMIT) {
147
- return `--- (middle of session omitted) ---\n${i + 1}. ${content}`;
148
- }
149
- return `${i + 1}. ${content}`;
150
- })
151
- .join('\n');
152
- let threadContext = null;
153
- try {
154
- threadContext = getThreadContextForSession(sessionId);
155
- }
156
- catch (err) {
157
- // Per the spec: do not block title generation if thread context resolution
158
- // throws. Log and continue with the no-context prompt.
159
- console.error('[autoTitle] thread context resolution failed:', err);
160
- threadContext = null;
161
- }
162
- const sections = [];
163
- if (threadContext) {
164
- sections.push(formatThreadContextBlock(threadContext));
165
- sections.push('');
166
- }
167
- sections.push(`You will receive a sample of user messages from a Claude Code session: the first ${AGENT_HEAD_LIMIT}`, `messages (initial intent) and the last ${AGENT_TAIL_LIMIT} messages (current direction).`, 'Write a single descriptive title, max 50 characters, focused on what the user is', 'currently trying to accomplish. If initial intent and current direction differ, prefer', 'the current direction. Output ONLY the title, with no quotes and no trailing punctuation.', '', 'Messages:', body);
168
- return sections.join('\n');
169
- }
170
- const SIBLING_DISPLAY_LIMIT = 5;
171
- function formatThreadContextBlock(ctx) {
172
- const lines = [];
173
- lines.push('Thread context:');
174
- lines.push(`- This session is part of thread "${ctx.thread_name}".`);
175
- if (ctx.parent_session) {
176
- lines.push(`- Parent session: "${ctx.parent_session.title}"`);
177
- }
178
- const sibCount = ctx.siblings.length;
179
- if (sibCount > 0) {
180
- const shown = ctx.siblings.slice(0, SIBLING_DISPLAY_LIMIT);
181
- const titles = shown.map((s) => `"${s.title}"`).join(', ');
182
- const overflow = sibCount > SIBLING_DISPLAY_LIMIT
183
- ? `, and ${sibCount - SIBLING_DISPLAY_LIMIT} more`
184
- : '';
185
- lines.push(`- Sibling sessions (${sibCount}): ${titles}${overflow}`);
186
- }
187
- lines.push('');
188
- lines.push("Generate a title that reflects this session's role in the thread.");
189
- lines.push('If siblings use a pattern like "Phase A / Phase B" or "Wave 1 of 4",');
190
- lines.push('follow the same pattern.');
191
- return lines.join('\n');
192
- }
193
- /**
194
- * Run the user's local `claude` CLI over the first 20 user messages and
195
- * return a ≤50-char descriptive title. Throws if the CLI is unavailable
196
- * or exits non-zero. Callers are expected to have already checked the
197
- * `autoTitle.agentEnabled` config flag.
198
- *
199
- * The runner is imported lazily so that headless consumers of autoTitle
200
- * (tests, the MCP server) don't pay the daemon-only import cost.
201
- */
202
- export async function deriveAgentTitle(sessionId) {
203
- const prompt = buildAgentTitlePrompt(sessionId);
204
- const { spawnClaudePrompt, isClaudeCliAvailable } = await import('../daemon/tag-scanner/claude-cli-driver.js');
205
- if (!isClaudeCliAvailable()) {
206
- throw new Error('claude CLI not found on PATH');
207
- }
208
- // No MCP tools, this is a one-shot text-only summarisation, no DB writes.
209
- const result = await spawnClaudePrompt(prompt, [], {});
210
- if (!result.success) {
211
- throw new Error(`claude CLI exited ${result.exitCode}: ${result.stderr.slice(-500)}`);
212
- }
213
- const title = extractTitleFromCliResult(result.stdout);
214
- if (!title)
215
- throw new Error('claude CLI returned an empty title');
216
- return title.slice(0, AGENT_TITLE_MAX);
217
- }
218
- /**
219
- * `claude -p … --output-format json` emits a JSON envelope with a `result`
220
- * string. Plain-text output is just the raw title. We accept both.
221
- */
222
- function extractTitleFromCliResult(stdout) {
223
- const trimmed = stdout.trim();
224
- if (!trimmed)
225
- return '';
226
- try {
227
- const parsed = JSON.parse(trimmed);
228
- if (parsed && typeof parsed === 'object') {
229
- const result = parsed.result;
230
- if (typeof result === 'string')
231
- return sanitiseTitle(result);
232
- }
233
- }
234
- catch {
235
- /* not JSON — fall through to raw */
236
- }
237
- return sanitiseTitle(trimmed);
238
- }
239
- function sanitiseTitle(raw) {
240
- return raw
241
- .trim()
242
- // Strip paired wrapping quotes the model sometimes adds despite the prompt.
243
- .replace(/^["'`]+|["'`]+$/g, '')
244
- // Collapse internal whitespace + drop trailing punctuation.
245
- .replace(/\s+/g, ' ')
246
- .replace(/[.!?]+$/g, '')
247
- .trim();
248
- }
249
- /**
250
- * Triple-layer write. Demotion-guarded: a heuristic write never clobbers an
251
- * existing agent title. Idempotent — writing the same title twice is a no-op.
252
- */
253
- export function setAutoTitle(sessionId, title, source) {
254
- const trimmed = title.trim();
255
- if (!trimmed)
256
- return;
257
- const db = getDb();
258
- const existing = db
259
- .prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
260
- FROM sessions WHERE id = ?`)
261
- .get(sessionId);
262
- if (!existing)
263
- return; // session not yet indexed; caller races with indexer
264
- // Demotion guard: heuristic never overwrites an agent title. Reindex fires
265
- // on every file mtime bump; without this the user's explicit ✨ choice
266
- // would silently regress every time Claude Code appends a new line.
267
- if (source === 'heuristic' &&
268
- existing.auto_title_source === 'agent' &&
269
- existing.auto_title) {
270
- return;
271
- }
272
- // Idempotent: same title, same source → no write, no history push.
273
- if (existing.auto_title === trimmed && existing.auto_title_source === source) {
274
- return;
275
- }
276
- const history = parseHistory(existing.auto_title_history);
277
- const now = new Date().toISOString();
278
- if (existing.auto_title && existing.auto_title_source) {
279
- history.push({
280
- title: existing.auto_title,
281
- source: existing.auto_title_source,
282
- replaced_at: now,
283
- });
284
- }
285
- db.prepare(`UPDATE sessions
286
- SET auto_title = ?,
287
- auto_title_source = ?,
288
- auto_title_generated_at = ?,
289
- auto_title_history = ?
290
- WHERE id = ?`).run(trimmed, source, Date.now(), JSON.stringify(history), sessionId);
291
- writeTitleFile(sessionId, trimmed, source, now);
292
- }
293
- export function getAutoTitle(sessionId) {
294
- const row = getDb()
295
- .prepare(`SELECT auto_title, auto_title_source, auto_title_generated_at, auto_title_history
296
- FROM sessions WHERE id = ?`)
297
- .get(sessionId);
298
- if (!row)
299
- return null;
300
- return {
301
- auto_title: row.auto_title,
302
- auto_title_source: row.auto_title_source ?? null,
303
- auto_title_generated_at: row.auto_title_generated_at,
304
- auto_title_history: parseHistory(row.auto_title_history),
305
- };
306
- }
307
- /**
308
- * One-time startup backfill: fill heuristic titles for every session whose
309
- * `auto_title` is NULL and `first_user_message` is present. Cheap to re-run
310
- * on every daemon boot — the NULL check keeps it idempotent after the first
311
- * pass. Intentionally synchronous; the sessions table is small and this runs
312
- * before we start servicing HTTP.
313
- */
314
- export function backfillHeuristicTitles() {
315
- const db = getDb();
316
- const rows = db
317
- .prepare(`SELECT id, first_user_message
318
- FROM sessions
319
- WHERE auto_title IS NULL
320
- AND first_user_message IS NOT NULL`)
321
- .all();
322
- let updated = 0;
323
- for (const r of rows) {
324
- const title = deriveHeuristicTitle(r.first_user_message);
325
- if (!title)
326
- continue;
327
- setAutoTitle(r.id, title, 'heuristic');
328
- updated += 1;
329
- }
330
- return { updated };
331
- }
332
- function ensureTitlesDir() {
333
- ensureRecallHome();
334
- if (!existsSync(TITLES_DIR))
335
- mkdirSync(TITLES_DIR, { recursive: true });
336
- }
337
- function writeTitleFile(sessionId, title, source, updatedAt) {
338
- try {
339
- ensureTitlesDir();
340
- const filePath = join(TITLES_DIR, `${sessionId}.txt`);
341
- const header = `# Claude Recall auto-title · session ${sessionId} · source ${source} · updated ${updatedAt}\n`;
342
- writeFileSync(filePath, header + title + '\n');
343
- }
344
- catch (err) {
345
- console.error('[autoTitle] mirror write failed:', err);
346
- }
347
- }
348
- //# sourceMappingURL=autoTitle.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"autoTitle.js","sourceRoot":"","sources":["../../src/utils/autoTitle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EACL,0BAA0B,GAE3B,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAEtD,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAClC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,2EAA2E;AAC3E,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,kEAAkE;AAClE,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAwBzC,SAAS,YAAY,CAAC,GAAkB;IACtC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,CAAC,EAA8B,EAAE,CAChC,CAAC,CAAC,CAAC;gBACH,OAAO,CAAC,KAAK,QAAQ;gBACrB,OAAQ,CAAyB,CAAC,KAAK,KAAK,QAAQ;gBACpD,OAAQ,CAA+B,CAAC,WAAW,KAAK,QAAQ,CACnE,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAkB;IACrD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC,GAAG,GAAG,CAAC;IACZ,qEAAqE;IACrE,0DAA0D;IAC1D,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACtC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC/B,0EAA0E;IAC1E,oBAAoB;IACpB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAClE,MAAM,GAAG,GACP,aAAa,IAAI,aAAa,CAAC,MAAM,IAAI,sBAAsB;QAC7D,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACvB,OAAO,GAAG,IAAI,IAAI,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACrD,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,0EAA0E;IAC1E,4EAA4E;IAC5E,kEAAkE;IAClE,+CAA+C;IAC/C,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;;;;;gBAKU,CACX;SACA,GAAG,CAAC,SAAS,EAAE,gBAAgB,CAAiD,CAAC;IACpF,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;;;;;gBAKU,CACX;SACA,GAAG,CAAC,SAAS,EAAE,gBAAgB,CAAiD,CAAC;IAEpF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;IACvD,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;IACvD,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;SACrC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3B,GAAG,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;IAEjD,uEAAuE;IACvE,0EAA0E;IAC1E,0EAA0E;IAC1E,4DAA4D;IAC5D,MAAM,MAAM,GACV,IAAI,CAAC,MAAM,KAAK,gBAAgB;QAChC,IAAI,CAAC,MAAM,KAAK,gBAAgB;QAChC,KAAK,CAAC,IAAI,KAAK,gBAAgB,GAAG,gBAAgB,CAAC;IAErD,MAAM,IAAI,GAAG,IAAI;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;QAC9E,IAAI,MAAM,IAAI,CAAC,KAAK,gBAAgB,EAAE,CAAC;YACrC,OAAO,wCAAwC,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC;QACrE,CAAC;QACD,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC;IAChC,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,IAAI,aAAa,GAAiC,IAAI,CAAC;IACvD,IAAI,CAAC;QACH,aAAa,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,2EAA2E;QAC3E,uDAAuD;QACvD,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAC;QACpE,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,aAAa,EAAE,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC,CAAC;QACvD,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IACD,QAAQ,CAAC,IAAI,CACX,oFAAoF,gBAAgB,EAAE,EACtG,0CAA0C,gBAAgB,gCAAgC,EAC1F,kFAAkF,EAClF,wFAAwF,EACxF,2FAA2F,EAC3F,EAAE,EACF,WAAW,EACX,IAAI,CACL,CAAC;IACF,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEhC,SAAS,wBAAwB,CAAC,GAA0B;IAC1D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC9B,KAAK,CAAC,IAAI,CAAC,qCAAqC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC;IACrE,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,sBAAsB,GAAG,CAAC,cAAc,CAAC,KAAK,GAAG,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;IACrC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,QAAQ,GACZ,QAAQ,GAAG,qBAAqB;YAC9B,CAAC,CAAC,SAAS,QAAQ,GAAG,qBAAqB,OAAO;YAClD,CAAC,CAAC,EAAE,CAAC;QACT,KAAK,CAAC,IAAI,CAAC,uBAAuB,QAAQ,MAAM,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;IAChF,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;IACnF,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IACtD,MAAM,MAAM,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAEhD,MAAM,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAC9D,4CAA4C,CAC7C,CAAC;IACF,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,0EAA0E;IAC1E,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,qBAAqB,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CACrE,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,yBAAyB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvD,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAClE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,SAAS,yBAAyB,CAAC,MAAc;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YACzC,MAAM,MAAM,GAAI,MAA+B,CAAC,MAAM,CAAC;YACvD,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;IACD,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,OAAO,GAAG;SACP,IAAI,EAAE;QACP,4EAA4E;SAC3E,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;QAChC,4DAA4D;SAC3D,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,SAAiB,EACjB,KAAa,EACb,MAAuB;IAEvB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO;QAAE,OAAO;IAErB,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,QAAQ,GAAG,EAAE;SAChB,OAAO,CACN;oCAC8B,CAC/B;SACA,GAAG,CAAC,SAAS,CAA+B,CAAC;IAChD,IAAI,CAAC,QAAQ;QAAE,OAAO,CAAC,qDAAqD;IAE5E,2EAA2E;IAC3E,sEAAsE;IACtE,oEAAoE;IACpE,IACE,MAAM,KAAK,WAAW;QACtB,QAAQ,CAAC,iBAAiB,KAAK,OAAO;QACtC,QAAQ,CAAC,UAAU,EACnB,CAAC;QACD,OAAO;IACT,CAAC;IAED,mEAAmE;IACnE,IAAI,QAAQ,CAAC,UAAU,KAAK,OAAO,IAAI,QAAQ,CAAC,iBAAiB,KAAK,MAAM,EAAE,CAAC;QAC7E,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,iBAAiB,EAAE,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC;YACX,KAAK,EAAE,QAAQ,CAAC,UAAU;YAC1B,MAAM,EAAE,QAAQ,CAAC,iBAAoC;YACrD,WAAW,EAAE,GAAG;SACjB,CAAC,CAAC;IACL,CAAC;IAED,EAAE,CAAC,OAAO,CACR;;;;;mBAKe,CAChB,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;IAEvE,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,MAAM,GAAG,GAAG,KAAK,EAAE;SAChB,OAAO,CACN;oCAC8B,CAC/B;SACA,GAAG,CAAC,SAAS,CAA+B,CAAC;IAChD,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,iBAAiB,EAAG,GAAG,CAAC,iBAA4C,IAAI,IAAI;QAC5E,uBAAuB,EAAE,GAAG,CAAC,uBAAuB;QACpD,kBAAkB,EAAE,YAAY,CAAC,GAAG,CAAC,kBAAkB,CAAC;KACzD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB;IACrC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACnB,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;;;6CAGuC,CACxC;SACA,GAAG,EAA8D,CAAC;IAErE,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,oBAAoB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC,CAAC;IACf,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AAED,SAAS,eAAe;IACtB,gBAAgB,EAAE,CAAC;IACnB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,SAAS,cAAc,CACrB,SAAiB,EACjB,KAAa,EACb,MAAuB,EACvB,SAAiB;IAEjB,IAAI,CAAC;QACH,eAAe,EAAE,CAAC;QAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,SAAS,MAAM,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,wCAAwC,SAAS,aAAa,MAAM,cAAc,SAAS,IAAI,CAAC;QAC/G,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC;AACH,CAAC"}