@aigne/ash 0.0.1

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 (146) hide show
  1. package/DESIGN.md +41 -0
  2. package/dist/ai-dev-loop/ash-run-result.cjs +12 -0
  3. package/dist/ai-dev-loop/ash-run-result.d.cts +28 -0
  4. package/dist/ai-dev-loop/ash-run-result.d.cts.map +1 -0
  5. package/dist/ai-dev-loop/ash-run-result.d.mts +28 -0
  6. package/dist/ai-dev-loop/ash-run-result.d.mts.map +1 -0
  7. package/dist/ai-dev-loop/ash-run-result.mjs +11 -0
  8. package/dist/ai-dev-loop/ash-run-result.mjs.map +1 -0
  9. package/dist/ai-dev-loop/ash-typed-error.cjs +51 -0
  10. package/dist/ai-dev-loop/ash-typed-error.d.cts +54 -0
  11. package/dist/ai-dev-loop/ash-typed-error.d.cts.map +1 -0
  12. package/dist/ai-dev-loop/ash-typed-error.d.mts +54 -0
  13. package/dist/ai-dev-loop/ash-typed-error.d.mts.map +1 -0
  14. package/dist/ai-dev-loop/ash-typed-error.mjs +50 -0
  15. package/dist/ai-dev-loop/ash-typed-error.mjs.map +1 -0
  16. package/dist/ai-dev-loop/ash-validate.cjs +27 -0
  17. package/dist/ai-dev-loop/ash-validate.d.cts +7 -0
  18. package/dist/ai-dev-loop/ash-validate.d.cts.map +1 -0
  19. package/dist/ai-dev-loop/ash-validate.d.mts +7 -0
  20. package/dist/ai-dev-loop/ash-validate.d.mts.map +1 -0
  21. package/dist/ai-dev-loop/ash-validate.mjs +28 -0
  22. package/dist/ai-dev-loop/ash-validate.mjs.map +1 -0
  23. package/dist/ai-dev-loop/dev-loop.cjs +134 -0
  24. package/dist/ai-dev-loop/dev-loop.d.cts +28 -0
  25. package/dist/ai-dev-loop/dev-loop.d.cts.map +1 -0
  26. package/dist/ai-dev-loop/dev-loop.d.mts +28 -0
  27. package/dist/ai-dev-loop/dev-loop.d.mts.map +1 -0
  28. package/dist/ai-dev-loop/dev-loop.mjs +135 -0
  29. package/dist/ai-dev-loop/dev-loop.mjs.map +1 -0
  30. package/dist/ai-dev-loop/index.cjs +24 -0
  31. package/dist/ai-dev-loop/index.d.cts +9 -0
  32. package/dist/ai-dev-loop/index.d.mts +9 -0
  33. package/dist/ai-dev-loop/index.mjs +10 -0
  34. package/dist/ai-dev-loop/live-mode.cjs +17 -0
  35. package/dist/ai-dev-loop/live-mode.d.cts +24 -0
  36. package/dist/ai-dev-loop/live-mode.d.cts.map +1 -0
  37. package/dist/ai-dev-loop/live-mode.d.mts +24 -0
  38. package/dist/ai-dev-loop/live-mode.d.mts.map +1 -0
  39. package/dist/ai-dev-loop/live-mode.mjs +17 -0
  40. package/dist/ai-dev-loop/live-mode.mjs.map +1 -0
  41. package/dist/ai-dev-loop/meta-tools.cjs +123 -0
  42. package/dist/ai-dev-loop/meta-tools.d.cts +24 -0
  43. package/dist/ai-dev-loop/meta-tools.d.cts.map +1 -0
  44. package/dist/ai-dev-loop/meta-tools.d.mts +24 -0
  45. package/dist/ai-dev-loop/meta-tools.d.mts.map +1 -0
  46. package/dist/ai-dev-loop/meta-tools.mjs +120 -0
  47. package/dist/ai-dev-loop/meta-tools.mjs.map +1 -0
  48. package/dist/ai-dev-loop/structured-runner.cjs +154 -0
  49. package/dist/ai-dev-loop/structured-runner.d.cts +12 -0
  50. package/dist/ai-dev-loop/structured-runner.d.cts.map +1 -0
  51. package/dist/ai-dev-loop/structured-runner.d.mts +12 -0
  52. package/dist/ai-dev-loop/structured-runner.d.mts.map +1 -0
  53. package/dist/ai-dev-loop/structured-runner.mjs +155 -0
  54. package/dist/ai-dev-loop/structured-runner.mjs.map +1 -0
  55. package/dist/ai-dev-loop/system-prompt.cjs +55 -0
  56. package/dist/ai-dev-loop/system-prompt.d.cts +20 -0
  57. package/dist/ai-dev-loop/system-prompt.d.cts.map +1 -0
  58. package/dist/ai-dev-loop/system-prompt.d.mts +20 -0
  59. package/dist/ai-dev-loop/system-prompt.d.mts.map +1 -0
  60. package/dist/ai-dev-loop/system-prompt.mjs +54 -0
  61. package/dist/ai-dev-loop/system-prompt.mjs.map +1 -0
  62. package/dist/ast.d.cts +140 -0
  63. package/dist/ast.d.cts.map +1 -0
  64. package/dist/ast.d.mts +140 -0
  65. package/dist/ast.d.mts.map +1 -0
  66. package/dist/compiler.cjs +802 -0
  67. package/dist/compiler.d.cts +103 -0
  68. package/dist/compiler.d.cts.map +1 -0
  69. package/dist/compiler.d.mts +103 -0
  70. package/dist/compiler.d.mts.map +1 -0
  71. package/dist/compiler.mjs +802 -0
  72. package/dist/compiler.mjs.map +1 -0
  73. package/dist/index.cjs +14 -0
  74. package/dist/index.d.cts +7 -0
  75. package/dist/index.d.mts +7 -0
  76. package/dist/index.mjs +7 -0
  77. package/dist/lexer.cjs +451 -0
  78. package/dist/lexer.d.cts +14 -0
  79. package/dist/lexer.d.cts.map +1 -0
  80. package/dist/lexer.d.mts +14 -0
  81. package/dist/lexer.d.mts.map +1 -0
  82. package/dist/lexer.mjs +451 -0
  83. package/dist/lexer.mjs.map +1 -0
  84. package/dist/parser.cjs +734 -0
  85. package/dist/parser.d.cts +40 -0
  86. package/dist/parser.d.cts.map +1 -0
  87. package/dist/parser.d.mts +40 -0
  88. package/dist/parser.d.mts.map +1 -0
  89. package/dist/parser.mjs +734 -0
  90. package/dist/parser.mjs.map +1 -0
  91. package/dist/reference.cjs +130 -0
  92. package/dist/reference.d.cts +11 -0
  93. package/dist/reference.d.cts.map +1 -0
  94. package/dist/reference.d.mts +11 -0
  95. package/dist/reference.d.mts.map +1 -0
  96. package/dist/reference.mjs +130 -0
  97. package/dist/reference.mjs.map +1 -0
  98. package/dist/template.cjs +85 -0
  99. package/dist/template.mjs +84 -0
  100. package/dist/template.mjs.map +1 -0
  101. package/dist/type-checker.cjs +582 -0
  102. package/dist/type-checker.d.cts +31 -0
  103. package/dist/type-checker.d.cts.map +1 -0
  104. package/dist/type-checker.d.mts +31 -0
  105. package/dist/type-checker.d.mts.map +1 -0
  106. package/dist/type-checker.mjs +573 -0
  107. package/dist/type-checker.mjs.map +1 -0
  108. package/package.json +29 -0
  109. package/src/ai-dev-loop/ash-run-result.test.ts +113 -0
  110. package/src/ai-dev-loop/ash-run-result.ts +46 -0
  111. package/src/ai-dev-loop/ash-typed-error.test.ts +136 -0
  112. package/src/ai-dev-loop/ash-typed-error.ts +50 -0
  113. package/src/ai-dev-loop/ash-validate.test.ts +54 -0
  114. package/src/ai-dev-loop/ash-validate.ts +34 -0
  115. package/src/ai-dev-loop/dev-loop.test.ts +364 -0
  116. package/src/ai-dev-loop/dev-loop.ts +156 -0
  117. package/src/ai-dev-loop/dry-run.test.ts +107 -0
  118. package/src/ai-dev-loop/e2e-multi-fix.test.ts +473 -0
  119. package/src/ai-dev-loop/e2e.test.ts +324 -0
  120. package/src/ai-dev-loop/index.ts +15 -0
  121. package/src/ai-dev-loop/invariants.test.ts +253 -0
  122. package/src/ai-dev-loop/live-mode.test.ts +63 -0
  123. package/src/ai-dev-loop/live-mode.ts +33 -0
  124. package/src/ai-dev-loop/meta-tools.test.ts +120 -0
  125. package/src/ai-dev-loop/meta-tools.ts +142 -0
  126. package/src/ai-dev-loop/structured-runner.test.ts +159 -0
  127. package/src/ai-dev-loop/structured-runner.ts +209 -0
  128. package/src/ai-dev-loop/system-prompt.test.ts +102 -0
  129. package/src/ai-dev-loop/system-prompt.ts +81 -0
  130. package/src/ast.ts +186 -0
  131. package/src/compiler.test.ts +2933 -0
  132. package/src/compiler.ts +1103 -0
  133. package/src/e2e.test.ts +552 -0
  134. package/src/index.ts +16 -0
  135. package/src/lexer.test.ts +538 -0
  136. package/src/lexer.ts +222 -0
  137. package/src/parser.test.ts +1024 -0
  138. package/src/parser.ts +835 -0
  139. package/src/reference.test.ts +166 -0
  140. package/src/reference.ts +125 -0
  141. package/src/template.test.ts +210 -0
  142. package/src/template.ts +139 -0
  143. package/src/type-checker.test.ts +1494 -0
  144. package/src/type-checker.ts +785 -0
  145. package/tsconfig.json +9 -0
  146. package/tsdown.config.ts +12 -0
package/src/lexer.ts ADDED
@@ -0,0 +1,222 @@
1
+ export type TokenType =
2
+ | "JOB" | "FIND" | "WHERE" | "MAP" | "SAVE" | "PUBLISH" | "TEE" | "FANOUT" | "INPUT" | "OUTPUT"
3
+ | "ACTION" | "ROUTE" | "LOOKUP" | "ARROW"
4
+ | "PLUS" | "MINUS" | "STAR" | "SLASH"
5
+ | "PIPE" | "ASSIGN" | "DOT" | "COMMA" | "COLON"
6
+ | "LPAREN" | "RPAREN" | "LBRACKET" | "RBRACKET" | "LBRACE" | "RBRACE"
7
+ | "IDENTIFIER" | "STRING" | "NUMBER" | "PATH" | "AT"
8
+ | "GT" | "LT" | "GTE" | "LTE" | "EQ" | "NEQ"
9
+ | "LET" | "PARAM" | "ON" | "DOLLAR" | "COUNT" | "GROUP_BY"
10
+ | "NEWLINE" | "EOF";
11
+
12
+ export interface Token {
13
+ type: TokenType;
14
+ value: string;
15
+ line: number;
16
+ column: number;
17
+ }
18
+
19
+ const KEYWORDS: Record<string, TokenType> = {
20
+ job: "JOB",
21
+ find: "FIND",
22
+ where: "WHERE",
23
+ map: "MAP",
24
+ save: "SAVE",
25
+ publish: "PUBLISH",
26
+ tee: "TEE",
27
+ fanout: "FANOUT",
28
+ input: "INPUT",
29
+ output: "OUTPUT",
30
+ let: "LET",
31
+ count: "COUNT",
32
+ action: "ACTION",
33
+ route: "ROUTE",
34
+ lookup: "LOOKUP",
35
+ param: "PARAM",
36
+ on: "ON",
37
+ };
38
+
39
+ export class AshLexer {
40
+ tokenize(source: string): Token[] {
41
+ const tokens: Token[] = [];
42
+ let pos = 0;
43
+ let line = 1;
44
+ let col = 1;
45
+
46
+ while (pos < source.length) {
47
+ const ch = source[pos];
48
+
49
+ // Newline
50
+ if (ch === "\n" || ch === "\r") {
51
+ if (ch === "\r" && source[pos + 1] === "\n") pos++;
52
+ tokens.push({ type: "NEWLINE", value: "\\n", line, column: col });
53
+ pos++;
54
+ line++;
55
+ col = 1;
56
+ continue;
57
+ }
58
+
59
+ // Whitespace (skip)
60
+ if (ch === " " || ch === "\t") {
61
+ pos++;
62
+ col++;
63
+ continue;
64
+ }
65
+
66
+ // Comment: # to end of line
67
+ if (ch === "#") {
68
+ while (pos < source.length && source[pos] !== "\n" && source[pos] !== "\r") {
69
+ pos++;
70
+ col++;
71
+ }
72
+ continue;
73
+ }
74
+
75
+ // String literal
76
+ if (ch === '"') {
77
+ const startCol = col;
78
+ pos++; col++;
79
+ let value = "";
80
+ while (pos < source.length && source[pos] !== '"') {
81
+ if (source[pos] === "\\") {
82
+ pos++; col++;
83
+ if (pos >= source.length) break;
84
+ const escaped = source[pos];
85
+ if (escaped === '"') value += '"';
86
+ else if (escaped === "\\") value += "\\";
87
+ else if (escaped === "n") value += "\n";
88
+ else if (escaped === "t") value += "\t";
89
+ else if (escaped === "$") value += "\\$"; // preserve for template escape detection
90
+ else value += escaped;
91
+ } else {
92
+ if (source[pos] === "\n") {
93
+ throw new Error(`Unterminated string at line ${line}, column ${startCol}`);
94
+ }
95
+ value += source[pos];
96
+ }
97
+ pos++; col++;
98
+ }
99
+ if (pos >= source.length) {
100
+ throw new Error(`Unterminated string at line ${line}, column ${startCol}`);
101
+ }
102
+ pos++; col++; // closing quote
103
+ tokens.push({ type: "STRING", value, line, column: startCol });
104
+ continue;
105
+ }
106
+
107
+ // Number
108
+ if (ch >= "0" && ch <= "9") {
109
+ const startCol = col;
110
+ let num = "";
111
+ while (pos < source.length && ((source[pos] >= "0" && source[pos] <= "9") || source[pos] === ".")) {
112
+ num += source[pos];
113
+ pos++; col++;
114
+ }
115
+ tokens.push({ type: "NUMBER", value: num, line, column: startCol });
116
+ continue;
117
+ }
118
+
119
+ // Path or SLASH: `/` followed by a letter, `.`, `_`, or `/` starts a PATH; otherwise SLASH
120
+ if (ch === "/") {
121
+ const next = source[pos + 1];
122
+ if (next !== undefined && ((next >= "a" && next <= "z") || (next >= "A" && next <= "Z") || next === "_" || next === "." || next === "/")) {
123
+ const startCol = col;
124
+ let path = "";
125
+ while (pos < source.length && source[pos] !== " " && source[pos] !== "\t" && source[pos] !== "\n" && source[pos] !== "\r" && source[pos] !== "|" && source[pos] !== "}" && source[pos] !== ")" && source[pos] !== "," && source[pos] !== ":") {
126
+ // Handle ${...} template blocks atomically — don't stop at } inside template
127
+ if (source[pos] === "$" && pos + 1 < source.length && source[pos + 1] === "{") {
128
+ path += source[pos]; pos++; col++; // $
129
+ path += source[pos]; pos++; col++; // {
130
+ while (pos < source.length && source[pos] !== "}") {
131
+ path += source[pos]; pos++; col++;
132
+ }
133
+ if (pos < source.length) {
134
+ path += source[pos]; pos++; col++; // closing }
135
+ }
136
+ continue;
137
+ }
138
+ path += source[pos];
139
+ pos++; col++;
140
+ }
141
+ tokens.push({ type: "PATH", value: path, line, column: startCol });
142
+ continue;
143
+ }
144
+ tokens.push({ type: "SLASH", value: "/", line, column: col }); pos++; col++; continue;
145
+ }
146
+
147
+ // Identifier / keyword
148
+ if ((ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z") || ch === "_") {
149
+ const startCol = col;
150
+ let ident = "";
151
+ while (pos < source.length && ((source[pos] >= "a" && source[pos] <= "z") || (source[pos] >= "A" && source[pos] <= "Z") || (source[pos] >= "0" && source[pos] <= "9") || source[pos] === "_")) {
152
+ ident += source[pos];
153
+ pos++; col++;
154
+ }
155
+ // Handle compound keyword: group-by
156
+ if (ident === "group" && pos < source.length && source[pos] === "-") {
157
+ const rest = source.slice(pos + 1, pos + 3);
158
+ if (rest === "by") {
159
+ pos += 3; col += 3;
160
+ tokens.push({ type: "GROUP_BY", value: "group-by", line, column: startCol });
161
+ continue;
162
+ }
163
+ }
164
+ const kw = Object.hasOwn(KEYWORDS, ident) ? KEYWORDS[ident] : undefined;
165
+ tokens.push({ type: kw ?? "IDENTIFIER", value: ident, line, column: startCol });
166
+ continue;
167
+ }
168
+
169
+ // Operators and punctuation
170
+ // Arithmetic operators
171
+ if (ch === "+") { tokens.push({ type: "PLUS", value: "+", line, column: col }); pos++; col++; continue; }
172
+ if (ch === "-") {
173
+ if (source[pos + 1] === ">") {
174
+ tokens.push({ type: "ARROW", value: "->", line, column: col }); pos += 2; col += 2; continue;
175
+ }
176
+ tokens.push({ type: "MINUS", value: "-", line, column: col }); pos++; col++; continue;
177
+ }
178
+ if (ch === "*") { tokens.push({ type: "STAR", value: "*", line, column: col }); pos++; col++; continue; }
179
+
180
+ if (ch === "|") { tokens.push({ type: "PIPE", value: "|", line, column: col }); pos++; col++; continue; }
181
+ if (ch === "=") {
182
+ if (source[pos + 1] === "=") {
183
+ tokens.push({ type: "EQ", value: "==", line, column: col }); pos += 2; col += 2; continue;
184
+ }
185
+ tokens.push({ type: "ASSIGN", value: "=", line, column: col }); pos++; col++; continue;
186
+ }
187
+ if (ch === "!") {
188
+ if (source[pos + 1] === "=") {
189
+ tokens.push({ type: "NEQ", value: "!=", line, column: col }); pos += 2; col += 2; continue;
190
+ }
191
+ }
192
+ if (ch === ">") {
193
+ if (source[pos + 1] === "=") {
194
+ tokens.push({ type: "GTE", value: ">=", line, column: col }); pos += 2; col += 2; continue;
195
+ }
196
+ tokens.push({ type: "GT", value: ">", line, column: col }); pos++; col++; continue;
197
+ }
198
+ if (ch === "<") {
199
+ if (source[pos + 1] === "=") {
200
+ tokens.push({ type: "LTE", value: "<=", line, column: col }); pos += 2; col += 2; continue;
201
+ }
202
+ tokens.push({ type: "LT", value: "<", line, column: col }); pos++; col++; continue;
203
+ }
204
+ if (ch === ".") { tokens.push({ type: "DOT", value: ".", line, column: col }); pos++; col++; continue; }
205
+ if (ch === ",") { tokens.push({ type: "COMMA", value: ",", line, column: col }); pos++; col++; continue; }
206
+ if (ch === "(") { tokens.push({ type: "LPAREN", value: "(", line, column: col }); pos++; col++; continue; }
207
+ if (ch === ")") { tokens.push({ type: "RPAREN", value: ")", line, column: col }); pos++; col++; continue; }
208
+ if (ch === "[") { tokens.push({ type: "LBRACKET", value: "[", line, column: col }); pos++; col++; continue; }
209
+ if (ch === "]") { tokens.push({ type: "RBRACKET", value: "]", line, column: col }); pos++; col++; continue; }
210
+ if (ch === "{") { tokens.push({ type: "LBRACE", value: "{", line, column: col }); pos++; col++; continue; }
211
+ if (ch === "}") { tokens.push({ type: "RBRACE", value: "}", line, column: col }); pos++; col++; continue; }
212
+ if (ch === "@") { tokens.push({ type: "AT", value: "@", line, column: col }); pos++; col++; continue; }
213
+ if (ch === "$") { tokens.push({ type: "DOLLAR", value: "$", line, column: col }); pos++; col++; continue; }
214
+ if (ch === ":") { tokens.push({ type: "COLON", value: ":", line, column: col }); pos++; col++; continue; }
215
+
216
+ throw new Error(`Unrecognized character '${ch}' at line ${line}, column ${col}`);
217
+ }
218
+
219
+ tokens.push({ type: "EOF", value: "", line, column: col });
220
+ return tokens;
221
+ }
222
+ }