@vibe-lang/runtime 0.2.5

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 (250) hide show
  1. package/package.json +46 -0
  2. package/src/ast/index.ts +375 -0
  3. package/src/ast.ts +2 -0
  4. package/src/debug/advanced-features.ts +482 -0
  5. package/src/debug/bun-inspector.ts +424 -0
  6. package/src/debug/handoff-manager.ts +283 -0
  7. package/src/debug/index.ts +150 -0
  8. package/src/debug/runner.ts +365 -0
  9. package/src/debug/server.ts +565 -0
  10. package/src/debug/stack-merger.ts +267 -0
  11. package/src/debug/state.ts +581 -0
  12. package/src/debug/test/advanced-features.test.ts +300 -0
  13. package/src/debug/test/e2e.test.ts +218 -0
  14. package/src/debug/test/handoff-manager.test.ts +256 -0
  15. package/src/debug/test/runner.test.ts +256 -0
  16. package/src/debug/test/stack-merger.test.ts +163 -0
  17. package/src/debug/test/state.test.ts +400 -0
  18. package/src/debug/test/ts-debug-integration.test.ts +374 -0
  19. package/src/debug/test/ts-import-tracker.test.ts +125 -0
  20. package/src/debug/test/ts-source-map.test.ts +169 -0
  21. package/src/debug/ts-import-tracker.ts +151 -0
  22. package/src/debug/ts-source-map.ts +171 -0
  23. package/src/errors/index.ts +124 -0
  24. package/src/index.ts +358 -0
  25. package/src/lexer/index.ts +348 -0
  26. package/src/lexer.ts +2 -0
  27. package/src/parser/index.ts +792 -0
  28. package/src/parser/parse.ts +45 -0
  29. package/src/parser/test/async.test.ts +248 -0
  30. package/src/parser/test/destructuring.test.ts +167 -0
  31. package/src/parser/test/do-expression.test.ts +486 -0
  32. package/src/parser/test/errors/do-expression.test.ts +95 -0
  33. package/src/parser/test/errors/error-locations.test.ts +230 -0
  34. package/src/parser/test/errors/invalid-expressions.test.ts +144 -0
  35. package/src/parser/test/errors/missing-tokens.test.ts +126 -0
  36. package/src/parser/test/errors/model-declaration.test.ts +185 -0
  37. package/src/parser/test/errors/nested-blocks.test.ts +226 -0
  38. package/src/parser/test/errors/unclosed-delimiters.test.ts +122 -0
  39. package/src/parser/test/errors/unexpected-tokens.test.ts +120 -0
  40. package/src/parser/test/import-export.test.ts +143 -0
  41. package/src/parser/test/literals.test.ts +404 -0
  42. package/src/parser/test/model-declaration.test.ts +161 -0
  43. package/src/parser/test/nested-blocks.test.ts +402 -0
  44. package/src/parser/test/parser.test.ts +743 -0
  45. package/src/parser/test/private.test.ts +136 -0
  46. package/src/parser/test/template-literal.test.ts +127 -0
  47. package/src/parser/test/tool-declaration.test.ts +302 -0
  48. package/src/parser/test/ts-block.test.ts +252 -0
  49. package/src/parser/test/type-annotations.test.ts +254 -0
  50. package/src/parser/visitor/helpers.ts +330 -0
  51. package/src/parser/visitor.ts +794 -0
  52. package/src/parser.ts +2 -0
  53. package/src/runtime/ai/cache-chunking.test.ts +69 -0
  54. package/src/runtime/ai/cache-chunking.ts +73 -0
  55. package/src/runtime/ai/client.ts +109 -0
  56. package/src/runtime/ai/context.ts +168 -0
  57. package/src/runtime/ai/formatters.ts +316 -0
  58. package/src/runtime/ai/index.ts +38 -0
  59. package/src/runtime/ai/language-ref.ts +38 -0
  60. package/src/runtime/ai/providers/anthropic.ts +253 -0
  61. package/src/runtime/ai/providers/google.ts +201 -0
  62. package/src/runtime/ai/providers/openai.ts +156 -0
  63. package/src/runtime/ai/retry.ts +100 -0
  64. package/src/runtime/ai/return-tools.ts +301 -0
  65. package/src/runtime/ai/test/client.test.ts +83 -0
  66. package/src/runtime/ai/test/formatters.test.ts +485 -0
  67. package/src/runtime/ai/test/retry.test.ts +137 -0
  68. package/src/runtime/ai/test/return-tools.test.ts +450 -0
  69. package/src/runtime/ai/test/tool-loop.test.ts +319 -0
  70. package/src/runtime/ai/test/tool-schema.test.ts +241 -0
  71. package/src/runtime/ai/tool-loop.ts +203 -0
  72. package/src/runtime/ai/tool-schema.ts +151 -0
  73. package/src/runtime/ai/types.ts +113 -0
  74. package/src/runtime/ai-logger.ts +255 -0
  75. package/src/runtime/ai-provider.ts +347 -0
  76. package/src/runtime/async/dependencies.ts +276 -0
  77. package/src/runtime/async/executor.ts +293 -0
  78. package/src/runtime/async/index.ts +43 -0
  79. package/src/runtime/async/scheduling.ts +163 -0
  80. package/src/runtime/async/test/dependencies.test.ts +284 -0
  81. package/src/runtime/async/test/executor.test.ts +388 -0
  82. package/src/runtime/context.ts +357 -0
  83. package/src/runtime/exec/ai.ts +139 -0
  84. package/src/runtime/exec/expressions.ts +475 -0
  85. package/src/runtime/exec/frames.ts +26 -0
  86. package/src/runtime/exec/functions.ts +305 -0
  87. package/src/runtime/exec/interpolation.ts +312 -0
  88. package/src/runtime/exec/statements.ts +604 -0
  89. package/src/runtime/exec/tools.ts +129 -0
  90. package/src/runtime/exec/typescript.ts +215 -0
  91. package/src/runtime/exec/variables.ts +279 -0
  92. package/src/runtime/index.ts +975 -0
  93. package/src/runtime/modules.ts +452 -0
  94. package/src/runtime/serialize.ts +103 -0
  95. package/src/runtime/state.ts +489 -0
  96. package/src/runtime/stdlib/core.ts +45 -0
  97. package/src/runtime/stdlib/directory.test.ts +156 -0
  98. package/src/runtime/stdlib/edit.test.ts +154 -0
  99. package/src/runtime/stdlib/fastEdit.test.ts +201 -0
  100. package/src/runtime/stdlib/glob.test.ts +106 -0
  101. package/src/runtime/stdlib/grep.test.ts +144 -0
  102. package/src/runtime/stdlib/index.ts +16 -0
  103. package/src/runtime/stdlib/readFile.test.ts +123 -0
  104. package/src/runtime/stdlib/tools/index.ts +707 -0
  105. package/src/runtime/stdlib/writeFile.test.ts +157 -0
  106. package/src/runtime/step.ts +969 -0
  107. package/src/runtime/test/ai-context.test.ts +1086 -0
  108. package/src/runtime/test/ai-result-object.test.ts +419 -0
  109. package/src/runtime/test/ai-tool-flow.test.ts +859 -0
  110. package/src/runtime/test/async-execution-order.test.ts +618 -0
  111. package/src/runtime/test/async-execution.test.ts +344 -0
  112. package/src/runtime/test/async-nested.test.ts +660 -0
  113. package/src/runtime/test/async-parallel-timing.test.ts +546 -0
  114. package/src/runtime/test/basic1.test.ts +154 -0
  115. package/src/runtime/test/binary-operators.test.ts +431 -0
  116. package/src/runtime/test/break-statement.test.ts +257 -0
  117. package/src/runtime/test/context-modes.test.ts +650 -0
  118. package/src/runtime/test/context.test.ts +466 -0
  119. package/src/runtime/test/core-functions.test.ts +228 -0
  120. package/src/runtime/test/e2e.test.ts +88 -0
  121. package/src/runtime/test/error-locations/error-locations.test.ts +80 -0
  122. package/src/runtime/test/error-locations/main-error.vibe +4 -0
  123. package/src/runtime/test/error-locations/main-import-error.vibe +3 -0
  124. package/src/runtime/test/error-locations/utils/helper.vibe +5 -0
  125. package/src/runtime/test/for-in.test.ts +312 -0
  126. package/src/runtime/test/helpers.ts +69 -0
  127. package/src/runtime/test/imports.test.ts +334 -0
  128. package/src/runtime/test/json-expressions.test.ts +232 -0
  129. package/src/runtime/test/literals.test.ts +372 -0
  130. package/src/runtime/test/logical-indexing.test.ts +478 -0
  131. package/src/runtime/test/member-methods.test.ts +324 -0
  132. package/src/runtime/test/model-config.test.ts +338 -0
  133. package/src/runtime/test/null-handling.test.ts +342 -0
  134. package/src/runtime/test/private-visibility.test.ts +332 -0
  135. package/src/runtime/test/runtime-state.test.ts +514 -0
  136. package/src/runtime/test/scoping.test.ts +370 -0
  137. package/src/runtime/test/string-interpolation.test.ts +354 -0
  138. package/src/runtime/test/template-literal.test.ts +181 -0
  139. package/src/runtime/test/tool-execution.test.ts +467 -0
  140. package/src/runtime/test/tool-schema-generation.test.ts +477 -0
  141. package/src/runtime/test/tostring.test.ts +210 -0
  142. package/src/runtime/test/ts-block.test.ts +594 -0
  143. package/src/runtime/test/ts-error-location.test.ts +231 -0
  144. package/src/runtime/test/types.test.ts +732 -0
  145. package/src/runtime/test/verbose-logger.test.ts +710 -0
  146. package/src/runtime/test/vibe-expression.test.ts +54 -0
  147. package/src/runtime/test/vibe-value-errors.test.ts +541 -0
  148. package/src/runtime/test/while.test.ts +232 -0
  149. package/src/runtime/tools/builtin.ts +30 -0
  150. package/src/runtime/tools/directory-tools.ts +70 -0
  151. package/src/runtime/tools/file-tools.ts +228 -0
  152. package/src/runtime/tools/index.ts +5 -0
  153. package/src/runtime/tools/registry.ts +48 -0
  154. package/src/runtime/tools/search-tools.ts +134 -0
  155. package/src/runtime/tools/security.ts +36 -0
  156. package/src/runtime/tools/system-tools.ts +312 -0
  157. package/src/runtime/tools/test/fixtures/base-types.ts +40 -0
  158. package/src/runtime/tools/test/fixtures/test-types.ts +132 -0
  159. package/src/runtime/tools/test/registry.test.ts +713 -0
  160. package/src/runtime/tools/test/security.test.ts +86 -0
  161. package/src/runtime/tools/test/system-tools.test.ts +679 -0
  162. package/src/runtime/tools/test/ts-schema.test.ts +357 -0
  163. package/src/runtime/tools/ts-schema.ts +341 -0
  164. package/src/runtime/tools/types.ts +89 -0
  165. package/src/runtime/tools/utility-tools.ts +198 -0
  166. package/src/runtime/ts-eval.ts +126 -0
  167. package/src/runtime/types.ts +797 -0
  168. package/src/runtime/validation.ts +160 -0
  169. package/src/runtime/verbose-logger.ts +459 -0
  170. package/src/runtime.ts +2 -0
  171. package/src/semantic/analyzer-context.ts +62 -0
  172. package/src/semantic/analyzer-validators.ts +575 -0
  173. package/src/semantic/analyzer-visitors.ts +534 -0
  174. package/src/semantic/analyzer.ts +83 -0
  175. package/src/semantic/index.ts +11 -0
  176. package/src/semantic/symbol-table.ts +58 -0
  177. package/src/semantic/test/async-validation.test.ts +301 -0
  178. package/src/semantic/test/compress-validation.test.ts +179 -0
  179. package/src/semantic/test/const-reassignment.test.ts +111 -0
  180. package/src/semantic/test/control-flow.test.ts +346 -0
  181. package/src/semantic/test/destructuring.test.ts +185 -0
  182. package/src/semantic/test/duplicate-declarations.test.ts +168 -0
  183. package/src/semantic/test/export-validation.test.ts +111 -0
  184. package/src/semantic/test/fixtures/math.ts +31 -0
  185. package/src/semantic/test/imports.test.ts +148 -0
  186. package/src/semantic/test/json-type.test.ts +68 -0
  187. package/src/semantic/test/literals.test.ts +127 -0
  188. package/src/semantic/test/model-validation.test.ts +179 -0
  189. package/src/semantic/test/prompt-validation.test.ts +343 -0
  190. package/src/semantic/test/scoping.test.ts +312 -0
  191. package/src/semantic/test/tool-validation.test.ts +306 -0
  192. package/src/semantic/test/ts-type-checking.test.ts +563 -0
  193. package/src/semantic/test/type-constraints.test.ts +111 -0
  194. package/src/semantic/test/type-inference.test.ts +87 -0
  195. package/src/semantic/test/type-validation.test.ts +552 -0
  196. package/src/semantic/test/undefined-variables.test.ts +163 -0
  197. package/src/semantic/ts-block-checker.ts +204 -0
  198. package/src/semantic/ts-signatures.ts +194 -0
  199. package/src/semantic/ts-types.ts +170 -0
  200. package/src/semantic/types.ts +58 -0
  201. package/tests/fixtures/conditional-logic.vibe +14 -0
  202. package/tests/fixtures/function-call.vibe +16 -0
  203. package/tests/fixtures/imports/cycle-detection/a.vibe +6 -0
  204. package/tests/fixtures/imports/cycle-detection/b.vibe +5 -0
  205. package/tests/fixtures/imports/cycle-detection/main.vibe +3 -0
  206. package/tests/fixtures/imports/module-isolation/main-b.vibe +8 -0
  207. package/tests/fixtures/imports/module-isolation/main.vibe +9 -0
  208. package/tests/fixtures/imports/module-isolation/moduleA.vibe +6 -0
  209. package/tests/fixtures/imports/module-isolation/moduleB.vibe +6 -0
  210. package/tests/fixtures/imports/nested-import/helper.vibe +6 -0
  211. package/tests/fixtures/imports/nested-import/main.vibe +3 -0
  212. package/tests/fixtures/imports/nested-import/utils.ts +3 -0
  213. package/tests/fixtures/imports/nested-isolation/file2.vibe +15 -0
  214. package/tests/fixtures/imports/nested-isolation/file3.vibe +10 -0
  215. package/tests/fixtures/imports/nested-isolation/main.vibe +21 -0
  216. package/tests/fixtures/imports/pure-cycle/a.vibe +5 -0
  217. package/tests/fixtures/imports/pure-cycle/b.vibe +5 -0
  218. package/tests/fixtures/imports/pure-cycle/main.vibe +3 -0
  219. package/tests/fixtures/imports/ts-boolean/checks.ts +14 -0
  220. package/tests/fixtures/imports/ts-boolean/main.vibe +10 -0
  221. package/tests/fixtures/imports/ts-boolean/type-mismatch.vibe +5 -0
  222. package/tests/fixtures/imports/ts-boolean/use-constant.vibe +18 -0
  223. package/tests/fixtures/imports/ts-error-handling/helpers.ts +42 -0
  224. package/tests/fixtures/imports/ts-error-handling/main.vibe +5 -0
  225. package/tests/fixtures/imports/ts-import/main.vibe +4 -0
  226. package/tests/fixtures/imports/ts-import/math.ts +9 -0
  227. package/tests/fixtures/imports/ts-variables/call-non-function.vibe +5 -0
  228. package/tests/fixtures/imports/ts-variables/data.ts +10 -0
  229. package/tests/fixtures/imports/ts-variables/import-json.vibe +5 -0
  230. package/tests/fixtures/imports/ts-variables/import-type-mismatch.vibe +5 -0
  231. package/tests/fixtures/imports/ts-variables/import-variable.vibe +5 -0
  232. package/tests/fixtures/imports/vibe-import/greet.vibe +5 -0
  233. package/tests/fixtures/imports/vibe-import/main.vibe +3 -0
  234. package/tests/fixtures/multiple-ai-calls.vibe +10 -0
  235. package/tests/fixtures/simple-greeting.vibe +6 -0
  236. package/tests/fixtures/template-literals.vibe +11 -0
  237. package/tests/integration/basic-ai/basic-ai.integration.test.ts +166 -0
  238. package/tests/integration/basic-ai/basic-ai.vibe +12 -0
  239. package/tests/integration/bug-fix/bug-fix.integration.test.ts +201 -0
  240. package/tests/integration/bug-fix/buggy-code.ts +22 -0
  241. package/tests/integration/bug-fix/fix-bug.vibe +21 -0
  242. package/tests/integration/compress/compress.integration.test.ts +206 -0
  243. package/tests/integration/destructuring/destructuring.integration.test.ts +92 -0
  244. package/tests/integration/hello-world-translator/hello-world-translator.integration.test.ts +61 -0
  245. package/tests/integration/line-annotator/context-modes.integration.test.ts +261 -0
  246. package/tests/integration/line-annotator/line-annotator.integration.test.ts +148 -0
  247. package/tests/integration/multi-feature/cumulative-sum.integration.test.ts +75 -0
  248. package/tests/integration/multi-feature/number-analyzer.integration.test.ts +191 -0
  249. package/tests/integration/multi-feature/number-analyzer.vibe +59 -0
  250. package/tests/integration/tool-calls/tool-calls.integration.test.ts +93 -0
@@ -0,0 +1,482 @@
1
+ /**
2
+ * Advanced Debug Features
3
+ * Conditional breakpoints, logpoints, watch expressions, exception breakpoints
4
+ */
5
+
6
+ import type { RuntimeState } from '../runtime/types';
7
+ import type { VibeDebugState } from './state';
8
+ import type { SourceLocation, Breakpoint } from '@vibe-lang/debug-core';
9
+
10
+ // Extended breakpoint with advanced features
11
+ export interface AdvancedBreakpoint extends Breakpoint {
12
+ // Condition expression (only break if true)
13
+ condition?: string;
14
+ // Hit count condition (e.g., ">=5", "==10", "%3")
15
+ hitCondition?: string;
16
+ // Log message instead of breaking (logpoint)
17
+ logMessage?: string;
18
+ // Current hit count
19
+ hitCount: number;
20
+ }
21
+
22
+ // Watch expression
23
+ export interface WatchExpression {
24
+ id: number;
25
+ expression: string;
26
+ // Last evaluated value
27
+ lastValue?: string;
28
+ // Error if evaluation failed
29
+ error?: string;
30
+ }
31
+
32
+ // Exception breakpoint configuration
33
+ export interface ExceptionBreakpointConfig {
34
+ // Break on all exceptions
35
+ all: boolean;
36
+ // Break on uncaught exceptions only
37
+ uncaught: boolean;
38
+ // Break on specific exception types
39
+ filters: string[];
40
+ }
41
+
42
+ // Advanced debug state
43
+ export interface AdvancedDebugState {
44
+ // Advanced breakpoints (keyed by file:line)
45
+ advancedBreakpoints: Map<string, AdvancedBreakpoint>;
46
+ // Watch expressions
47
+ watchExpressions: WatchExpression[];
48
+ nextWatchId: number;
49
+ // Exception breakpoint settings
50
+ exceptionBreakpoints: ExceptionBreakpointConfig;
51
+ // Log output buffer for logpoints
52
+ logOutput: string[];
53
+ }
54
+
55
+ /**
56
+ * Create initial advanced debug state
57
+ */
58
+ export function createAdvancedDebugState(): AdvancedDebugState {
59
+ return {
60
+ advancedBreakpoints: new Map(),
61
+ watchExpressions: [],
62
+ nextWatchId: 1,
63
+ exceptionBreakpoints: {
64
+ all: false,
65
+ uncaught: true,
66
+ filters: [],
67
+ },
68
+ logOutput: [],
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Set an advanced breakpoint
74
+ */
75
+ export function setAdvancedBreakpoint(
76
+ state: AdvancedDebugState,
77
+ file: string,
78
+ line: number,
79
+ options?: {
80
+ condition?: string;
81
+ hitCondition?: string;
82
+ logMessage?: string;
83
+ }
84
+ ): { state: AdvancedDebugState; breakpoint: AdvancedBreakpoint } {
85
+ const key = `${normalizeFilePath(file)}:${line}`;
86
+
87
+ const breakpoint: AdvancedBreakpoint = {
88
+ id: Date.now(), // Simple unique ID
89
+ file,
90
+ line,
91
+ verified: true,
92
+ condition: options?.condition,
93
+ hitCondition: options?.hitCondition,
94
+ logMessage: options?.logMessage,
95
+ hitCount: 0,
96
+ };
97
+
98
+ const newBreakpoints = new Map(state.advancedBreakpoints);
99
+ newBreakpoints.set(key, breakpoint);
100
+
101
+ return {
102
+ state: { ...state, advancedBreakpoints: newBreakpoints },
103
+ breakpoint,
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Remove an advanced breakpoint
109
+ */
110
+ export function removeAdvancedBreakpoint(
111
+ state: AdvancedDebugState,
112
+ file: string,
113
+ line: number
114
+ ): AdvancedDebugState {
115
+ const key = `${normalizeFilePath(file)}:${line}`;
116
+ const newBreakpoints = new Map(state.advancedBreakpoints);
117
+ newBreakpoints.delete(key);
118
+ return { ...state, advancedBreakpoints: newBreakpoints };
119
+ }
120
+
121
+ /**
122
+ * Get advanced breakpoint at location
123
+ */
124
+ export function getAdvancedBreakpoint(
125
+ state: AdvancedDebugState,
126
+ file: string,
127
+ line: number
128
+ ): AdvancedBreakpoint | undefined {
129
+ const key = `${normalizeFilePath(file)}:${line}`;
130
+ return state.advancedBreakpoints.get(key);
131
+ }
132
+
133
+ /**
134
+ * Evaluate condition expression
135
+ * Returns true if condition passes (or no condition)
136
+ */
137
+ export function evaluateCondition(
138
+ condition: string | undefined,
139
+ runtimeState: RuntimeState
140
+ ): boolean {
141
+ if (!condition) return true;
142
+
143
+ try {
144
+ // Get current frame's variables
145
+ const frame = runtimeState.callStack[runtimeState.callStack.length - 1];
146
+ if (!frame) return true;
147
+
148
+ // Build context for evaluation
149
+ const context: Record<string, unknown> = {};
150
+ for (const [name, variable] of Object.entries(frame.locals)) {
151
+ context[name] = variable.value;
152
+ }
153
+
154
+ // Simple expression evaluation
155
+ // Supports: variable comparisons, logical operators, simple math
156
+ return evaluateSimpleExpression(condition, context);
157
+ } catch {
158
+ // If evaluation fails, don't break
159
+ return false;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Check hit count condition
165
+ */
166
+ export function checkHitCondition(
167
+ hitCondition: string | undefined,
168
+ hitCount: number
169
+ ): boolean {
170
+ if (!hitCondition) return true;
171
+
172
+ const trimmed = hitCondition.trim();
173
+
174
+ // Check different hit condition formats
175
+ if (trimmed.startsWith('>=')) {
176
+ const value = parseInt(trimmed.slice(2), 10);
177
+ return hitCount >= value;
178
+ }
179
+ if (trimmed.startsWith('<=')) {
180
+ const value = parseInt(trimmed.slice(2), 10);
181
+ return hitCount <= value;
182
+ }
183
+ if (trimmed.startsWith('>')) {
184
+ const value = parseInt(trimmed.slice(1), 10);
185
+ return hitCount > value;
186
+ }
187
+ if (trimmed.startsWith('<')) {
188
+ const value = parseInt(trimmed.slice(1), 10);
189
+ return hitCount < value;
190
+ }
191
+ if (trimmed.startsWith('==') || trimmed.startsWith('=')) {
192
+ const value = parseInt(trimmed.replace(/^==?/, ''), 10);
193
+ return hitCount === value;
194
+ }
195
+ if (trimmed.startsWith('%')) {
196
+ const value = parseInt(trimmed.slice(1), 10);
197
+ return value > 0 && hitCount % value === 0;
198
+ }
199
+
200
+ // Default: break when hit count reaches the value
201
+ const value = parseInt(trimmed, 10);
202
+ return hitCount >= value;
203
+ }
204
+
205
+ /**
206
+ * Check if breakpoint should trigger
207
+ * Handles condition, hit count, and logpoint
208
+ */
209
+ export function shouldBreakpointTrigger(
210
+ state: AdvancedDebugState,
211
+ runtimeState: RuntimeState,
212
+ location: SourceLocation
213
+ ): { shouldBreak: boolean; logMessage?: string; newState: AdvancedDebugState } {
214
+ const bp = getAdvancedBreakpoint(state, location.file, location.line);
215
+ if (!bp) {
216
+ return { shouldBreak: false, newState: state };
217
+ }
218
+
219
+ // Increment hit count
220
+ const newBp: AdvancedBreakpoint = { ...bp, hitCount: bp.hitCount + 1 };
221
+ const newBreakpoints = new Map(state.advancedBreakpoints);
222
+ newBreakpoints.set(`${normalizeFilePath(location.file)}:${location.line}`, newBp);
223
+ let newState: AdvancedDebugState = { ...state, advancedBreakpoints: newBreakpoints };
224
+
225
+ // Check condition
226
+ if (!evaluateCondition(bp.condition, runtimeState)) {
227
+ return { shouldBreak: false, newState };
228
+ }
229
+
230
+ // Check hit condition
231
+ if (!checkHitCondition(bp.hitCondition, newBp.hitCount)) {
232
+ return { shouldBreak: false, newState };
233
+ }
234
+
235
+ // Handle logpoint
236
+ if (bp.logMessage) {
237
+ const message = interpolateLogMessage(bp.logMessage, runtimeState);
238
+ newState = {
239
+ ...newState,
240
+ logOutput: [...newState.logOutput, message],
241
+ };
242
+ // Logpoints don't break
243
+ return { shouldBreak: false, logMessage: message, newState };
244
+ }
245
+
246
+ return { shouldBreak: true, newState };
247
+ }
248
+
249
+ /**
250
+ * Interpolate variables in log message
251
+ * Supports {variableName} syntax
252
+ */
253
+ export function interpolateLogMessage(
254
+ message: string,
255
+ runtimeState: RuntimeState
256
+ ): string {
257
+ const frame = runtimeState.callStack[runtimeState.callStack.length - 1];
258
+ if (!frame) return message;
259
+
260
+ return message.replace(/\{(\w+)\}/g, (match, varName) => {
261
+ const variable = frame.locals[varName];
262
+ if (variable) {
263
+ return formatValueForLog(variable.value);
264
+ }
265
+ return match; // Keep original if variable not found
266
+ });
267
+ }
268
+
269
+ /**
270
+ * Add a watch expression
271
+ */
272
+ export function addWatchExpression(
273
+ state: AdvancedDebugState,
274
+ expression: string
275
+ ): { state: AdvancedDebugState; watch: WatchExpression } {
276
+ const watch: WatchExpression = {
277
+ id: state.nextWatchId,
278
+ expression,
279
+ };
280
+
281
+ return {
282
+ state: {
283
+ ...state,
284
+ watchExpressions: [...state.watchExpressions, watch],
285
+ nextWatchId: state.nextWatchId + 1,
286
+ },
287
+ watch,
288
+ };
289
+ }
290
+
291
+ /**
292
+ * Remove a watch expression
293
+ */
294
+ export function removeWatchExpression(
295
+ state: AdvancedDebugState,
296
+ watchId: number
297
+ ): AdvancedDebugState {
298
+ return {
299
+ ...state,
300
+ watchExpressions: state.watchExpressions.filter(w => w.id !== watchId),
301
+ };
302
+ }
303
+
304
+ /**
305
+ * Evaluate all watch expressions
306
+ */
307
+ export function evaluateWatchExpressions(
308
+ state: AdvancedDebugState,
309
+ runtimeState: RuntimeState
310
+ ): AdvancedDebugState {
311
+ const evaluated = state.watchExpressions.map(watch => {
312
+ try {
313
+ const frame = runtimeState.callStack[runtimeState.callStack.length - 1];
314
+ if (!frame) {
315
+ return { ...watch, lastValue: undefined, error: 'No active frame' };
316
+ }
317
+
318
+ const context: Record<string, unknown> = {};
319
+ for (const [name, variable] of Object.entries(frame.locals)) {
320
+ context[name] = variable.value;
321
+ }
322
+
323
+ const value = evaluateExpression(watch.expression, context);
324
+ return {
325
+ ...watch,
326
+ lastValue: formatValueForLog(value),
327
+ error: undefined,
328
+ };
329
+ } catch (error) {
330
+ return {
331
+ ...watch,
332
+ lastValue: undefined,
333
+ error: error instanceof Error ? error.message : String(error),
334
+ };
335
+ }
336
+ });
337
+
338
+ return { ...state, watchExpressions: evaluated };
339
+ }
340
+
341
+ /**
342
+ * Configure exception breakpoints
343
+ */
344
+ export function setExceptionBreakpoints(
345
+ state: AdvancedDebugState,
346
+ config: Partial<ExceptionBreakpointConfig>
347
+ ): AdvancedDebugState {
348
+ return {
349
+ ...state,
350
+ exceptionBreakpoints: {
351
+ ...state.exceptionBreakpoints,
352
+ ...config,
353
+ },
354
+ };
355
+ }
356
+
357
+ /**
358
+ * Check if we should break on an exception
359
+ */
360
+ export function shouldBreakOnException(
361
+ state: AdvancedDebugState,
362
+ error: Error,
363
+ isCaught: boolean
364
+ ): boolean {
365
+ const config = state.exceptionBreakpoints;
366
+
367
+ // Break on all exceptions
368
+ if (config.all) {
369
+ return true;
370
+ }
371
+
372
+ // Break on uncaught only
373
+ if (config.uncaught && !isCaught) {
374
+ return true;
375
+ }
376
+
377
+ // Check filters
378
+ if (config.filters.length > 0) {
379
+ const errorType = error.constructor.name;
380
+ return config.filters.some(f =>
381
+ errorType.toLowerCase().includes(f.toLowerCase()) ||
382
+ error.message.toLowerCase().includes(f.toLowerCase())
383
+ );
384
+ }
385
+
386
+ return false;
387
+ }
388
+
389
+ /**
390
+ * Get log output and clear buffer
391
+ */
392
+ export function flushLogOutput(state: AdvancedDebugState): {
393
+ state: AdvancedDebugState;
394
+ logs: string[];
395
+ } {
396
+ return {
397
+ state: { ...state, logOutput: [] },
398
+ logs: state.logOutput,
399
+ };
400
+ }
401
+
402
+ // Helper functions
403
+
404
+ function normalizeFilePath(path: string): string {
405
+ return path.replace(/\\/g, '/').toLowerCase();
406
+ }
407
+
408
+ function formatValueForLog(value: unknown): string {
409
+ if (value === null) return 'null';
410
+ if (value === undefined) return 'undefined';
411
+ if (typeof value === 'string') return value;
412
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value);
413
+ if (Array.isArray(value)) return JSON.stringify(value);
414
+ if (typeof value === 'object') {
415
+ // Check for VibeValue
416
+ if ('value' in value) {
417
+ return formatValueForLog((value as any).value);
418
+ }
419
+ return JSON.stringify(value);
420
+ }
421
+ return String(value);
422
+ }
423
+
424
+ function evaluateSimpleExpression(
425
+ expression: string,
426
+ context: Record<string, unknown>
427
+ ): boolean {
428
+ // Replace variable names with their values
429
+ let evaluated = expression;
430
+
431
+ for (const [name, value] of Object.entries(context)) {
432
+ const regex = new RegExp(`\\b${name}\\b`, 'g');
433
+ evaluated = evaluated.replace(regex, JSON.stringify(value));
434
+ }
435
+
436
+ // Simple expression evaluation using Function constructor
437
+ // Only supports basic comparisons and logical ops
438
+ try {
439
+ // Sanitize - only allow safe operators and values
440
+ if (!/^[\s\d\w"'<>=!&|+\-*/%().]+$/.test(evaluated)) {
441
+ return false;
442
+ }
443
+ const fn = new Function(`return ${evaluated}`);
444
+ return !!fn();
445
+ } catch {
446
+ return false;
447
+ }
448
+ }
449
+
450
+ function evaluateExpression(
451
+ expression: string,
452
+ context: Record<string, unknown>
453
+ ): unknown {
454
+ // Simple variable lookup
455
+ if (context.hasOwnProperty(expression)) {
456
+ return context[expression];
457
+ }
458
+
459
+ // Property access (e.g., "obj.prop")
460
+ const parts = expression.split('.');
461
+ if (parts.length > 1) {
462
+ let value: unknown = context[parts[0]];
463
+ for (let i = 1; i < parts.length && value != null; i++) {
464
+ value = (value as any)[parts[i]];
465
+ }
466
+ return value;
467
+ }
468
+
469
+ // Try evaluating as expression
470
+ let evaluated = expression;
471
+ for (const [name, value] of Object.entries(context)) {
472
+ const regex = new RegExp(`\\b${name}\\b`, 'g');
473
+ evaluated = evaluated.replace(regex, JSON.stringify(value));
474
+ }
475
+
476
+ try {
477
+ const fn = new Function(`return ${evaluated}`);
478
+ return fn();
479
+ } catch {
480
+ throw new Error(`Cannot evaluate: ${expression}`);
481
+ }
482
+ }