@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,581 @@
1
+ /**
2
+ * Debug State - Functional debug state management
3
+ * Pure functions for managing debug state alongside RuntimeState
4
+ */
5
+
6
+ import type {
7
+ Breakpoint,
8
+ SourceLocation,
9
+ StackFrame,
10
+ Variable,
11
+ Scope,
12
+ ContextEntry,
13
+ ToolCallRecord,
14
+ StopReason,
15
+ StepMode,
16
+ DebugState,
17
+ } from '@vibe-lang/debug-core';
18
+
19
+ import type { RuntimeState } from '../runtime/types';
20
+
21
+ // Extended debug state with runtime reference tracking
22
+ export interface VibeDebugState extends DebugState {
23
+ breakpoints: Map<string, Breakpoint[]>; // file -> breakpoints
24
+ nextBreakpointId: number;
25
+ variableReferences: Map<number, VariableReference>; // For expandable variables
26
+ nextVariableRef: number;
27
+ }
28
+
29
+ // Reference to a variable that can be expanded
30
+ export interface VariableReference {
31
+ type: 'object' | 'array' | 'vibeValue' | 'scope';
32
+ value: unknown;
33
+ frameId?: number;
34
+ scopeType?: 'local' | 'global' | 'context';
35
+ }
36
+
37
+ /**
38
+ * Create initial debug state
39
+ */
40
+ export function createDebugState(options?: {
41
+ stopOnEntry?: boolean;
42
+ }): VibeDebugState {
43
+ return {
44
+ running: false,
45
+ paused: options?.stopOnEntry ?? false,
46
+ pausedAt: null,
47
+ stopReason: options?.stopOnEntry ? 'entry' : null,
48
+ stepMode: 'none',
49
+ breakpoints: new Map(),
50
+ nextBreakpointId: 1,
51
+ variableReferences: new Map(),
52
+ nextVariableRef: 1,
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Set breakpoints for a file
58
+ * Returns the new debug state and verified breakpoints
59
+ */
60
+ export function setBreakpoints(
61
+ debugState: VibeDebugState,
62
+ file: string,
63
+ lines: number[],
64
+ conditions?: (string | undefined)[]
65
+ ): { debugState: VibeDebugState; breakpoints: Breakpoint[] } {
66
+ const breakpoints: Breakpoint[] = lines.map((line, i) => ({
67
+ id: debugState.nextBreakpointId + i,
68
+ file,
69
+ line,
70
+ verified: true, // We assume all breakpoints are valid for now
71
+ condition: conditions?.[i],
72
+ }));
73
+
74
+ const newBreakpoints = new Map(debugState.breakpoints);
75
+ newBreakpoints.set(normalizeFilePath(file), breakpoints);
76
+
77
+ return {
78
+ debugState: {
79
+ ...debugState,
80
+ breakpoints: newBreakpoints,
81
+ nextBreakpointId: debugState.nextBreakpointId + lines.length,
82
+ },
83
+ breakpoints,
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Clear all breakpoints for a file
89
+ */
90
+ export function clearBreakpoints(
91
+ debugState: VibeDebugState,
92
+ file: string
93
+ ): VibeDebugState {
94
+ const newBreakpoints = new Map(debugState.breakpoints);
95
+ newBreakpoints.delete(normalizeFilePath(file));
96
+ return { ...debugState, breakpoints: newBreakpoints };
97
+ }
98
+
99
+ /**
100
+ * Check if execution should pause at current location
101
+ */
102
+ export function shouldPauseAtLocation(
103
+ debugState: VibeDebugState,
104
+ runtimeState: RuntimeState,
105
+ location: SourceLocation
106
+ ): { shouldPause: boolean; reason: StopReason | null } {
107
+ // Check breakpoints
108
+ const fileBreakpoints = debugState.breakpoints.get(normalizeFilePath(location.file));
109
+ if (fileBreakpoints) {
110
+ const hitBreakpoint = fileBreakpoints.find(bp => bp.line === location.line);
111
+ if (hitBreakpoint) {
112
+ // Check condition if present
113
+ if (hitBreakpoint.condition) {
114
+ // TODO: Evaluate condition expression
115
+ // For now, always break on conditional breakpoints
116
+ }
117
+ return { shouldPause: true, reason: 'breakpoint' };
118
+ }
119
+ }
120
+
121
+ // Check step mode
122
+ if (debugState.stepMode !== 'none') {
123
+ return { shouldPause: true, reason: 'step' };
124
+ }
125
+
126
+ return { shouldPause: false, reason: null };
127
+ }
128
+
129
+ /**
130
+ * Pause execution
131
+ */
132
+ export function pauseExecution(
133
+ debugState: VibeDebugState,
134
+ location: SourceLocation,
135
+ reason: StopReason
136
+ ): VibeDebugState {
137
+ return {
138
+ ...debugState,
139
+ running: false,
140
+ paused: true,
141
+ pausedAt: location,
142
+ stopReason: reason,
143
+ stepMode: 'none',
144
+ };
145
+ }
146
+
147
+ /**
148
+ * Resume execution (continue)
149
+ */
150
+ export function resumeExecution(debugState: VibeDebugState): VibeDebugState {
151
+ return {
152
+ ...debugState,
153
+ running: true,
154
+ paused: false,
155
+ pausedAt: null,
156
+ stopReason: null,
157
+ stepMode: 'none',
158
+ };
159
+ }
160
+
161
+ /**
162
+ * Set step mode
163
+ */
164
+ export function setStepMode(
165
+ debugState: VibeDebugState,
166
+ mode: StepMode
167
+ ): VibeDebugState {
168
+ return {
169
+ ...debugState,
170
+ running: true,
171
+ paused: false,
172
+ stepMode: mode,
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Get current source location from runtime state
178
+ */
179
+ export function getCurrentLocation(runtimeState: RuntimeState): SourceLocation | null {
180
+ // Get location from current instruction or statement
181
+ const instruction = runtimeState.instructionStack[0];
182
+ if (instruction?.location) {
183
+ return {
184
+ file: instruction.location.file ?? runtimeState.rootDir ?? '',
185
+ line: instruction.location.line,
186
+ column: instruction.location.column,
187
+ };
188
+ }
189
+
190
+ // Fallback to current frame's location
191
+ const frame = runtimeState.callStack[runtimeState.callStack.length - 1];
192
+ if (frame?.currentLocation) {
193
+ return {
194
+ file: frame.currentLocation.file ?? runtimeState.rootDir ?? '',
195
+ line: frame.currentLocation.line,
196
+ column: frame.currentLocation.column,
197
+ };
198
+ }
199
+
200
+ return null;
201
+ }
202
+
203
+ /**
204
+ * Get stack trace from runtime state
205
+ */
206
+ export function getStackTrace(runtimeState: RuntimeState): {
207
+ stackFrames: StackFrame[];
208
+ totalFrames: number;
209
+ } {
210
+ const stackFrames: StackFrame[] = runtimeState.callStack.map((frame, index) => ({
211
+ id: index,
212
+ name: frame.functionName ?? '<main>',
213
+ source: {
214
+ file: frame.currentLocation?.file ?? '',
215
+ line: frame.currentLocation?.line ?? 1,
216
+ column: frame.currentLocation?.column ?? 1,
217
+ },
218
+ isVibeCode: true, // For now, all frames are Vibe code
219
+ })).reverse(); // Most recent frame first
220
+
221
+ return {
222
+ stackFrames,
223
+ totalFrames: stackFrames.length,
224
+ };
225
+ }
226
+
227
+ /**
228
+ * Get scopes for a stack frame
229
+ */
230
+ export function getScopes(
231
+ debugState: VibeDebugState,
232
+ runtimeState: RuntimeState,
233
+ frameId: number
234
+ ): { debugState: VibeDebugState; scopes: Scope[] } {
235
+ const scopes: Scope[] = [];
236
+ let newDebugState = debugState;
237
+
238
+ // Local scope
239
+ const localRef = newDebugState.nextVariableRef++;
240
+ newDebugState = {
241
+ ...newDebugState,
242
+ variableReferences: new Map(newDebugState.variableReferences).set(localRef, {
243
+ type: 'scope',
244
+ value: null,
245
+ frameId,
246
+ scopeType: 'local',
247
+ }),
248
+ };
249
+ scopes.push({
250
+ name: 'Local',
251
+ type: 'local',
252
+ variablesReference: localRef,
253
+ expensive: false,
254
+ });
255
+
256
+ // Global scope (if not at top level)
257
+ if (frameId < runtimeState.callStack.length - 1) {
258
+ const globalRef = newDebugState.nextVariableRef++;
259
+ newDebugState = {
260
+ ...newDebugState,
261
+ variableReferences: new Map(newDebugState.variableReferences).set(globalRef, {
262
+ type: 'scope',
263
+ value: null,
264
+ frameId: 0,
265
+ scopeType: 'global',
266
+ }),
267
+ };
268
+ scopes.push({
269
+ name: 'Global',
270
+ type: 'global',
271
+ variablesReference: globalRef,
272
+ expensive: false,
273
+ });
274
+ }
275
+
276
+ // Context scope (AI context)
277
+ const contextRef = newDebugState.nextVariableRef++;
278
+ newDebugState = {
279
+ ...newDebugState,
280
+ variableReferences: new Map(newDebugState.variableReferences).set(contextRef, {
281
+ type: 'scope',
282
+ value: null,
283
+ frameId,
284
+ scopeType: 'context',
285
+ }),
286
+ };
287
+ scopes.push({
288
+ name: 'AI Context',
289
+ type: 'context',
290
+ variablesReference: contextRef,
291
+ expensive: true, // Context can be large
292
+ });
293
+
294
+ return { debugState: newDebugState, scopes };
295
+ }
296
+
297
+ /**
298
+ * Get variables for a reference
299
+ */
300
+ export function getVariables(
301
+ debugState: VibeDebugState,
302
+ runtimeState: RuntimeState,
303
+ variablesReference: number
304
+ ): { debugState: VibeDebugState; variables: Variable[] } {
305
+ const ref = debugState.variableReferences.get(variablesReference);
306
+ if (!ref) {
307
+ return { debugState, variables: [] };
308
+ }
309
+
310
+ let newDebugState = debugState;
311
+ const variables: Variable[] = [];
312
+
313
+ if (ref.type === 'scope') {
314
+ // Get variables from a scope
315
+ const frame = runtimeState.callStack[runtimeState.callStack.length - 1 - (ref.frameId ?? 0)];
316
+ if (!frame) {
317
+ return { debugState, variables: [] };
318
+ }
319
+
320
+ if (ref.scopeType === 'local' || ref.scopeType === 'global') {
321
+ // Get local/global variables
322
+ // Pass the entire VibeValue so createVariable can detect .err and .toolCalls
323
+ for (const [name, variable] of Object.entries(frame.locals)) {
324
+ const { debugState: ds, variable: v } = createVariable(newDebugState, name, variable, variable.typeAnnotation);
325
+ newDebugState = ds;
326
+ variables.push(v);
327
+ }
328
+ } else if (ref.scopeType === 'context') {
329
+ // Get context entries
330
+ const contextEntries = runtimeState.localContext ?? [];
331
+ for (const entry of contextEntries) {
332
+ variables.push({
333
+ name: entry.name ?? 'context',
334
+ value: String(entry.value).slice(0, 100),
335
+ type: 'context',
336
+ variablesReference: 0,
337
+ });
338
+ }
339
+ }
340
+ } else if (ref.type === 'object' || ref.type === 'array') {
341
+ // Expand object or array
342
+ const value = ref.value;
343
+ if (Array.isArray(value)) {
344
+ value.forEach((item, index) => {
345
+ const { debugState: ds, variable: v } = createVariable(newDebugState, `[${index}]`, item);
346
+ newDebugState = ds;
347
+ variables.push(v);
348
+ });
349
+ } else if (typeof value === 'object' && value !== null) {
350
+ for (const [key, val] of Object.entries(value)) {
351
+ const { debugState: ds, variable: v } = createVariable(newDebugState, key, val);
352
+ newDebugState = ds;
353
+ variables.push(v);
354
+ }
355
+ }
356
+ } else if (ref.type === 'vibeValue') {
357
+ // Expand VibeValue (show .value, .err, .toolCalls)
358
+ const vibeValue = ref.value as any;
359
+ if (vibeValue) {
360
+ variables.push({
361
+ name: 'value',
362
+ value: formatValue(vibeValue.value),
363
+ type: typeof vibeValue.value,
364
+ variablesReference: 0,
365
+ });
366
+ if (vibeValue.err && vibeValue.errDetails) {
367
+ const errMsg = vibeValue.errDetails.message ?? 'unknown error';
368
+ variables.push({
369
+ name: 'err',
370
+ value: 'true',
371
+ type: 'boolean',
372
+ variablesReference: 0,
373
+ });
374
+ variables.push({
375
+ name: 'errDetails',
376
+ value: errMsg,
377
+ type: 'error',
378
+ variablesReference: 0,
379
+ hasError: true,
380
+ errorMessage: errMsg,
381
+ });
382
+ }
383
+ if (vibeValue.toolCalls && vibeValue.toolCalls.length > 0) {
384
+ const toolCallsRef = newDebugState.nextVariableRef++;
385
+ newDebugState = {
386
+ ...newDebugState,
387
+ variableReferences: new Map(newDebugState.variableReferences).set(toolCallsRef, {
388
+ type: 'array',
389
+ value: vibeValue.toolCalls,
390
+ }),
391
+ };
392
+ variables.push({
393
+ name: 'toolCalls',
394
+ value: `Array(${vibeValue.toolCalls.length})`,
395
+ type: 'array',
396
+ variablesReference: toolCallsRef,
397
+ hasToolCalls: true,
398
+ toolCallCount: vibeValue.toolCalls.length,
399
+ });
400
+ }
401
+ }
402
+ }
403
+
404
+ return { debugState: newDebugState, variables };
405
+ }
406
+
407
+ /**
408
+ * Create a variable from a value
409
+ */
410
+ function createVariable(
411
+ debugState: VibeDebugState,
412
+ name: string,
413
+ value: unknown,
414
+ typeAnnotation?: string | null
415
+ ): { debugState: VibeDebugState; variable: Variable } {
416
+ let variablesReference = 0;
417
+ let newDebugState = debugState;
418
+ let displayType = typeAnnotation ?? typeof value;
419
+ let hasError = false;
420
+ let errorMessage: string | undefined;
421
+ let hasToolCalls = false;
422
+ let toolCallCount: number | undefined;
423
+ let isPrivate = false;
424
+
425
+ // Check if it's a VibeValue
426
+ if (isVibeValue(value)) {
427
+ const vibeValue = value as any;
428
+ variablesReference = newDebugState.nextVariableRef++;
429
+ newDebugState = {
430
+ ...newDebugState,
431
+ variableReferences: new Map(newDebugState.variableReferences).set(variablesReference, {
432
+ type: 'vibeValue',
433
+ value: vibeValue,
434
+ }),
435
+ };
436
+ displayType = 'VibeValue';
437
+ hasError = !!vibeValue.err;
438
+ // Extract error message from errDetails object (err is now boolean)
439
+ errorMessage = vibeValue.errDetails?.message ? String(vibeValue.errDetails.message) : undefined;
440
+ hasToolCalls = vibeValue.toolCalls && vibeValue.toolCalls.length > 0;
441
+ toolCallCount = vibeValue.toolCalls?.length;
442
+ isPrivate = vibeValue.isPrivate === true;
443
+ } else if (Array.isArray(value)) {
444
+ variablesReference = newDebugState.nextVariableRef++;
445
+ newDebugState = {
446
+ ...newDebugState,
447
+ variableReferences: new Map(newDebugState.variableReferences).set(variablesReference, {
448
+ type: 'array',
449
+ value,
450
+ }),
451
+ };
452
+ displayType = 'array';
453
+ } else if (typeof value === 'object' && value !== null) {
454
+ variablesReference = newDebugState.nextVariableRef++;
455
+ newDebugState = {
456
+ ...newDebugState,
457
+ variableReferences: new Map(newDebugState.variableReferences).set(variablesReference, {
458
+ type: 'object',
459
+ value,
460
+ }),
461
+ };
462
+ displayType = 'object';
463
+ }
464
+
465
+ // Add [private] suffix to display name if variable is private
466
+ const displayName = isPrivate ? `${name} [private]` : name;
467
+
468
+ return {
469
+ debugState: newDebugState,
470
+ variable: {
471
+ name: displayName,
472
+ value: formatValue(value),
473
+ type: displayType,
474
+ variablesReference,
475
+ hasError,
476
+ errorMessage,
477
+ hasToolCalls,
478
+ toolCallCount,
479
+ ...(isPrivate ? { isPrivate: true } : {}),
480
+ },
481
+ };
482
+ }
483
+
484
+ /**
485
+ * Format a value for display
486
+ */
487
+ function formatValue(value: unknown): string {
488
+ if (value === null) return 'null';
489
+ if (value === undefined) return 'undefined';
490
+ if (typeof value === 'string') return `"${value.slice(0, 100)}${value.length > 100 ? '...' : ''}"`;
491
+ if (typeof value === 'number' || typeof value === 'boolean') return String(value);
492
+ if (Array.isArray(value)) return `Array(${value.length})`;
493
+ if (isVibeValue(value)) {
494
+ const v = value as any;
495
+ if (v.err) return `VibeValue(error: ${v.errDetails?.message ?? 'unknown error'})`;
496
+ return `VibeValue(${formatValue(v.value)})`;
497
+ }
498
+ if (typeof value === 'object') return `{...}`;
499
+ return String(value);
500
+ }
501
+
502
+ /**
503
+ * Check if a value is a VibeValue
504
+ */
505
+ function isVibeValue(value: unknown): boolean {
506
+ return (
507
+ typeof value === 'object' &&
508
+ value !== null &&
509
+ 'value' in value &&
510
+ ('err' in value || 'toolCalls' in value || 'typeAnnotation' in value)
511
+ );
512
+ }
513
+
514
+ /**
515
+ * Normalize file path for comparison
516
+ */
517
+ function normalizeFilePath(path: string): string {
518
+ return path.replace(/\\/g, '/').toLowerCase();
519
+ }
520
+
521
+ /**
522
+ * Get tool calls from a VibeValue
523
+ */
524
+ export function getToolCalls(
525
+ debugState: VibeDebugState,
526
+ variablesReference: number
527
+ ): ToolCallRecord[] {
528
+ const ref = debugState.variableReferences.get(variablesReference);
529
+ if (!ref || ref.type !== 'vibeValue') {
530
+ return [];
531
+ }
532
+
533
+ const vibeValue = ref.value as any;
534
+ if (!vibeValue?.toolCalls) {
535
+ return [];
536
+ }
537
+
538
+ return vibeValue.toolCalls.map((tc: any) => {
539
+ // Support both old format (error) and new format (err/errDetails)
540
+ const hasError = tc.err ?? (tc.error != null);
541
+ const errorMessage = tc.errDetails?.message ?? tc.error ?? null;
542
+ return {
543
+ toolName: tc.name ?? tc.toolName ?? 'unknown',
544
+ args: tc.args ?? tc.arguments ?? {},
545
+ result: tc.result,
546
+ err: hasError,
547
+ errDetails: hasError ? { message: errorMessage } : null,
548
+ duration: tc.duration ?? 0,
549
+ };
550
+ });
551
+ }
552
+
553
+ /**
554
+ * Get AI context entries
555
+ */
556
+ export function getContextEntries(
557
+ runtimeState: RuntimeState,
558
+ contextType: 'default' | 'local'
559
+ ): ContextEntry[] {
560
+ const entries: ContextEntry[] = [];
561
+
562
+ if (contextType === 'local') {
563
+ // Get local context
564
+ for (const entry of runtimeState.localContext ?? []) {
565
+ entries.push({
566
+ role: 'user',
567
+ content: `${entry.name}: ${entry.value}`,
568
+ });
569
+ }
570
+ } else {
571
+ // Get default context
572
+ for (const entry of runtimeState.defaultContext ?? []) {
573
+ entries.push({
574
+ role: entry.role as 'user' | 'assistant' | 'system' | 'tool',
575
+ content: String(entry.content),
576
+ });
577
+ }
578
+ }
579
+
580
+ return entries;
581
+ }