@tznthou/ccrecall 0.1.2

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 (87) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +290 -0
  3. package/README_ZH.md +288 -0
  4. package/dist/api/routes.d.ts +13 -0
  5. package/dist/api/routes.d.ts.map +1 -0
  6. package/dist/api/routes.js +428 -0
  7. package/dist/api/routes.js.map +1 -0
  8. package/dist/api/server.d.ts +7 -0
  9. package/dist/api/server.d.ts.map +1 -0
  10. package/dist/api/server.js +44 -0
  11. package/dist/api/server.js.map +1 -0
  12. package/dist/cli/daemon.d.ts +35 -0
  13. package/dist/cli/daemon.d.ts.map +1 -0
  14. package/dist/cli/daemon.js +163 -0
  15. package/dist/cli/daemon.js.map +1 -0
  16. package/dist/core/compression.d.ts +37 -0
  17. package/dist/core/compression.d.ts.map +1 -0
  18. package/dist/core/compression.js +129 -0
  19. package/dist/core/compression.js.map +1 -0
  20. package/dist/core/database.d.ts +219 -0
  21. package/dist/core/database.d.ts.map +1 -0
  22. package/dist/core/database.js +1513 -0
  23. package/dist/core/database.js.map +1 -0
  24. package/dist/core/index.d.ts +9 -0
  25. package/dist/core/index.d.ts.map +1 -0
  26. package/dist/core/index.js +8 -0
  27. package/dist/core/index.js.map +1 -0
  28. package/dist/core/indexer.d.ts +15 -0
  29. package/dist/core/indexer.d.ts.map +1 -0
  30. package/dist/core/indexer.js +224 -0
  31. package/dist/core/indexer.js.map +1 -0
  32. package/dist/core/lint.d.ts +17 -0
  33. package/dist/core/lint.d.ts.map +1 -0
  34. package/dist/core/lint.js +51 -0
  35. package/dist/core/lint.js.map +1 -0
  36. package/dist/core/log-safe.d.ts +6 -0
  37. package/dist/core/log-safe.d.ts.map +1 -0
  38. package/dist/core/log-safe.js +11 -0
  39. package/dist/core/log-safe.js.map +1 -0
  40. package/dist/core/maintenance-coordinator.d.ts +26 -0
  41. package/dist/core/maintenance-coordinator.d.ts.map +1 -0
  42. package/dist/core/maintenance-coordinator.js +67 -0
  43. package/dist/core/maintenance-coordinator.js.map +1 -0
  44. package/dist/core/memory-service.d.ts +31 -0
  45. package/dist/core/memory-service.d.ts.map +1 -0
  46. package/dist/core/memory-service.js +47 -0
  47. package/dist/core/memory-service.js.map +1 -0
  48. package/dist/core/parser.d.ts +17 -0
  49. package/dist/core/parser.d.ts.map +1 -0
  50. package/dist/core/parser.js +205 -0
  51. package/dist/core/parser.js.map +1 -0
  52. package/dist/core/scanner.d.ts +8 -0
  53. package/dist/core/scanner.d.ts.map +1 -0
  54. package/dist/core/scanner.js +123 -0
  55. package/dist/core/scanner.js.map +1 -0
  56. package/dist/core/summarizer.d.ts +12 -0
  57. package/dist/core/summarizer.d.ts.map +1 -0
  58. package/dist/core/summarizer.js +430 -0
  59. package/dist/core/summarizer.js.map +1 -0
  60. package/dist/core/topic-extractor.d.ts +11 -0
  61. package/dist/core/topic-extractor.d.ts.map +1 -0
  62. package/dist/core/topic-extractor.js +51 -0
  63. package/dist/core/topic-extractor.js.map +1 -0
  64. package/dist/core/types.d.ts +329 -0
  65. package/dist/core/types.d.ts.map +1 -0
  66. package/dist/core/types.js +12 -0
  67. package/dist/core/types.js.map +1 -0
  68. package/dist/core/watcher.d.ts +30 -0
  69. package/dist/core/watcher.d.ts.map +1 -0
  70. package/dist/core/watcher.js +146 -0
  71. package/dist/core/watcher.js.map +1 -0
  72. package/dist/index.d.ts +3 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +116 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/mcp/server.d.ts +3 -0
  77. package/dist/mcp/server.d.ts.map +1 -0
  78. package/dist/mcp/server.js +32 -0
  79. package/dist/mcp/server.js.map +1 -0
  80. package/dist/mcp/tools.d.ts +39 -0
  81. package/dist/mcp/tools.d.ts.map +1 -0
  82. package/dist/mcp/tools.js +215 -0
  83. package/dist/mcp/tools.js.map +1 -0
  84. package/hooks/README.md +78 -0
  85. package/hooks/session-end.mjs +92 -0
  86. package/hooks/session-start.mjs +112 -0
  87. package/package.json +54 -0
package/README_ZH.md ADDED
@@ -0,0 +1,288 @@
1
+ # ccRecall
2
+
3
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
4
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.8+-3178C6.svg)](https://www.typescriptlang.org/)
5
+ [![Node.js](https://img.shields.io/badge/Node.js-20--22-339933.svg)](https://nodejs.org/)
6
+ [![SQLite](https://img.shields.io/badge/SQLite-FTS5-003B57.svg)](https://www.sqlite.org/)
7
+
8
+ [English](README.md)
9
+
10
+ Claude Code 的本地記憶服務——索引你的對話歷史,按需召回相關 context,注入到未來的 session。零 API 成本。
11
+
12
+ ---
13
+
14
+ ## 核心概念
15
+
16
+ 每次開一個新的 Claude Code session,AI 就完全失憶。花 20 分鐘講清楚的架構、一起 debug 的那個 bug、做過的決策——全部歸零,下次重來。
17
+
18
+ CLAUDE.md 和 RESUME.md 能幫忙,但它們是你手動維護的靜態檔案。ccRecall 把這件事自動化:讀取 JSONL 對話記錄、建立可搜尋的索引、透過 hooks 和 MCP 工具把相關記憶回傳給 Claude Code。AI 自己記住學過的東西——你不用再提醒它。
19
+
20
+ ccRecall 是 [ccRewind](https://github.com/tznthou/ccRewind)(對話回放 GUI)的「記憶」對應。ccRewind 讓人回頭看發生了什麼;ccRecall 讓 AI 記住發生了什麼。
21
+
22
+ > **命名說明**:本專案與 [spences10/ccrecall](https://github.com/spences10/ccrecall)(一個 analytics 導向的工具,恰好同名)無關。由於 npm 上 `ccrecall` 已被佔用,我們以 `@tznthou/ccrecall` 發佈,CLI 命令名為 `ccmem`。
23
+
24
+ ---
25
+
26
+ ## 功能特色
27
+
28
+ | 功能 | 說明 |
29
+ |------|------|
30
+ | **規則式摘要引擎** | 從 session 中提取意圖、動作、結果、標籤——不呼叫 LLM,零 API 成本 |
31
+ | **FTS5 全文搜尋** | 所有對話歷史的關鍵詞搜尋 <100ms,快到可以在 hook 中注入 |
32
+ | **增量索引** | 只重新索引有變動的 session(mtime 比對),透過 UUID 去重處理接續 session |
33
+ | **元認知** | `knowledge_map` 聚合 session + memory 的主題提及。由 mention count 衍生深度(shallow / medium / deep)。透過 `/metacognition/check` 與 MCP `recall_context` 暴露 |
34
+ | **遺忘曲線** | 記憶隨時間壓縮:原始→摘要→一行結論→刪除。未使用的記憶信心衰減。背景維護 tick 每 5 分鐘跑一次 |
35
+ | **Watch mode** | 基於 chokidar 的 JSONL watcher 在 2 秒內偵測新 session;每 10 分鐘 full-resync 補救 FS 事件漏接 |
36
+ | **Rescue reindex** | `/session/end` 遇到 cache miss 時會重 index 再試一次——hook 和 daemon 間不會有 fresh-session race |
37
+ | **macOS 自動啟動** | `ccmem install-daemon` 安裝 LaunchAgent,重開機自動復原服務 |
38
+ | **純唯讀** | 絕不修改 `~/.claude/`——只讀取 JSONL 記錄 |
39
+
40
+ ---
41
+
42
+ ## 架構
43
+
44
+ ```mermaid
45
+ flowchart TB
46
+ subgraph Input["資料來源(唯讀)"]
47
+ JSONL["~/.claude/projects/*/*.jsonl"]
48
+ end
49
+
50
+ subgraph Core["ccRecall 服務(port 7749)"]
51
+ Scanner["Scanner<br/>掃描 JSONL 檔案"]
52
+ Parser["Parser<br/>解析對話"]
53
+ Summarizer["Summarizer<br/>規則式萃取"]
54
+ DB["SQLite + FTS5<br/>索引與搜尋"]
55
+ API["HTTP API<br/>7 個端點"]
56
+ end
57
+
58
+ subgraph Consumers["Context 注入"]
59
+ Hook["Claude Code Hooks<br/>SessionStart / SessionEnd"]
60
+ MCP["MCP Server<br/>recall_query / recall_save"]
61
+ end
62
+
63
+ JSONL --> Scanner --> Parser --> Summarizer --> DB
64
+ DB --> API
65
+ API --> Hook
66
+ API --> MCP
67
+ ```
68
+
69
+ ---
70
+
71
+ ## 技術棧
72
+
73
+ | 技術 | 用途 | 備註 |
74
+ |------|------|------|
75
+ | Node.js 20–22 + TypeScript | 執行環境 | ES modules、strict mode |
76
+ | better-sqlite3 | 資料庫 | 同步 API、零外部依賴 |
77
+ | FTS5 | 全文搜尋 | SQLite 內建、unicode61 tokenizer |
78
+ | 原生 `http` | HTTP 伺服器 | 不用 Express——最小表面積、僅 localhost |
79
+ | chokidar | 檔案系統 watcher | 跨平台 JSONL 變動偵測,2 秒 debounce + single-flight |
80
+ | vitest | 測試 | 396 個測試(26 檔案)、整合式風格 |
81
+ | `@modelcontextprotocol/sdk` | MCP server | stdio transport,透過 WAL 共用 SQLite |
82
+
83
+ ---
84
+
85
+ ## 快速開始
86
+
87
+ ### 環境需求
88
+
89
+ - Node.js `>=20.0.0,<23.0.0`
90
+ - pnpm
91
+
92
+ ### 安裝
93
+
94
+ ```bash
95
+ git clone https://github.com/tznthou/ccRecall.git
96
+ cd ccRecall
97
+
98
+ pnpm install
99
+
100
+ # 啟動開發伺服器(啟動時自動索引,並 watch ~/.claude/projects)
101
+ pnpm dev
102
+ ```
103
+
104
+ 服務啟動在 `http://127.0.0.1:7749`,會自動索引 `~/.claude/projects/` 下所有 JSONL 檔案。
105
+
106
+ ### 驗證
107
+
108
+ ```bash
109
+ # 健康檢查——sessionCount 應該 > 0
110
+ curl http://127.0.0.1:7749/health
111
+
112
+ # 搜尋你的對話歷史
113
+ curl "http://127.0.0.1:7749/memory/query?q=authentication&limit=5"
114
+ ```
115
+
116
+ ---
117
+
118
+ ## API 端點
119
+
120
+ | 端點 | 方法 | 說明 | 狀態 |
121
+ |------|------|------|------|
122
+ | `/health` | GET | 服務健康 + DB 統計 | 已上線 |
123
+ | `/memory/query?q=...&limit=...&project=...` | GET | FTS5 跨 session 搜尋,可選 project 過濾 | 已上線 |
124
+ | `/memory/save` | POST | 儲存記憶條目(Origin 驗證) | 已上線 |
125
+ | `/session/end` | POST | 從結束的 session 萃取記憶(idempotent) | 已上線 |
126
+ | `/memory/context?session_id=...` | GET | Session context 查詢 | Stub |
127
+ | `/metacognition/check?projectId=...[&topic=...]` | GET | 知識地圖:summary(top/recent/stale topics + counts)或 topic detail(memories + related topics) | 已上線 |
128
+ | `/session/checkpoint` | POST | 會話中途快照寫入獨立 `session_checkpoints` 表(不會被 harvest 成 memory) | 已上線 |
129
+ | `/lint/warnings` | GET | Lint 報告:orphan(session 已刪)+ stale(低信心、長期未用)記憶警告 | 已上線 |
130
+
131
+ ## MCP 工具
132
+
133
+ | 工具 | 用途 |
134
+ |------|------|
135
+ | `recall_query` | 純 FTS5 關鍵字搜尋 memories |
136
+ | `recall_context` | 按 topic 分組的檢索——normalize keywords、依匹配 topic 分組 memories 並附 depth 訊號,無 topic 匹配時退回 per-keyword FTS |
137
+ | `recall_save` | 儲存新記憶(type:decision / discovery / preference / pattern / feedback) |
138
+
139
+ 註冊到 Claude Code。`pnpm build` 後 `dist/mcp/server.js` 就是可執行的 MCP server:
140
+
141
+ ```bash
142
+ # 用 build 出的 bin(pnpm build 之後)
143
+ claude mcp add ccrecall --scope user -- /absolute/path/to/ccRecall/dist/mcp/server.js
144
+
145
+ # 或開發時用 tsx 不經 build
146
+ claude mcp add ccrecall --scope user -- /absolute/path/to/ccRecall/node_modules/.bin/tsx /absolute/path/to/ccRecall/src/mcp/server.ts
147
+ ```
148
+
149
+ 可直接複製的範本:[.mcp.json.example](.mcp.json.example)。
150
+
151
+ SessionStart / SessionEnd hook 安裝見 [hooks/README.md](hooks/README.md)。
152
+
153
+ ---
154
+
155
+ ## 作為服務運行(macOS)
156
+
157
+ ccRecall 是本地 HTTP daemon。要重開機也維持運行,註冊 per-user LaunchAgent:
158
+
159
+ ```bash
160
+ pnpm build
161
+ node dist/index.js install-daemon # 或 `ccmem install-daemon`(若已全域 link)
162
+ node dist/index.js install-daemon --dry-run # 預覽 plist 不寫檔
163
+
164
+ # 驗證
165
+ launchctl list | grep ccrecall
166
+ curl http://127.0.0.1:7749/health
167
+
168
+ # 移除
169
+ node dist/index.js uninstall-daemon
170
+ ```
171
+
172
+ installer 的行為:
173
+ - 寫入 `~/Library/LaunchAgents/com.tznthou.ccrecall.plist`
174
+ - log 路由到 `~/Library/Logs/ccrecall/ccrecall.{out,err}.log`
175
+ - 從當前 shell 的 `CCRECALL_PORT` / `CCRECALL_DB_PATH` 寫入 plist,確保
176
+ LaunchAgent 用和你互動執行時一致的設定
177
+ - 拒絕覆蓋 `Label` 不匹配的 plist(安全檢查)
178
+
179
+ 完整手動安裝、troubleshooting、uninstall 文件:[docs/launchd.md](docs/launchd.md)。
180
+
181
+ Linux/Windows 對應版本(systemd unit、Windows service)列在 Phase 5。目前
182
+ Linux 可用 `nohup` 或自選 process manager。
183
+
184
+ ---
185
+
186
+ ## 專案結構
187
+
188
+ ```
189
+ ccRecall/
190
+ ├── src/
191
+ │ ├── core/
192
+ │ │ ├── types.ts # 所有型別定義
193
+ │ │ ├── parser.ts # JSONL 對話解析
194
+ │ │ ├── scanner.ts # 檔案系統掃描
195
+ │ │ ├── summarizer.ts # 規則式 session 摘要
196
+ │ │ ├── topic-extractor.ts # 規則式 topic 抽取
197
+ │ │ ├── database.ts # SQLite + FTS5(從 ccRewind 裁剪)
198
+ │ │ ├── indexer.ts # 索引 pipeline 調度
199
+ │ │ ├── memory-service.ts # 記憶生命週期(touch / delete / update)
200
+ │ │ ├── compression.ts # L0→L1→L2→delete 狀態機
201
+ │ │ ├── lint.ts # Orphan / stale 記憶偵測
202
+ │ │ ├── maintenance-coordinator.ts # 背景壓縮 tick
203
+ │ │ ├── watcher.ts # chokidar JSONL watcher(Phase 4e)
204
+ │ │ └── log-safe.ts # scrubErrorMessage — log-injection 防護
205
+ │ ├── api/
206
+ │ │ ├── server.ts # HTTP 伺服器
207
+ │ │ └── routes.ts # 路由 + rescue reindex
208
+ │ ├── mcp/
209
+ │ │ ├── server.ts # MCP stdio server 入口(含 shebang)
210
+ │ │ └── tools.ts # recall_query + recall_context + recall_save
211
+ │ ├── cli/
212
+ │ │ └── daemon.ts # install-daemon / uninstall-daemon(macOS)
213
+ │ └── index.ts # HTTP 入口 + 子指令分派
214
+ ├── hooks/
215
+ │ ├── session-start.mjs # SessionStart 注入記憶(stdout)
216
+ │ ├── session-end.mjs # SessionEnd 呼叫 /session/end
217
+ │ └── README.md # Hook 安裝指南
218
+ ├── docs/
219
+ │ └── launchd.md # macOS LaunchAgent 安裝/troubleshoot
220
+ ├── tests/ # 396 個測試橫跨 26 檔案(parser /
221
+ │ │ # scanner / summarizer / database /
222
+ │ │ # indexer / e2e / memories / mcp /
223
+ │ │ # session-end / compression / lint /
224
+ │ │ # watcher / bin-smoke / cli-daemon /
225
+ │ │ # migration-v18 / decay /
226
+ │ │ # maintenance-coordinator / memory-service /
227
+ │ │ # memory-project-scope / touch /
228
+ │ │ # hooks-session-start / hooks-session-end /
229
+ │ │ # knowledge-map / topic-extractor /
230
+ │ │ # metacognition / session-checkpoint)
231
+ │ └── fixtures/ # 測試用 JSONL + 共用 helpers
232
+ ├── .mcp.json.example # MCP client 設定範本
233
+ ├── NOTICE / SECURITY.md / CONTRIBUTING.md / CODE_OF_CONDUCT.md
234
+ └── .claude/
235
+ └── pi-research/ # 架構研究文件
236
+ ```
237
+
238
+ ---
239
+
240
+ ## 相關專案
241
+
242
+ - **[ccRewind](https://github.com/user/ccRewind)** — Claude Code 的 session 回放 GUI。ccRecall 的核心模組(parser, scanner, summarizer, database, indexer)從 ccRewind 抽取而來。
243
+
244
+ ---
245
+
246
+ ## 隨想
247
+
248
+ ### 為什麼做這個
249
+
250
+ Anthropic Claude Code 團隊的 Thariq 在 2026 年 4 月[發表了 context 管理的文章](https://x.com/trq212)——11,908 個書籤,因為大家存起來反覆看但沒人有工具做到。他把問題講得很精準:context rot 讓長 session 的模型表現退化,autocompact 在最爛的時機觸發。
251
+
252
+ 但他給了方法論,沒給工具。ccRecall 就是那個工具。
253
+
254
+ 真正的觸發點更簡單:我受夠了每次跨 session 都要重新跟 Claude Code 解釋同一個架構。不是 AI 記性差——它根本不能記。每個 session 從零開始。CLAUDE.md 能幫忙,但它是我手動維護的靜態檔案。維護成本的增長速度超過知識的增值速度。聽起來很熟?這正是人類放棄 wiki 的原因(Karpathy 的 LLM Wiki 洞見)。
255
+
256
+ ### 設計抉擇
257
+
258
+ **規則式摘要引擎而非 LLM 呼叫。** claude-mem 用 Claude API 做摘要——花 AI 的錢幫 AI 記東西。ccRecall 用 heuristic 萃取(regex 模式、工具使用分析、outcome 推斷)。沒有 LLM 精緻,但成本精確歸零。對 session 摘要來說,「Edit×8, 5 files, committed」比一段文字更有用。
259
+
260
+ **FTS5 而非向量資料庫。** 語義搜尋聽起來更高級,但對話記錄搜尋的是具體的工具名、檔案路徑、錯誤訊息——關鍵詞匹配就夠了。FTS5 查詢在本地 <10ms。不需要 embedding model、不需要 Chroma、不需要 Docker container。在我們的規模(數百個 session,不是百萬文件),Karpathy 自己的分析也確認:「500 個來源以下,樸素索引 + 關鍵詞搜尋已經夠用。」
261
+
262
+ **HTTP + MCP 雙介面。** 研究顯示 MCP server tools 是注入 context 到 Claude 最穩定的方式(pull-based,Claude 決定何時取)。但 SessionStart hooks(push-based,自動注入)也穩定。所以 ccRecall 兩個都跑:HTTP 給 hooks 用,MCP 給按需查詢。同一個 SQLite 後端,兩種存取模式。
263
+
264
+ **唯讀約束。** ccRecall 絕不修改 `~/.claude/`。這不只是禮貌——是信任邊界。如果一個背景服務能寫入你的 Claude Code 設定,一個 bug 就可能毀掉你的 session。唯讀意味著最壞情況是「ccRecall 搜尋結果不好」,不是「ccRecall 搞壞了我的設定」。
265
+
266
+ ### 刻意不做的事
267
+
268
+ **不用 Docker、不用 Electron、不用向量資料庫。** 這些是刻意排除,不是缺失的功能。Docker 對一個 `pnpm dev` 就能跑的東西增加了部署摩擦。Electron 是給 GUI 用的——ccRecall 沒有 UI(那是 ccRewind 的事)。向量資料庫解決的是我們在這個規模不存在的問題。
269
+
270
+ **任何操作都不依賴 LLM。** 如果 ccRecall 需要 API key 才能運作,它就失敗了。核心就是零成本、本地運行的記憶。摘要是規則式的,搜尋是 FTS5。需要 LLM 呼叫的那天,就是我們 overscope 的那天。
271
+
272
+ **不做「智慧」記憶注入。** ccRecall 不替 Claude 決定該記住什麼。它提供搜尋 API——注入層(hooks、MCP)呈現結果,Claude 自己整合。帶偏見的記憶篩選是過早優化,而且會以我們無法預測的方式出錯。
273
+
274
+ **不修改使用者資料。** ccRecall 讀取 `~/.claude/projects/` 的 JSONL 檔案。它絕不寫入那個目錄、絕不修改 session 檔案、絕不自動把自己注入 Claude Code 的設定。使用者自己決定設定 hooks 和 MCP——ccRecall 不會自己安裝自己。
275
+
276
+ ---
277
+
278
+ ## 授權
279
+
280
+ 本專案使用 Apache License 2.0 授權 —— 見 [LICENSE](LICENSE)。
281
+
282
+ Copyright 2026 tznthou
283
+
284
+ ---
285
+
286
+ ## 作者
287
+
288
+ tznthou — [tznthou.com](https://tznthou.com) · [tznthou@gmail.com](mailto:tznthou@gmail.com)
@@ -0,0 +1,13 @@
1
+ import http from 'node:http';
2
+ import type { Database, MemoryInput } from '../core/database.js';
3
+ import type { MemoryType, SessionMeta, OutcomeStatus } from '../core/types.js';
4
+ export declare function inferMemoryType(outcome: OutcomeStatus): MemoryType;
5
+ export declare function inferConfidence(outcome: OutcomeStatus): number;
6
+ export declare function buildMemoryFromSession(session: SessionMeta): MemoryInput | null;
7
+ export interface RequestHandlerOptions {
8
+ /** Called when /session/end sees a missing session — typically `() => runIndexer(db)`
9
+ * — so a fresh-session hook can harvest after a forced reindex retry. */
10
+ rescueReindex?: () => Promise<void>;
11
+ }
12
+ export declare function createRequestHandler(db: Database, opts?: RequestHandlerOptions): (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void>;
13
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,WAAW,CAAA;AAG5B,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAIhE,OAAO,KAAK,EACY,UAAU,EAAE,WAAW,EAAE,aAAa,EAE7D,MAAM,kBAAkB,CAAA;AA8DzB,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,UAAU,CAGlE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAI9D;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,GAAG,IAAI,CAc/E;AAgED,MAAM,WAAW,qBAAqB;IACpC;8EAC0E;IAC1E,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,EACZ,IAAI,GAAE,qBAA0B,IAI9B,KAAK,IAAI,CAAC,eAAe,EACzB,KAAK,IAAI,CAAC,cAAc,KACvB,OAAO,CAAC,IAAI,CAAC,CAgTjB"}