@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,452 @@
1
+ // Module loading system for Vibe
2
+ // Handles loading both TypeScript and Vibe imports with cycle detection
3
+
4
+ import * as AST from '../ast';
5
+ import { parse } from '../parser/parse';
6
+ import type { RuntimeState, TsModule, VibeModule, ExportedItem, VibeValue } from './types';
7
+ import { createVibeValue } from './types';
8
+ import { resolve, dirname, join } from 'path';
9
+
10
+ // Map system module names to their implementation files
11
+ const SYSTEM_MODULES: Record<string, string> = {
12
+ 'system': join(__dirname, 'stdlib', 'index.ts'),
13
+ 'system/tools': join(__dirname, 'stdlib', 'tools', 'index.ts'),
14
+ };
15
+
16
+ // Blocked system module paths - these cannot be imported
17
+ // Core functions (print, env) are auto-imported and cannot be explicitly imported
18
+ const BLOCKED_SYSTEM_MODULES = new Set([
19
+ 'system/core',
20
+ 'core',
21
+ ]);
22
+
23
+ // Check if an import source is a system module
24
+ function isSystemModule(source: string): boolean {
25
+ return source === 'system' || source.startsWith('system/');
26
+ }
27
+
28
+ // Resolve a module path, handling system modules specially
29
+ function resolveModulePath(source: string, basePath: string): string {
30
+ // Block certain system module paths that should not be importable
31
+ if (BLOCKED_SYSTEM_MODULES.has(source)) {
32
+ throw new Error(
33
+ `Import error: '${source}' cannot be imported. Core functions like print() and env() are auto-imported and available without explicit import.`
34
+ );
35
+ }
36
+
37
+ if (isSystemModule(source)) {
38
+ const systemPath = SYSTEM_MODULES[source];
39
+ if (!systemPath) {
40
+ throw new Error(`Unknown system module: '${source}'`);
41
+ }
42
+ return systemPath;
43
+ }
44
+ return resolve(dirname(basePath), source);
45
+ }
46
+
47
+ // Track modules currently being loaded (for cycle detection)
48
+ type LoadingSet = Set<string>;
49
+
50
+ // Load all imports from a program and return updated state
51
+ export async function loadImports(
52
+ state: RuntimeState,
53
+ basePath: string
54
+ ): Promise<RuntimeState> {
55
+ // Start with empty loading set for cycle detection
56
+ return loadImportsRecursive(state, basePath, new Set());
57
+ }
58
+
59
+ // Internal recursive loader with cycle detection
60
+ async function loadImportsRecursive(
61
+ state: RuntimeState,
62
+ basePath: string,
63
+ loading: LoadingSet
64
+ ): Promise<RuntimeState> {
65
+ const imports = state.program.body.filter(
66
+ (stmt): stmt is AST.ImportDeclaration => stmt.type === 'ImportDeclaration'
67
+ );
68
+
69
+ let newState = state;
70
+
71
+ for (const importDecl of imports) {
72
+ if (importDecl.sourceType === 'ts') {
73
+ newState = await loadTsModule(newState, importDecl, basePath);
74
+ } else {
75
+ newState = await loadVibeModuleRecursive(newState, importDecl, basePath, loading);
76
+ }
77
+ }
78
+
79
+ return newState;
80
+ }
81
+
82
+ // Load a TypeScript module using Bun's import()
83
+ async function loadTsModule(
84
+ state: RuntimeState,
85
+ importDecl: AST.ImportDeclaration,
86
+ basePath: string
87
+ ): Promise<RuntimeState> {
88
+ const modulePath = resolveModulePath(importDecl.source, basePath);
89
+
90
+ // Check if already loaded
91
+ if (state.tsModules[modulePath]) {
92
+ // Register the imported names (allows shared imports across modules)
93
+ return registerImportedNames(state, importDecl, modulePath, 'ts');
94
+ }
95
+
96
+ // Load the module using Bun's import()
97
+ const module = await import(modulePath);
98
+
99
+ // Extract the requested exports
100
+ const exports: Record<string, unknown> = {};
101
+ for (const spec of importDecl.specifiers) {
102
+ if (!(spec.imported in module)) {
103
+ throw new Error(
104
+ `Import error: '${spec.imported}' is not exported from '${importDecl.source}'`
105
+ );
106
+ }
107
+ exports[spec.local] = module[spec.imported];
108
+ }
109
+
110
+ const tsModule: TsModule = { exports };
111
+
112
+ const newState: RuntimeState = {
113
+ ...state,
114
+ tsModules: {
115
+ ...state.tsModules,
116
+ [modulePath]: tsModule,
117
+ },
118
+ };
119
+
120
+ // Register the imported names
121
+ return registerImportedNames(newState, importDecl, modulePath, 'ts');
122
+ }
123
+
124
+ // Load a Vibe module with recursive import loading and cycle detection
125
+ async function loadVibeModuleRecursive(
126
+ state: RuntimeState,
127
+ importDecl: AST.ImportDeclaration,
128
+ basePath: string,
129
+ loading: LoadingSet
130
+ ): Promise<RuntimeState> {
131
+ const modulePath = resolve(dirname(basePath), importDecl.source);
132
+
133
+ // Check for import cycle FIRST (before checking if loaded)
134
+ // This catches cycles even if the module was partially loaded
135
+ if (loading.has(modulePath)) {
136
+ // Build cycle path for error message
137
+ const cyclePath = [...loading, modulePath].join(' -> ');
138
+ throw new Error(
139
+ `Import error: Circular dependency detected: ${cyclePath}`
140
+ );
141
+ }
142
+
143
+ // Check if already loaded
144
+ if (state.vibeModules[modulePath]) {
145
+ // Register the imported names (allows shared imports across modules)
146
+ return registerImportedNames(state, importDecl, modulePath, 'vibe');
147
+ }
148
+
149
+ // Mark this module as being loaded
150
+ const newLoading = new Set(loading);
151
+ newLoading.add(modulePath);
152
+
153
+ // Read and parse the .vibe file
154
+ const source = await Bun.file(modulePath).text();
155
+ // Use import source path for error messages (relative path as written in import)
156
+ const program = parse(source, { file: importDecl.source });
157
+
158
+ // Extract exports from the program
159
+ const exports = extractVibeExports(program);
160
+
161
+ // Verify all requested imports exist
162
+ for (const spec of importDecl.specifiers) {
163
+ if (!(spec.imported in exports)) {
164
+ throw new Error(
165
+ `Import error: '${spec.imported}' is not exported from '${importDecl.source}'`
166
+ );
167
+ }
168
+ }
169
+
170
+ // Extract all module-level variables (for module scope isolation)
171
+ const globals = extractModuleGlobals(program);
172
+
173
+ const vibeModule: VibeModule = { exports, program, globals };
174
+
175
+ let newState: RuntimeState = {
176
+ ...state,
177
+ vibeModules: {
178
+ ...state.vibeModules,
179
+ [modulePath]: vibeModule,
180
+ },
181
+ };
182
+
183
+ // Recursively load this module's imports (these are NOT the main program's imports)
184
+ const moduleImports = program.body.filter(
185
+ (stmt): stmt is AST.ImportDeclaration => stmt.type === 'ImportDeclaration'
186
+ );
187
+
188
+ for (const nestedImport of moduleImports) {
189
+ if (nestedImport.sourceType === 'ts') {
190
+ newState = await loadTsModule(newState, nestedImport, modulePath);
191
+ } else {
192
+ newState = await loadVibeModuleRecursive(newState, nestedImport, modulePath, newLoading);
193
+ }
194
+ }
195
+
196
+ // Register the imported names
197
+ return registerImportedNames(newState, importDecl, modulePath, 'vibe');
198
+ }
199
+
200
+ // Extract exported items from a Vibe program
201
+ function extractVibeExports(program: AST.Program): Record<string, ExportedItem> {
202
+ const exports: Record<string, ExportedItem> = {};
203
+
204
+ for (const stmt of program.body) {
205
+ if (stmt.type !== 'ExportDeclaration') continue;
206
+
207
+ const decl = stmt.declaration;
208
+
209
+ switch (decl.type) {
210
+ case 'FunctionDeclaration':
211
+ exports[decl.name] = { kind: 'function', declaration: decl };
212
+ break;
213
+
214
+ case 'LetDeclaration':
215
+ exports[decl.name] = {
216
+ kind: 'variable',
217
+ name: decl.name,
218
+ value: null, // Will be evaluated when module runs
219
+ isConst: false,
220
+ typeAnnotation: decl.typeAnnotation,
221
+ };
222
+ break;
223
+
224
+ case 'ConstDeclaration':
225
+ exports[decl.name] = {
226
+ kind: 'variable',
227
+ name: decl.name,
228
+ value: null, // Will be evaluated when module runs
229
+ isConst: true,
230
+ typeAnnotation: decl.typeAnnotation,
231
+ };
232
+ break;
233
+
234
+ case 'ModelDeclaration':
235
+ exports[decl.name] = { kind: 'model', declaration: decl };
236
+ break;
237
+ }
238
+ }
239
+
240
+ return exports;
241
+ }
242
+
243
+ // Extract all module-level variables (both exported and non-exported)
244
+ // These form the module's isolated global scope
245
+ function extractModuleGlobals(program: AST.Program): Record<string, VibeValue> {
246
+ const globals: Record<string, VibeValue> = {};
247
+
248
+ for (const stmt of program.body) {
249
+ // Handle direct declarations
250
+ if (stmt.type === 'LetDeclaration') {
251
+ globals[stmt.name] = createVibeValue(evaluateSimpleLiteral(stmt.initializer), {
252
+ isConst: false,
253
+ typeAnnotation: stmt.typeAnnotation,
254
+ });
255
+ } else if (stmt.type === 'ConstDeclaration') {
256
+ globals[stmt.name] = createVibeValue(evaluateSimpleLiteral(stmt.initializer), {
257
+ isConst: true,
258
+ typeAnnotation: stmt.typeAnnotation,
259
+ });
260
+ }
261
+ // Handle exported declarations
262
+ else if (stmt.type === 'ExportDeclaration') {
263
+ const decl = stmt.declaration;
264
+ if (decl.type === 'LetDeclaration') {
265
+ globals[decl.name] = createVibeValue(evaluateSimpleLiteral(decl.initializer), {
266
+ isConst: false,
267
+ typeAnnotation: decl.typeAnnotation,
268
+ });
269
+ } else if (decl.type === 'ConstDeclaration') {
270
+ globals[decl.name] = createVibeValue(evaluateSimpleLiteral(decl.initializer), {
271
+ isConst: true,
272
+ typeAnnotation: decl.typeAnnotation,
273
+ });
274
+ }
275
+ }
276
+ // Note: Functions and models are accessed via exports, not globals
277
+ }
278
+
279
+ return globals;
280
+ }
281
+
282
+ // Evaluate simple literal expressions for module initialization
283
+ // Complex expressions will be null (would need full runtime evaluation)
284
+ function evaluateSimpleLiteral(expr: AST.Expression | null): unknown {
285
+ if (!expr) return null;
286
+
287
+ switch (expr.type) {
288
+ case 'StringLiteral':
289
+ return expr.value;
290
+ case 'NumberLiteral':
291
+ return expr.value;
292
+ case 'BooleanLiteral':
293
+ return expr.value;
294
+ case 'NullLiteral':
295
+ return null;
296
+ case 'ArrayLiteral':
297
+ return expr.elements.map(e => evaluateSimpleLiteral(e));
298
+ case 'ObjectLiteral':
299
+ const obj: Record<string, unknown> = {};
300
+ for (const prop of expr.properties) {
301
+ obj[prop.key] = evaluateSimpleLiteral(prop.value);
302
+ }
303
+ return obj;
304
+ default:
305
+ // Complex expression - can't evaluate statically
306
+ return null;
307
+ }
308
+ }
309
+
310
+ // Register imported names in the state for lookup
311
+ function registerImportedNames(
312
+ state: RuntimeState,
313
+ importDecl: AST.ImportDeclaration,
314
+ modulePath: string,
315
+ sourceType: 'ts' | 'vibe'
316
+ ): RuntimeState {
317
+ const newImportedNames = { ...state.importedNames };
318
+
319
+ for (const spec of importDecl.specifiers) {
320
+ // Check for name collision
321
+ if (newImportedNames[spec.local]) {
322
+ const existing = newImportedNames[spec.local];
323
+ // Allow same import from same source (nested modules can share imports)
324
+ if (existing.source === modulePath && existing.sourceType === sourceType) {
325
+ continue; // Already registered, skip
326
+ }
327
+ throw new Error(
328
+ `Import error: '${spec.local}' is already imported from '${existing.source}'`
329
+ );
330
+ }
331
+
332
+ newImportedNames[spec.local] = {
333
+ source: modulePath,
334
+ sourceType,
335
+ };
336
+ }
337
+
338
+ return {
339
+ ...state,
340
+ importedNames: newImportedNames,
341
+ };
342
+ }
343
+
344
+ // Get an imported value by name
345
+ export function getImportedValue(
346
+ state: RuntimeState,
347
+ name: string
348
+ ): unknown | undefined {
349
+ const importInfo = state.importedNames[name];
350
+ if (!importInfo) return undefined;
351
+
352
+ if (importInfo.sourceType === 'ts') {
353
+ const module = state.tsModules[importInfo.source];
354
+ return module?.exports[name];
355
+ } else {
356
+ const module = state.vibeModules[importInfo.source];
357
+ const exported = module?.exports[name];
358
+ if (!exported) return undefined;
359
+
360
+ if (exported.kind === 'function') {
361
+ // Return a marker that this is an imported Vibe function
362
+ return { __vibeImportedFunction: true, name, source: importInfo.source };
363
+ } else if (exported.kind === 'variable') {
364
+ return exported.value;
365
+ } else if (exported.kind === 'model') {
366
+ // Return the model config as a value
367
+ return { __vibeModel: true, ...exported.declaration.config };
368
+ }
369
+ }
370
+
371
+ return undefined;
372
+ }
373
+
374
+ // Check if a name is an imported TypeScript function
375
+ export function isImportedTsFunction(
376
+ state: RuntimeState,
377
+ name: string
378
+ ): boolean {
379
+ const importInfo = state.importedNames[name];
380
+ if (!importInfo || importInfo.sourceType !== 'ts') return false;
381
+
382
+ const module = state.tsModules[importInfo.source];
383
+ const value = module?.exports[name];
384
+ return typeof value === 'function';
385
+ }
386
+
387
+ // Check if a name is an imported Vibe function
388
+ export function isImportedVibeFunction(
389
+ state: RuntimeState,
390
+ name: string
391
+ ): boolean {
392
+ const importInfo = state.importedNames[name];
393
+ if (!importInfo || importInfo.sourceType !== 'vibe') return false;
394
+
395
+ const module = state.vibeModules[importInfo.source];
396
+ const exported = module?.exports[name];
397
+ return exported?.kind === 'function';
398
+ }
399
+
400
+ // Get an imported Vibe function declaration
401
+ export function getImportedVibeFunction(
402
+ state: RuntimeState,
403
+ name: string
404
+ ): AST.FunctionDeclaration | undefined {
405
+ const importInfo = state.importedNames[name];
406
+ if (!importInfo || importInfo.sourceType !== 'vibe') return undefined;
407
+
408
+ const module = state.vibeModules[importInfo.source];
409
+ const exported = module?.exports[name];
410
+ if (exported?.kind !== 'function') return undefined;
411
+
412
+ return exported.declaration;
413
+ }
414
+
415
+ // Get an imported TypeScript function
416
+ export function getImportedTsFunction(
417
+ state: RuntimeState,
418
+ name: string
419
+ ): ((...args: unknown[]) => unknown) | undefined {
420
+ const importInfo = state.importedNames[name];
421
+ if (!importInfo || importInfo.sourceType !== 'ts') return undefined;
422
+
423
+ const module = state.tsModules[importInfo.source];
424
+ const value = module?.exports[name];
425
+ if (typeof value !== 'function') return undefined;
426
+
427
+ return value as (...args: unknown[]) => unknown;
428
+ }
429
+
430
+ // Get the module path for an imported Vibe function
431
+ // Returns undefined if not an imported Vibe function
432
+ export function getImportedVibeFunctionModulePath(
433
+ state: RuntimeState,
434
+ name: string
435
+ ): string | undefined {
436
+ const importInfo = state.importedNames[name];
437
+ if (!importInfo || importInfo.sourceType !== 'vibe') return undefined;
438
+
439
+ const module = state.vibeModules[importInfo.source];
440
+ const exported = module?.exports[name];
441
+ if (exported?.kind !== 'function') return undefined;
442
+
443
+ return importInfo.source;
444
+ }
445
+
446
+ // Get module globals by module path
447
+ export function getModuleGlobals(
448
+ state: RuntimeState,
449
+ modulePath: string
450
+ ): Record<string, VibeValue> | undefined {
451
+ return state.vibeModules[modulePath]?.globals;
452
+ }
@@ -0,0 +1,103 @@
1
+ import type { RuntimeState } from './types';
2
+
3
+ // Serialize runtime state to JSON string
4
+ export function serializeState(state: RuntimeState): string {
5
+ return JSON.stringify(state, null, 2);
6
+ }
7
+
8
+ // Deserialize runtime state from JSON string
9
+ export function deserializeState(json: string): RuntimeState {
10
+ const state = JSON.parse(json) as RuntimeState;
11
+
12
+ // Validate required fields
13
+ if (!state.status) {
14
+ throw new Error('Invalid state: missing status');
15
+ }
16
+ if (!state.program) {
17
+ throw new Error('Invalid state: missing program');
18
+ }
19
+ if (!Array.isArray(state.callStack)) {
20
+ throw new Error('Invalid state: missing or invalid callStack');
21
+ }
22
+ if (!Array.isArray(state.instructionStack)) {
23
+ throw new Error('Invalid state: missing or invalid instructionStack');
24
+ }
25
+
26
+ return state;
27
+ }
28
+
29
+ // Create a deep clone of the state (useful for debugging/testing)
30
+ export function cloneState(state: RuntimeState): RuntimeState {
31
+ return JSON.parse(JSON.stringify(state)) as RuntimeState;
32
+ }
33
+
34
+ /**
35
+ * Create a true deep clone of the state, properly handling Maps and Sets.
36
+ * Handles non-cloneable objects like Promises by omitting them.
37
+ */
38
+ export function deepCloneState(state: RuntimeState): RuntimeState {
39
+ // Create a version of the state without non-cloneable objects (Promises)
40
+ // We need to strip promises from asyncOperations before cloning
41
+ const cleanAsyncOps = new Map<string, unknown>();
42
+ for (const [id, op] of state.asyncOperations) {
43
+ // Clone operation without the promise field
44
+ const { promise, ...rest } = op;
45
+ cleanAsyncOps.set(id, rest);
46
+ }
47
+
48
+ // Create a clean state object for cloning
49
+ const stateForCloning = {
50
+ ...state,
51
+ asyncOperations: cleanAsyncOps,
52
+ };
53
+
54
+ // Now we can safely use structuredClone
55
+ const cloned = structuredClone(stateForCloning);
56
+
57
+ // Restore proper typing for asyncOperations Map
58
+ return {
59
+ ...cloned,
60
+ asyncOperations: cloned.asyncOperations as RuntimeState['asyncOperations'],
61
+ };
62
+ }
63
+
64
+ // Get a summary of the current state (for debugging)
65
+ export function getStateSummary(state: RuntimeState): {
66
+ status: string;
67
+ frameCount: number;
68
+ currentFrame: string;
69
+ instructionCount: number;
70
+ nextInstruction: string | null;
71
+ variables: Record<string, unknown>;
72
+ lastResult: unknown;
73
+ pendingAsyncCount: number;
74
+ } {
75
+ const currentFrame = state.callStack[state.callStack.length - 1];
76
+ const nextInstruction = state.instructionStack[0];
77
+
78
+ const variables: Record<string, unknown> = {};
79
+ if (currentFrame) {
80
+ for (const [name, variable] of Object.entries(currentFrame.locals)) {
81
+ // Check if this is a pending async variable
82
+ if (variable.asyncOperationId) {
83
+ const op = state.asyncOperations.get(variable.asyncOperationId);
84
+ if (op && (op.status === 'pending' || op.status === 'running')) {
85
+ variables[name] = `[pending: ${op.operationType}]`;
86
+ continue;
87
+ }
88
+ }
89
+ variables[name] = variable.value;
90
+ }
91
+ }
92
+
93
+ return {
94
+ status: state.status,
95
+ frameCount: state.callStack.length,
96
+ currentFrame: currentFrame?.name ?? 'none',
97
+ instructionCount: state.instructionStack.length,
98
+ nextInstruction: nextInstruction ? nextInstruction.op : null,
99
+ variables,
100
+ lastResult: state.lastResult,
101
+ pendingAsyncCount: state.pendingAsyncIds.size,
102
+ };
103
+ }