@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,300 @@
1
+ import { describe, test, expect, beforeEach } from 'bun:test';
2
+ import {
3
+ createAdvancedDebugState,
4
+ setAdvancedBreakpoint,
5
+ removeAdvancedBreakpoint,
6
+ getAdvancedBreakpoint,
7
+ evaluateCondition,
8
+ checkHitCondition,
9
+ shouldBreakpointTrigger,
10
+ interpolateLogMessage,
11
+ addWatchExpression,
12
+ removeWatchExpression,
13
+ evaluateWatchExpressions,
14
+ setExceptionBreakpoints,
15
+ shouldBreakOnException,
16
+ flushLogOutput,
17
+ } from '../advanced-features';
18
+ import { createInitialState } from '../../runtime/state';
19
+ import { parse } from '../../parser/parse';
20
+ import { runUntilPause } from '../../runtime/step';
21
+
22
+ describe('Advanced Debug Features', () => {
23
+ describe('createAdvancedDebugState', () => {
24
+ test('creates initial state', () => {
25
+ const state = createAdvancedDebugState();
26
+
27
+ expect(state.advancedBreakpoints.size).toBe(0);
28
+ expect(state.watchExpressions).toEqual([]);
29
+ expect(state.nextWatchId).toBe(1);
30
+ expect(state.exceptionBreakpoints.all).toBe(false);
31
+ expect(state.exceptionBreakpoints.uncaught).toBe(true);
32
+ expect(state.logOutput).toEqual([]);
33
+ });
34
+ });
35
+
36
+ describe('Conditional Breakpoints', () => {
37
+ test('setAdvancedBreakpoint with condition', () => {
38
+ let state = createAdvancedDebugState();
39
+
40
+ const { state: newState, breakpoint } = setAdvancedBreakpoint(
41
+ state,
42
+ '/test.vibe',
43
+ 10,
44
+ { condition: 'x > 5' }
45
+ );
46
+
47
+ expect(breakpoint.condition).toBe('x > 5');
48
+ expect(breakpoint.line).toBe(10);
49
+ expect(newState.advancedBreakpoints.size).toBe(1);
50
+ });
51
+
52
+ test('getAdvancedBreakpoint retrieves breakpoint', () => {
53
+ let state = createAdvancedDebugState();
54
+ const { state: newState } = setAdvancedBreakpoint(state, '/test.vibe', 15, {
55
+ condition: 'y == 10',
56
+ });
57
+
58
+ const bp = getAdvancedBreakpoint(newState, '/test.vibe', 15);
59
+ expect(bp).toBeDefined();
60
+ expect(bp?.condition).toBe('y == 10');
61
+ });
62
+
63
+ test('removeAdvancedBreakpoint removes breakpoint', () => {
64
+ let state = createAdvancedDebugState();
65
+ const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 10, {});
66
+ const newState = removeAdvancedBreakpoint(state2, '/test.vibe', 10);
67
+
68
+ expect(getAdvancedBreakpoint(newState, '/test.vibe', 10)).toBeUndefined();
69
+ });
70
+ });
71
+
72
+ describe('evaluateCondition', () => {
73
+ test('returns true for no condition', () => {
74
+ const ast = parse('let x = 5');
75
+ const runtimeState = createInitialState(ast);
76
+
77
+ expect(evaluateCondition(undefined, runtimeState)).toBe(true);
78
+ });
79
+
80
+ test('evaluates simple comparisons', () => {
81
+ const ast = parse('let x = 10');
82
+ let runtimeState = createInitialState(ast);
83
+ runtimeState = runUntilPause(runtimeState);
84
+
85
+ // x should be 10
86
+ expect(evaluateCondition('x > 5', runtimeState)).toBe(true);
87
+ expect(evaluateCondition('x < 5', runtimeState)).toBe(false);
88
+ expect(evaluateCondition('x == 10', runtimeState)).toBe(true);
89
+ });
90
+ });
91
+
92
+ describe('Hit Count Conditions', () => {
93
+ test('checkHitCondition with >= operator', () => {
94
+ expect(checkHitCondition('>=5', 5)).toBe(true);
95
+ expect(checkHitCondition('>=5', 4)).toBe(false);
96
+ expect(checkHitCondition('>=5', 10)).toBe(true);
97
+ });
98
+
99
+ test('checkHitCondition with == operator', () => {
100
+ expect(checkHitCondition('==5', 5)).toBe(true);
101
+ expect(checkHitCondition('==5', 4)).toBe(false);
102
+ expect(checkHitCondition('=5', 5)).toBe(true);
103
+ });
104
+
105
+ test('checkHitCondition with modulo operator', () => {
106
+ expect(checkHitCondition('%3', 3)).toBe(true);
107
+ expect(checkHitCondition('%3', 6)).toBe(true);
108
+ expect(checkHitCondition('%3', 4)).toBe(false);
109
+ });
110
+
111
+ test('checkHitCondition with plain number', () => {
112
+ expect(checkHitCondition('5', 5)).toBe(true);
113
+ expect(checkHitCondition('5', 10)).toBe(true);
114
+ expect(checkHitCondition('5', 3)).toBe(false);
115
+ });
116
+ });
117
+
118
+ describe('Logpoints', () => {
119
+ test('setAdvancedBreakpoint with logMessage', () => {
120
+ let state = createAdvancedDebugState();
121
+
122
+ const { state: newState, breakpoint } = setAdvancedBreakpoint(
123
+ state,
124
+ '/test.vibe',
125
+ 10,
126
+ { logMessage: 'Value is {x}' }
127
+ );
128
+
129
+ expect(breakpoint.logMessage).toBe('Value is {x}');
130
+ });
131
+
132
+ test('interpolateLogMessage replaces variables', () => {
133
+ const ast = parse('let x = 42\nlet y = "hello"');
134
+ let runtimeState = createInitialState(ast);
135
+ runtimeState = runUntilPause(runtimeState);
136
+
137
+ const message = interpolateLogMessage('x = {x}, y = {y}', runtimeState);
138
+ expect(message).toBe('x = 42, y = hello');
139
+ });
140
+
141
+ test('shouldBreakpointTrigger returns logMessage for logpoint', () => {
142
+ let state = createAdvancedDebugState();
143
+ const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 2, {
144
+ logMessage: 'Debug: {x}',
145
+ });
146
+
147
+ const ast = parse('let x = 100');
148
+ let runtimeState = createInitialState(ast);
149
+ runtimeState = runUntilPause(runtimeState);
150
+
151
+ const result = shouldBreakpointTrigger(state2, runtimeState, {
152
+ file: '/test.vibe',
153
+ line: 2,
154
+ column: 1,
155
+ });
156
+
157
+ expect(result.shouldBreak).toBe(false); // Logpoints don't break
158
+ expect(result.logMessage).toBe('Debug: 100');
159
+ });
160
+ });
161
+
162
+ describe('Watch Expressions', () => {
163
+ test('addWatchExpression adds watch', () => {
164
+ let state = createAdvancedDebugState();
165
+
166
+ const { state: newState, watch } = addWatchExpression(state, 'x + y');
167
+
168
+ expect(watch.expression).toBe('x + y');
169
+ expect(watch.id).toBe(1);
170
+ expect(newState.watchExpressions.length).toBe(1);
171
+ });
172
+
173
+ test('removeWatchExpression removes watch', () => {
174
+ let state = createAdvancedDebugState();
175
+ const { state: state2, watch } = addWatchExpression(state, 'x');
176
+ const newState = removeWatchExpression(state2, watch.id);
177
+
178
+ expect(newState.watchExpressions.length).toBe(0);
179
+ });
180
+
181
+ test('evaluateWatchExpressions evaluates all watches', () => {
182
+ let state = createAdvancedDebugState();
183
+ const { state: state2 } = addWatchExpression(state, 'x');
184
+ const { state: state3 } = addWatchExpression(state2, 'y');
185
+
186
+ const ast = parse('let x = 10\nlet y = 20');
187
+ let runtimeState = createInitialState(ast);
188
+ runtimeState = runUntilPause(runtimeState);
189
+
190
+ const newState = evaluateWatchExpressions(state3, runtimeState);
191
+
192
+ expect(newState.watchExpressions[0].lastValue).toBe('10');
193
+ expect(newState.watchExpressions[1].lastValue).toBe('20');
194
+ });
195
+ });
196
+
197
+ describe('Exception Breakpoints', () => {
198
+ test('setExceptionBreakpoints updates config', () => {
199
+ let state = createAdvancedDebugState();
200
+
201
+ state = setExceptionBreakpoints(state, { all: true });
202
+ expect(state.exceptionBreakpoints.all).toBe(true);
203
+
204
+ state = setExceptionBreakpoints(state, { filters: ['TypeError'] });
205
+ expect(state.exceptionBreakpoints.filters).toEqual(['TypeError']);
206
+ });
207
+
208
+ test('shouldBreakOnException respects all flag', () => {
209
+ let state = createAdvancedDebugState();
210
+ state = setExceptionBreakpoints(state, { all: true });
211
+
212
+ expect(shouldBreakOnException(state, new Error('test'), true)).toBe(true);
213
+ expect(shouldBreakOnException(state, new Error('test'), false)).toBe(true);
214
+ });
215
+
216
+ test('shouldBreakOnException respects uncaught flag', () => {
217
+ let state = createAdvancedDebugState();
218
+ state = setExceptionBreakpoints(state, { all: false, uncaught: true });
219
+
220
+ expect(shouldBreakOnException(state, new Error('test'), true)).toBe(false);
221
+ expect(shouldBreakOnException(state, new Error('test'), false)).toBe(true);
222
+ });
223
+
224
+ test('shouldBreakOnException respects filters', () => {
225
+ let state = createAdvancedDebugState();
226
+ state = setExceptionBreakpoints(state, {
227
+ all: false,
228
+ uncaught: false,
229
+ filters: ['TypeError'],
230
+ });
231
+
232
+ expect(shouldBreakOnException(state, new TypeError('test'), true)).toBe(true);
233
+ expect(shouldBreakOnException(state, new Error('test'), true)).toBe(false);
234
+ });
235
+ });
236
+
237
+ describe('Log Output', () => {
238
+ test('flushLogOutput returns and clears logs', () => {
239
+ let state = createAdvancedDebugState();
240
+ const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 1, {
241
+ logMessage: 'Log 1',
242
+ });
243
+
244
+ const ast = parse('let x = 1');
245
+ let runtimeState = createInitialState(ast);
246
+
247
+ // Trigger the logpoint
248
+ const { newState: state3 } = shouldBreakpointTrigger(state2, runtimeState, {
249
+ file: '/test.vibe',
250
+ line: 1,
251
+ column: 1,
252
+ });
253
+
254
+ const { state: state4, logs } = flushLogOutput(state3);
255
+
256
+ expect(logs.length).toBe(1);
257
+ expect(logs[0]).toBe('Log 1');
258
+ expect(state4.logOutput.length).toBe(0);
259
+ });
260
+ });
261
+
262
+ describe('shouldBreakpointTrigger', () => {
263
+ test('increments hit count', () => {
264
+ let state = createAdvancedDebugState();
265
+ const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 1, {});
266
+
267
+ const ast = parse('let x = 1');
268
+ const runtimeState = createInitialState(ast);
269
+ const location = { file: '/test.vibe', line: 1, column: 1 };
270
+
271
+ let { newState: state3 } = shouldBreakpointTrigger(state2, runtimeState, location);
272
+ expect(getAdvancedBreakpoint(state3, '/test.vibe', 1)?.hitCount).toBe(1);
273
+
274
+ let { newState: state4 } = shouldBreakpointTrigger(state3, runtimeState, location);
275
+ expect(getAdvancedBreakpoint(state4, '/test.vibe', 1)?.hitCount).toBe(2);
276
+ });
277
+
278
+ test('respects hit condition', () => {
279
+ let state = createAdvancedDebugState();
280
+ const { state: state2 } = setAdvancedBreakpoint(state, '/test.vibe', 1, {
281
+ hitCondition: '>=3',
282
+ });
283
+
284
+ const ast = parse('let x = 1');
285
+ const runtimeState = createInitialState(ast);
286
+ const location = { file: '/test.vibe', line: 1, column: 1 };
287
+
288
+ // First two hits should not break
289
+ let { shouldBreak: b1, newState: s1 } = shouldBreakpointTrigger(state2, runtimeState, location);
290
+ expect(b1).toBe(false);
291
+
292
+ let { shouldBreak: b2, newState: s2 } = shouldBreakpointTrigger(s1, runtimeState, location);
293
+ expect(b2).toBe(false);
294
+
295
+ // Third hit should break
296
+ let { shouldBreak: b3 } = shouldBreakpointTrigger(s2, runtimeState, location);
297
+ expect(b3).toBe(true);
298
+ });
299
+ });
300
+ });
@@ -0,0 +1,218 @@
1
+ import { describe, test, expect } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { createInitialState } from '../../runtime/state';
4
+ import { loadImports } from '../../runtime/modules';
5
+ import {
6
+ createDebugState,
7
+ setBreakpoints,
8
+ getStackTrace,
9
+ getScopes,
10
+ getVariables,
11
+ getCurrentLocation,
12
+ } from '../state';
13
+ import { runWithDebug, createOutputEvent } from '../runner';
14
+ import type { RuntimeEvent } from '@vibe-lang/debug-core';
15
+ import type { AIProvider, AIExecutionResult } from '../../runtime';
16
+
17
+ // Mock AI provider for testing
18
+ const mockAIProvider: AIProvider = {
19
+ async execute(prompt: string): Promise<AIExecutionResult> {
20
+ return { value: `Mock response to: ${prompt.slice(0, 50)}...` };
21
+ },
22
+ async generateCode(prompt: string): Promise<AIExecutionResult> {
23
+ return { value: '// mock code' };
24
+ },
25
+ async askUser(prompt: string): Promise<string> {
26
+ return 'mock user input';
27
+ },
28
+ };
29
+
30
+ describe('End-to-End Debug Session', () => {
31
+ test('full debug session with breakpoints', async () => {
32
+ const code = `
33
+ let x = 10
34
+ let y = 20
35
+ let z = x + y
36
+ `;
37
+ const ast = parse(code, { file: '/test.vibe' });
38
+ let runtimeState = createInitialState(ast);
39
+ let debugState = createDebugState();
40
+
41
+ // Set breakpoint on line 3 (let y = 20)
42
+ const bpResult = setBreakpoints(debugState, '/test.vibe', [3]);
43
+ debugState = bpResult.debugState;
44
+
45
+ // Collect events
46
+ const events: RuntimeEvent[] = [];
47
+ const onEvent = (event: RuntimeEvent) => events.push(event);
48
+
49
+ // Run with debug
50
+ const result = await runWithDebug(runtimeState, debugState, mockAIProvider, onEvent);
51
+
52
+ // Should have stopped at breakpoint or completed
53
+ expect(result.runtimeState).toBeDefined();
54
+ expect(result.debugState).toBeDefined();
55
+ });
56
+
57
+ test('stop on entry', async () => {
58
+ const code = 'let x = 1';
59
+ const ast = parse(code, { file: '/test.vibe' });
60
+ const runtimeState = createInitialState(ast);
61
+ const debugState = createDebugState({ stopOnEntry: true });
62
+
63
+ const events: RuntimeEvent[] = [];
64
+ const result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => events.push(e));
65
+
66
+ // Should be paused at entry
67
+ expect(result.debugState.paused).toBe(true);
68
+ expect(result.debugState.stopReason).toBe('entry');
69
+ });
70
+
71
+ test('inspect variables at breakpoint', async () => {
72
+ const code = `
73
+ let x = 42
74
+ let y = "hello"
75
+ let z = x
76
+ `;
77
+ const ast = parse(code, { file: '/test.vibe' });
78
+ let runtimeState = createInitialState(ast);
79
+ let debugState = createDebugState();
80
+
81
+ // Set breakpoint on line 4 (after x and y are set)
82
+ const bpResult = setBreakpoints(debugState, '/test.vibe', [4]);
83
+ debugState = bpResult.debugState;
84
+
85
+ const events: RuntimeEvent[] = [];
86
+ const result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => events.push(e));
87
+
88
+ runtimeState = result.runtimeState;
89
+ debugState = result.debugState;
90
+
91
+ // Get stack trace
92
+ const { stackFrames } = getStackTrace(runtimeState);
93
+ expect(stackFrames.length).toBeGreaterThan(0);
94
+
95
+ // Get scopes
96
+ const scopeResult = getScopes(debugState, runtimeState, 0);
97
+ debugState = scopeResult.debugState;
98
+ expect(scopeResult.scopes.length).toBeGreaterThan(0);
99
+
100
+ // Get local variables
101
+ const localScope = scopeResult.scopes.find(s => s.type === 'local');
102
+ if (localScope) {
103
+ const varResult = getVariables(debugState, runtimeState, localScope.variablesReference);
104
+ expect(Array.isArray(varResult.variables)).toBe(true);
105
+ }
106
+ });
107
+
108
+ test('step through function calls', async () => {
109
+ const code = `
110
+ function double(n: number): number {
111
+ return n * 2
112
+ }
113
+
114
+ let x = 5
115
+ let y = double(x)
116
+ `;
117
+ const ast = parse(code, { file: '/test.vibe' });
118
+ let runtimeState = createInitialState(ast);
119
+ let debugState = createDebugState({ stopOnEntry: true });
120
+
121
+ const events: RuntimeEvent[] = [];
122
+ let result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => events.push(e));
123
+
124
+ // Should stop on entry
125
+ expect(result.debugState.paused).toBe(true);
126
+
127
+ // Continue to completion
128
+ debugState = { ...result.debugState, paused: false, stepMode: 'none' as const, running: true };
129
+ result = await runWithDebug(result.runtimeState, debugState, mockAIProvider, (e) => events.push(e));
130
+
131
+ // Should complete
132
+ expect(result.runtimeState.status).toBe('completed');
133
+ });
134
+
135
+ test('handles AI calls during debug', async () => {
136
+ const code = `
137
+ let question = "What is 2+2?"
138
+ let answer = vibe "{question}"
139
+ `;
140
+ const ast = parse(code, { file: '/test.vibe' });
141
+ let runtimeState = createInitialState(ast);
142
+ const debugState = createDebugState();
143
+
144
+ const events: RuntimeEvent[] = [];
145
+ const result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => events.push(e));
146
+
147
+ // Debug runner should execute without throwing
148
+ // The exact final status depends on runtime behavior with mock AI
149
+ expect(result.runtimeState).toBeDefined();
150
+ expect(result.debugState).toBeDefined();
151
+ // Should reach some terminal state (completed, error, or awaiting)
152
+ expect(['completed', 'awaiting_ai', 'error'].includes(result.runtimeState.status)).toBe(true);
153
+ });
154
+
155
+ test('multiple breakpoints', async () => {
156
+ const code = `
157
+ let a = 1
158
+ let b = 2
159
+ let c = 3
160
+ let d = 4
161
+ `;
162
+ const ast = parse(code, { file: '/test.vibe' });
163
+ let runtimeState = createInitialState(ast);
164
+ let debugState = createDebugState();
165
+
166
+ // Set breakpoints on lines 2 and 4
167
+ const bpResult = setBreakpoints(debugState, '/test.vibe', [2, 4]);
168
+ debugState = bpResult.debugState;
169
+
170
+ const events: RuntimeEvent[] = [];
171
+ const stoppedEvents: RuntimeEvent[] = [];
172
+
173
+ // First run - should stop at first breakpoint
174
+ let result = await runWithDebug(runtimeState, debugState, mockAIProvider, (e) => {
175
+ events.push(e);
176
+ if (e.event === 'stopped') stoppedEvents.push(e);
177
+ });
178
+
179
+ // Should have some events
180
+ expect(events.length).toBeGreaterThanOrEqual(0);
181
+ });
182
+ });
183
+
184
+ describe('Debug Protocol Messages', () => {
185
+ test('createOutputEvent creates proper event', () => {
186
+ const event = createOutputEvent('Hello World', 'stdout');
187
+
188
+ expect(event.type).toBe('event');
189
+ expect(event.event).toBe('output');
190
+ expect(event.body.output).toBe('Hello World');
191
+ expect(event.body.category).toBe('stdout');
192
+ });
193
+
194
+ test('createOutputEvent defaults to stdout', () => {
195
+ const event = createOutputEvent('Test output');
196
+
197
+ expect(event.body.category).toBe('stdout');
198
+ });
199
+ });
200
+
201
+ describe('Location Tracking', () => {
202
+ test('getCurrentLocation returns location from runtime state', () => {
203
+ const code = `
204
+ let x = 1
205
+ let y = 2
206
+ `;
207
+ const ast = parse(code, { file: '/test.vibe' });
208
+ const runtimeState = createInitialState(ast);
209
+
210
+ const location = getCurrentLocation(runtimeState);
211
+
212
+ // May or may not have location depending on state
213
+ if (location) {
214
+ expect(typeof location.line).toBe('number');
215
+ expect(typeof location.column).toBe('number');
216
+ }
217
+ });
218
+ });