fixo-cli 1.0.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 (303) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +530 -0
  3. package/dist/agent/agent-client.d.ts +108 -0
  4. package/dist/agent/agent-client.d.ts.map +1 -0
  5. package/dist/agent/agent-client.js +1247 -0
  6. package/dist/agent/agent-client.js.map +1 -0
  7. package/dist/agent/agent-pool.d.ts +20 -0
  8. package/dist/agent/agent-pool.d.ts.map +1 -0
  9. package/dist/agent/agent-pool.js +217 -0
  10. package/dist/agent/agent-pool.js.map +1 -0
  11. package/dist/agent/background-awareness.d.ts +55 -0
  12. package/dist/agent/background-awareness.d.ts.map +1 -0
  13. package/dist/agent/background-awareness.js +104 -0
  14. package/dist/agent/background-awareness.js.map +1 -0
  15. package/dist/agent/command-parser.d.ts +33 -0
  16. package/dist/agent/command-parser.d.ts.map +1 -0
  17. package/dist/agent/command-parser.js +120 -0
  18. package/dist/agent/command-parser.js.map +1 -0
  19. package/dist/agent/context-budget.d.ts +91 -0
  20. package/dist/agent/context-budget.d.ts.map +1 -0
  21. package/dist/agent/context-budget.js +219 -0
  22. package/dist/agent/context-budget.js.map +1 -0
  23. package/dist/agent/conversation.d.ts +190 -0
  24. package/dist/agent/conversation.d.ts.map +1 -0
  25. package/dist/agent/conversation.js +547 -0
  26. package/dist/agent/conversation.js.map +1 -0
  27. package/dist/agent/hooks.d.ts +72 -0
  28. package/dist/agent/hooks.d.ts.map +1 -0
  29. package/dist/agent/hooks.js +214 -0
  30. package/dist/agent/hooks.js.map +1 -0
  31. package/dist/agent/mcp-bridge.d.ts +13 -0
  32. package/dist/agent/mcp-bridge.d.ts.map +1 -0
  33. package/dist/agent/mcp-bridge.js +86 -0
  34. package/dist/agent/mcp-bridge.js.map +1 -0
  35. package/dist/agent/mcp-client.d.ts +24 -0
  36. package/dist/agent/mcp-client.d.ts.map +1 -0
  37. package/dist/agent/mcp-client.js +146 -0
  38. package/dist/agent/mcp-client.js.map +1 -0
  39. package/dist/agent/mcp-manager.d.ts +13 -0
  40. package/dist/agent/mcp-manager.d.ts.map +1 -0
  41. package/dist/agent/mcp-manager.js +84 -0
  42. package/dist/agent/mcp-manager.js.map +1 -0
  43. package/dist/agent/mcp-registry.d.ts +45 -0
  44. package/dist/agent/mcp-registry.d.ts.map +1 -0
  45. package/dist/agent/mcp-registry.js +98 -0
  46. package/dist/agent/mcp-registry.js.map +1 -0
  47. package/dist/agent/orchestrator.d.ts +14 -0
  48. package/dist/agent/orchestrator.d.ts.map +1 -0
  49. package/dist/agent/orchestrator.js +118 -0
  50. package/dist/agent/orchestrator.js.map +1 -0
  51. package/dist/agent/parser-adapter.d.ts +120 -0
  52. package/dist/agent/parser-adapter.d.ts.map +1 -0
  53. package/dist/agent/parser-adapter.js +265 -0
  54. package/dist/agent/parser-adapter.js.map +1 -0
  55. package/dist/agent/parsers/imports.d.ts +11 -0
  56. package/dist/agent/parsers/imports.d.ts.map +1 -0
  57. package/dist/agent/parsers/imports.js +94 -0
  58. package/dist/agent/parsers/imports.js.map +1 -0
  59. package/dist/agent/parsers/shell.d.ts +23 -0
  60. package/dist/agent/parsers/shell.d.ts.map +1 -0
  61. package/dist/agent/parsers/shell.js +200 -0
  62. package/dist/agent/parsers/shell.js.map +1 -0
  63. package/dist/agent/parsers/symbols.d.ts +17 -0
  64. package/dist/agent/parsers/symbols.d.ts.map +1 -0
  65. package/dist/agent/parsers/symbols.js +103 -0
  66. package/dist/agent/parsers/symbols.js.map +1 -0
  67. package/dist/agent/permissions.d.ts +65 -0
  68. package/dist/agent/permissions.d.ts.map +1 -0
  69. package/dist/agent/permissions.js +219 -0
  70. package/dist/agent/permissions.js.map +1 -0
  71. package/dist/agent/predictive-gate.d.ts +69 -0
  72. package/dist/agent/predictive-gate.d.ts.map +1 -0
  73. package/dist/agent/predictive-gate.js +128 -0
  74. package/dist/agent/predictive-gate.js.map +1 -0
  75. package/dist/agent/provider-cooldown.d.ts +144 -0
  76. package/dist/agent/provider-cooldown.d.ts.map +1 -0
  77. package/dist/agent/provider-cooldown.js +300 -0
  78. package/dist/agent/provider-cooldown.js.map +1 -0
  79. package/dist/agent/providers-manager.d.ts +109 -0
  80. package/dist/agent/providers-manager.d.ts.map +1 -0
  81. package/dist/agent/providers-manager.js +464 -0
  82. package/dist/agent/providers-manager.js.map +1 -0
  83. package/dist/agent/repo-map.d.ts +6 -0
  84. package/dist/agent/repo-map.d.ts.map +1 -0
  85. package/dist/agent/repo-map.js +221 -0
  86. package/dist/agent/repo-map.js.map +1 -0
  87. package/dist/agent/retry.d.ts +103 -0
  88. package/dist/agent/retry.d.ts.map +1 -0
  89. package/dist/agent/retry.js +276 -0
  90. package/dist/agent/retry.js.map +1 -0
  91. package/dist/agent/search/index.d.ts +61 -0
  92. package/dist/agent/search/index.d.ts.map +1 -0
  93. package/dist/agent/search/index.js +314 -0
  94. package/dist/agent/search/index.js.map +1 -0
  95. package/dist/agent/single-agent.d.ts +76 -0
  96. package/dist/agent/single-agent.d.ts.map +1 -0
  97. package/dist/agent/single-agent.js +697 -0
  98. package/dist/agent/single-agent.js.map +1 -0
  99. package/dist/agent/skills.d.ts +22 -0
  100. package/dist/agent/skills.d.ts.map +1 -0
  101. package/dist/agent/skills.js +139 -0
  102. package/dist/agent/skills.js.map +1 -0
  103. package/dist/agent/stream-glue.d.ts +85 -0
  104. package/dist/agent/stream-glue.d.ts.map +1 -0
  105. package/dist/agent/stream-glue.js +120 -0
  106. package/dist/agent/stream-glue.js.map +1 -0
  107. package/dist/agent/subagent.d.ts +72 -0
  108. package/dist/agent/subagent.d.ts.map +1 -0
  109. package/dist/agent/subagent.js +193 -0
  110. package/dist/agent/subagent.js.map +1 -0
  111. package/dist/agent/telemetry.d.ts +192 -0
  112. package/dist/agent/telemetry.d.ts.map +1 -0
  113. package/dist/agent/telemetry.js +400 -0
  114. package/dist/agent/telemetry.js.map +1 -0
  115. package/dist/agent/tokenizer.d.ts +42 -0
  116. package/dist/agent/tokenizer.d.ts.map +1 -0
  117. package/dist/agent/tokenizer.js +107 -0
  118. package/dist/agent/tokenizer.js.map +1 -0
  119. package/dist/agent/tool-executor.d.ts +289 -0
  120. package/dist/agent/tool-executor.d.ts.map +1 -0
  121. package/dist/agent/tool-executor.js +2519 -0
  122. package/dist/agent/tool-executor.js.map +1 -0
  123. package/dist/agent/web-impl.d.ts +2 -0
  124. package/dist/agent/web-impl.d.ts.map +1 -0
  125. package/dist/agent/web-impl.js +34 -0
  126. package/dist/agent/web-impl.js.map +1 -0
  127. package/dist/agent/web.d.ts +8 -0
  128. package/dist/agent/web.d.ts.map +1 -0
  129. package/dist/agent/web.js +8 -0
  130. package/dist/agent/web.js.map +1 -0
  131. package/dist/agent/worker-agent.d.ts +27 -0
  132. package/dist/agent/worker-agent.d.ts.map +1 -0
  133. package/dist/agent/worker-agent.js +503 -0
  134. package/dist/agent/worker-agent.js.map +1 -0
  135. package/dist/config.d.ts +162 -0
  136. package/dist/config.d.ts.map +1 -0
  137. package/dist/config.js +138 -0
  138. package/dist/config.js.map +1 -0
  139. package/dist/context/fixo-md-watcher.d.ts +42 -0
  140. package/dist/context/fixo-md-watcher.d.ts.map +1 -0
  141. package/dist/context/fixo-md-watcher.js +126 -0
  142. package/dist/context/fixo-md-watcher.js.map +1 -0
  143. package/dist/context/fixo-md.d.ts +50 -0
  144. package/dist/context/fixo-md.d.ts.map +1 -0
  145. package/dist/context/fixo-md.js +118 -0
  146. package/dist/context/fixo-md.js.map +1 -0
  147. package/dist/context/todo.d.ts +65 -0
  148. package/dist/context/todo.d.ts.map +1 -0
  149. package/dist/context/todo.js +194 -0
  150. package/dist/context/todo.js.map +1 -0
  151. package/dist/git/git-manager.d.ts +33 -0
  152. package/dist/git/git-manager.d.ts.map +1 -0
  153. package/dist/git/git-manager.js +293 -0
  154. package/dist/git/git-manager.js.map +1 -0
  155. package/dist/git/git-ops.d.ts +10 -0
  156. package/dist/git/git-ops.d.ts.map +1 -0
  157. package/dist/git/git-ops.js +131 -0
  158. package/dist/git/git-ops.js.map +1 -0
  159. package/dist/index.d.ts +3 -0
  160. package/dist/index.d.ts.map +1 -0
  161. package/dist/index.js +352 -0
  162. package/dist/index.js.map +1 -0
  163. package/dist/indexer.d.ts +30 -0
  164. package/dist/indexer.d.ts.map +1 -0
  165. package/dist/indexer.js +273 -0
  166. package/dist/indexer.js.map +1 -0
  167. package/dist/lsp/lsp-client.d.ts +24 -0
  168. package/dist/lsp/lsp-client.d.ts.map +1 -0
  169. package/dist/lsp/lsp-client.js +205 -0
  170. package/dist/lsp/lsp-client.js.map +1 -0
  171. package/dist/lsp/lsp-manager.d.ts +17 -0
  172. package/dist/lsp/lsp-manager.d.ts.map +1 -0
  173. package/dist/lsp/lsp-manager.js +154 -0
  174. package/dist/lsp/lsp-manager.js.map +1 -0
  175. package/dist/lsp/lsp-pre-save.d.ts +137 -0
  176. package/dist/lsp/lsp-pre-save.d.ts.map +1 -0
  177. package/dist/lsp/lsp-pre-save.js +245 -0
  178. package/dist/lsp/lsp-pre-save.js.map +1 -0
  179. package/dist/lsp/syntax-fallback.d.ts +83 -0
  180. package/dist/lsp/syntax-fallback.d.ts.map +1 -0
  181. package/dist/lsp/syntax-fallback.js +275 -0
  182. package/dist/lsp/syntax-fallback.js.map +1 -0
  183. package/dist/model-outcomes.d.ts +12 -0
  184. package/dist/model-outcomes.d.ts.map +1 -0
  185. package/dist/model-outcomes.js +46 -0
  186. package/dist/model-outcomes.js.map +1 -0
  187. package/dist/planner.d.ts +32 -0
  188. package/dist/planner.d.ts.map +1 -0
  189. package/dist/planner.js +163 -0
  190. package/dist/planner.js.map +1 -0
  191. package/dist/project-memory.d.ts +29 -0
  192. package/dist/project-memory.d.ts.map +1 -0
  193. package/dist/project-memory.js +349 -0
  194. package/dist/project-memory.js.map +1 -0
  195. package/dist/review.d.ts +2 -0
  196. package/dist/review.d.ts.map +1 -0
  197. package/dist/review.js +61 -0
  198. package/dist/review.js.map +1 -0
  199. package/dist/runtime/background-jobs.d.ts +97 -0
  200. package/dist/runtime/background-jobs.d.ts.map +1 -0
  201. package/dist/runtime/background-jobs.js +331 -0
  202. package/dist/runtime/background-jobs.js.map +1 -0
  203. package/dist/runtime/credential-vault.d.ts +124 -0
  204. package/dist/runtime/credential-vault.d.ts.map +1 -0
  205. package/dist/runtime/credential-vault.js +184 -0
  206. package/dist/runtime/credential-vault.js.map +1 -0
  207. package/dist/runtime/loop-trap.d.ts +197 -0
  208. package/dist/runtime/loop-trap.d.ts.map +1 -0
  209. package/dist/runtime/loop-trap.js +420 -0
  210. package/dist/runtime/loop-trap.js.map +1 -0
  211. package/dist/runtime/policy.d.ts +15 -0
  212. package/dist/runtime/policy.d.ts.map +1 -0
  213. package/dist/runtime/policy.js +60 -0
  214. package/dist/runtime/policy.js.map +1 -0
  215. package/dist/runtime/redaction.d.ts +66 -0
  216. package/dist/runtime/redaction.d.ts.map +1 -0
  217. package/dist/runtime/redaction.js +155 -0
  218. package/dist/runtime/redaction.js.map +1 -0
  219. package/dist/runtime/session-snapshots.d.ts +76 -0
  220. package/dist/runtime/session-snapshots.d.ts.map +1 -0
  221. package/dist/runtime/session-snapshots.js +166 -0
  222. package/dist/runtime/session-snapshots.js.map +1 -0
  223. package/dist/runtime/staging.d.ts +205 -0
  224. package/dist/runtime/staging.d.ts.map +1 -0
  225. package/dist/runtime/staging.js +526 -0
  226. package/dist/runtime/staging.js.map +1 -0
  227. package/dist/runtime/task-session.d.ts +95 -0
  228. package/dist/runtime/task-session.d.ts.map +1 -0
  229. package/dist/runtime/task-session.js +263 -0
  230. package/dist/runtime/task-session.js.map +1 -0
  231. package/dist/runtime/worktree.d.ts +55 -0
  232. package/dist/runtime/worktree.d.ts.map +1 -0
  233. package/dist/runtime/worktree.js +175 -0
  234. package/dist/runtime/worktree.js.map +1 -0
  235. package/dist/setup-wizard.d.ts +8 -0
  236. package/dist/setup-wizard.d.ts.map +1 -0
  237. package/dist/setup-wizard.js +73 -0
  238. package/dist/setup-wizard.js.map +1 -0
  239. package/dist/shared/content.d.ts +43 -0
  240. package/dist/shared/content.d.ts.map +1 -0
  241. package/dist/shared/content.js +61 -0
  242. package/dist/shared/content.js.map +1 -0
  243. package/dist/shared/types.d.ts +217 -0
  244. package/dist/shared/types.d.ts.map +1 -0
  245. package/dist/shared/types.js +3 -0
  246. package/dist/shared/types.js.map +1 -0
  247. package/dist/test-runner.d.ts +5 -0
  248. package/dist/test-runner.d.ts.map +1 -0
  249. package/dist/test-runner.js +42 -0
  250. package/dist/test-runner.js.map +1 -0
  251. package/dist/types.d.ts +85 -0
  252. package/dist/types.d.ts.map +1 -0
  253. package/dist/types.js +2 -0
  254. package/dist/types.js.map +1 -0
  255. package/dist/ui/ascii.d.ts +23 -0
  256. package/dist/ui/ascii.d.ts.map +1 -0
  257. package/dist/ui/ascii.js +45 -0
  258. package/dist/ui/ascii.js.map +1 -0
  259. package/dist/ui/colors.d.ts +111 -0
  260. package/dist/ui/colors.d.ts.map +1 -0
  261. package/dist/ui/colors.js +166 -0
  262. package/dist/ui/colors.js.map +1 -0
  263. package/dist/ui/image-attach.d.ts +27 -0
  264. package/dist/ui/image-attach.d.ts.map +1 -0
  265. package/dist/ui/image-attach.js +100 -0
  266. package/dist/ui/image-attach.js.map +1 -0
  267. package/dist/ui/index.d.ts +18 -0
  268. package/dist/ui/index.d.ts.map +1 -0
  269. package/dist/ui/index.js +18 -0
  270. package/dist/ui/index.js.map +1 -0
  271. package/dist/ui/markdown-stream.d.ts +91 -0
  272. package/dist/ui/markdown-stream.d.ts.map +1 -0
  273. package/dist/ui/markdown-stream.js +524 -0
  274. package/dist/ui/markdown-stream.js.map +1 -0
  275. package/dist/ui/plan-renderer.d.ts +36 -0
  276. package/dist/ui/plan-renderer.d.ts.map +1 -0
  277. package/dist/ui/plan-renderer.js +79 -0
  278. package/dist/ui/plan-renderer.js.map +1 -0
  279. package/dist/ui/prompt.d.ts +11 -0
  280. package/dist/ui/prompt.d.ts.map +1 -0
  281. package/dist/ui/prompt.js +1960 -0
  282. package/dist/ui/prompt.js.map +1 -0
  283. package/dist/ui/render-primitives.d.ts +117 -0
  284. package/dist/ui/render-primitives.d.ts.map +1 -0
  285. package/dist/ui/render-primitives.js +322 -0
  286. package/dist/ui/render-primitives.js.map +1 -0
  287. package/dist/ui/render.d.ts +133 -0
  288. package/dist/ui/render.d.ts.map +1 -0
  289. package/dist/ui/render.js +547 -0
  290. package/dist/ui/render.js.map +1 -0
  291. package/dist/ui/session-header.d.ts +30 -0
  292. package/dist/ui/session-header.d.ts.map +1 -0
  293. package/dist/ui/session-header.js +74 -0
  294. package/dist/ui/session-header.js.map +1 -0
  295. package/dist/workspace-guard.d.ts +68 -0
  296. package/dist/workspace-guard.d.ts.map +1 -0
  297. package/dist/workspace-guard.js +168 -0
  298. package/dist/workspace-guard.js.map +1 -0
  299. package/dist/workspace-lock.d.ts +27 -0
  300. package/dist/workspace-lock.d.ts.map +1 -0
  301. package/dist/workspace-lock.js +95 -0
  302. package/dist/workspace-lock.js.map +1 -0
  303. package/package.json +63 -0
@@ -0,0 +1,547 @@
1
+ /**
2
+ * ConversationManager — manages multi-turn chat context for the FixO CLI agent.
3
+ *
4
+ * Provides automatic context window management inspired by OpenCode:
5
+ * 1. Tracks estimated token usage per model's context window limit
6
+ * 2. Auto-compacts when the next request would overflow the context
7
+ * 3. Uses a structured summary template to preserve critical information
8
+ * 4. Preserves the N most-recent turns verbatim for continuity
9
+ * 5. Prunes old tool outputs to free space before full compaction
10
+ */
11
+ import { countMessagesTokens, countTokens } from './tokenizer.js';
12
+ import { ContextBudgetEnforcer } from './context-budget.js';
13
+ // ---------------------------------------------------------------------------
14
+ // Constants
15
+ // ---------------------------------------------------------------------------
16
+ /**
17
+ * Known context window limits (input tokens) for models/providers.
18
+ * These are conservative estimates — we leave headroom for output tokens.
19
+ * Format: pattern → max input tokens (context minus output reservation).
20
+ */
21
+ const MODEL_CONTEXT_LIMITS = [
22
+ // Google Gemini — huge contexts
23
+ [/gemini-2\.5-flash/i, 900_000],
24
+ [/gemini-2\.5-pro/i, 900_000],
25
+ [/gemini-2\.0/i, 900_000],
26
+ [/gemini/i, 900_000],
27
+ // Groq — standard
28
+ [/llama-3\.3-70b/i, 120_000],
29
+ [/llama-4/i, 120_000],
30
+ [/deepseek-r1/i, 120_000],
31
+ [/compound/i, 120_000],
32
+ [/gpt-oss/i, 120_000],
33
+ // Cerebras
34
+ [/qwen-3-235b/i, 8_000], // Very small on free tier
35
+ [/llama3\.1-8b/i, 8_000],
36
+ // SambaNova
37
+ [/deepseek-v3/i, 120_000],
38
+ [/qwen3-coder/i, 120_000],
39
+ // Mistral
40
+ [/mistral-large/i, 120_000],
41
+ [/codestral/i, 250_000],
42
+ [/devstral/i, 120_000],
43
+ [/magistral/i, 120_000],
44
+ // OpenRouter — varies by model
45
+ [/openrouter/i, 120_000],
46
+ // Cloudflare — depends on model
47
+ [/cloudflare/i, 120_000],
48
+ // Cohere
49
+ [/command-r/i, 120_000],
50
+ // Zen / NVIDIA
51
+ [/zen|nvidia/i, 120_000],
52
+ ];
53
+ /** Default context limit when model is unknown */
54
+ const DEFAULT_CONTEXT_LIMIT = 120_000;
55
+ /** Reserve this many tokens for the output response */
56
+ const OUTPUT_TOKEN_RESERVATION = 8_000;
57
+ /**
58
+ * Resolve the *usable input* context limit for a model identifier.
59
+ * The result is the model's full window minus {@link OUTPUT_TOKEN_RESERVATION}
60
+ * so callers that only care about how much room they have left for input
61
+ * tokens (predictive gate, budget planner) can use the answer directly.
62
+ */
63
+ export function resolveModelContextLimit(model) {
64
+ if (!model)
65
+ return DEFAULT_CONTEXT_LIMIT - OUTPUT_TOKEN_RESERVATION;
66
+ for (const [pattern, limit] of MODEL_CONTEXT_LIMITS) {
67
+ if (pattern.test(model))
68
+ return limit - OUTPUT_TOKEN_RESERVATION;
69
+ }
70
+ return DEFAULT_CONTEXT_LIMIT - OUTPUT_TOKEN_RESERVATION;
71
+ }
72
+ /** Maximum token budget for conversation history (usable input space) */
73
+ const DEFAULT_MAX_TOKEN_BUDGET = 100_000;
74
+ /** Minimum number of individual messages to keep (2 turn-pairs = 4 messages). */
75
+ const MIN_MESSAGES_TO_KEEP = 4;
76
+ /** Number of recent turn-pairs to preserve verbatim during compaction */
77
+ const TAIL_TURNS = 2;
78
+ /** Maximum characters for tool output in old messages before truncation */
79
+ const TOOL_OUTPUT_MAX_CHARS = 2_000;
80
+ /** Structured summary template (inspired by OpenCode) */
81
+ const SUMMARY_TEMPLATE = `Output exactly the Markdown structure shown below. Keep every section even when empty.
82
+
83
+ ## Goal
84
+ - [single-sentence task summary]
85
+
86
+ ## Constraints & Preferences
87
+ - [user constraints, preferences, specs, or "(none)"]
88
+
89
+ ## Progress
90
+ ### Done
91
+ - [completed work or "(none)"]
92
+
93
+ ### In Progress
94
+ - [current work or "(none)"]
95
+
96
+ ## Key Decisions
97
+ - [decision and why, or "(none)"]
98
+
99
+ ## Next Steps
100
+ - [ordered next actions or "(none)"]
101
+
102
+ ## Critical Context
103
+ - [important technical facts, errors, open questions, or "(none)"]
104
+
105
+ ## Relevant Files
106
+ - [file or directory path: why it matters, or "(none)"]
107
+
108
+ Rules:
109
+ - Use terse bullets, not prose paragraphs.
110
+ - Preserve exact file paths, commands, error strings, and identifiers.
111
+ - Do not mention the summary process or that context was compacted.`;
112
+ // ---------------------------------------------------------------------------
113
+ // ConversationManager
114
+ // ---------------------------------------------------------------------------
115
+ export class ConversationManager {
116
+ history = [];
117
+ maxTokenBudget;
118
+ summary = '';
119
+ contextLimit = DEFAULT_CONTEXT_LIMIT;
120
+ _lastCompactionInfo = null;
121
+ /**
122
+ * When set (>0), `getTotalTokens()` returns this value instead of
123
+ * summing the history. Used by `--resume` so the restored session
124
+ * shows the same token count the user saw at save time.
125
+ */
126
+ tokenOverride = 0;
127
+ constructor(maxTokenBudget = DEFAULT_MAX_TOKEN_BUDGET) {
128
+ this.maxTokenBudget = maxTokenBudget;
129
+ }
130
+ // ---------------------------------------------------------------------------
131
+ // Model-aware context limits
132
+ // ---------------------------------------------------------------------------
133
+ /**
134
+ * Auto-configure the context budget based on the model being used.
135
+ * Call this whenever the model changes.
136
+ */
137
+ setContextLimit(model) {
138
+ for (const [pattern, limit] of MODEL_CONTEXT_LIMITS) {
139
+ if (pattern.test(model)) {
140
+ this.contextLimit = limit - OUTPUT_TOKEN_RESERVATION;
141
+ this.maxTokenBudget = Math.min(this.maxTokenBudget, this.contextLimit);
142
+ return;
143
+ }
144
+ }
145
+ this.contextLimit = DEFAULT_CONTEXT_LIMIT - OUTPUT_TOKEN_RESERVATION;
146
+ }
147
+ getContextLimit() {
148
+ return this.contextLimit;
149
+ }
150
+ /** Returns info about the last compaction (for UX display). */
151
+ getLastCompactionInfo() {
152
+ const info = this._lastCompactionInfo;
153
+ this._lastCompactionInfo = null;
154
+ return info;
155
+ }
156
+ // ---------------------------------------------------------------------------
157
+ // Token estimation
158
+ // ---------------------------------------------------------------------------
159
+ /**
160
+ * Real BPE token count for a piece of text. Uses the OpenAI cl100k
161
+ * encoding by default (good proxy for llama-3, mistral, qwen,
162
+ * deepseek, gemini etc. that the FreeLLMAPI proxy fronts). Pass the
163
+ * model name for an encoder-tuned count.
164
+ */
165
+ estimateTokens(text, model) {
166
+ return countTokens(text, model);
167
+ }
168
+ /**
169
+ * Estimate tokens consumed by a single message, accounting for both its
170
+ * `content` and any attached `tool_calls`.
171
+ */
172
+ estimateMessageTokens(message) {
173
+ return countMessagesTokens([message]);
174
+ }
175
+ /**
176
+ * Calculate the total estimated token count across the entire history.
177
+ */
178
+ getTotalTokens() {
179
+ if (this.tokenOverride > 0)
180
+ return this.tokenOverride;
181
+ return this.history.reduce((sum, msg) => sum + this.estimateMessageTokens(msg), 0);
182
+ }
183
+ /**
184
+ * Restore the conversation from a previously-saved snapshot. Replaces
185
+ * the entire history, summary, and token override atomically. The
186
+ * `tokens` argument is the value recorded at save time; subsequent
187
+ * reads of `getTotalTokens()` will prefer this override so the
188
+ * resumed session shows the same context-usage meter the user saw
189
+ * when they saved.
190
+ */
191
+ restoreFromSnapshot(messages, summary, tokens) {
192
+ this.history = [...messages];
193
+ this.summary = summary;
194
+ this.tokenOverride = Math.max(0, tokens);
195
+ }
196
+ /**
197
+ * Estimate the total token count for the NEXT LLM request.
198
+ * This is what actually matters for context overflow detection.
199
+ */
200
+ estimateNextRequestTokens(systemPrompt, userMessage) {
201
+ const systemTokens = this.estimateTokens(systemPrompt);
202
+ const historyTokens = this.getTotalTokens();
203
+ const userTokens = this.estimateTokens(userMessage);
204
+ const summaryTokens = this.summary ? this.estimateTokens(this.summary) : 0;
205
+ return systemTokens + summaryTokens + historyTokens + userTokens;
206
+ }
207
+ // ---------------------------------------------------------------------------
208
+ // Budget enforcement (Pillar 4)
209
+ // ---------------------------------------------------------------------------
210
+ /**
211
+ * Proactively trim the conversation to fit a token budget, using the
212
+ * tiered {@link ContextBudgetEnforcer} strategy. The `model` argument
213
+ * is forwarded to the BPE encoder so the counts are tuned to the
214
+ * downstream provider.
215
+ *
216
+ * If the enforcer cannot fit the budget even after pruning tool
217
+ * outputs, dropping old turns, and truncating tool arguments, it
218
+ * sets `report.markForCompaction = true`; the caller should then
219
+ * invoke {@link ConversationManager.compact} to summarise the
220
+ * oldest turns via an LLM.
221
+ *
222
+ * Returns a report describing the actions taken and the new total
223
+ * token count.
224
+ */
225
+ enforceBudget(maxTokens, model) {
226
+ const enforcer = new ContextBudgetEnforcer(model);
227
+ const { messages, report } = enforcer.enforce(this.history, { maxTokens, model });
228
+ if (report.actions[0] !== 'none') {
229
+ this.history = messages;
230
+ }
231
+ return {
232
+ trimmed: report.actions[0] !== 'none',
233
+ report: {
234
+ tokensBefore: report.tokensBefore,
235
+ tokensAfter: report.tokensAfter,
236
+ actions: report.actions,
237
+ markForCompaction: report.markForCompaction,
238
+ withinBudget: report.withinBudget,
239
+ },
240
+ };
241
+ }
242
+ // ---------------------------------------------------------------------------
243
+ // Mutation helpers
244
+ // ---------------------------------------------------------------------------
245
+ /**
246
+ * Add a user message and the corresponding assistant response as a single
247
+ * conversational turn, then prune if the budget is exceeded.
248
+ */
249
+ addTurn(userMessage, assistantResponse) {
250
+ this.history.push({ role: 'user', content: userMessage }, { role: 'assistant', content: assistantResponse });
251
+ this.pruneToFitBudget();
252
+ }
253
+ /**
254
+ * Add a raw {@link ChatMessage} (useful for tool-call results or other
255
+ * non-standard messages), then prune if the budget is exceeded.
256
+ */
257
+ addMessage(message) {
258
+ this.history.push(message);
259
+ this.pruneToFitBudget();
260
+ }
261
+ // ---------------------------------------------------------------------------
262
+ // Accessors
263
+ // ---------------------------------------------------------------------------
264
+ /**
265
+ * Return all messages for injection into the LLM context.
266
+ * If a compacted summary exists, it is prepended as the first message.
267
+ */
268
+ getMessages() {
269
+ const msgs = [];
270
+ if (this.summary) {
271
+ msgs.push({
272
+ role: 'assistant',
273
+ content: `[Previous conversation context]\n\n${this.summary}`,
274
+ });
275
+ }
276
+ msgs.push(...this.history);
277
+ return msgs;
278
+ }
279
+ /** Number of complete user/assistant turn pairs in the history. */
280
+ getTurnCount() {
281
+ return Math.floor(this.history.length / 2);
282
+ }
283
+ /** Total number of messages in history (excluding summary). */
284
+ getMessageCount() {
285
+ return this.history.length;
286
+ }
287
+ // ---------------------------------------------------------------------------
288
+ // Pruning
289
+ // ---------------------------------------------------------------------------
290
+ /**
291
+ * Remove the oldest user/assistant pairs until the total token estimate
292
+ * fits within {@link maxTokenBudget}.
293
+ */
294
+ pruneToFitBudget() {
295
+ while (this.getTotalTokens() > this.maxTokenBudget &&
296
+ this.history.length > MIN_MESSAGES_TO_KEEP) {
297
+ let nextUserIndex = -1;
298
+ for (let i = 1; i < this.history.length; i++) {
299
+ if (this.history[i].role === 'user') {
300
+ nextUserIndex = i;
301
+ break;
302
+ }
303
+ }
304
+ if (nextUserIndex !== -1 && (this.history.length - nextUserIndex) >= MIN_MESSAGES_TO_KEEP) {
305
+ this.history.splice(0, nextUserIndex);
306
+ }
307
+ else {
308
+ break;
309
+ }
310
+ }
311
+ }
312
+ /**
313
+ * Prune large tool outputs in older messages to free context space.
314
+ * Keeps the last TAIL_TURNS * 2 messages untouched.
315
+ */
316
+ pruneToolOutputs() {
317
+ let freedChars = 0;
318
+ const keepFrom = Math.max(0, this.history.length - TAIL_TURNS * 2);
319
+ for (let i = 0; i < keepFrom; i++) {
320
+ const msg = this.history[i];
321
+ if (msg.role === 'tool' && msg.content && msg.content.length > TOOL_OUTPUT_MAX_CHARS) {
322
+ const original = msg.content.length;
323
+ msg.content = msg.content.slice(0, TOOL_OUTPUT_MAX_CHARS) +
324
+ `\n\n... [truncated: ${original} → ${TOOL_OUTPUT_MAX_CHARS} chars to save context]`;
325
+ freedChars += original - TOOL_OUTPUT_MAX_CHARS;
326
+ }
327
+ // Also truncate large assistant tool_calls arguments
328
+ if (msg.role === 'assistant' && msg.tool_calls) {
329
+ for (const tc of msg.tool_calls) {
330
+ if (tc.function?.arguments && tc.function.arguments.length > TOOL_OUTPUT_MAX_CHARS * 2) {
331
+ const original = tc.function.arguments.length;
332
+ tc.function.arguments = tc.function.arguments.slice(0, TOOL_OUTPUT_MAX_CHARS) + '...}';
333
+ freedChars += original - TOOL_OUTPUT_MAX_CHARS;
334
+ }
335
+ }
336
+ }
337
+ }
338
+ return Math.ceil(freedChars / 4); // Return estimated tokens freed
339
+ }
340
+ // ---------------------------------------------------------------------------
341
+ // Lifecycle
342
+ // ---------------------------------------------------------------------------
343
+ /** Clear all conversation history and summary. */
344
+ clear() {
345
+ this.history = [];
346
+ this.summary = '';
347
+ }
348
+ // ---------------------------------------------------------------------------
349
+ // Serialisation — session persistence / recovery
350
+ // ---------------------------------------------------------------------------
351
+ /** Export a deep copy of the raw history for external persistence. */
352
+ exportHistory() {
353
+ return this.history.map((msg) => ({ ...msg }));
354
+ }
355
+ /**
356
+ * Import a previously-exported history, replacing the current one.
357
+ * Automatically prunes to fit the current token budget after import.
358
+ */
359
+ importHistory(messages) {
360
+ this.history = messages.map((msg) => ({ ...msg }));
361
+ this.pruneToFitBudget();
362
+ }
363
+ // ---------------------------------------------------------------------------
364
+ // Compaction & Summarization
365
+ // ---------------------------------------------------------------------------
366
+ getSummary() {
367
+ return this.summary;
368
+ }
369
+ setSummary(summary) {
370
+ this.summary = summary;
371
+ }
372
+ /**
373
+ * Check if the conversation should be compacted before the next request.
374
+ * Uses the estimated next request size vs the model's context limit.
375
+ * If systemPrompt/userMessage are not provided, uses a simpler history-only check.
376
+ */
377
+ shouldCompact(systemPrompt, userMessage) {
378
+ if (this.history.length <= MIN_MESSAGES_TO_KEEP)
379
+ return false;
380
+ if (systemPrompt && userMessage) {
381
+ // Predictive check: will the next request overflow the context window?
382
+ const estimated = this.estimateNextRequestTokens(systemPrompt, userMessage);
383
+ // Trigger compaction at 75% of context limit to leave headroom
384
+ return estimated > this.contextLimit * 0.75;
385
+ }
386
+ // Fallback: simple history-based check
387
+ return this.getTotalTokens() > this.maxTokenBudget * 0.7;
388
+ }
389
+ /**
390
+ * Compact the conversation using a structured summary.
391
+ * - Preserves the last TAIL_TURNS turn-pairs verbatim
392
+ * - Summarizes everything else using the SUMMARY_TEMPLATE
393
+ * - Prunes old tool outputs before summarizing
394
+ *
395
+ * Returns true if compaction succeeded.
396
+ */
397
+ async compact(client, model) {
398
+ if (this.history.length <= MIN_MESSAGES_TO_KEEP) {
399
+ return false;
400
+ }
401
+ const messagesBefore = this.history.length;
402
+ const tokensBefore = this.getTotalTokens();
403
+ // Step 1: Prune tool outputs to free immediate space
404
+ this.pruneToolOutputs();
405
+ // Step 2: Identify what to compact vs preserve
406
+ // Preserve: last TAIL_TURNS turn-pairs (user+assistant = 2 messages each)
407
+ const tailMessages = TAIL_TURNS * 2;
408
+ const keepCount = Math.min(tailMessages, this.history.length);
409
+ const toCompact = this.history.slice(0, this.history.length - keepCount);
410
+ const preserved = this.history.slice(this.history.length - keepCount);
411
+ if (toCompact.length === 0) {
412
+ return false;
413
+ }
414
+ // Step 3: Format history for summarization
415
+ const formattedHistory = toCompact
416
+ .map((msg) => {
417
+ const role = msg.role.toUpperCase();
418
+ if (msg.role === 'tool') {
419
+ const content = (msg.content ?? '').slice(0, 500);
420
+ return `TOOL_RESULT (${msg.tool_call_id ?? 'unknown'}): ${content}`;
421
+ }
422
+ if (msg.tool_calls && msg.tool_calls.length > 0) {
423
+ const tools = msg.tool_calls.map(tc => ` → ${tc.function?.name}(${(tc.function?.arguments ?? '').slice(0, 100)}...)`).join('\n');
424
+ return `${role}: ${msg.content || '(tool calls)'}\n${tools}`;
425
+ }
426
+ return `${role}: ${msg.content || '(empty)'}`;
427
+ })
428
+ .join('\n\n');
429
+ // Step 4: Build compaction prompt
430
+ const previousSummarySection = this.summary
431
+ ? `Here is the previous summary to UPDATE (preserve still-true details, remove stale details, merge new facts):\n<previous-summary>\n${this.summary}\n</previous-summary>\n\n`
432
+ : '';
433
+ const compactionPrompt = `${previousSummarySection}Create a comprehensive summary from the conversation history above.\n\n${SUMMARY_TEMPLATE}`;
434
+ try {
435
+ const response = await client.chat([
436
+ {
437
+ role: 'system',
438
+ content: 'You are a technical context summarization engine. You produce structured summaries that preserve every critical fact needed to continue a coding conversation.',
439
+ },
440
+ {
441
+ role: 'user',
442
+ content: `Here is the conversation history to summarize:\n\n${formattedHistory}\n\n${compactionPrompt}`,
443
+ },
444
+ ], model, { max_tokens: 4000, agent_task_type: 'investigation', required_capabilities: ['fast'] });
445
+ this.summary = response.content?.trim() || '';
446
+ // Replace history with only the preserved tail messages
447
+ this.history = [...preserved];
448
+ const tokensAfter = this.getTotalTokens() + this.estimateTokens(this.summary);
449
+ this._lastCompactionInfo = {
450
+ messagesBefore,
451
+ tokensFreed: Math.max(0, tokensBefore - tokensAfter),
452
+ };
453
+ return true;
454
+ }
455
+ catch (error) {
456
+ console.warn(`[Context Compaction] Failed to compact: ${error instanceof Error ? error.message : String(error)}`);
457
+ return false;
458
+ }
459
+ }
460
+ /**
461
+ * Check if an error indicates context window overflow from the provider.
462
+ * If true, the caller should auto-compact and retry.
463
+ */
464
+ static isContextOverflowError(error) {
465
+ const msg = (error?.message ?? '').toLowerCase();
466
+ return msg.includes('too many tokens')
467
+ || msg.includes('context length')
468
+ || msg.includes('context_length_exceeded')
469
+ || msg.includes('maximum context')
470
+ || msg.includes('token limit')
471
+ || msg.includes('input too long')
472
+ || msg.includes('request too large')
473
+ || (msg.includes('413') && (msg.includes('token') || msg.includes('too large')))
474
+ || (msg.includes('400') && msg.includes('token'));
475
+ }
476
+ }
477
+ import fs from 'node:fs';
478
+ import path from 'node:path';
479
+ import crypto from 'node:crypto';
480
+ import { getConfigDir } from '../config.js';
481
+ export class SessionManager {
482
+ static getSessionsDir() {
483
+ const dir = path.join(getConfigDir(), 'sessions');
484
+ if (!fs.existsSync(dir)) {
485
+ fs.mkdirSync(dir, { recursive: true });
486
+ }
487
+ return dir;
488
+ }
489
+ static saveSession(conversation, model, modifiedFiles, tokenUsage, sessionId) {
490
+ const id = sessionId || crypto.randomUUID();
491
+ const dir = this.getSessionsDir();
492
+ const filePath = path.join(dir, `session_${id}.json`);
493
+ const data = {
494
+ sessionId: id,
495
+ timestamp: new Date().toISOString(),
496
+ model,
497
+ history: conversation.exportHistory(),
498
+ summary: conversation.getSummary(),
499
+ modifiedFiles,
500
+ tokenUsage,
501
+ };
502
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), { encoding: 'utf-8', mode: 0o600 });
503
+ return id;
504
+ }
505
+ static listSessions() {
506
+ const dir = this.getSessionsDir();
507
+ const results = [];
508
+ try {
509
+ const files = fs.readdirSync(dir);
510
+ for (const file of files) {
511
+ if (file.startsWith('session_') && file.endsWith('.json')) {
512
+ try {
513
+ const raw = fs.readFileSync(path.join(dir, file), 'utf-8');
514
+ const data = JSON.parse(raw);
515
+ results.push({
516
+ sessionId: data.sessionId,
517
+ timestamp: data.timestamp,
518
+ model: data.model,
519
+ messageCount: data.history.length,
520
+ summary: data.summary,
521
+ totalTokens: data.tokenUsage?.total_tokens || 0,
522
+ });
523
+ }
524
+ catch (err) {
525
+ console.warn(`[Debug Warning] Failed to parse session file ${file}:`, err.message || err);
526
+ }
527
+ }
528
+ }
529
+ }
530
+ catch (err) {
531
+ if (err.code !== 'ENOENT') {
532
+ console.warn(`[Debug Warning] Failed to list sessions in ${dir}:`, err.message || err);
533
+ }
534
+ }
535
+ return results.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
536
+ }
537
+ static loadSession(id) {
538
+ const dir = this.getSessionsDir();
539
+ const filePath = path.join(dir, `session_${id}.json`);
540
+ if (!fs.existsSync(filePath)) {
541
+ throw new Error(`Session file not found for ID: ${id}`);
542
+ }
543
+ const raw = fs.readFileSync(filePath, 'utf-8');
544
+ return JSON.parse(raw);
545
+ }
546
+ }
547
+ //# sourceMappingURL=conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../src/agent/conversation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ export type HookEvent = 'PreToolUse' | 'PostToolUse';
2
+ export type HookDecision = 'allow' | 'deny' | 'modify';
3
+ export interface HookPayload {
4
+ event: HookEvent;
5
+ tool: string;
6
+ args: Record<string, unknown>;
7
+ sessionId: string;
8
+ /** Cwd at the time the hook fired. */
9
+ cwd: string;
10
+ }
11
+ export interface HookCommandResult {
12
+ decision: HookDecision;
13
+ reason?: string;
14
+ modifiedArgs?: Record<string, unknown>;
15
+ }
16
+ export interface HookSpec {
17
+ /** Stable identifier for the hook (used in telemetry). */
18
+ id: string;
19
+ /** Event this hook listens to. */
20
+ event: HookEvent;
21
+ /** Command to run, including args. */
22
+ command: string;
23
+ /** Args passed to the command. */
24
+ args?: string[];
25
+ /** When false, the hook is skipped. Default: true. */
26
+ enabled?: boolean;
27
+ /** Per-hook timeout in ms. Default: 5000. */
28
+ timeoutMs?: number;
29
+ }
30
+ export interface HooksFile {
31
+ version: 1;
32
+ hooks: HookSpec[];
33
+ }
34
+ export interface HookExecutionResult {
35
+ fired: boolean;
36
+ decision: HookDecision;
37
+ reason?: string;
38
+ modifiedArgs?: Record<string, unknown>;
39
+ durationMs: number;
40
+ hookId: string | null;
41
+ }
42
+ /** Read `.fixo/hooks.json` from cwd. Returns null if absent. */
43
+ export declare function loadHooksFile(cwd: string): HooksFile | null;
44
+ /** Save the hooks file. Used by /hooks slash command. */
45
+ export declare function saveHooksFile(cwd: string, file: HooksFile): {
46
+ ok: boolean;
47
+ error?: string;
48
+ };
49
+ /** Hooks for a given event. */
50
+ export declare function getHooksForEvent(cwd: string, event: HookEvent): HookSpec[];
51
+ /**
52
+ * Fire all hooks for an event, in declaration order. The
53
+ * first non-`allow` decision wins. Returns the aggregated
54
+ * result.
55
+ */
56
+ export declare function fireHooks(cwd: string, event: HookEvent, payload: Omit<HookPayload, 'event' | 'cwd'>): HookExecutionResult;
57
+ /**
58
+ * Apply a pre-hook's `modify` decision: re-validate
59
+ * `modifiedArgs` through `WorkspaceGuard.resolve()` to
60
+ * prevent an attacker-controlled hook from writing outside
61
+ * the workspace. The check is a *best-effort* scan: any
62
+ * `path`/`filePath`/`cwd` field in the args must resolve
63
+ * inside `cwd` (relative paths are fine).
64
+ */
65
+ export declare function applyModifiedArgs(cwd: string, original: Record<string, unknown>, modified: Record<string, unknown>): {
66
+ ok: boolean;
67
+ args: Record<string, unknown>;
68
+ reason?: string;
69
+ };
70
+ /** Get the hooks file path for a cwd (test-only introspection). */
71
+ export declare function getHooksPath(cwd: string): string;
72
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/agent/hooks.ts"],"names":[],"mappings":"AAoCA,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,aAAa,CAAC;AAErD,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,QAAQ;IACvB,0DAA0D;IAC1D,EAAE,EAAE,MAAM,CAAC;IACX,kCAAkC;IAClC,KAAK,EAAE,SAAS,CAAC;IACjB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAMD,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAU3D;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAS3F;AAED,+BAA+B;AAC/B,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,QAAQ,EAAE,CAI1E;AAsDD;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,KAAK,CAAC,GAC1C,mBAAmB,CAyCrB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBjE;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD"}