@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,256 @@
1
+ import { describe, test, expect, beforeEach } from 'bun:test';
2
+ import {
3
+ createHandoffState,
4
+ shouldInitiateHandoff,
5
+ initiateHandoff,
6
+ completeHandoff,
7
+ shouldReturnControl,
8
+ returnToVibe,
9
+ handleTsStepIn,
10
+ handleTsStepOut,
11
+ getCurrentMode,
12
+ isInTsMode,
13
+ getSavedVibeState,
14
+ } from '../handoff-manager';
15
+ import { createDebugState } from '../state';
16
+ import { createInitialState } from '../../runtime/state';
17
+ import { parse } from '../../parser/parse';
18
+ import { clearTsBlockMappings } from '../ts-source-map';
19
+
20
+ describe('Handoff Manager', () => {
21
+ beforeEach(() => {
22
+ clearTsBlockMappings();
23
+ });
24
+
25
+ describe('createHandoffState', () => {
26
+ test('creates initial state in Vibe mode', () => {
27
+ const state = createHandoffState();
28
+
29
+ expect(getCurrentMode(state)).toBe('vibe');
30
+ expect(isInTsMode(state)).toBe(false);
31
+ expect(state.handoffInProgress).toBe(false);
32
+ expect(state.handoffReason).toBeNull();
33
+ });
34
+ });
35
+
36
+ describe('shouldInitiateHandoff', () => {
37
+ test('returns false for normal running state', () => {
38
+ const ast = parse('let x = 1');
39
+ const runtimeState = createInitialState(ast);
40
+ const handoffState = createHandoffState();
41
+
42
+ const result = shouldInitiateHandoff(runtimeState, handoffState);
43
+ expect(result.shouldHandoff).toBe(false);
44
+ expect(result.reason).toBeNull();
45
+ });
46
+
47
+ test('returns false if already in TS mode', () => {
48
+ const ast = parse('let x = 1');
49
+ const runtimeState = createInitialState(ast);
50
+ let handoffState = createHandoffState();
51
+
52
+ // Simulate being in TS mode
53
+ const debugState = createDebugState();
54
+ handoffState = initiateHandoff(
55
+ { ...runtimeState, status: 'awaiting_ts', pendingTS: { params: [], body: 'x', paramValues: [] } } as any,
56
+ debugState,
57
+ handoffState,
58
+ 'ts_block'
59
+ );
60
+
61
+ const result = shouldInitiateHandoff(runtimeState, handoffState);
62
+ expect(result.shouldHandoff).toBe(false);
63
+ });
64
+ });
65
+
66
+ describe('initiateHandoff', () => {
67
+ test('switches to TS mode for ts_block', () => {
68
+ const ast = parse('let x = 1');
69
+ const runtimeState = {
70
+ ...createInitialState(ast),
71
+ status: 'awaiting_ts' as const,
72
+ pendingTS: {
73
+ params: ['a'],
74
+ body: 'return a + 1',
75
+ paramValues: [5],
76
+ location: { file: '/test.vibe', line: 10, column: 5 },
77
+ },
78
+ };
79
+ const debugState = createDebugState();
80
+ const handoffState = createHandoffState();
81
+
82
+ const newState = initiateHandoff(runtimeState as any, debugState, handoffState, 'ts_block');
83
+
84
+ expect(newState.context.mode).toBe('typescript');
85
+ expect(newState.context.currentTsBlockId).toBeTruthy();
86
+ expect(newState.handoffInProgress).toBe(true);
87
+ expect(newState.handoffReason).toBe('ts_block');
88
+ expect(newState.savedVibeState).toBe(debugState);
89
+ });
90
+
91
+ test('switches to TS mode for ts_import', () => {
92
+ const ast = parse('let x = 1');
93
+ const runtimeState = {
94
+ ...createInitialState(ast),
95
+ status: 'awaiting_ts' as const,
96
+ pendingImportedTsCall: {
97
+ funcName: 'calculate',
98
+ args: [1, 2],
99
+ },
100
+ };
101
+ const debugState = createDebugState();
102
+ const handoffState = createHandoffState();
103
+
104
+ const newState = initiateHandoff(runtimeState as any, debugState, handoffState, 'ts_import');
105
+
106
+ expect(newState.context.mode).toBe('typescript');
107
+ expect(newState.context.currentTsImport).toBe('calculate');
108
+ expect(newState.handoffReason).toBe('ts_import');
109
+ });
110
+ });
111
+
112
+ describe('completeHandoff', () => {
113
+ test('marks handoff as no longer in progress', () => {
114
+ const ast = parse('let x = 1');
115
+ const runtimeState = {
116
+ ...createInitialState(ast),
117
+ status: 'awaiting_ts' as const,
118
+ pendingTS: { params: [], body: 'x', paramValues: [], location: { file: '', line: 1, column: 1 } },
119
+ };
120
+ const debugState = createDebugState();
121
+ let state = createHandoffState();
122
+
123
+ state = initiateHandoff(runtimeState as any, debugState, state, 'ts_block');
124
+ expect(state.handoffInProgress).toBe(true);
125
+
126
+ state = completeHandoff(state);
127
+ expect(state.handoffInProgress).toBe(false);
128
+ // Still in TS mode though
129
+ expect(state.context.mode).toBe('typescript');
130
+ });
131
+ });
132
+
133
+ describe('shouldReturnControl', () => {
134
+ test('returns false in Vibe mode', () => {
135
+ const state = createHandoffState();
136
+ expect(shouldReturnControl(state, 0)).toBe(false);
137
+ });
138
+
139
+ test('returns true in TS mode when call depth is zero', () => {
140
+ const ast = parse('let x = 1');
141
+ const runtimeState = {
142
+ ...createInitialState(ast),
143
+ status: 'awaiting_ts' as const,
144
+ pendingTS: { params: [], body: 'x', paramValues: [], location: { file: '', line: 1, column: 1 } },
145
+ };
146
+ let state = createHandoffState();
147
+ state = initiateHandoff(runtimeState as any, createDebugState(), state, 'ts_block');
148
+
149
+ expect(shouldReturnControl(state, 0)).toBe(true);
150
+ });
151
+
152
+ test('returns false in TS mode when call depth is positive', () => {
153
+ const ast = parse('let x = 1');
154
+ const runtimeState = {
155
+ ...createInitialState(ast),
156
+ status: 'awaiting_ts' as const,
157
+ pendingTS: { params: [], body: 'x', paramValues: [], location: { file: '', line: 1, column: 1 } },
158
+ };
159
+ let state = createHandoffState();
160
+ state = initiateHandoff(runtimeState as any, createDebugState(), state, 'ts_block');
161
+
162
+ expect(shouldReturnControl(state, 2)).toBe(false);
163
+ });
164
+ });
165
+
166
+ describe('returnToVibe', () => {
167
+ test('switches back to Vibe mode', () => {
168
+ const ast = parse('let x = 1');
169
+ const runtimeState = {
170
+ ...createInitialState(ast),
171
+ status: 'awaiting_ts' as const,
172
+ pendingTS: { params: [], body: 'x', paramValues: [], location: { file: '', line: 1, column: 1 } },
173
+ };
174
+ let state = createHandoffState();
175
+ state = initiateHandoff(runtimeState as any, createDebugState(), state, 'ts_block');
176
+
177
+ state = returnToVibe(state);
178
+
179
+ expect(state.context.mode).toBe('vibe');
180
+ expect(state.handoffInProgress).toBe(false);
181
+ expect(state.handoffReason).toBeNull();
182
+ expect(state.savedVibeState).toBeNull();
183
+ });
184
+ });
185
+
186
+ describe('handleTsStepIn', () => {
187
+ test('increments TS call depth', () => {
188
+ const ast = parse('let x = 1');
189
+ const runtimeState = {
190
+ ...createInitialState(ast),
191
+ status: 'awaiting_ts' as const,
192
+ pendingTS: { params: [], body: 'x', paramValues: [], location: { file: '', line: 1, column: 1 } },
193
+ };
194
+ let state = createHandoffState();
195
+ state = initiateHandoff(runtimeState as any, createDebugState(), state, 'ts_block');
196
+
197
+ expect(state.context.tsCallDepth).toBe(1);
198
+
199
+ state = handleTsStepIn(state);
200
+ expect(state.context.tsCallDepth).toBe(2);
201
+ });
202
+ });
203
+
204
+ describe('handleTsStepOut', () => {
205
+ test('decrements TS call depth', () => {
206
+ const ast = parse('let x = 1');
207
+ const runtimeState = {
208
+ ...createInitialState(ast),
209
+ status: 'awaiting_ts' as const,
210
+ pendingTS: { params: [], body: 'x', paramValues: [], location: { file: '', line: 1, column: 1 } },
211
+ };
212
+ let state = createHandoffState();
213
+ state = initiateHandoff(runtimeState as any, createDebugState(), state, 'ts_block');
214
+ state = handleTsStepIn(state); // depth = 2
215
+
216
+ state = handleTsStepOut(state);
217
+ expect(state.context.tsCallDepth).toBe(1);
218
+ expect(state.context.mode).toBe('typescript');
219
+ });
220
+
221
+ test('returns to Vibe mode when depth reaches zero', () => {
222
+ const ast = parse('let x = 1');
223
+ const runtimeState = {
224
+ ...createInitialState(ast),
225
+ status: 'awaiting_ts' as const,
226
+ pendingTS: { params: [], body: 'x', paramValues: [], location: { file: '', line: 1, column: 1 } },
227
+ };
228
+ let state = createHandoffState();
229
+ state = initiateHandoff(runtimeState as any, createDebugState(), state, 'ts_block');
230
+
231
+ state = handleTsStepOut(state); // depth goes to 0, exits TS mode
232
+
233
+ expect(state.context.mode).toBe('vibe');
234
+ expect(state.context.tsCallDepth).toBe(0);
235
+ });
236
+ });
237
+
238
+ describe('getSavedVibeState', () => {
239
+ test('returns saved state after handoff', () => {
240
+ const ast = parse('let x = 1');
241
+ const runtimeState = {
242
+ ...createInitialState(ast),
243
+ status: 'awaiting_ts' as const,
244
+ pendingTS: { params: [], body: 'x', paramValues: [], location: { file: '', line: 1, column: 1 } },
245
+ };
246
+ const debugState = createDebugState();
247
+ let state = createHandoffState();
248
+
249
+ state = initiateHandoff(runtimeState as any, debugState, state, 'ts_block');
250
+
251
+ const saved = getSavedVibeState(state);
252
+ expect(saved.debugState).toBe(debugState);
253
+ expect(saved.runtimeState).toBeDefined();
254
+ });
255
+ });
256
+ });
@@ -0,0 +1,256 @@
1
+ import { describe, test, expect } from 'bun:test';
2
+ import {
3
+ initDebugSession,
4
+ debugStep,
5
+ debugContinue,
6
+ debugStepIn,
7
+ debugStepOver,
8
+ debugStepOut,
9
+ } from '../runner';
10
+ import { createDebugState, setBreakpoints, setStepMode } from '../state';
11
+ import { createInitialState } from '../../runtime/state';
12
+ import { parse } from '../../parser/parse';
13
+
14
+ describe('Debug Runner', () => {
15
+ describe('initDebugSession', () => {
16
+ test('initializes debug session without stopOnEntry', () => {
17
+ const debugState = initDebugSession();
18
+
19
+ expect(debugState.paused).toBe(false);
20
+ expect(debugState.stopReason).toBeNull();
21
+ });
22
+
23
+ test('initializes debug session with stopOnEntry', () => {
24
+ const debugState = initDebugSession({ stopOnEntry: true });
25
+
26
+ expect(debugState.paused).toBe(true);
27
+ expect(debugState.stopReason).toBe('entry');
28
+ });
29
+ });
30
+
31
+ describe('debugStep', () => {
32
+ test('steps one instruction', () => {
33
+ const code = `
34
+ let x = 1
35
+ let y = 2
36
+ `;
37
+ const ast = parse(code);
38
+ const runtimeState = createInitialState(ast);
39
+ const debugState = createDebugState();
40
+
41
+ const result = debugStep(runtimeState, debugState);
42
+
43
+ // Should have progressed
44
+ expect(result.runtimeState).toBeDefined();
45
+ expect(result.debugState).toBeDefined();
46
+ });
47
+
48
+ test('returns terminated event when complete', () => {
49
+ const code = 'let x = 1';
50
+ const ast = parse(code);
51
+ let runtimeState = createInitialState(ast);
52
+ let debugState = createDebugState();
53
+
54
+ // Run until complete
55
+ while (runtimeState.status !== 'completed' && runtimeState.status !== 'error') {
56
+ const result = debugStep(runtimeState, debugState);
57
+ runtimeState = result.runtimeState;
58
+ debugState = result.debugState;
59
+ if (result.event?.event === 'terminated') break;
60
+ }
61
+
62
+ expect(runtimeState.status).toBe('completed');
63
+ });
64
+
65
+ test('stops at breakpoint', () => {
66
+ const code = `
67
+ let x = 1
68
+ let y = 2
69
+ let z = 3
70
+ `;
71
+ const ast = parse(code, { file: '/test.vibe' });
72
+ let runtimeState = createInitialState(ast);
73
+ let debugState = createDebugState();
74
+
75
+ // Set breakpoint on line 3 (let y = 2)
76
+ const bpResult = setBreakpoints(debugState, '/test.vibe', [3]);
77
+ debugState = bpResult.debugState;
78
+
79
+ // Continue until we hit breakpoint or complete
80
+ const result = debugContinue(runtimeState, debugState);
81
+
82
+ // Should have stopped
83
+ if (result.event?.event === 'stopped') {
84
+ expect(result.event.body.reason).toBe('breakpoint');
85
+ }
86
+ });
87
+ });
88
+
89
+ describe('debugContinue', () => {
90
+ test('runs until completion when no breakpoints', () => {
91
+ const code = `
92
+ let x = 1
93
+ let y = 2
94
+ `;
95
+ const ast = parse(code);
96
+ const runtimeState = createInitialState(ast);
97
+ const debugState = createDebugState();
98
+
99
+ const result = debugContinue(runtimeState, debugState);
100
+
101
+ // Should complete or await async
102
+ expect(['completed', 'awaiting_ai', 'awaiting_ts'].includes(result.runtimeState.status) || result.event?.event === 'terminated').toBe(true);
103
+ });
104
+ });
105
+
106
+ describe('debugStepIn', () => {
107
+ test('sets step into mode and steps', () => {
108
+ const code = 'let x = 1';
109
+ const ast = parse(code);
110
+ const runtimeState = createInitialState(ast);
111
+ const debugState = createDebugState();
112
+
113
+ const result = debugStepIn(runtimeState, debugState);
114
+
115
+ expect(result.runtimeState).toBeDefined();
116
+ });
117
+ });
118
+
119
+ describe('debugStepOver', () => {
120
+ test('sets step over mode and steps', () => {
121
+ const code = 'let x = 1';
122
+ const ast = parse(code);
123
+ const runtimeState = createInitialState(ast);
124
+ const debugState = createDebugState();
125
+
126
+ const result = debugStepOver(runtimeState, debugState);
127
+
128
+ expect(result.runtimeState).toBeDefined();
129
+ });
130
+ });
131
+
132
+ describe('debugStepOut', () => {
133
+ test('sets step out mode and continues', () => {
134
+ const code = `
135
+ function foo() {
136
+ let x = 1
137
+ return x
138
+ }
139
+ foo()
140
+ `;
141
+ const ast = parse(code);
142
+ const runtimeState = createInitialState(ast);
143
+ const debugState = createDebugState();
144
+
145
+ const result = debugStepOut(runtimeState, debugState);
146
+
147
+ expect(result.runtimeState).toBeDefined();
148
+ });
149
+ });
150
+ });
151
+
152
+ describe('Debug Events', () => {
153
+ test('emits stopped event at breakpoint', () => {
154
+ const code = `
155
+ let x = 1
156
+ let y = 2
157
+ `;
158
+ const ast = parse(code, { file: '/test.vibe' });
159
+ let runtimeState = createInitialState(ast);
160
+ let debugState = createDebugState();
161
+
162
+ // Set breakpoint on line 3
163
+ const bpResult = setBreakpoints(debugState, '/test.vibe', [3]);
164
+ debugState = bpResult.debugState;
165
+
166
+ const result = debugContinue(runtimeState, debugState);
167
+
168
+ if (result.event) {
169
+ expect(result.event.type).toBe('event');
170
+ expect(['stopped', 'terminated']).toContain(result.event.event);
171
+ }
172
+ });
173
+
174
+ test('emits terminated event when complete', () => {
175
+ const code = 'let x = 1';
176
+ const ast = parse(code);
177
+ const runtimeState = createInitialState(ast);
178
+ const debugState = createDebugState();
179
+
180
+ const result = debugContinue(runtimeState, debugState);
181
+
182
+ expect(result.event?.event).toBe('terminated');
183
+ });
184
+ });
185
+
186
+ describe('Step Modes', () => {
187
+ test('step into pauses on each instruction', () => {
188
+ const code = `
189
+ let x = 1
190
+ let y = 2
191
+ `;
192
+ const ast = parse(code);
193
+ let runtimeState = createInitialState(ast);
194
+ let debugState = setStepMode(createDebugState(), 'into');
195
+
196
+ // First step
197
+ let result = debugStep(runtimeState, debugState);
198
+
199
+ // Should pause (step mode triggers pause)
200
+ if (result.event?.event === 'stopped') {
201
+ expect(result.event.body.reason).toBe('step');
202
+ }
203
+ });
204
+ });
205
+
206
+ describe('Complex Programs', () => {
207
+ test('handles function calls', () => {
208
+ const code = `
209
+ function add(a: number, b: number): number {
210
+ return a + b
211
+ }
212
+ let result = add(1, 2)
213
+ `;
214
+ const ast = parse(code);
215
+ const runtimeState = createInitialState(ast);
216
+ const debugState = createDebugState();
217
+
218
+ const result = debugContinue(runtimeState, debugState);
219
+
220
+ expect(result.runtimeState.status).toBe('completed');
221
+ });
222
+
223
+ test('handles conditionals', () => {
224
+ const code = `
225
+ let x = 10
226
+ if x > 5 {
227
+ let y = "big"
228
+ } else {
229
+ let y = "small"
230
+ }
231
+ `;
232
+ const ast = parse(code);
233
+ const runtimeState = createInitialState(ast);
234
+ const debugState = createDebugState();
235
+
236
+ const result = debugContinue(runtimeState, debugState);
237
+
238
+ expect(result.runtimeState.status).toBe('completed');
239
+ });
240
+
241
+ test('handles loops', () => {
242
+ const code = `
243
+ let sum = 0
244
+ for i in 1..3 {
245
+ sum = sum + i
246
+ }
247
+ `;
248
+ const ast = parse(code);
249
+ const runtimeState = createInitialState(ast);
250
+ const debugState = createDebugState();
251
+
252
+ const result = debugContinue(runtimeState, debugState);
253
+
254
+ expect(result.runtimeState.status).toBe('completed');
255
+ });
256
+ });
@@ -0,0 +1,163 @@
1
+ import { describe, test, expect } from 'bun:test';
2
+ import {
3
+ createDebugExecutionContext,
4
+ enterTsBlock,
5
+ enterTsImport,
6
+ exitTsMode,
7
+ incrementTsCallDepth,
8
+ decrementTsCallDepth,
9
+ mergeStackFrames,
10
+ shouldReturnToVibe,
11
+ } from '../stack-merger';
12
+ import type { StackFrame } from '@vibe-lang/debug-core';
13
+
14
+ describe('Debug Execution Context', () => {
15
+ describe('createDebugExecutionContext', () => {
16
+ test('creates initial context in Vibe mode', () => {
17
+ const context = createDebugExecutionContext();
18
+
19
+ expect(context.mode).toBe('vibe');
20
+ expect(context.tsCallDepth).toBe(0);
21
+ expect(context.vibeCallDepthOnTsEntry).toBe(0);
22
+ expect(context.currentTsBlockId).toBeNull();
23
+ expect(context.currentTsImport).toBeNull();
24
+ });
25
+ });
26
+
27
+ describe('enterTsBlock', () => {
28
+ test('switches to TS mode for ts block', () => {
29
+ let context = createDebugExecutionContext();
30
+ context = enterTsBlock(context, 'ts_block_1', 3);
31
+
32
+ expect(context.mode).toBe('typescript');
33
+ expect(context.tsCallDepth).toBe(1);
34
+ expect(context.vibeCallDepthOnTsEntry).toBe(3);
35
+ expect(context.currentTsBlockId).toBe('ts_block_1');
36
+ expect(context.currentTsImport).toBeNull();
37
+ });
38
+ });
39
+
40
+ describe('enterTsImport', () => {
41
+ test('switches to TS mode for imported function', () => {
42
+ let context = createDebugExecutionContext();
43
+ context = enterTsImport(context, 'myTsFunction', 2);
44
+
45
+ expect(context.mode).toBe('typescript');
46
+ expect(context.tsCallDepth).toBe(1);
47
+ expect(context.vibeCallDepthOnTsEntry).toBe(2);
48
+ expect(context.currentTsBlockId).toBeNull();
49
+ expect(context.currentTsImport).toBe('myTsFunction');
50
+ });
51
+ });
52
+
53
+ describe('exitTsMode', () => {
54
+ test('returns to Vibe mode', () => {
55
+ let context = createDebugExecutionContext();
56
+ context = enterTsBlock(context, 'ts_block_1', 3);
57
+ context = exitTsMode(context);
58
+
59
+ expect(context.mode).toBe('vibe');
60
+ expect(context.tsCallDepth).toBe(0);
61
+ expect(context.vibeCallDepthOnTsEntry).toBe(0);
62
+ expect(context.currentTsBlockId).toBeNull();
63
+ });
64
+ });
65
+
66
+ describe('incrementTsCallDepth', () => {
67
+ test('increments call depth', () => {
68
+ let context = createDebugExecutionContext();
69
+ context = enterTsBlock(context, 'ts_block_1', 2);
70
+ context = incrementTsCallDepth(context);
71
+
72
+ expect(context.tsCallDepth).toBe(2);
73
+ });
74
+ });
75
+
76
+ describe('decrementTsCallDepth', () => {
77
+ test('decrements call depth', () => {
78
+ let context = createDebugExecutionContext();
79
+ context = enterTsBlock(context, 'ts_block_1', 2);
80
+ context = incrementTsCallDepth(context); // depth = 2
81
+ context = decrementTsCallDepth(context);
82
+
83
+ expect(context.tsCallDepth).toBe(1);
84
+ expect(context.mode).toBe('typescript');
85
+ });
86
+
87
+ test('exits TS mode when depth reaches zero', () => {
88
+ let context = createDebugExecutionContext();
89
+ context = enterTsBlock(context, 'ts_block_1', 2);
90
+ context = decrementTsCallDepth(context); // depth = 0
91
+
92
+ expect(context.mode).toBe('vibe');
93
+ expect(context.tsCallDepth).toBe(0);
94
+ });
95
+ });
96
+ });
97
+
98
+ describe('Stack Frame Merging', () => {
99
+ const vibeFrames: StackFrame[] = [
100
+ { id: 0, name: 'main', source: { file: '/app.vibe', line: 1, column: 1 }, isVibeCode: true },
101
+ { id: 1, name: 'helper', source: { file: '/app.vibe', line: 10, column: 1 }, isVibeCode: true },
102
+ ];
103
+
104
+ const tsFrames: StackFrame[] = [
105
+ { id: 0, name: 'tsFunc', source: { file: '/utils.ts', line: 5, column: 1 }, isVibeCode: false },
106
+ { id: 1, name: 'innerTs', source: { file: '/utils.ts', line: 15, column: 1 }, isVibeCode: false },
107
+ ];
108
+
109
+ describe('mergeStackFrames', () => {
110
+ test('returns only Vibe frames in Vibe mode', () => {
111
+ const context = createDebugExecutionContext();
112
+ const merged = mergeStackFrames(vibeFrames, tsFrames, context);
113
+
114
+ expect(merged.length).toBe(2);
115
+ expect(merged.every(f => f.origin === 'vibe')).toBe(true);
116
+ });
117
+
118
+ test('merges TS and Vibe frames in TS mode', () => {
119
+ let context = createDebugExecutionContext();
120
+ context = enterTsBlock(context, 'ts_block_1', 1);
121
+
122
+ const merged = mergeStackFrames(vibeFrames, tsFrames, context);
123
+
124
+ // TS frames on top, then Vibe frames
125
+ expect(merged.length).toBeGreaterThan(0);
126
+ expect(merged[0].origin).toBe('typescript');
127
+ expect(merged[1].origin).toBe('typescript');
128
+ });
129
+
130
+ test('assigns sequential IDs to merged frames', () => {
131
+ let context = createDebugExecutionContext();
132
+ context = enterTsBlock(context, 'ts_block_1', 0);
133
+
134
+ const merged = mergeStackFrames(vibeFrames, tsFrames, context);
135
+
136
+ merged.forEach((frame, index) => {
137
+ expect(frame.id).toBe(index);
138
+ });
139
+ });
140
+ });
141
+ });
142
+
143
+ describe('shouldReturnToVibe', () => {
144
+ test('returns true when TS call depth is zero', () => {
145
+ let context = createDebugExecutionContext();
146
+ context = enterTsBlock(context, 'ts_block_1', 2);
147
+
148
+ expect(shouldReturnToVibe(context, 0)).toBe(true);
149
+ });
150
+
151
+ test('returns false when TS call depth is positive', () => {
152
+ let context = createDebugExecutionContext();
153
+ context = enterTsBlock(context, 'ts_block_1', 2);
154
+
155
+ expect(shouldReturnToVibe(context, 2)).toBe(false);
156
+ });
157
+
158
+ test('returns false in Vibe mode', () => {
159
+ const context = createDebugExecutionContext();
160
+
161
+ expect(shouldReturnToVibe(context, 0)).toBe(false);
162
+ });
163
+ });