@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
package/src/index.ts ADDED
@@ -0,0 +1,358 @@
1
+ // Version (updated by publish script)
2
+ export const VERSION = '0.2.4';
3
+
4
+ // Re-export public API
5
+ export { VibeLexer, tokenize, allTokens } from './lexer';
6
+ export { vibeParser } from './parser';
7
+ export { parse } from './parser/parse';
8
+ export { analyze } from './semantic';
9
+ export { Runtime, RuntimeStatus } from './runtime';
10
+ export type { RuntimeState, AIProvider } from './runtime';
11
+ export * as AST from './ast';
12
+ export * from './errors';
13
+
14
+ import { parse } from './parser/parse';
15
+ import { analyze } from './semantic';
16
+ import { Runtime, AIProvider, createRealAIProvider } from './runtime';
17
+ import { readdirSync, rmSync, statSync } from 'fs';
18
+ import { join, dirname } from 'path';
19
+
20
+ // Clean up orphaned temp directories from previous failed updates (Windows)
21
+ function cleanupOrphanedDirs(): void {
22
+ if (process.platform !== 'win32') return;
23
+
24
+ try {
25
+ // Find @vibe-lang in the executable path (works with nvm, volta, standard installs)
26
+ const execPath = process.execPath;
27
+ const marker = '@vibe-lang';
28
+ const markerIndex = execPath.indexOf(marker);
29
+ if (markerIndex === -1) return;
30
+
31
+ // Construct path to node_modules/@vibe-lang
32
+ const vibeLangDir = execPath.substring(0, markerIndex + marker.length);
33
+
34
+ const entries = readdirSync(vibeLangDir);
35
+
36
+ // Look for orphaned .vibe-* temp directories
37
+ for (const entry of entries) {
38
+ if (entry.startsWith('.vibe-')) {
39
+ const fullPath = join(vibeLangDir, entry);
40
+ try {
41
+ const stat = statSync(fullPath);
42
+ // Only delete if it's a directory and older than 1 minute
43
+ if (stat.isDirectory() && Date.now() - stat.mtimeMs > 60000) {
44
+ rmSync(fullPath, { recursive: true, force: true });
45
+ }
46
+ } catch {
47
+ // Ignore errors - directory may still be locked
48
+ }
49
+ }
50
+ }
51
+ } catch {
52
+ // Silently ignore cleanup errors
53
+ }
54
+ }
55
+
56
+ // Simple mock AI provider for testing
57
+ class MockAIProvider implements AIProvider {
58
+ async execute(prompt: string) {
59
+ return { value: `[AI Response to: ${prompt}]` };
60
+ }
61
+
62
+ async generateCode(prompt: string) {
63
+ return { value: `// Generated code for: ${prompt}\nlet result = "generated"` };
64
+ }
65
+
66
+ async askUser(prompt: string): Promise<string> {
67
+ return `[User response to: ${prompt}]`;
68
+ }
69
+ }
70
+
71
+ // Options for running a vibe program
72
+ export interface RunVibeOptions {
73
+ aiProvider?: AIProvider;
74
+ file?: string;
75
+ }
76
+
77
+ // Main function to run a vibe program
78
+ export async function runVibe(source: string, options?: RunVibeOptions): Promise<unknown> {
79
+ // 1. Parse
80
+ const ast = parse(source, { file: options?.file });
81
+
82
+ // 2. Semantic analysis
83
+ const errors = analyze(ast, source);
84
+ if (errors.length > 0) {
85
+ throw errors[0];
86
+ }
87
+
88
+ // 3. Runtime
89
+ const runtime = new Runtime(ast, options?.aiProvider ?? new MockAIProvider(), { basePath: options?.file });
90
+ return runtime.run();
91
+ }
92
+
93
+ // CLI entry point
94
+ async function main(): Promise<void> {
95
+ // Clean up orphaned temp directories from previous updates
96
+ cleanupOrphanedDirs();
97
+
98
+ const args = Bun.argv.slice(2);
99
+
100
+ // Handle upgrade/update command
101
+ if (args[0] === 'upgrade' || args[0] === 'update') {
102
+ const targetVersion = args[1] || 'latest';
103
+ const packageSpec = `@vibe-lang/vibe@${targetVersion}`;
104
+ console.log(`Upgrading vibe to ${targetVersion}...`);
105
+
106
+ const proc = Bun.spawn(['npm', 'install', '-g', packageSpec], {
107
+ stdout: 'pipe',
108
+ stderr: 'pipe',
109
+ });
110
+
111
+ // Stream stdout directly
112
+ (async () => {
113
+ const reader = proc.stdout.getReader();
114
+ while (true) {
115
+ const { done, value } = await reader.read();
116
+ if (done) break;
117
+ process.stdout.write(value);
118
+ }
119
+ })();
120
+
121
+ // Filter stderr to suppress cleanup warnings on Windows
122
+ (async () => {
123
+ const reader = proc.stderr.getReader();
124
+ const decoder = new TextDecoder();
125
+ let buffer = '';
126
+
127
+ while (true) {
128
+ const { done, value } = await reader.read();
129
+ if (done) break;
130
+
131
+ buffer += decoder.decode(value, { stream: true });
132
+ const lines = buffer.split('\n');
133
+ buffer = lines.pop() || ''; // Keep incomplete line in buffer
134
+
135
+ for (const line of lines) {
136
+ // Skip npm cleanup warnings (Windows file locking issue)
137
+ if (line.includes('npm warn cleanup')) continue;
138
+ if (line.trim()) {
139
+ process.stderr.write(line + '\n');
140
+ }
141
+ }
142
+ }
143
+
144
+ // Handle remaining buffer
145
+ if (buffer.trim() && !buffer.includes('npm warn cleanup')) {
146
+ process.stderr.write(buffer + '\n');
147
+ }
148
+ })();
149
+
150
+ const exitCode = await proc.exited;
151
+
152
+ if (exitCode === 0) {
153
+ console.log('vibe upgraded successfully!');
154
+ }
155
+
156
+ process.exit(exitCode);
157
+ }
158
+
159
+ // Handle version flag
160
+ if (args.includes('--version') || args.includes('-v')) {
161
+ console.log(`vibe ${VERSION}`);
162
+ return;
163
+ }
164
+
165
+ // Parse flags
166
+ const verbose = args.includes('--verbose');
167
+ const inspect = args.includes('--inspect');
168
+ const inspectBrk = args.includes('--inspect-brk');
169
+ const debugMode = inspect || inspectBrk;
170
+ const stopOnEntry = inspectBrk;
171
+
172
+ // Parse --inspect-port=PORT option
173
+ let debugPort = 9229; // Default debug port
174
+ const portArg = args.find(arg => arg.startsWith('--inspect-port='));
175
+ if (portArg) {
176
+ debugPort = parseInt(portArg.split('=')[1], 10);
177
+ }
178
+
179
+ // Parse --log-dir=PATH option
180
+ let logDir: string | undefined;
181
+ const logDirArg = args.find(arg => arg.startsWith('--log-dir='));
182
+ if (logDirArg) {
183
+ logDir = logDirArg.split('=')[1];
184
+ }
185
+
186
+ // Parse --max-parallel=N option (for async operations)
187
+ let maxParallel = 4; // Default
188
+ const maxParallelArg = args.find(arg => arg.startsWith('--max-parallel='));
189
+ if (maxParallelArg) {
190
+ const parsed = parseInt(maxParallelArg.split('=')[1], 10);
191
+ if (!isNaN(parsed) && parsed > 0) {
192
+ maxParallel = parsed;
193
+ }
194
+ }
195
+
196
+ const fileArgs = args.filter(arg => !arg.startsWith('--'));
197
+
198
+ if (fileArgs.length === 0) {
199
+ console.log('Vibe - AI Agent Language');
200
+ console.log('Usage: vibe [command] [options] <file.vibe>');
201
+ console.log('');
202
+ console.log('Commands:');
203
+ console.log(' upgrade [version] Update vibe (default: latest)');
204
+ console.log('');
205
+ console.log('Options:');
206
+ console.log(' --verbose Enable verbose JSONL logging (console + file)');
207
+ console.log(' --log-dir=PATH Directory for logs (default: .vibe-logs)');
208
+ console.log(' --max-parallel=N Max concurrent async operations (default: 4)');
209
+ console.log(' --inspect Start with debugger server');
210
+ console.log(' --inspect-brk Start with debugger, break on entry');
211
+ console.log(' --inspect-port=PORT Debug server port (default: 9229)');
212
+ console.log(' -v, --version Show version number');
213
+ console.log('');
214
+ console.log('Example program:');
215
+ console.log(' let x = "hello"');
216
+ console.log(' let y = vibe "what is 2 + 2?"');
217
+ console.log(' function greet(name) {');
218
+ console.log(' return "Hello, {name}!"');
219
+ console.log(' }');
220
+ return;
221
+ }
222
+
223
+ const filePath = fileArgs[0];
224
+ const file = Bun.file(filePath);
225
+
226
+ if (!(await file.exists())) {
227
+ console.error(`Error: File not found: ${filePath}`);
228
+ process.exit(1);
229
+ }
230
+
231
+ const source = await file.text();
232
+
233
+ try {
234
+ // Parse and analyze
235
+ const ast = parse(source, { file: filePath });
236
+ const errors = analyze(ast, source);
237
+ if (errors.length > 0) {
238
+ throw errors[0];
239
+ }
240
+
241
+ if (debugMode) {
242
+ // Run in debug mode
243
+ await runDebugMode(ast, filePath, debugPort, stopOnEntry, verbose, logDir);
244
+ } else {
245
+ // Normal execution
246
+ const runtime: Runtime = new Runtime(
247
+ ast,
248
+ createRealAIProvider(() => runtime.getState()),
249
+ {
250
+ basePath: filePath,
251
+ verbose,
252
+ logDir,
253
+ maxParallel,
254
+ }
255
+ );
256
+
257
+ const result = await runtime.run();
258
+
259
+ // Show log paths if verbose logging was enabled
260
+ if (verbose) {
261
+ const mainLogPath = runtime.getMainLogPath();
262
+ const contextDir = runtime.getContextDir();
263
+ if (mainLogPath) {
264
+ console.error(`[Verbose] Logs written to: ${mainLogPath}`);
265
+ }
266
+ if (contextDir) {
267
+ console.error(`[Verbose] Context files in: ${contextDir}`);
268
+ }
269
+ }
270
+
271
+ if (result !== null && result !== undefined) {
272
+ console.log('Result:', result);
273
+ }
274
+ }
275
+ } catch (error) {
276
+ console.error('Error:', error instanceof Error ? error.message : error);
277
+ process.exit(1);
278
+ }
279
+ }
280
+
281
+ // Debug mode execution
282
+ async function runDebugMode(
283
+ ast: AST.Program,
284
+ filePath: string,
285
+ port: number,
286
+ stopOnEntry: boolean,
287
+ verbose?: boolean,
288
+ logDir?: string
289
+ ): Promise<void> {
290
+ // Import debug modules
291
+ const { createDebugState, runWithDebug, getCurrentLocation } = await import('./debug');
292
+ const { startDebugServer, sendEvent, stopDebugServer } = await import('./debug/server');
293
+ const { createInitialState } = await import('./runtime/state');
294
+ const { loadImports } = await import('./runtime/modules');
295
+ const { createRealAIProvider } = await import('./runtime/ai-provider');
296
+
297
+ // Create initial state
298
+ // Note: verbose logging in debug mode is limited for now
299
+ let runtimeState = createInitialState(ast);
300
+
301
+ // Load imports
302
+ runtimeState = await loadImports(runtimeState, filePath);
303
+
304
+ // Create debug state
305
+ const debugState = createDebugState({ stopOnEntry });
306
+
307
+ // Create AI provider that uses the current state
308
+ const aiProvider = createRealAIProvider(() => runtimeState);
309
+
310
+ console.error(`[Debug] Starting debug server on port ${port}...`);
311
+ console.error(`[Debug] Waiting for debugger to attach...`);
312
+
313
+ // Start server and wait for connection
314
+ await startDebugServer(port, runtimeState, debugState, aiProvider);
315
+
316
+ console.error(`[Debug] Debugger attached, starting execution...`);
317
+
318
+ // If stop on entry, send stopped event
319
+ if (stopOnEntry) {
320
+ const location = getCurrentLocation(runtimeState);
321
+ if (location) {
322
+ sendEvent({
323
+ type: 'event',
324
+ event: 'stopped',
325
+ body: {
326
+ reason: 'entry',
327
+ location,
328
+ threadId: 1,
329
+ allThreadsStopped: true,
330
+ },
331
+ });
332
+ }
333
+ } else {
334
+ // Run until first breakpoint or completion
335
+ const result = await runWithDebug(
336
+ runtimeState,
337
+ debugState,
338
+ aiProvider,
339
+ sendEvent
340
+ );
341
+ runtimeState = result.runtimeState;
342
+ }
343
+
344
+ // Keep process alive while debugging
345
+ // The server will exit on disconnect
346
+ await new Promise<void>((resolve) => {
347
+ process.on('SIGINT', () => {
348
+ console.error('\n[Debug] Interrupted, shutting down...');
349
+ stopDebugServer();
350
+ resolve();
351
+ });
352
+ });
353
+ }
354
+
355
+ // Run if executed directly
356
+ if (import.meta.main) {
357
+ main();
358
+ }
@@ -0,0 +1,348 @@
1
+ import { createToken, Lexer, ITokenConfig } from 'chevrotain';
2
+ import { LexerError } from '../errors';
3
+
4
+ // Helper to create tokens
5
+ function token(config: ITokenConfig) {
6
+ return createToken(config);
7
+ }
8
+
9
+ // ============================================================================
10
+ // Whitespace & Comments (skipped)
11
+ // ============================================================================
12
+
13
+ export const WhiteSpace = token({
14
+ name: 'WhiteSpace',
15
+ pattern: /\s+/,
16
+ group: Lexer.SKIPPED,
17
+ });
18
+
19
+ export const LineComment = token({
20
+ name: 'LineComment',
21
+ pattern: /\/\/[^\n]*/,
22
+ group: Lexer.SKIPPED,
23
+ });
24
+
25
+ export const BlockComment = token({
26
+ name: 'BlockComment',
27
+ pattern: /\/\*[\s\S]*?\*\//,
28
+ group: Lexer.SKIPPED,
29
+ });
30
+
31
+ // ============================================================================
32
+ // Keywords (must come before Identifier)
33
+ // ============================================================================
34
+
35
+ // Identifier must be defined first for longer_alt references
36
+ export const Identifier = token({
37
+ name: 'Identifier',
38
+ pattern: /[a-zA-Z_][a-zA-Z0-9_]*/,
39
+ });
40
+
41
+ export const Let = token({ name: 'Let', pattern: /let/, longer_alt: Identifier });
42
+ export const Const = token({ name: 'Const', pattern: /const/, longer_alt: Identifier });
43
+ export const Vibe = token({ name: 'Vibe', pattern: /vibe/, longer_alt: Identifier });
44
+ export const Do = token({ name: 'Do', pattern: /do/, longer_alt: Identifier });
45
+ export const Function = token({ name: 'Function', pattern: /function/, longer_alt: Identifier });
46
+ export const Tool = token({ name: 'Tool', pattern: /tool/, longer_alt: Identifier });
47
+ export const Return = token({ name: 'Return', pattern: /return/, longer_alt: Identifier });
48
+ export const Break = token({ name: 'Break', pattern: /break/, longer_alt: Identifier });
49
+ export const If = token({ name: 'If', pattern: /if/, longer_alt: Identifier });
50
+ export const Else = token({ name: 'Else', pattern: /else/, longer_alt: Identifier });
51
+ export const While = token({ name: 'While', pattern: /while/, longer_alt: Identifier });
52
+ export const True = token({ name: 'True', pattern: /true/, longer_alt: Identifier });
53
+ export const False = token({ name: 'False', pattern: /false/, longer_alt: Identifier });
54
+ export const Null = token({ name: 'Null', pattern: /null/, longer_alt: Identifier });
55
+ export const Model = token({ name: 'Model', pattern: /model/, longer_alt: Identifier });
56
+ export const Default = token({ name: 'Default', pattern: /default/, longer_alt: Identifier });
57
+ export const Local = token({ name: 'Local', pattern: /local/, longer_alt: Identifier });
58
+ export const Import = token({ name: 'Import', pattern: /import/, longer_alt: Identifier });
59
+ export const Export = token({ name: 'Export', pattern: /export/, longer_alt: Identifier });
60
+ export const From = token({ name: 'From', pattern: /from/, longer_alt: Identifier });
61
+ export const Private = token({ name: 'Private', pattern: /private/, longer_alt: Identifier });
62
+ export const Async = token({ name: 'Async', pattern: /async/, longer_alt: Identifier });
63
+
64
+ // TsBlock pattern function: Captures entire ts(params) { body }
65
+ // Defined separately to avoid initialization issues
66
+ function matchTsBlock(text: string, startOffset: number): RegExpExecArray | null {
67
+ // Must start with 'ts'
68
+ if (text.slice(startOffset, startOffset + 2) !== 'ts') return null;
69
+
70
+ // Check it's not part of a longer identifier
71
+ const nextChar = text[startOffset + 2];
72
+ if (nextChar && /[a-zA-Z0-9_]/.test(nextChar)) return null;
73
+
74
+ let i = startOffset + 2;
75
+
76
+ // Skip whitespace
77
+ while (i < text.length && /\s/.test(text[i])) i++;
78
+
79
+ // Must have '('
80
+ if (text[i] !== '(') return null;
81
+ i++;
82
+
83
+ // Find matching ')'
84
+ let parenDepth = 1;
85
+ while (i < text.length && parenDepth > 0) {
86
+ if (text[i] === '(') parenDepth++;
87
+ else if (text[i] === ')') parenDepth--;
88
+ i++;
89
+ }
90
+ if (parenDepth !== 0) return null;
91
+
92
+ // Skip whitespace
93
+ while (i < text.length && /\s/.test(text[i])) i++;
94
+
95
+ // Must have '{'
96
+ if (text[i] !== '{') return null;
97
+ i++;
98
+
99
+ // Find matching '}' with balanced brace counting
100
+ // Handle strings and comments to avoid false matches
101
+ let braceDepth = 1;
102
+ while (i < text.length && braceDepth > 0) {
103
+ const char = text[i];
104
+
105
+ // Handle string literals
106
+ if (char === '"' || char === "'") {
107
+ const quote = char;
108
+ i++;
109
+ while (i < text.length && text[i] !== quote) {
110
+ if (text[i] === '\\') i++; // Skip escaped char
111
+ i++;
112
+ }
113
+ }
114
+ // Handle template literals
115
+ else if (char === '`') {
116
+ i++;
117
+ while (i < text.length && text[i] !== '`') {
118
+ if (text[i] === '\\') i++;
119
+ i++;
120
+ }
121
+ }
122
+ // Handle line comments
123
+ else if (char === '/' && text[i + 1] === '/') {
124
+ while (i < text.length && text[i] !== '\n') i++;
125
+ }
126
+ // Handle block comments
127
+ else if (char === '/' && text[i + 1] === '*') {
128
+ i += 2;
129
+ while (i < text.length - 1 && !(text[i] === '*' && text[i + 1] === '/')) i++;
130
+ i++; // Skip the '/'
131
+ }
132
+ // Handle braces
133
+ else if (char === '{') braceDepth++;
134
+ else if (char === '}') braceDepth--;
135
+
136
+ i++;
137
+ }
138
+
139
+ if (braceDepth !== 0) return null;
140
+
141
+ // Create a fake RegExpExecArray
142
+ const match = text.slice(startOffset, i);
143
+ const result = [match] as RegExpExecArray;
144
+ result.index = startOffset;
145
+ result.input = text;
146
+ return result;
147
+ }
148
+
149
+ // TsBlock: Captures entire ts(params) { body } as a single token
150
+ export const TsBlock = createToken({
151
+ name: 'TsBlock',
152
+ pattern: matchTsBlock,
153
+ line_breaks: true,
154
+ start_chars_hint: ['t'], // TsBlock always starts with 't' (from 'ts')
155
+ });
156
+
157
+ // Type keywords
158
+ export const TextType = token({ name: 'TextType', pattern: /text/, longer_alt: Identifier });
159
+ export const JsonType = token({ name: 'JsonType', pattern: /json/, longer_alt: Identifier });
160
+ export const PromptType = token({ name: 'PromptType', pattern: /prompt/, longer_alt: Identifier });
161
+ export const BooleanType = token({ name: 'BooleanType', pattern: /boolean/, longer_alt: Identifier });
162
+ export const NumberType = token({ name: 'NumberType', pattern: /number/, longer_alt: Identifier });
163
+
164
+ // Loop keywords
165
+ export const For = token({ name: 'For', pattern: /for/, longer_alt: Identifier });
166
+ export const In = token({ name: 'In', pattern: /in/, longer_alt: Identifier });
167
+
168
+ // Context mode keywords
169
+ export const Forget = token({ name: 'Forget', pattern: /forget/, longer_alt: Identifier });
170
+ export const Verbose = token({ name: 'Verbose', pattern: /verbose/, longer_alt: Identifier });
171
+ export const Compress = token({ name: 'Compress', pattern: /compress/, longer_alt: Identifier });
172
+
173
+ // Tool metadata decorators
174
+ export const AtDescription = token({ name: 'AtDescription', pattern: /@description/ });
175
+ export const AtParam = token({ name: 'AtParam', pattern: /@param/ });
176
+
177
+ // Logical operators (word-based)
178
+ export const And = token({ name: 'And', pattern: /and/, longer_alt: Identifier });
179
+ export const Or = token({ name: 'Or', pattern: /or/, longer_alt: Identifier });
180
+ export const Not = token({ name: 'Not', pattern: /not/, longer_alt: Identifier });
181
+
182
+ // ============================================================================
183
+ // Literals
184
+ // ============================================================================
185
+
186
+ export const StringLiteral = token({
187
+ name: 'StringLiteral',
188
+ pattern: /"([^"\\]|\\.)*"|'([^'\\]|\\.)*'/,
189
+ });
190
+
191
+ export const TemplateLiteral = token({
192
+ name: 'TemplateLiteral',
193
+ pattern: /`(?:[^`\\]|\\.|\r?\n)*`/,
194
+ });
195
+
196
+ // Number literals: integers and decimals (optional leading minus)
197
+ export const NumberLiteral = token({
198
+ name: 'NumberLiteral',
199
+ pattern: /-?[0-9]+(\.[0-9]+)?/,
200
+ });
201
+
202
+ // ============================================================================
203
+ // Operators
204
+ // ============================================================================
205
+
206
+ // Comparison (multi-char must come before single-char)
207
+ export const EqualEqual = token({ name: 'EqualEqual', pattern: /==/ });
208
+ export const NotEqual = token({ name: 'NotEqual', pattern: /!=/ });
209
+ export const LessEqual = token({ name: 'LessEqual', pattern: /<=/ });
210
+ export const GreaterEqual = token({ name: 'GreaterEqual', pattern: />=/ });
211
+ export const LessThan = token({ name: 'LessThan', pattern: /</ });
212
+ export const GreaterThan = token({ name: 'GreaterThan', pattern: />/ });
213
+
214
+ // Assignment (after == to avoid conflict)
215
+ export const Equals = token({ name: 'Equals', pattern: /=/ });
216
+
217
+ // Arithmetic
218
+ export const Plus = token({ name: 'Plus', pattern: /\+/ });
219
+ export const Minus = token({ name: 'Minus', pattern: /-/ });
220
+ export const Star = token({ name: 'Star', pattern: /\*/ });
221
+ export const Slash = token({ name: 'Slash', pattern: /\// });
222
+ export const Percent = token({ name: 'Percent', pattern: /%/ });
223
+
224
+ // ============================================================================
225
+ // Delimiters
226
+ // ============================================================================
227
+
228
+ export const LParen = token({ name: 'LParen', pattern: /\(/ });
229
+ export const RParen = token({ name: 'RParen', pattern: /\)/ });
230
+ export const LBrace = token({ name: 'LBrace', pattern: /\{/ });
231
+ export const RBrace = token({ name: 'RBrace', pattern: /\}/ });
232
+ export const LBracket = token({ name: 'LBracket', pattern: /\[/ });
233
+ export const RBracket = token({ name: 'RBracket', pattern: /\]/ });
234
+ export const Comma = token({ name: 'Comma', pattern: /,/ });
235
+ export const Colon = token({ name: 'Colon', pattern: /:/ });
236
+ export const DotDot = token({ name: 'DotDot', pattern: /\.\./ });
237
+ export const Dot = token({ name: 'Dot', pattern: /\./ }); // Must be after DotDot
238
+
239
+ // ============================================================================
240
+ // All tokens in order (order matters for matching!)
241
+ // ============================================================================
242
+
243
+ export const allTokens = [
244
+ // Whitespace & comments first
245
+ WhiteSpace,
246
+ LineComment,
247
+ BlockComment,
248
+
249
+ // Keywords before Identifier
250
+ Let,
251
+ Const,
252
+ Vibe,
253
+ Do,
254
+ Function,
255
+ Tool,
256
+ Return,
257
+ Break,
258
+ If,
259
+ Else,
260
+ While,
261
+ // Context mode keywords (Forget must come before For since 'forget' starts with 'for')
262
+ Forget,
263
+ Verbose,
264
+ Compress,
265
+ // Tool metadata decorators (must come before For/other identifiers)
266
+ AtDescription,
267
+ AtParam,
268
+ For,
269
+ In,
270
+ And,
271
+ Or,
272
+ Not,
273
+ True,
274
+ False,
275
+ Null,
276
+ Model,
277
+ Default,
278
+ Local,
279
+ Import,
280
+ Export,
281
+ From,
282
+ Private,
283
+ Async,
284
+ TsBlock, // Must be before Identifier - captures entire ts(...) { ... }
285
+ TextType,
286
+ JsonType,
287
+ PromptType,
288
+ BooleanType,
289
+ NumberType,
290
+
291
+ // Literals
292
+ StringLiteral,
293
+ TemplateLiteral,
294
+ NumberLiteral,
295
+
296
+ // Identifier after keywords
297
+ Identifier,
298
+
299
+ // Operators (multi-char before single-char)
300
+ EqualEqual,
301
+ NotEqual,
302
+ LessEqual,
303
+ GreaterEqual,
304
+ LessThan,
305
+ GreaterThan,
306
+ Equals,
307
+ Plus,
308
+ Minus,
309
+ Star,
310
+ Slash,
311
+ Percent,
312
+
313
+ // Delimiters
314
+ LParen,
315
+ RParen,
316
+ LBrace,
317
+ RBrace,
318
+ LBracket,
319
+ RBracket,
320
+ Comma,
321
+ Colon,
322
+ DotDot,
323
+ Dot,
324
+ ];
325
+
326
+ // ============================================================================
327
+ // Create the Lexer instance
328
+ // ============================================================================
329
+
330
+ export const VibeLexer = new Lexer(allTokens, {
331
+ ensureOptimizations: true,
332
+ });
333
+
334
+ // Helper function to tokenize source code
335
+ export function tokenize(source: string) {
336
+ const result = VibeLexer.tokenize(source);
337
+
338
+ if (result.errors.length > 0) {
339
+ const error = result.errors[0];
340
+ throw new LexerError(
341
+ error.message,
342
+ { line: error.line ?? 1, column: error.column ?? 1 },
343
+ source
344
+ );
345
+ }
346
+
347
+ return result.tokens;
348
+ }
package/src/lexer.ts ADDED
@@ -0,0 +1,2 @@
1
+ // Re-export from new location for backwards compatibility
2
+ export * from './lexer/index';