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,275 @@
1
+ /**
2
+ * syntax-fallback.ts — Pure-JS brace/paren/bracket balance check
3
+ * used as a fallback when no real language server is on the PATH.
4
+ *
5
+ * Why this exists
6
+ * ---------------
7
+ * The LspPreSaveGate calls into `LspManager` to ask the local
8
+ * language server for diagnostics. On a freshly-installed system
9
+ * there is no `tsserver` / `gopls` / `rust-analyzer` on the PATH —
10
+ * the user has a working FixO CLI but no editor infrastructure.
11
+ * In that case the pre-save gate would silently fall through and
12
+ * commit syntactically broken edits.
13
+ *
14
+ * This module provides a *very* cheap structural sanity check
15
+ * (brace/paren/bracket/quote balance) that runs in microseconds
16
+ * and catches the most common form of "LLM forgot a closing
17
+ * brace" corruption. It is intentionally not a real parser — it
18
+ * is a smoke detector, not a smoke alarm. If the syntax check
19
+ * reports `ok`, the real LSP may still surface semantic errors;
20
+ * if it reports `unbalanced`, the file is almost certainly
21
+ * broken and we should refuse the write.
22
+ *
23
+ * The check is env-gated behind `FIXO_LSP_FALLBACK=syntax-only`
24
+ * so a developer who *does* have a language server is never
25
+ * bothered by it.
26
+ */
27
+ import fs from 'node:fs';
28
+ import path from 'node:path';
29
+ /**
30
+ * Run the structural sanity check on a source string. Pure,
31
+ * sync, and allocation-light. The output is stable so tests can
32
+ * pin the verdict exactly.
33
+ */
34
+ export function syntaxHealthCheck(source) {
35
+ const stack = [];
36
+ const lineStarts = [0];
37
+ for (let i = 0; i < source.length; i++) {
38
+ if (source.charCodeAt(i) === 10)
39
+ lineStarts.push(i + 1);
40
+ }
41
+ let inSingle = false;
42
+ let inDouble = false;
43
+ let inTemplate = false;
44
+ let inLineComment = false;
45
+ let inBlockComment = false;
46
+ let blockCommentStartLine = 1;
47
+ let singleStartLine = 0;
48
+ let doubleStartLine = 0;
49
+ let templateStartLine = 0;
50
+ let prevCh = '';
51
+ for (let i = 0; i < source.length; i++) {
52
+ const ch = source[i];
53
+ const code = source.charCodeAt(i);
54
+ const nextCh = i + 1 < source.length ? source[i + 1] : '';
55
+ const line = lineNumberAt(lineStarts, i);
56
+ if (inLineComment) {
57
+ if (code === 10)
58
+ inLineComment = false;
59
+ prevCh = ch;
60
+ continue;
61
+ }
62
+ if (inBlockComment) {
63
+ if (prevCh === '*' && ch === '/') {
64
+ inBlockComment = false;
65
+ }
66
+ prevCh = ch;
67
+ continue;
68
+ }
69
+ if (inSingle) {
70
+ if (ch === '\\') {
71
+ // Skip the next char. (No need to handle surrogate pairs
72
+ // separately — `\\u{1F600}` etc. still consume 2 source
73
+ // chars; the skip-i+1 below handles it.)
74
+ i++;
75
+ prevCh = '';
76
+ continue;
77
+ }
78
+ if (ch === "'" && prevCh !== '\\') {
79
+ inSingle = false;
80
+ }
81
+ else if (code === 10) {
82
+ return { state: 'unterminated-string', line: singleStartLine };
83
+ }
84
+ prevCh = ch;
85
+ continue;
86
+ }
87
+ if (inDouble) {
88
+ if (ch === '\\') {
89
+ i++;
90
+ prevCh = '';
91
+ continue;
92
+ }
93
+ if (ch === '"' && prevCh !== '\\') {
94
+ inDouble = false;
95
+ }
96
+ else if (code === 10) {
97
+ return { state: 'unterminated-string', line: doubleStartLine };
98
+ }
99
+ prevCh = ch;
100
+ continue;
101
+ }
102
+ if (inTemplate) {
103
+ if (ch === '\\') {
104
+ i++;
105
+ prevCh = '';
106
+ continue;
107
+ }
108
+ if (ch === '`') {
109
+ inTemplate = false;
110
+ }
111
+ else if (code === 10) {
112
+ return { state: 'unterminated-string', line: templateStartLine };
113
+ }
114
+ prevCh = ch;
115
+ continue;
116
+ }
117
+ // Not in any string/comment — check for new states.
118
+ if (ch === '/' && nextCh === '/') {
119
+ inLineComment = true;
120
+ prevCh = ch;
121
+ i++;
122
+ continue;
123
+ }
124
+ if (ch === '/' && nextCh === '*') {
125
+ inBlockComment = true;
126
+ blockCommentStartLine = line;
127
+ prevCh = ch;
128
+ i++;
129
+ continue;
130
+ }
131
+ if (ch === "'") {
132
+ inSingle = true;
133
+ singleStartLine = line;
134
+ prevCh = ch;
135
+ continue;
136
+ }
137
+ if (ch === '"') {
138
+ inDouble = true;
139
+ doubleStartLine = line;
140
+ prevCh = ch;
141
+ continue;
142
+ }
143
+ if (ch === '`') {
144
+ inTemplate = true;
145
+ templateStartLine = line;
146
+ prevCh = ch;
147
+ continue;
148
+ }
149
+ if (ch === '{' || ch === '(' || ch === '[') {
150
+ stack.push({ ch: ch, line });
151
+ }
152
+ else if (ch === '}' || ch === ')' || ch === ']') {
153
+ const expected = ch === '}' ? '{' : ch === ')' ? '(' : '[';
154
+ const top = stack.pop();
155
+ if (!top || top.ch !== expected) {
156
+ // The first missing closer tells us the first unclosed
157
+ // opener, which is what we report. If the stack is empty
158
+ // we still report a synthetic 'unbalanced' so the caller
159
+ // sees a verdict.
160
+ if (top) {
161
+ return { state: 'unbalanced', opener: top.ch, line: top.line };
162
+ }
163
+ return { state: 'unbalanced', opener: expected, line };
164
+ }
165
+ }
166
+ prevCh = ch;
167
+ }
168
+ if (inBlockComment) {
169
+ return { state: 'unterminated-comment', line: blockCommentStartLine };
170
+ }
171
+ if (stack.length > 0) {
172
+ const top = stack[stack.length - 1];
173
+ return { state: 'unbalanced', opener: top.ch, line: top.line };
174
+ }
175
+ return { state: 'ok' };
176
+ }
177
+ function lineNumberAt(lineStarts, index) {
178
+ // Binary search would be O(log n) but a linear scan is fine for
179
+ // files up to ~10_000 lines, and the inlined version lets V8
180
+ // keep both arrays hot in the same cache line.
181
+ let line = 1;
182
+ for (let i = 0; i < lineStarts.length; i++) {
183
+ if (lineStarts[i] > index)
184
+ break;
185
+ line = i + 1;
186
+ }
187
+ return line;
188
+ }
189
+ /**
190
+ * Format a {@link SyntaxHealthVerdict} as a single-line summary
191
+ * suitable for the LLM's `tool_result`.
192
+ */
193
+ export function formatSyntaxVerdict(verdict) {
194
+ switch (verdict.state) {
195
+ case 'ok':
196
+ return 'Syntax health check: OK (balanced).';
197
+ case 'unbalanced':
198
+ return `Syntax health check: unbalanced — '${verdict.opener}' opened on line ${verdict.line} has no matching closer.`;
199
+ case 'unterminated-string':
200
+ return `Syntax health check: unterminated string starting on line ${verdict.line}.`;
201
+ case 'unterminated-comment':
202
+ return `Syntax health check: unterminated block comment starting on line ${verdict.line}.`;
203
+ }
204
+ }
205
+ const COMMON_LANGUAGE_SERVERS = [
206
+ 'typescript-language-server',
207
+ 'tsserver',
208
+ 'vscode-langservers-extracted',
209
+ 'gopls',
210
+ 'rust-analyzer',
211
+ 'pyright',
212
+ 'pylsp',
213
+ 'clangd',
214
+ 'jdtls',
215
+ 'solargraph',
216
+ ];
217
+ /**
218
+ * Synchronous PATH check for common language servers. Returns a
219
+ * {@link LspSanityResult} the boot code can use to decide whether
220
+ * to warn the user. Pure — no side effects, no I/O beyond
221
+ * `which`-style PATH scanning.
222
+ *
223
+ * The check is intentionally permissive: a missing language server
224
+ * is a `reason` to warn, not a hard failure. The user can always
225
+ * install one later. The hard fail mode is when neither a
226
+ * language server nor `FIXO_LSP_FALLBACK=syntax-only` is present
227
+ * AND the user has configured `lspPreSave: 'block'` — in that
228
+ * case the pre-save gate would block all writes, which is a much
229
+ * worse experience than a boot-time warning.
230
+ */
231
+ export function checkLspSanity(env = process.env) {
232
+ const syntaxOnly = env.FIXO_LSP_FALLBACK === 'syntax-only';
233
+ const pathEntries = (env.PATH ?? '').split(path.delimiter).filter(Boolean);
234
+ // `execFileSync('which', ...)` would spawn a child process —
235
+ // expensive and unnecessary. PATH scan is enough: a binary on
236
+ // the PATH is in one of these directories.
237
+ const pathDirs = pathEntries;
238
+ const found = [];
239
+ for (const server of COMMON_LANGUAGE_SERVERS) {
240
+ for (const dir of pathDirs) {
241
+ if (!dir)
242
+ continue;
243
+ try {
244
+ if (fs.existsSync(path.join(dir, server))) {
245
+ found.push(server);
246
+ break;
247
+ }
248
+ }
249
+ catch {
250
+ // ignore
251
+ }
252
+ }
253
+ }
254
+ if (found.length > 0) {
255
+ return { ok: true, reason: '', checked: [...COMMON_LANGUAGE_SERVERS], found, syntaxOnly };
256
+ }
257
+ if (syntaxOnly) {
258
+ return {
259
+ ok: true,
260
+ reason: 'FIXO_LSP_FALLBACK=syntax-only; brace-balance check will run instead of a real LSP.',
261
+ checked: [...COMMON_LANGUAGE_SERVERS],
262
+ found: [],
263
+ syntaxOnly: true,
264
+ };
265
+ }
266
+ return {
267
+ ok: false,
268
+ reason: 'No common language server found on PATH. Pre-save diagnostics will be skipped. ' +
269
+ 'Install typescript-language-server / gopls / rust-analyzer or set FIXO_LSP_FALLBACK=syntax-only.',
270
+ checked: [...COMMON_LANGUAGE_SERVERS],
271
+ found: [],
272
+ syntaxOnly: false,
273
+ };
274
+ }
275
+ //# sourceMappingURL=syntax-fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-fallback.js","sourceRoot":"","sources":["../../src/lsp/syntax-fallback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface ModelOutcome {
2
+ model: string;
3
+ taskType: string;
4
+ success: boolean;
5
+ latencyMs: number;
6
+ toolCalls: number;
7
+ verificationPassed: boolean | null;
8
+ timestamp: string;
9
+ }
10
+ export declare function recordModelOutcome(cwd: string, outcome: Omit<ModelOutcome, 'timestamp'>): void;
11
+ export declare function summarizeModelOutcomes(cwd: string): string;
12
+ //# sourceMappingURL=model-outcomes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-outcomes.d.ts","sourceRoot":"","sources":["../src/model-outcomes.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,GAAG,IAAI,CAM9F;AAeD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmB1D"}
@@ -0,0 +1,46 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ const MAX_OUTCOMES = 100;
4
+ export function recordModelOutcome(cwd, outcome) {
5
+ const dir = path.join(cwd, '.fixo');
6
+ fs.mkdirSync(dir, { recursive: true });
7
+ const file = path.join(dir, 'model-outcomes.jsonl');
8
+ fs.appendFileSync(file, JSON.stringify({ ...outcome, timestamp: new Date().toISOString() }) + '\n', 'utf-8');
9
+ pruneOutcomes(file);
10
+ }
11
+ function pruneOutcomes(file) {
12
+ try {
13
+ const content = fs.readFileSync(file, 'utf-8');
14
+ const lines = content.split('\n').filter(Boolean);
15
+ if (lines.length <= MAX_OUTCOMES)
16
+ return;
17
+ fs.writeFileSync(file, lines.slice(lines.length - MAX_OUTCOMES).join('\n') + '\n', 'utf-8');
18
+ }
19
+ catch (error) {
20
+ if (process.env.DEBUG || process.env.VERBOSE || process.argv.includes('--verbose')) {
21
+ console.warn(`[Debug Warning] Failed to prune model outcomes from ${file}: ${error.message || error}`);
22
+ }
23
+ }
24
+ }
25
+ export function summarizeModelOutcomes(cwd) {
26
+ const file = path.join(cwd, '.fixo', 'model-outcomes.jsonl');
27
+ if (!fs.existsSync(file))
28
+ return 'No model outcomes recorded.';
29
+ const rows = fs.readFileSync(file, 'utf-8')
30
+ .split('\n')
31
+ .filter(Boolean)
32
+ .map(line => JSON.parse(line));
33
+ const byModel = new Map();
34
+ for (const row of rows) {
35
+ const entry = byModel.get(row.model) ?? { total: 0, success: 0, latency: 0, verified: 0 };
36
+ entry.total++;
37
+ if (row.success)
38
+ entry.success++;
39
+ if (row.verificationPassed)
40
+ entry.verified++;
41
+ entry.latency += row.latencyMs;
42
+ byModel.set(row.model, entry);
43
+ }
44
+ return Array.from(byModel.entries()).map(([model, entry]) => `${model}: ${entry.success}/${entry.total} success, ${entry.verified}/${entry.total} verified, avg ${(entry.latency / entry.total / 1000).toFixed(1)}s`).join('\n');
45
+ }
46
+ //# sourceMappingURL=model-outcomes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-outcomes.js","sourceRoot":"","sources":["../src/model-outcomes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Re-exported here so external callers (e.g. `SingleAgent`,
3
+ * telemetry sinks) can import the entire loop-trap surface from
4
+ * `src/planner.ts` without taking a hard dependency on the
5
+ * `src/runtime/` directory layout. The implementation lives in
6
+ * `src/runtime/loop-trap.ts`; this file is the public façade.
7
+ */
8
+ export { LoopTrapDetector, LoopTrapAbortedError, DEFAULT_LOOP_TRAP_PREFS, canonicaliseArgs, } from './runtime/loop-trap.js';
9
+ export type { LoopSnapshot, LoopTrapVerdict, LoopTrapLayer, LoopTrapPreferences, } from './runtime/loop-trap.js';
10
+ export interface SavedPlan {
11
+ task: string;
12
+ createdAt: string;
13
+ taskType: 'chat' | 'review' | 'mutation' | 'test-fix' | 'refactor' | 'investigation';
14
+ expectedFiles: string[];
15
+ verificationCommand: string | null;
16
+ stages: string[];
17
+ }
18
+ export declare function createStructuredPlan(task: string): SavedPlan;
19
+ export declare function validatePlan(plan: unknown): plan is SavedPlan;
20
+ export declare function savePlan(cwd: string, task: string): SavedPlan;
21
+ export declare function loadPlan(cwd: string): SavedPlan | null;
22
+ export declare function renderPlan(plan: SavedPlan): string;
23
+ export declare const TRIVIAL_PATTERNS: RegExp[];
24
+ export declare function isTrivialQuery(input: string): boolean;
25
+ export interface ComplexityClassification {
26
+ complexity: 'simple' | 'complex';
27
+ reason: string;
28
+ }
29
+ export declare function classifyComplexityHeuristic(task: string): ComplexityClassification;
30
+ import type { AgentClient } from './agent/agent-client.js';
31
+ export declare function classifyComplexityModel(task: string, model: string, client: AgentClient): Promise<ComplexityClassification>;
32
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../src/planner.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EACV,YAAY,EACZ,eAAe,EACf,aAAa,EACb,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,eAAe,CAAC;IACrF,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAUD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAsB5D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,SAAS,CAS7D;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAM7D;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAKtD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CASlD;AAID,eAAO,MAAM,gBAAgB,UAO5B,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAUrD;AAID,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,wBAAwB,CA8BlF;AAED,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,wBAAwB,CAAC,CA4CnC"}
@@ -0,0 +1,163 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /* ──────────────────────── Loop-Trap Detector Re-Exports ─────────────────── */
4
+ /**
5
+ * Re-exported here so external callers (e.g. `SingleAgent`,
6
+ * telemetry sinks) can import the entire loop-trap surface from
7
+ * `src/planner.ts` without taking a hard dependency on the
8
+ * `src/runtime/` directory layout. The implementation lives in
9
+ * `src/runtime/loop-trap.ts`; this file is the public façade.
10
+ */
11
+ export { LoopTrapDetector, LoopTrapAbortedError, DEFAULT_LOOP_TRAP_PREFS, canonicaliseArgs, } from './runtime/loop-trap.js';
12
+ const DEFAULT_STAGES = [
13
+ 'Understand: inspect indexed context and relevant files before editing.',
14
+ 'Plan: choose patch-based edits and expected verification command.',
15
+ 'Act: apply minimal workspace-scoped changes through guarded tools.',
16
+ 'Verify: run detected checks or configured checkCommand.',
17
+ 'Summarize: report changed files, checks, and residual risk.',
18
+ ];
19
+ export function createStructuredPlan(task) {
20
+ const lower = task.toLowerCase();
21
+ const taskType = lower.includes('review') ? 'review'
22
+ : lower.includes('test') || lower.includes('failing') ? 'test-fix'
23
+ : lower.includes('refactor') ? 'refactor'
24
+ : /explain|what|why|how|list|show/.test(lower) ? 'investigation'
25
+ : /^(hi|hello|hey|thanks|thank you|ok|bye)\b/.test(lower) ? 'chat'
26
+ : 'mutation';
27
+ const extensions = '(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|rb|php|css|scss|json|md|yml|yaml|toml|sh|bash|txt|html|vue|svelte)';
28
+ const expectedFiles = Array.from(task.matchAll(new RegExp(`\\b([\\w./-]+\\.${extensions})\\b`, 'gi'))).map(match => match[1]);
29
+ const verificationCommand = taskType === 'chat' || taskType === 'investigation' || taskType === 'review'
30
+ ? null
31
+ : 'auto-detect';
32
+ return {
33
+ task,
34
+ taskType,
35
+ expectedFiles,
36
+ verificationCommand,
37
+ createdAt: new Date().toISOString(),
38
+ stages: DEFAULT_STAGES,
39
+ };
40
+ }
41
+ export function validatePlan(plan) {
42
+ if (!plan || typeof plan !== 'object')
43
+ return false;
44
+ const p = plan;
45
+ return typeof p.task === 'string'
46
+ && typeof p.createdAt === 'string'
47
+ && ['chat', 'review', 'mutation', 'test-fix', 'refactor', 'investigation'].includes(p.taskType)
48
+ && Array.isArray(p.expectedFiles)
49
+ && (typeof p.verificationCommand === 'string' || p.verificationCommand === null)
50
+ && Array.isArray(p.stages);
51
+ }
52
+ export function savePlan(cwd, task) {
53
+ const plan = createStructuredPlan(task);
54
+ const dir = path.join(cwd, '.fixo');
55
+ fs.mkdirSync(dir, { recursive: true });
56
+ fs.writeFileSync(path.join(dir, 'last-plan.json'), JSON.stringify(plan, null, 2) + '\n', 'utf-8');
57
+ return plan;
58
+ }
59
+ export function loadPlan(cwd) {
60
+ const file = path.join(cwd, '.fixo', 'last-plan.json');
61
+ if (!fs.existsSync(file))
62
+ return null;
63
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
64
+ return validatePlan(parsed) ? parsed : null;
65
+ }
66
+ export function renderPlan(plan) {
67
+ return [
68
+ `Task: ${plan.task}`,
69
+ `Type: ${plan.taskType}`,
70
+ `Created: ${plan.createdAt}`,
71
+ `Expected files: ${plan.expectedFiles.join(', ') || '(none)'}`,
72
+ `Verification: ${plan.verificationCommand ?? '(none)'}`,
73
+ ...plan.stages.map((stage, index) => `${index + 1}. ${stage}`),
74
+ ].join('\n');
75
+ }
76
+ /* ──────────────────────── Trivial Query Detection ──────────────────────── */
77
+ export const TRIVIAL_PATTERNS = [
78
+ /^(hi|hey|hello|howdy|yo|sup|greetings|hola|namaste)/i,
79
+ /^(thanks|thank you|thx|ty|cheers)/i,
80
+ /^(what can you do|who are you|help me|how does this work)/i,
81
+ /^(good morning|good evening|good night|gm|gn)/i,
82
+ /^(ok|okay|sure|great|nice|cool|awesome|perfect|got it)/i,
83
+ /^(bye|goodbye|see you|later|exit|quit)/i,
84
+ ];
85
+ export function isTrivialQuery(input) {
86
+ const trimmed = input.trim();
87
+ if (trimmed.length < 3)
88
+ return true;
89
+ if (trimmed.length > 100)
90
+ return false; // Long inputs are usually tasks
91
+ for (const pattern of TRIVIAL_PATTERNS) {
92
+ if (pattern.test(trimmed))
93
+ return true;
94
+ }
95
+ return false;
96
+ }
97
+ export function classifyComplexityHeuristic(task) {
98
+ const trimmed = task.trim();
99
+ if (isTrivialQuery(trimmed)) {
100
+ return { complexity: 'simple', reason: 'Trivial chat query' };
101
+ }
102
+ const plan = createStructuredPlan(trimmed);
103
+ if (plan.taskType === 'chat' || plan.taskType === 'investigation' || plan.taskType === 'review') {
104
+ return { complexity: 'simple', reason: `Task type is ${plan.taskType}` };
105
+ }
106
+ // Check expected files.
107
+ if (plan.expectedFiles.length > 1) {
108
+ return { complexity: 'complex', reason: `Affects multiple files: ${plan.expectedFiles.join(', ')}` };
109
+ }
110
+ // Keywords that hint at complex operations
111
+ const complexKeywords = [
112
+ 'system-wide', 'across the codebase', 'all files', 'every file', 'refactor the entire',
113
+ 'multiple modules', 'architecture', 'orchestration', 'parallel', 'concurrent'
114
+ ];
115
+ const lower = trimmed.toLowerCase();
116
+ for (const kw of complexKeywords) {
117
+ if (lower.includes(kw)) {
118
+ return { complexity: 'complex', reason: `Contains complexity keyword: "${kw}"` };
119
+ }
120
+ }
121
+ // Simple edits / single file modifications are default simple
122
+ return { complexity: 'simple', reason: 'Single-file or narrow mutation scope' };
123
+ }
124
+ export async function classifyComplexityModel(task, model, client) {
125
+ const heuristic = classifyComplexityHeuristic(task);
126
+ // If heuristic is already complex, or if it is trivially simple, return it to save latency/tokens.
127
+ if (heuristic.complexity === 'complex' || heuristic.reason.startsWith('Trivial')) {
128
+ return heuristic;
129
+ }
130
+ const systemPrompt = `You are the FixO Complexity Classifier. Your job is to classify if a software engineering task is SIMPLE or COMPLEX.
131
+
132
+ CRITERIA:
133
+ - SIMPLE: Questions, explanations, conceptual reviews, single-file mutations (e.g. adding a field, fixing a minor bug, writing a test for a single file), or basic script creation.
134
+ - COMPLEX: Multi-file changes, large refactoring, integration changes across layers (e.g. modifying both frontend and backend, changing API contracts between multiple files), or anything requiring parallel execution of subtasks.
135
+
136
+ Output ONLY a JSON object:
137
+ {
138
+ "complexity": "simple" | "complex",
139
+ "reason": "short explanation of the decision"
140
+ }
141
+ NO markdown formatting, NO backticks, and NO conversational text.`;
142
+ try {
143
+ const response = await client.chat([
144
+ { role: 'system', content: systemPrompt },
145
+ { role: 'user', content: task }
146
+ ], model, { agent_task_type: 'investigation', required_capabilities: ['fast'] });
147
+ const content = response.content?.trim() || '';
148
+ // Clean JSON from potential markdown blocks
149
+ const jsonMatch = content.match(/\{[\s\S]*\}/);
150
+ const parsed = JSON.parse(jsonMatch ? jsonMatch[0] : content);
151
+ if (parsed && (parsed.complexity === 'simple' || parsed.complexity === 'complex')) {
152
+ return {
153
+ complexity: parsed.complexity,
154
+ reason: parsed.reason || 'Model classification'
155
+ };
156
+ }
157
+ }
158
+ catch (err) {
159
+ // Fallback to heuristic
160
+ }
161
+ return heuristic;
162
+ }
163
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../src/planner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface ProjectFacts {
2
+ packageManager: 'npm' | 'pnpm' | 'yarn' | 'unknown';
3
+ scripts: Record<string, string>;
4
+ testCommands: string[];
5
+ buildCommands: string[];
6
+ tsconfigs: string[];
7
+ updatedAt: string;
8
+ allowRules: {
9
+ commands: string[];
10
+ };
11
+ }
12
+ export declare function detectProjectFacts(cwd: string): ProjectFacts;
13
+ import { DatabaseSync } from 'node:sqlite';
14
+ export declare function getDb(cwd: string): DatabaseSync;
15
+ export declare function calculateTfidfSimilarity(query: string, documents: string[]): number[];
16
+ export declare function retrieveRelevantFacts(cwd: string, query: string, client?: any, limit?: number): Promise<string[]>;
17
+ export declare function appendSessionSummary(cwd: string, summary: string): void;
18
+ export declare function readSessionHistory(cwd: string): string[];
19
+ export declare function memoryDir(cwd: string): string;
20
+ export declare function ensureProjectMemory(cwd: string): ProjectFacts;
21
+ export declare function readMemory(cwd: string): string;
22
+ export declare function appendMemory(cwd: string, text: string): void;
23
+ export declare function readAllowRules(cwd: string): {
24
+ commands: string[];
25
+ };
26
+ export declare function allowCommand(cwd: string, command: string): void;
27
+ export declare function forgetMemory(cwd: string): void;
28
+ export declare function doctor(cwd: string): string;
29
+ //# sourceMappingURL=project-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-memory.d.ts","sourceRoot":"","sources":["../src/project-memory.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CA8B5D;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAM3C,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAiE/C;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA4ErF;AAgBD,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,GAAG,EACZ,KAAK,SAAI,GACR,OAAO,CAAC,MAAM,EAAE,CAAC,CAmEnB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAIvE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAQ7D;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQ9C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAK5D;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAYlE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAM/D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAG9C;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmB1C"}