@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,276 @@
1
+ /**
2
+ * Dependency detection for async operations.
3
+ * Scans expressions for variable references and builds execution waves.
4
+ */
5
+
6
+ import type * as AST from '../../ast';
7
+ import type { AsyncOperation, AsyncWave, ContextEntry } from '../types';
8
+
9
+ /**
10
+ * Extracts all variable names referenced in an expression.
11
+ * Used to detect dependencies between async operations.
12
+ */
13
+ export function getReferencedVariables(expr: AST.Expression): string[] {
14
+ const variables: string[] = [];
15
+
16
+ function visit(node: AST.Expression): void {
17
+ switch (node.type) {
18
+ case 'Identifier':
19
+ variables.push(node.name);
20
+ break;
21
+
22
+ case 'BinaryExpression':
23
+ visit(node.left);
24
+ visit(node.right);
25
+ break;
26
+
27
+ case 'UnaryExpression':
28
+ visit(node.operand);
29
+ break;
30
+
31
+ case 'CallExpression':
32
+ visit(node.callee);
33
+ node.arguments.forEach(visit);
34
+ break;
35
+
36
+ case 'MemberExpression':
37
+ visit(node.object);
38
+ break;
39
+
40
+ case 'IndexExpression':
41
+ visit(node.object);
42
+ visit(node.index);
43
+ break;
44
+
45
+ case 'SliceExpression':
46
+ visit(node.object);
47
+ if (node.start) visit(node.start);
48
+ if (node.end) visit(node.end);
49
+ break;
50
+
51
+ case 'ArrayLiteral':
52
+ node.elements.forEach(visit);
53
+ break;
54
+
55
+ case 'ObjectLiteral':
56
+ node.properties.forEach((prop) => visit(prop.value));
57
+ break;
58
+
59
+ case 'RangeExpression':
60
+ visit(node.start);
61
+ visit(node.end);
62
+ break;
63
+
64
+ case 'AssignmentExpression':
65
+ visit(node.value);
66
+ break;
67
+
68
+ case 'VibeExpression':
69
+ visit(node.prompt);
70
+ if (node.model) visit(node.model);
71
+ break;
72
+
73
+ case 'TsBlock':
74
+ // TsBlock params are variable references
75
+ variables.push(...node.params);
76
+ break;
77
+
78
+ case 'TemplateLiteral':
79
+ // Extract variables from template interpolations like {varName}
80
+ const matches = node.value.matchAll(/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g);
81
+ for (const match of matches) {
82
+ variables.push(match[1]);
83
+ }
84
+ break;
85
+
86
+ // Literals don't reference variables
87
+ case 'StringLiteral':
88
+ case 'NumberLiteral':
89
+ case 'BooleanLiteral':
90
+ case 'NullLiteral':
91
+ break;
92
+ }
93
+ }
94
+
95
+ visit(expr);
96
+ return [...new Set(variables)]; // Remove duplicates
97
+ }
98
+
99
+ /**
100
+ * Detects which async operations the given expression depends on.
101
+ * Returns the IDs of async operations that must complete before this expression can be evaluated.
102
+ */
103
+ export function detectAsyncDependencies(
104
+ expr: AST.Expression,
105
+ asyncVarToOpId: Map<string, string>,
106
+ pendingAsyncIds: Set<string>
107
+ ): string[] {
108
+ const referencedVars = getReferencedVariables(expr);
109
+ const dependencies: string[] = [];
110
+
111
+ for (const varName of referencedVars) {
112
+ const opId = asyncVarToOpId.get(varName);
113
+ if (opId && pendingAsyncIds.has(opId)) {
114
+ dependencies.push(opId);
115
+ }
116
+ }
117
+
118
+ return dependencies;
119
+ }
120
+
121
+ /**
122
+ * Builds execution waves from a list of async operations.
123
+ * Operations with no pending dependencies go in the same wave.
124
+ * Uses topological sort to determine execution order.
125
+ */
126
+ export function buildExecutionWaves(
127
+ operations: AsyncOperation[],
128
+ contextSnapshot: ContextEntry[]
129
+ ): AsyncWave[] {
130
+ const waves: AsyncWave[] = [];
131
+ const remaining = new Set(operations.map((op) => op.id));
132
+ const completed = new Set<string>();
133
+
134
+ // Map from operation ID to operation
135
+ const opById = new Map(operations.map((op) => [op.id, op]));
136
+
137
+ // Map from variable name to operation ID
138
+ const varToOp = new Map<string, string>();
139
+ for (const op of operations) {
140
+ if (op.variableName) {
141
+ varToOp.set(op.variableName, op.id);
142
+ }
143
+ }
144
+
145
+ let waveId = 0;
146
+ while (remaining.size > 0) {
147
+ const waveOps: string[] = [];
148
+
149
+ for (const opId of remaining) {
150
+ const op = opById.get(opId)!;
151
+
152
+ // Check if all dependencies are completed (or not in our operation set)
153
+ const depsReady = op.dependencies.every((depVar) => {
154
+ const depOpId = varToOp.get(depVar);
155
+ return !depOpId || completed.has(depOpId) || !remaining.has(depOpId);
156
+ });
157
+
158
+ if (depsReady) {
159
+ waveOps.push(opId);
160
+ }
161
+ }
162
+
163
+ if (waveOps.length === 0 && remaining.size > 0) {
164
+ // Circular dependency detected - should be caught at semantic analysis
165
+ throw new Error('Circular dependency detected in async operations');
166
+ }
167
+
168
+ // Create the wave
169
+ const wave: AsyncWave = {
170
+ id: waveId,
171
+ operationIds: waveOps,
172
+ contextSnapshot: [...contextSnapshot], // Copy context at wave creation
173
+ startTime: 0, // Will be set when wave executes
174
+ };
175
+ waves.push(wave);
176
+
177
+ // Mark operations as completed for next iteration
178
+ for (const opId of waveOps) {
179
+ remaining.delete(opId);
180
+ completed.add(opId);
181
+ }
182
+
183
+ waveId++;
184
+ }
185
+
186
+ return waves;
187
+ }
188
+
189
+ /**
190
+ * Gets variable names that an instruction references.
191
+ * Used to check if an instruction needs to await pending async operations.
192
+ */
193
+ export function getInstructionDependencies(
194
+ instruction: { op: string; [key: string]: unknown },
195
+ asyncVarToOpId: Map<string, string>,
196
+ pendingAsyncIds: Set<string>
197
+ ): string[] {
198
+ const dependencies: string[] = [];
199
+
200
+ // Check expression-based instructions
201
+ if ('expr' in instruction && instruction.expr) {
202
+ const expr = instruction.expr as AST.Expression;
203
+ const deps = detectAsyncDependencies(expr, asyncVarToOpId, pendingAsyncIds);
204
+ dependencies.push(...deps);
205
+ }
206
+
207
+ // Check statement-based instructions
208
+ if ('stmt' in instruction && instruction.stmt) {
209
+ const stmt = instruction.stmt as AST.Statement;
210
+ const stmtDeps = getStatementDependencies(stmt, asyncVarToOpId, pendingAsyncIds);
211
+ dependencies.push(...stmtDeps);
212
+ }
213
+
214
+ return [...new Set(dependencies)];
215
+ }
216
+
217
+ /**
218
+ * Gets async operation IDs that a statement depends on.
219
+ */
220
+ function getStatementDependencies(
221
+ stmt: AST.Statement,
222
+ asyncVarToOpId: Map<string, string>,
223
+ pendingAsyncIds: Set<string>
224
+ ): string[] {
225
+ const dependencies: string[] = [];
226
+
227
+ switch (stmt.type) {
228
+ case 'LetDeclaration':
229
+ case 'ConstDeclaration':
230
+ if (stmt.initializer) {
231
+ dependencies.push(...detectAsyncDependencies(stmt.initializer, asyncVarToOpId, pendingAsyncIds));
232
+ }
233
+ break;
234
+
235
+ case 'DestructuringDeclaration':
236
+ dependencies.push(...detectAsyncDependencies(stmt.initializer, asyncVarToOpId, pendingAsyncIds));
237
+ break;
238
+
239
+ case 'ExpressionStatement':
240
+ dependencies.push(...detectAsyncDependencies(stmt.expression, asyncVarToOpId, pendingAsyncIds));
241
+ break;
242
+
243
+ case 'IfStatement':
244
+ dependencies.push(...detectAsyncDependencies(stmt.condition, asyncVarToOpId, pendingAsyncIds));
245
+ break;
246
+
247
+ case 'WhileStatement':
248
+ dependencies.push(...detectAsyncDependencies(stmt.condition, asyncVarToOpId, pendingAsyncIds));
249
+ break;
250
+
251
+ case 'ForInStatement':
252
+ dependencies.push(...detectAsyncDependencies(stmt.iterable, asyncVarToOpId, pendingAsyncIds));
253
+ break;
254
+
255
+ case 'ReturnStatement':
256
+ if (stmt.value) {
257
+ dependencies.push(...detectAsyncDependencies(stmt.value, asyncVarToOpId, pendingAsyncIds));
258
+ }
259
+ break;
260
+
261
+ case 'AsyncStatement':
262
+ dependencies.push(...detectAsyncDependencies(stmt.expression, asyncVarToOpId, pendingAsyncIds));
263
+ break;
264
+
265
+ // Declarations that don't have expression dependencies
266
+ case 'ImportDeclaration':
267
+ case 'ExportDeclaration':
268
+ case 'ModelDeclaration':
269
+ case 'FunctionDeclaration':
270
+ case 'ToolDeclaration':
271
+ case 'BlockStatement':
272
+ break;
273
+ }
274
+
275
+ return dependencies;
276
+ }
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Async execution engine.
3
+ * Executes async operations in waves with throttling.
4
+ */
5
+
6
+ import type { RuntimeState, AsyncOperation, AsyncWave, VibeValue, VibeError, ContextEntry } from '../types';
7
+ import { createVibeValue, createVibeError } from '../types';
8
+
9
+ /**
10
+ * Simple semaphore for limiting concurrent operations.
11
+ */
12
+ class Semaphore {
13
+ private permits: number;
14
+ private waiting: Array<() => void> = [];
15
+
16
+ constructor(permits: number) {
17
+ this.permits = permits;
18
+ }
19
+
20
+ async acquire(): Promise<void> {
21
+ if (this.permits > 0) {
22
+ this.permits--;
23
+ return;
24
+ }
25
+
26
+ return new Promise((resolve) => {
27
+ this.waiting.push(resolve);
28
+ });
29
+ }
30
+
31
+ release(): void {
32
+ const next = this.waiting.shift();
33
+ if (next) {
34
+ next();
35
+ } else {
36
+ this.permits++;
37
+ }
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Result of executing an async operation.
43
+ */
44
+ export interface AsyncExecutionResult {
45
+ operationId: string;
46
+ result?: VibeValue;
47
+ error?: VibeError;
48
+ }
49
+
50
+ /**
51
+ * Executor function type for running a single async operation.
52
+ * This will be provided by the runtime to handle different operation types.
53
+ */
54
+ export type AsyncOperationExecutor = (
55
+ operation: AsyncOperation,
56
+ contextSnapshot: ContextEntry[]
57
+ ) => Promise<VibeValue>;
58
+
59
+ /**
60
+ * Executes all operations in a wave with parallelism throttling.
61
+ * Returns the results of all operations.
62
+ */
63
+ export async function executeWave(
64
+ wave: AsyncWave,
65
+ operations: Map<string, AsyncOperation>,
66
+ executor: AsyncOperationExecutor,
67
+ maxParallel: number
68
+ ): Promise<AsyncExecutionResult[]> {
69
+ const semaphore = new Semaphore(maxParallel);
70
+ const startTime = Date.now();
71
+
72
+ // Update wave start time
73
+ wave.startTime = startTime;
74
+
75
+ const results = await Promise.all(
76
+ wave.operationIds.map(async (opId) => {
77
+ const operation = operations.get(opId);
78
+ if (!operation) {
79
+ return {
80
+ operationId: opId,
81
+ error: {
82
+ message: `Operation ${opId} not found`,
83
+ type: 'InternalError',
84
+ location: null,
85
+ },
86
+ };
87
+ }
88
+
89
+ await semaphore.acquire();
90
+
91
+ try {
92
+ // Update operation status
93
+ operation.status = 'running';
94
+ operation.startTime = Date.now();
95
+
96
+ // Execute the operation
97
+ const result = await executor(operation, wave.contextSnapshot);
98
+
99
+ // Update operation with result
100
+ operation.status = 'completed';
101
+ operation.endTime = Date.now();
102
+ operation.result = result;
103
+
104
+ return { operationId: opId, result };
105
+ } catch (err) {
106
+ // Handle exceptions (these crash the program per design)
107
+ const error: VibeError = {
108
+ message: err instanceof Error ? err.message : String(err),
109
+ type: err instanceof Error ? err.constructor.name : 'Error',
110
+ location: null,
111
+ stack: err instanceof Error ? err.stack : undefined,
112
+ };
113
+
114
+ operation.status = 'failed';
115
+ operation.endTime = Date.now();
116
+ operation.error = error;
117
+
118
+ return { operationId: opId, error };
119
+ } finally {
120
+ semaphore.release();
121
+ }
122
+ })
123
+ );
124
+
125
+ wave.endTime = Date.now();
126
+ return results;
127
+ }
128
+
129
+ /**
130
+ * Awaits specific async operations by their IDs.
131
+ * Returns when all specified operations are complete.
132
+ */
133
+ export async function awaitOperations(
134
+ operationIds: string[],
135
+ operations: Map<string, AsyncOperation>
136
+ ): Promise<Map<string, VibeValue>> {
137
+ const results = new Map<string, VibeValue>();
138
+
139
+ for (const opId of operationIds) {
140
+ const operation = operations.get(opId);
141
+ if (!operation) {
142
+ results.set(opId, createVibeError(`Operation ${opId} not found`));
143
+ continue;
144
+ }
145
+
146
+ // If operation has a promise, wait for it
147
+ if (operation.promise) {
148
+ try {
149
+ const result = await operation.promise;
150
+ results.set(opId, result);
151
+ } catch (err) {
152
+ results.set(opId, createVibeError(err instanceof Error ? err : String(err)));
153
+ }
154
+ } else if (operation.result) {
155
+ // Already completed
156
+ results.set(opId, operation.result);
157
+ } else if (operation.error) {
158
+ // Already failed
159
+ results.set(opId, createVibeError(operation.error.message));
160
+ } else {
161
+ // Operation not started yet - this shouldn't happen
162
+ results.set(opId, createVibeError(`Operation ${opId} has not started`));
163
+ }
164
+ }
165
+
166
+ return results;
167
+ }
168
+
169
+ /**
170
+ * Awaits all pending async operations in the state.
171
+ * Used at block boundaries and before sync instructions that need async results.
172
+ */
173
+ export async function awaitAllPending(
174
+ state: RuntimeState
175
+ ): Promise<Map<string, VibeValue>> {
176
+ const pendingIds = Array.from(state.pendingAsyncIds);
177
+ return awaitOperations(pendingIds, state.asyncOperations);
178
+ }
179
+
180
+ /**
181
+ * Awaits async operations that a variable depends on.
182
+ * Used for implicit await when a variable's value is needed.
183
+ */
184
+ export async function awaitVariable(
185
+ variableName: string,
186
+ state: RuntimeState
187
+ ): Promise<VibeValue | null> {
188
+ const opId = state.asyncVarToOpId.get(variableName);
189
+ if (!opId) {
190
+ return null; // Not an async variable
191
+ }
192
+
193
+ if (!state.pendingAsyncIds.has(opId)) {
194
+ // Already completed
195
+ const operation = state.asyncOperations.get(opId);
196
+ return operation?.result ?? null;
197
+ }
198
+
199
+ const results = await awaitOperations([opId], state.asyncOperations);
200
+ return results.get(opId) ?? null;
201
+ }
202
+
203
+ /**
204
+ * Generates a unique async operation ID.
205
+ * Note: Caller is responsible for incrementing state.nextAsyncId.
206
+ */
207
+ export function generateAsyncId(state: RuntimeState): string {
208
+ return `async-${String(state.nextAsyncId).padStart(6, '0')}`;
209
+ }
210
+
211
+ /**
212
+ * Registers a new async operation in the state.
213
+ */
214
+ export function registerAsyncOperation(
215
+ state: RuntimeState,
216
+ operation: Omit<AsyncOperation, 'id' | 'waveId'>
217
+ ): AsyncOperation {
218
+ const id = generateAsyncId(state);
219
+ const fullOperation: AsyncOperation = {
220
+ ...operation,
221
+ id,
222
+ waveId: state.currentWaveId,
223
+ };
224
+
225
+ state.asyncOperations.set(id, fullOperation);
226
+ state.pendingAsyncIds.add(id);
227
+
228
+ if (operation.variableName) {
229
+ state.asyncVarToOpId.set(operation.variableName, id);
230
+ }
231
+
232
+ return fullOperation;
233
+ }
234
+
235
+ /**
236
+ * Marks an async operation as complete and removes from pending.
237
+ */
238
+ export function completeAsyncOperation(
239
+ state: RuntimeState,
240
+ operationId: string,
241
+ result: VibeValue
242
+ ): void {
243
+ const operation = state.asyncOperations.get(operationId);
244
+ if (operation) {
245
+ operation.status = 'completed';
246
+ operation.endTime = Date.now();
247
+ operation.result = result;
248
+ }
249
+ state.pendingAsyncIds.delete(operationId);
250
+ }
251
+
252
+ /**
253
+ * Marks an async operation as failed and removes from pending.
254
+ */
255
+ export function failAsyncOperation(
256
+ state: RuntimeState,
257
+ operationId: string,
258
+ error: VibeError
259
+ ): void {
260
+ const operation = state.asyncOperations.get(operationId);
261
+ if (operation) {
262
+ operation.status = 'failed';
263
+ operation.endTime = Date.now();
264
+ operation.error = error;
265
+ }
266
+ state.pendingAsyncIds.delete(operationId);
267
+ }
268
+
269
+ /**
270
+ * Checks if any async operations are still pending.
271
+ */
272
+ export function hasPendingAsync(state: RuntimeState): boolean {
273
+ return state.pendingAsyncIds.size > 0;
274
+ }
275
+
276
+ /**
277
+ * Gets the IDs of pending async operations that a list of variables depend on.
278
+ */
279
+ export function getPendingDependencies(
280
+ variableNames: string[],
281
+ state: RuntimeState
282
+ ): string[] {
283
+ const deps: string[] = [];
284
+
285
+ for (const varName of variableNames) {
286
+ const opId = state.asyncVarToOpId.get(varName);
287
+ if (opId && state.pendingAsyncIds.has(opId)) {
288
+ deps.push(opId);
289
+ }
290
+ }
291
+
292
+ return deps;
293
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Async execution module for parallel operations.
3
+ *
4
+ * This module provides:
5
+ * - Dependency detection for async operations
6
+ * - Wave-based execution with throttling
7
+ * - Async operation scheduling helpers
8
+ * - Utilities for managing async operation state
9
+ */
10
+
11
+ // Dependency detection
12
+ export {
13
+ getReferencedVariables,
14
+ detectAsyncDependencies,
15
+ buildExecutionWaves,
16
+ getInstructionDependencies,
17
+ } from './dependencies';
18
+
19
+ // Execution engine
20
+ export {
21
+ executeWave,
22
+ awaitOperations,
23
+ awaitAllPending,
24
+ awaitVariable,
25
+ generateAsyncId,
26
+ registerAsyncOperation,
27
+ completeAsyncOperation,
28
+ failAsyncOperation,
29
+ hasPendingAsync,
30
+ getPendingDependencies,
31
+ } from './executor';
32
+
33
+ // Scheduling helpers
34
+ export {
35
+ scheduleAsyncOperation,
36
+ clearAsyncContext,
37
+ isInAsyncContext,
38
+ createAsyncVibeError,
39
+ startAsyncOperation,
40
+ } from './scheduling';
41
+
42
+ export type { AsyncExecutionResult, AsyncOperationExecutor } from './executor';
43
+ export type { AsyncOperationDetails } from './scheduling';