react-agentic 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.
- package/LICENSE +21 -0
- package/README.md +402 -0
- package/dist/chunk-263OAOFB.js +7903 -0
- package/dist/chunk-263OAOFB.js.map +1 -0
- package/dist/chunk-OO3V32L6.js +34 -0
- package/dist/chunk-OO3V32L6.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +416 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +3320 -0
- package/dist/index.js +2800 -0
- package/dist/index.js.map +1 -0
- package/dist/sqlite-QIS455OH.js +278 -0
- package/dist/sqlite-QIS455OH.js.map +1 -0
- package/package.json +80 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2800 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RuntimeMarkdownEmitter,
|
|
3
|
+
TranspileError,
|
|
4
|
+
buildRuntimeFile,
|
|
5
|
+
bundleCodeSplit,
|
|
6
|
+
bundleSingleEntryRuntime,
|
|
7
|
+
createProject,
|
|
8
|
+
createRuntimeContext,
|
|
9
|
+
detectRuntime,
|
|
10
|
+
emit,
|
|
11
|
+
emitAgent,
|
|
12
|
+
emitDocument,
|
|
13
|
+
emitRuntime,
|
|
14
|
+
emitSettings,
|
|
15
|
+
emitSkill,
|
|
16
|
+
emitSkillFile,
|
|
17
|
+
extractExportedFunctionNames,
|
|
18
|
+
extractExternalComponentDeclarations,
|
|
19
|
+
extractFunctions,
|
|
20
|
+
extractInlineText,
|
|
21
|
+
extractInputObjectLiteral,
|
|
22
|
+
extractInterfaceProperties,
|
|
23
|
+
extractLocalComponentDeclarations,
|
|
24
|
+
extractPromptPlaceholders,
|
|
25
|
+
extractRuntimeFnDeclarations,
|
|
26
|
+
extractRuntimeVarDeclarations,
|
|
27
|
+
extractText,
|
|
28
|
+
extractTypeArguments,
|
|
29
|
+
extractVariableDeclarations,
|
|
30
|
+
findRootJsxElement,
|
|
31
|
+
generateRuntime,
|
|
32
|
+
getArrayAttributeValue,
|
|
33
|
+
getAttributeValue,
|
|
34
|
+
getElementName,
|
|
35
|
+
getJsxChildren,
|
|
36
|
+
getNodeLocation,
|
|
37
|
+
getRuntimeFunctionNames,
|
|
38
|
+
getRuntimeImportPaths,
|
|
39
|
+
getSourceCode,
|
|
40
|
+
hasRuntimeImports,
|
|
41
|
+
init_parser,
|
|
42
|
+
init_project,
|
|
43
|
+
isRuntimeFile,
|
|
44
|
+
isWhitespaceOnlyText,
|
|
45
|
+
mergeSettings,
|
|
46
|
+
normalizeWhitespace,
|
|
47
|
+
parseFile,
|
|
48
|
+
parseSource,
|
|
49
|
+
resolveComponentImport,
|
|
50
|
+
resolveSpreadAttribute,
|
|
51
|
+
resolveTypeImport,
|
|
52
|
+
transformAgent,
|
|
53
|
+
transformMCPConfig,
|
|
54
|
+
transformRuntimeBlockChildren,
|
|
55
|
+
transformRuntimeCommand,
|
|
56
|
+
transformSkill,
|
|
57
|
+
transformState,
|
|
58
|
+
transformToRuntimeBlock
|
|
59
|
+
} from "./chunk-263OAOFB.js";
|
|
60
|
+
import "./chunk-OO3V32L6.js";
|
|
61
|
+
|
|
62
|
+
// src/components/markdown.ts
|
|
63
|
+
function Markdown(_props) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function XmlBlock(_props) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
function Indent(_props) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/components/structured.ts
|
|
74
|
+
function Table(_props) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
function List(_props) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/components/Command.ts
|
|
82
|
+
function Command(_props) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/components/Agent.ts
|
|
87
|
+
function defineAgent(config) {
|
|
88
|
+
return {
|
|
89
|
+
name: config.name,
|
|
90
|
+
path: config.path,
|
|
91
|
+
__isAgentRef: true
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function isAgentRef(value) {
|
|
95
|
+
if (!value || typeof value !== "object") return false;
|
|
96
|
+
return value.__isAgentRef === true;
|
|
97
|
+
}
|
|
98
|
+
function getAgentName(agent) {
|
|
99
|
+
return isAgentRef(agent) ? agent.name : agent;
|
|
100
|
+
}
|
|
101
|
+
function getAgentPath(agent) {
|
|
102
|
+
return isAgentRef(agent) ? agent.path : void 0;
|
|
103
|
+
}
|
|
104
|
+
function useOutput(agent) {
|
|
105
|
+
return {
|
|
106
|
+
agent,
|
|
107
|
+
field: (name) => `{${agent}.${String(name)}}`
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function Agent(_props) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
function SpawnAgent(_props) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
function OnStatus(_props) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/components/runtime-var.ts
|
|
121
|
+
var RUNTIME_VAR_MARKER = /* @__PURE__ */ Symbol.for("react-agentic:runtime-var");
|
|
122
|
+
function createRuntimeVarProxy(varName, path) {
|
|
123
|
+
const target = {
|
|
124
|
+
__varName: varName,
|
|
125
|
+
__path: path,
|
|
126
|
+
[RUNTIME_VAR_MARKER]: true
|
|
127
|
+
};
|
|
128
|
+
return new Proxy(target, {
|
|
129
|
+
get(_target, prop) {
|
|
130
|
+
if (prop === "__varName") return varName;
|
|
131
|
+
if (prop === "__path") return path;
|
|
132
|
+
if (prop === RUNTIME_VAR_MARKER) return true;
|
|
133
|
+
if (typeof prop === "symbol") return void 0;
|
|
134
|
+
return createRuntimeVarProxy(varName, [...path, prop]);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function useRuntimeVar(name) {
|
|
139
|
+
return createRuntimeVarProxy(name, []);
|
|
140
|
+
}
|
|
141
|
+
function isRuntimeVar(value) {
|
|
142
|
+
if (!value || typeof value !== "object") return false;
|
|
143
|
+
return value[RUNTIME_VAR_MARKER] === true;
|
|
144
|
+
}
|
|
145
|
+
function getRuntimeVarInfo(runtimeVar) {
|
|
146
|
+
return {
|
|
147
|
+
varName: runtimeVar.__varName,
|
|
148
|
+
path: runtimeVar.__path
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function toJqExpression(runtimeVar) {
|
|
152
|
+
const { varName, path } = getRuntimeVarInfo(runtimeVar);
|
|
153
|
+
const jqPath = path.length === 0 ? "." : "." + path.join(".");
|
|
154
|
+
return `$(echo "$${varName}" | jq -r '${jqPath}')`;
|
|
155
|
+
}
|
|
156
|
+
function toJqPath(runtimeVar) {
|
|
157
|
+
const { path } = getRuntimeVarInfo(runtimeVar);
|
|
158
|
+
return path.length === 0 ? "." : "." + path.join(".");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/components/runtime-fn.ts
|
|
162
|
+
var RUNTIME_FN_MARKER = /* @__PURE__ */ Symbol.for("react-agentic:runtime-fn");
|
|
163
|
+
var runtimeFnRegistry = /* @__PURE__ */ new Map();
|
|
164
|
+
function runtimeFn(fn) {
|
|
165
|
+
const fnName = fn.name;
|
|
166
|
+
if (!fnName) {
|
|
167
|
+
throw new Error(
|
|
168
|
+
"runtimeFn requires a named function. Anonymous functions cannot be extracted to runtime.js."
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
runtimeFnRegistry.set(fnName, fn);
|
|
172
|
+
const Call = (_props) => {
|
|
173
|
+
return null;
|
|
174
|
+
};
|
|
175
|
+
const wrapper = {
|
|
176
|
+
Call,
|
|
177
|
+
fnName,
|
|
178
|
+
fn,
|
|
179
|
+
__isRuntimeFn: true,
|
|
180
|
+
[RUNTIME_FN_MARKER]: true
|
|
181
|
+
};
|
|
182
|
+
return wrapper;
|
|
183
|
+
}
|
|
184
|
+
function isRuntimeFn(value) {
|
|
185
|
+
if (!value || typeof value !== "object") return false;
|
|
186
|
+
return value.__isRuntimeFn === true;
|
|
187
|
+
}
|
|
188
|
+
function getRuntimeFnRegistry() {
|
|
189
|
+
return new Map(runtimeFnRegistry);
|
|
190
|
+
}
|
|
191
|
+
function clearRuntimeFnRegistry() {
|
|
192
|
+
runtimeFnRegistry.clear();
|
|
193
|
+
}
|
|
194
|
+
function getRuntimeFn(name) {
|
|
195
|
+
return runtimeFnRegistry.get(name);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/components/control.ts
|
|
199
|
+
function If(_props) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
function Else(_props) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
function Loop(_props) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
function Break(_props) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
function Return(_props) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
var IF_MARKER = /* @__PURE__ */ Symbol.for("react-agentic:if");
|
|
215
|
+
var ELSE_MARKER = /* @__PURE__ */ Symbol.for("react-agentic:else");
|
|
216
|
+
var LOOP_MARKER = /* @__PURE__ */ Symbol.for("react-agentic:loop");
|
|
217
|
+
var BREAK_MARKER = /* @__PURE__ */ Symbol.for("react-agentic:break");
|
|
218
|
+
var RETURN_MARKER = /* @__PURE__ */ Symbol.for("react-agentic:return");
|
|
219
|
+
Object.defineProperty(If, IF_MARKER, { value: true });
|
|
220
|
+
Object.defineProperty(Else, ELSE_MARKER, { value: true });
|
|
221
|
+
Object.defineProperty(Loop, LOOP_MARKER, { value: true });
|
|
222
|
+
Object.defineProperty(Break, BREAK_MARKER, { value: true });
|
|
223
|
+
Object.defineProperty(Return, RETURN_MARKER, { value: true });
|
|
224
|
+
|
|
225
|
+
// src/components/ask-user.ts
|
|
226
|
+
function AskUser(_props) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
var ASK_USER_MARKER = /* @__PURE__ */ Symbol.for("react-agentic:ask-user");
|
|
230
|
+
Object.defineProperty(AskUser, ASK_USER_MARKER, { value: true });
|
|
231
|
+
|
|
232
|
+
// src/ir/nodes.ts
|
|
233
|
+
function assertNever(x) {
|
|
234
|
+
throw new Error(`Unexpected node: ${JSON.stringify(x)}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/ir/runtime-nodes.ts
|
|
238
|
+
function isRuntimeNode(node) {
|
|
239
|
+
if (!node || typeof node !== "object") return false;
|
|
240
|
+
const kind = node.kind;
|
|
241
|
+
return [
|
|
242
|
+
"runtimeVarDecl",
|
|
243
|
+
"runtimeCall",
|
|
244
|
+
"if",
|
|
245
|
+
"else",
|
|
246
|
+
"loop",
|
|
247
|
+
"break",
|
|
248
|
+
"return",
|
|
249
|
+
"askUser",
|
|
250
|
+
"spawnAgent"
|
|
251
|
+
].includes(kind ?? "");
|
|
252
|
+
}
|
|
253
|
+
function isDocument(node) {
|
|
254
|
+
if (!node || typeof node !== "object") return false;
|
|
255
|
+
return node.kind === "document";
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/index.ts
|
|
259
|
+
init_project();
|
|
260
|
+
|
|
261
|
+
// src/parser/index.ts
|
|
262
|
+
init_parser();
|
|
263
|
+
|
|
264
|
+
// src/parser/transformer.ts
|
|
265
|
+
import {
|
|
266
|
+
Node
|
|
267
|
+
} from "ts-morph";
|
|
268
|
+
init_parser();
|
|
269
|
+
function toSnakeCase(name) {
|
|
270
|
+
return name.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
|
|
271
|
+
}
|
|
272
|
+
var HTML_ELEMENTS = /* @__PURE__ */ new Set([
|
|
273
|
+
"h1",
|
|
274
|
+
"h2",
|
|
275
|
+
"h3",
|
|
276
|
+
"h4",
|
|
277
|
+
"h5",
|
|
278
|
+
"h6",
|
|
279
|
+
"p",
|
|
280
|
+
"div",
|
|
281
|
+
"span",
|
|
282
|
+
"ul",
|
|
283
|
+
"ol",
|
|
284
|
+
"li",
|
|
285
|
+
"a",
|
|
286
|
+
"b",
|
|
287
|
+
"i",
|
|
288
|
+
"strong",
|
|
289
|
+
"em",
|
|
290
|
+
"code",
|
|
291
|
+
"pre",
|
|
292
|
+
"blockquote",
|
|
293
|
+
"br",
|
|
294
|
+
"hr"
|
|
295
|
+
]);
|
|
296
|
+
var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
|
|
297
|
+
"a",
|
|
298
|
+
"b",
|
|
299
|
+
"i",
|
|
300
|
+
"strong",
|
|
301
|
+
"em",
|
|
302
|
+
"code",
|
|
303
|
+
"span",
|
|
304
|
+
"br"
|
|
305
|
+
]);
|
|
306
|
+
function isInlineElement(tagName) {
|
|
307
|
+
return INLINE_ELEMENTS.has(tagName);
|
|
308
|
+
}
|
|
309
|
+
var SPECIAL_COMPONENTS = /* @__PURE__ */ new Set([
|
|
310
|
+
"Command",
|
|
311
|
+
"Markdown",
|
|
312
|
+
"XmlBlock",
|
|
313
|
+
"Agent",
|
|
314
|
+
"SpawnAgent",
|
|
315
|
+
"Assign",
|
|
316
|
+
"AssignGroup",
|
|
317
|
+
"If",
|
|
318
|
+
"Else",
|
|
319
|
+
"Loop",
|
|
320
|
+
"OnStatus",
|
|
321
|
+
"Skill",
|
|
322
|
+
"SkillFile",
|
|
323
|
+
"SkillStatic",
|
|
324
|
+
"ReadState",
|
|
325
|
+
"WriteState",
|
|
326
|
+
"MCPServer",
|
|
327
|
+
"MCPStdioServer",
|
|
328
|
+
"MCPHTTPServer",
|
|
329
|
+
"MCPConfig",
|
|
330
|
+
"State",
|
|
331
|
+
"Operation",
|
|
332
|
+
"Table",
|
|
333
|
+
"List",
|
|
334
|
+
// Semantic workflow components
|
|
335
|
+
"ExecutionContext",
|
|
336
|
+
"SuccessCriteria",
|
|
337
|
+
"OfferNext",
|
|
338
|
+
"XmlSection",
|
|
339
|
+
"DeviationRules",
|
|
340
|
+
"CommitRules",
|
|
341
|
+
"WaveExecution",
|
|
342
|
+
"CheckpointHandling",
|
|
343
|
+
// Step workflow primitive
|
|
344
|
+
"Step",
|
|
345
|
+
// Code block primitives
|
|
346
|
+
"Bash",
|
|
347
|
+
// File reading
|
|
348
|
+
"ReadFiles",
|
|
349
|
+
// Template primitives
|
|
350
|
+
"PromptTemplate"
|
|
351
|
+
]);
|
|
352
|
+
function isCustomComponent(tagName) {
|
|
353
|
+
if (HTML_ELEMENTS.has(tagName)) return false;
|
|
354
|
+
if (SPECIAL_COMPONENTS.has(tagName)) return false;
|
|
355
|
+
return /^[A-Z]/.test(tagName);
|
|
356
|
+
}
|
|
357
|
+
var XML_NAME_REGEX = /^[a-zA-Z_][a-zA-Z0-9_.\-]*$/;
|
|
358
|
+
function isValidXmlName(name) {
|
|
359
|
+
if (!name) return false;
|
|
360
|
+
if (!XML_NAME_REGEX.test(name)) return false;
|
|
361
|
+
if (name.toLowerCase().startsWith("xml")) return false;
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
var Transformer = class {
|
|
365
|
+
/** Source file for component resolution (optional - only needed for composition) */
|
|
366
|
+
sourceFile;
|
|
367
|
+
/** Visited paths for circular import detection */
|
|
368
|
+
visitedPaths = /* @__PURE__ */ new Set();
|
|
369
|
+
/** Extracted useVariable declarations from source file */
|
|
370
|
+
variables = /* @__PURE__ */ new Map();
|
|
371
|
+
/** Extracted useOutput declarations: identifier name -> agent name */
|
|
372
|
+
outputs = /* @__PURE__ */ new Map();
|
|
373
|
+
/** Extracted useStateRef declarations: identifier name -> state key */
|
|
374
|
+
stateRefs = /* @__PURE__ */ new Map();
|
|
375
|
+
/** Current render props context for interpolation (set during Command/Agent transformation) */
|
|
376
|
+
renderPropsContext;
|
|
377
|
+
/**
|
|
378
|
+
* Create a TranspileError with source location context from a node
|
|
379
|
+
*/
|
|
380
|
+
createError(message, node) {
|
|
381
|
+
const location = getNodeLocation(node);
|
|
382
|
+
const sourceCode = getSourceCode(node.getSourceFile());
|
|
383
|
+
return new TranspileError(message, location, sourceCode);
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Build a TransformContext from instance state for delegation to document transformers
|
|
387
|
+
*/
|
|
388
|
+
buildContext() {
|
|
389
|
+
return {
|
|
390
|
+
sourceFile: this.sourceFile,
|
|
391
|
+
visitedPaths: this.visitedPaths,
|
|
392
|
+
variables: this.variables,
|
|
393
|
+
outputs: this.outputs,
|
|
394
|
+
stateRefs: this.stateRefs,
|
|
395
|
+
renderPropsContext: this.renderPropsContext,
|
|
396
|
+
createError: this.createError.bind(this),
|
|
397
|
+
// Provide V1 transformBlockChildren - ignores ctx since we use instance state
|
|
398
|
+
transformBlockChildren: (children, _ctx) => this.transformBlockChildren(children)
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Transform a root JSX element/fragment into AgentDocumentNode, SkillDocumentNode, MCPConfigDocumentNode, or StateDocumentNode
|
|
403
|
+
*
|
|
404
|
+
* Note: Command documents use the runtime transformer (transformRuntimeCommand) for runtime feature support.
|
|
405
|
+
*
|
|
406
|
+
* @param node - The root JSX element/fragment to transform
|
|
407
|
+
* @param sourceFile - Optional source file for component composition resolution
|
|
408
|
+
*/
|
|
409
|
+
transform(node, sourceFile) {
|
|
410
|
+
this.sourceFile = sourceFile;
|
|
411
|
+
this.visitedPaths = /* @__PURE__ */ new Set();
|
|
412
|
+
this.variables = /* @__PURE__ */ new Map();
|
|
413
|
+
this.outputs = /* @__PURE__ */ new Map();
|
|
414
|
+
this.stateRefs = /* @__PURE__ */ new Map();
|
|
415
|
+
if (sourceFile) {
|
|
416
|
+
this.visitedPaths.add(sourceFile.getFilePath());
|
|
417
|
+
this.variables = extractVariableDeclarations(sourceFile);
|
|
418
|
+
this.outputs = this.extractOutputDeclarations(sourceFile);
|
|
419
|
+
this.stateRefs = this.extractStateRefDeclarations(sourceFile);
|
|
420
|
+
}
|
|
421
|
+
if (Node.isJsxElement(node) || Node.isJsxSelfClosingElement(node)) {
|
|
422
|
+
const name = getElementName(node);
|
|
423
|
+
if (name === "Command") {
|
|
424
|
+
return this.transformCommand(node);
|
|
425
|
+
}
|
|
426
|
+
if (name === "Agent") {
|
|
427
|
+
return this.transformAgent(node);
|
|
428
|
+
}
|
|
429
|
+
if (name === "Skill") {
|
|
430
|
+
return this.transformSkill(node);
|
|
431
|
+
}
|
|
432
|
+
if (name === "MCPConfig") {
|
|
433
|
+
return this.transformMCPConfig(node);
|
|
434
|
+
}
|
|
435
|
+
if (name === "State") {
|
|
436
|
+
return this.transformState(node);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (Node.isJsxFragment(node)) {
|
|
440
|
+
throw new Error(
|
|
441
|
+
"JSX Fragment not supported. Use a document wrapper: <Agent>, <Skill>, <MCPConfig>, <State>, or use runtime transformer for <Command>."
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
throw new Error(
|
|
445
|
+
`Unknown root element. Use a document wrapper: <Agent>, <Skill>, <MCPConfig>, <State>, or use runtime transformer for <Command>.`
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Merge Command props from spread attributes and explicit attributes
|
|
450
|
+
*
|
|
451
|
+
* Processes attributes in order - later props override earlier ones.
|
|
452
|
+
* Supports spread attributes: {...baseProps}
|
|
453
|
+
* Supports explicit attributes: name="value" or name={"value"} or name={["a", "b"]}
|
|
454
|
+
*/
|
|
455
|
+
mergeCommandProps(opening) {
|
|
456
|
+
const merged = {};
|
|
457
|
+
for (const attr of opening.getAttributes()) {
|
|
458
|
+
if (Node.isJsxSpreadAttribute(attr)) {
|
|
459
|
+
const spreadProps = resolveSpreadAttribute(attr);
|
|
460
|
+
Object.assign(merged, spreadProps);
|
|
461
|
+
} else if (Node.isJsxAttribute(attr)) {
|
|
462
|
+
const attrName = attr.getNameNode().getText();
|
|
463
|
+
const stringValue = getAttributeValue(opening, attrName);
|
|
464
|
+
if (stringValue !== void 0) {
|
|
465
|
+
merged[attrName] = stringValue;
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
const arrayValue = getArrayAttributeValue(opening, attrName);
|
|
469
|
+
if (arrayValue !== void 0) {
|
|
470
|
+
merged[attrName] = arrayValue;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return merged;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Transform a Command element
|
|
478
|
+
*
|
|
479
|
+
* NOTE: This transformer is deprecated for Commands. Commands should use the runtime transformer
|
|
480
|
+
* which supports runtime features (useRuntimeVar, If/Else/Loop, etc.).
|
|
481
|
+
*/
|
|
482
|
+
transformCommand(node) {
|
|
483
|
+
throw this.createError(
|
|
484
|
+
"This transformer is deprecated for Commands. Use the runtime transformer (transformRuntimeCommand) instead. Commands should import from react-agentic and use runtime features (useRuntimeVar, If, Else, Loop).",
|
|
485
|
+
node
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Transform an Agent element to AgentDocumentNode with frontmatter
|
|
490
|
+
* Delegates to document.ts transformAgent()
|
|
491
|
+
*/
|
|
492
|
+
transformAgent(node) {
|
|
493
|
+
return transformAgent(node, this.buildContext());
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Transform a Skill element to SkillDocumentNode with frontmatter, body, files, and statics
|
|
497
|
+
* Delegates to document.ts transformSkill()
|
|
498
|
+
*/
|
|
499
|
+
transformSkill(node) {
|
|
500
|
+
return transformSkill(node, this.buildContext());
|
|
501
|
+
}
|
|
502
|
+
transformFragmentChildren(node) {
|
|
503
|
+
return this.transformBlockChildren(node.getJsxChildren());
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Transform arrow function body to IR blocks
|
|
507
|
+
* Handles both block body { return ... } and expression body
|
|
508
|
+
*/
|
|
509
|
+
transformArrowFunctionBody(arrowFn) {
|
|
510
|
+
const body = arrowFn.getBody();
|
|
511
|
+
if (Node.isBlock(body)) {
|
|
512
|
+
const returnStmt = body.getStatements().find((stmt) => Node.isReturnStatement(stmt));
|
|
513
|
+
if (returnStmt && Node.isReturnStatement(returnStmt)) {
|
|
514
|
+
const returnExpr = returnStmt.getExpression();
|
|
515
|
+
if (returnExpr) {
|
|
516
|
+
if (Node.isJsxElement(returnExpr) || Node.isJsxSelfClosingElement(returnExpr)) {
|
|
517
|
+
const block = this.transformToBlock(returnExpr);
|
|
518
|
+
return block ? [block] : [];
|
|
519
|
+
}
|
|
520
|
+
if (Node.isJsxFragment(returnExpr)) {
|
|
521
|
+
return this.transformFragmentChildren(returnExpr);
|
|
522
|
+
}
|
|
523
|
+
if (Node.isParenthesizedExpression(returnExpr)) {
|
|
524
|
+
const inner = returnExpr.getExpression();
|
|
525
|
+
if (Node.isJsxElement(inner) || Node.isJsxSelfClosingElement(inner)) {
|
|
526
|
+
const block = this.transformToBlock(inner);
|
|
527
|
+
return block ? [block] : [];
|
|
528
|
+
}
|
|
529
|
+
if (Node.isJsxFragment(inner)) {
|
|
530
|
+
return this.transformFragmentChildren(inner);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return [];
|
|
536
|
+
}
|
|
537
|
+
if (Node.isJsxElement(body) || Node.isJsxSelfClosingElement(body)) {
|
|
538
|
+
const block = this.transformToBlock(body);
|
|
539
|
+
return block ? [block] : [];
|
|
540
|
+
}
|
|
541
|
+
if (Node.isJsxFragment(body)) {
|
|
542
|
+
return this.transformFragmentChildren(body);
|
|
543
|
+
}
|
|
544
|
+
if (Node.isParenthesizedExpression(body)) {
|
|
545
|
+
const inner = body.getExpression();
|
|
546
|
+
if (Node.isJsxElement(inner) || Node.isJsxSelfClosingElement(inner)) {
|
|
547
|
+
const block = this.transformToBlock(inner);
|
|
548
|
+
return block ? [block] : [];
|
|
549
|
+
}
|
|
550
|
+
if (Node.isJsxFragment(inner)) {
|
|
551
|
+
return this.transformFragmentChildren(inner);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return [];
|
|
555
|
+
}
|
|
556
|
+
transformToBlock(node) {
|
|
557
|
+
if (Node.isJsxText(node)) {
|
|
558
|
+
const text = extractText(node);
|
|
559
|
+
if (!text) return null;
|
|
560
|
+
return { kind: "paragraph", children: [{ kind: "text", value: text }] };
|
|
561
|
+
}
|
|
562
|
+
if (Node.isJsxElement(node) || Node.isJsxSelfClosingElement(node)) {
|
|
563
|
+
const name = getElementName(node);
|
|
564
|
+
return this.transformElement(name, node);
|
|
565
|
+
}
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
transformElement(name, node) {
|
|
569
|
+
const headingMatch = name.match(/^h([1-6])$/);
|
|
570
|
+
if (headingMatch) {
|
|
571
|
+
const level = parseInt(headingMatch[1], 10);
|
|
572
|
+
const children = Node.isJsxElement(node) ? this.transformInlineChildren(node) : [];
|
|
573
|
+
return { kind: "heading", level, children };
|
|
574
|
+
}
|
|
575
|
+
if (name === "p") {
|
|
576
|
+
const children = Node.isJsxElement(node) ? this.transformInlineChildren(node) : [];
|
|
577
|
+
return { kind: "paragraph", children };
|
|
578
|
+
}
|
|
579
|
+
if (name === "hr") {
|
|
580
|
+
return { kind: "thematicBreak" };
|
|
581
|
+
}
|
|
582
|
+
if (name === "ul") {
|
|
583
|
+
return this.transformList(node, false);
|
|
584
|
+
}
|
|
585
|
+
if (name === "ol") {
|
|
586
|
+
return this.transformList(node, true);
|
|
587
|
+
}
|
|
588
|
+
if (name === "blockquote") {
|
|
589
|
+
return this.transformBlockquote(node);
|
|
590
|
+
}
|
|
591
|
+
if (name === "pre") {
|
|
592
|
+
return this.transformCodeBlock(node);
|
|
593
|
+
}
|
|
594
|
+
if (name === "div") {
|
|
595
|
+
return this.transformDiv(node);
|
|
596
|
+
}
|
|
597
|
+
if (name === "XmlBlock") {
|
|
598
|
+
return this.transformXmlBlock(node);
|
|
599
|
+
}
|
|
600
|
+
if (name === "SpawnAgent") {
|
|
601
|
+
return this.transformSpawnAgent(node);
|
|
602
|
+
}
|
|
603
|
+
if (name === "Assign") {
|
|
604
|
+
return this.transformAssign(node);
|
|
605
|
+
}
|
|
606
|
+
if (name === "AssignGroup") {
|
|
607
|
+
return this.transformAssignGroup(node);
|
|
608
|
+
}
|
|
609
|
+
if (name === "If") {
|
|
610
|
+
return this.transformIf(node);
|
|
611
|
+
}
|
|
612
|
+
if (name === "Else") {
|
|
613
|
+
throw this.createError("<Else> must follow <If> as sibling", node);
|
|
614
|
+
}
|
|
615
|
+
if (name === "Loop") {
|
|
616
|
+
return this.transformLoop(node);
|
|
617
|
+
}
|
|
618
|
+
if (name === "OnStatus") {
|
|
619
|
+
return this.transformOnStatus(node);
|
|
620
|
+
}
|
|
621
|
+
if (name === "ReadState") {
|
|
622
|
+
return this.transformReadState(node);
|
|
623
|
+
}
|
|
624
|
+
if (name === "WriteState") {
|
|
625
|
+
return this.transformWriteState(node);
|
|
626
|
+
}
|
|
627
|
+
if (name === "Table") {
|
|
628
|
+
return this.transformTable(node);
|
|
629
|
+
}
|
|
630
|
+
if (name === "List") {
|
|
631
|
+
return this.transformPropList(node);
|
|
632
|
+
}
|
|
633
|
+
if (name === "ExecutionContext") {
|
|
634
|
+
return this.transformExecutionContext(node);
|
|
635
|
+
}
|
|
636
|
+
if (name === "SuccessCriteria") {
|
|
637
|
+
return this.transformSuccessCriteria(node);
|
|
638
|
+
}
|
|
639
|
+
if (name === "OfferNext") {
|
|
640
|
+
return this.transformOfferNext(node);
|
|
641
|
+
}
|
|
642
|
+
if (name === "XmlSection") {
|
|
643
|
+
return this.transformXmlSection(node);
|
|
644
|
+
}
|
|
645
|
+
if (name === "DeviationRules" || name === "CommitRules" || name === "WaveExecution" || name === "CheckpointHandling") {
|
|
646
|
+
return this.transformXmlWrapper(name, node);
|
|
647
|
+
}
|
|
648
|
+
if (name === "Step") {
|
|
649
|
+
return this.transformStep(node);
|
|
650
|
+
}
|
|
651
|
+
if (name === "Bash") {
|
|
652
|
+
return this.transformBash(node);
|
|
653
|
+
}
|
|
654
|
+
if (name === "ReadFiles") {
|
|
655
|
+
return this.transformReadFiles(node);
|
|
656
|
+
}
|
|
657
|
+
if (name === "PromptTemplate") {
|
|
658
|
+
return this.transformPromptTemplate(node);
|
|
659
|
+
}
|
|
660
|
+
if (name === "Markdown") {
|
|
661
|
+
return this.transformMarkdown(node);
|
|
662
|
+
}
|
|
663
|
+
if (isCustomComponent(name)) {
|
|
664
|
+
return this.transformCustomComponent(name, node);
|
|
665
|
+
}
|
|
666
|
+
throw this.createError(`Unsupported block element: <${name}>`, node);
|
|
667
|
+
}
|
|
668
|
+
transformList(node, ordered) {
|
|
669
|
+
if (Node.isJsxSelfClosingElement(node)) {
|
|
670
|
+
return { kind: "list", ordered, items: [] };
|
|
671
|
+
}
|
|
672
|
+
const items = [];
|
|
673
|
+
for (const child of node.getJsxChildren()) {
|
|
674
|
+
if (Node.isJsxElement(child)) {
|
|
675
|
+
const childName = getElementName(child);
|
|
676
|
+
if (childName === "li") {
|
|
677
|
+
items.push(this.transformListItem(child));
|
|
678
|
+
} else {
|
|
679
|
+
throw this.createError(`Expected <li> inside list, got <${childName}>`, child);
|
|
680
|
+
}
|
|
681
|
+
} else if (Node.isJsxText(child) && !child.containsOnlyTriviaWhiteSpaces()) {
|
|
682
|
+
throw this.createError("Lists can only contain <li> elements", child);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return { kind: "list", ordered, items };
|
|
686
|
+
}
|
|
687
|
+
transformListItem(node) {
|
|
688
|
+
const children = [];
|
|
689
|
+
const jsxChildren = node.getJsxChildren();
|
|
690
|
+
const isBlockContent = (child) => {
|
|
691
|
+
if (Node.isJsxElement(child) || Node.isJsxSelfClosingElement(child)) {
|
|
692
|
+
const name = getElementName(child);
|
|
693
|
+
return name === "ul" || name === "ol" || name === "p";
|
|
694
|
+
}
|
|
695
|
+
return false;
|
|
696
|
+
};
|
|
697
|
+
let inlineSequence = [];
|
|
698
|
+
const flushInlineSequence = () => {
|
|
699
|
+
if (inlineSequence.length === 0) return;
|
|
700
|
+
const inlines = [];
|
|
701
|
+
for (const child of inlineSequence) {
|
|
702
|
+
const inline = this.transformToInline(child);
|
|
703
|
+
if (inline) inlines.push(inline);
|
|
704
|
+
}
|
|
705
|
+
this.trimBoundaryTextNodes(inlines);
|
|
706
|
+
if (inlines.length > 0) {
|
|
707
|
+
const lastChild = children[children.length - 1];
|
|
708
|
+
if (lastChild?.kind === "paragraph") {
|
|
709
|
+
lastChild.children.push(...inlines);
|
|
710
|
+
} else {
|
|
711
|
+
children.push({ kind: "paragraph", children: inlines });
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
inlineSequence = [];
|
|
715
|
+
};
|
|
716
|
+
for (const child of jsxChildren) {
|
|
717
|
+
if (isBlockContent(child)) {
|
|
718
|
+
flushInlineSequence();
|
|
719
|
+
const childName = getElementName(child);
|
|
720
|
+
if (childName === "ul" || childName === "ol") {
|
|
721
|
+
const nestedList = this.transformElement(childName, child);
|
|
722
|
+
if (nestedList) children.push(nestedList);
|
|
723
|
+
} else if (childName === "p") {
|
|
724
|
+
const para = this.transformElement(childName, child);
|
|
725
|
+
if (para) children.push(para);
|
|
726
|
+
}
|
|
727
|
+
} else {
|
|
728
|
+
inlineSequence.push(child);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
flushInlineSequence();
|
|
732
|
+
return { kind: "listItem", children };
|
|
733
|
+
}
|
|
734
|
+
transformBlockquote(node) {
|
|
735
|
+
if (Node.isJsxSelfClosingElement(node)) {
|
|
736
|
+
return { kind: "blockquote", children: [] };
|
|
737
|
+
}
|
|
738
|
+
const children = this.transformBlockChildren(node.getJsxChildren());
|
|
739
|
+
return { kind: "blockquote", children };
|
|
740
|
+
}
|
|
741
|
+
transformCodeBlock(node) {
|
|
742
|
+
if (Node.isJsxSelfClosingElement(node)) {
|
|
743
|
+
return { kind: "codeBlock", content: "" };
|
|
744
|
+
}
|
|
745
|
+
const children = node.getJsxChildren();
|
|
746
|
+
for (const child of children) {
|
|
747
|
+
if (Node.isJsxElement(child) && getElementName(child) === "code") {
|
|
748
|
+
const language = getAttributeValue(
|
|
749
|
+
child.getOpeningElement(),
|
|
750
|
+
"className"
|
|
751
|
+
)?.replace(/^language-/, "");
|
|
752
|
+
const content2 = this.extractCodeContent(child);
|
|
753
|
+
return { kind: "codeBlock", language, content: content2 };
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
const content = this.extractCodeContent(node);
|
|
757
|
+
return { kind: "codeBlock", content };
|
|
758
|
+
}
|
|
759
|
+
extractCodeContent(node) {
|
|
760
|
+
const parts = [];
|
|
761
|
+
for (const child of node.getJsxChildren()) {
|
|
762
|
+
if (Node.isJsxText(child)) {
|
|
763
|
+
parts.push(child.getText());
|
|
764
|
+
} else if (Node.isJsxExpression(child)) {
|
|
765
|
+
const expr = child.getExpression();
|
|
766
|
+
if (expr) {
|
|
767
|
+
if (Node.isStringLiteral(expr)) {
|
|
768
|
+
parts.push(expr.getLiteralValue());
|
|
769
|
+
} else if (Node.isNoSubstitutionTemplateLiteral(expr)) {
|
|
770
|
+
parts.push(expr.getLiteralValue());
|
|
771
|
+
} else if (Node.isTemplateExpression(expr)) {
|
|
772
|
+
parts.push(this.extractTemplateText(expr));
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
return parts.join("").trim();
|
|
778
|
+
}
|
|
779
|
+
transformInlineChildren(node) {
|
|
780
|
+
const children = node.getJsxChildren();
|
|
781
|
+
const inlines = [];
|
|
782
|
+
for (const child of children) {
|
|
783
|
+
const inline = this.transformToInline(child);
|
|
784
|
+
if (inline) inlines.push(inline);
|
|
785
|
+
}
|
|
786
|
+
this.trimBoundaryTextNodes(inlines);
|
|
787
|
+
return inlines;
|
|
788
|
+
}
|
|
789
|
+
trimBoundaryTextNodes(inlines) {
|
|
790
|
+
if (inlines.length === 0) return;
|
|
791
|
+
const first = inlines[0];
|
|
792
|
+
if (first.kind === "text") {
|
|
793
|
+
first.value = first.value.trimStart();
|
|
794
|
+
if (!first.value) {
|
|
795
|
+
inlines.shift();
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
if (inlines.length === 0) return;
|
|
799
|
+
const last = inlines[inlines.length - 1];
|
|
800
|
+
if (last.kind === "text") {
|
|
801
|
+
last.value = last.value.trimEnd();
|
|
802
|
+
if (!last.value) {
|
|
803
|
+
inlines.pop();
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
transformToInline(node) {
|
|
808
|
+
if (Node.isJsxText(node)) {
|
|
809
|
+
const text = extractInlineText(node);
|
|
810
|
+
if (!text) return null;
|
|
811
|
+
return { kind: "text", value: text };
|
|
812
|
+
}
|
|
813
|
+
if (Node.isJsxSelfClosingElement(node)) {
|
|
814
|
+
const name = getElementName(node);
|
|
815
|
+
if (name === "br") {
|
|
816
|
+
return { kind: "lineBreak" };
|
|
817
|
+
}
|
|
818
|
+
throw this.createError(`Unsupported inline self-closing element: <${name}>`, node);
|
|
819
|
+
}
|
|
820
|
+
if (Node.isJsxElement(node)) {
|
|
821
|
+
const name = getElementName(node);
|
|
822
|
+
return this.transformInlineElement(name, node);
|
|
823
|
+
}
|
|
824
|
+
if (Node.isJsxExpression(node)) {
|
|
825
|
+
const expr = node.getExpression();
|
|
826
|
+
if (!expr) return null;
|
|
827
|
+
if (Node.isStringLiteral(expr)) {
|
|
828
|
+
const value = expr.getLiteralValue();
|
|
829
|
+
if (value) {
|
|
830
|
+
return { kind: "text", value };
|
|
831
|
+
}
|
|
832
|
+
return null;
|
|
833
|
+
}
|
|
834
|
+
if (Node.isCallExpression(expr)) {
|
|
835
|
+
const propAccess = expr.getExpression();
|
|
836
|
+
if (Node.isPropertyAccessExpression(propAccess)) {
|
|
837
|
+
const methodName = propAccess.getName();
|
|
838
|
+
const objExpr = propAccess.getExpression();
|
|
839
|
+
if (methodName === "field" && Node.isIdentifier(objExpr)) {
|
|
840
|
+
const outputName = objExpr.getText();
|
|
841
|
+
if (this.outputs.has(outputName)) {
|
|
842
|
+
const args = expr.getArguments();
|
|
843
|
+
if (args.length >= 1) {
|
|
844
|
+
const keyArg = args[0];
|
|
845
|
+
if (Node.isStringLiteral(keyArg)) {
|
|
846
|
+
const fieldKey = keyArg.getLiteralValue();
|
|
847
|
+
return { kind: "text", value: `{output.${fieldKey}}` };
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
if (Node.isPropertyAccessExpression(expr)) {
|
|
855
|
+
const objExpr = expr.getExpression();
|
|
856
|
+
const propName = expr.getName();
|
|
857
|
+
if (Node.isIdentifier(objExpr) && this.renderPropsContext) {
|
|
858
|
+
const objName = objExpr.getText();
|
|
859
|
+
if (objName === this.renderPropsContext.paramName) {
|
|
860
|
+
const value = this.renderPropsContext.values[propName];
|
|
861
|
+
if (value !== void 0) {
|
|
862
|
+
return { kind: "text", value };
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
869
|
+
return null;
|
|
870
|
+
}
|
|
871
|
+
transformInlineElement(name, node) {
|
|
872
|
+
if (name === "b" || name === "strong") {
|
|
873
|
+
return { kind: "bold", children: this.transformInlineChildren(node) };
|
|
874
|
+
}
|
|
875
|
+
if (name === "i" || name === "em") {
|
|
876
|
+
return { kind: "italic", children: this.transformInlineChildren(node) };
|
|
877
|
+
}
|
|
878
|
+
if (name === "code") {
|
|
879
|
+
const text = this.extractAllText(node);
|
|
880
|
+
return { kind: "inlineCode", value: text };
|
|
881
|
+
}
|
|
882
|
+
if (name === "a") {
|
|
883
|
+
return this.transformLink(node);
|
|
884
|
+
}
|
|
885
|
+
throw this.createError(`Unsupported inline element: <${name}>`, node);
|
|
886
|
+
}
|
|
887
|
+
extractAllText(node) {
|
|
888
|
+
const parts = [];
|
|
889
|
+
for (const child of node.getJsxChildren()) {
|
|
890
|
+
if (Node.isJsxText(child)) {
|
|
891
|
+
const text = extractText(child);
|
|
892
|
+
if (text) parts.push(text);
|
|
893
|
+
} else if (Node.isJsxExpression(child)) {
|
|
894
|
+
const expr = child.getExpression();
|
|
895
|
+
if (expr) {
|
|
896
|
+
if (Node.isStringLiteral(expr)) {
|
|
897
|
+
parts.push(expr.getLiteralValue());
|
|
898
|
+
} else if (Node.isNoSubstitutionTemplateLiteral(expr)) {
|
|
899
|
+
parts.push(expr.getLiteralValue());
|
|
900
|
+
} else if (Node.isTemplateExpression(expr)) {
|
|
901
|
+
parts.push(this.extractTemplateText(expr));
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return parts.join("");
|
|
907
|
+
}
|
|
908
|
+
transformLink(node) {
|
|
909
|
+
const href = getAttributeValue(node.getOpeningElement(), "href");
|
|
910
|
+
if (!href) {
|
|
911
|
+
throw this.createError("<a> element requires href attribute", node);
|
|
912
|
+
}
|
|
913
|
+
const children = this.transformInlineChildren(node);
|
|
914
|
+
return { kind: "link", url: href, children };
|
|
915
|
+
}
|
|
916
|
+
transformDiv(node) {
|
|
917
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
918
|
+
const nameAttr = getAttributeValue(openingElement, "name");
|
|
919
|
+
const children = Node.isJsxElement(node) ? this.transformMixedChildren(node.getJsxChildren()) : [];
|
|
920
|
+
if (!nameAttr) {
|
|
921
|
+
return {
|
|
922
|
+
kind: "group",
|
|
923
|
+
children
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
if (!isValidXmlName(nameAttr)) {
|
|
927
|
+
throw this.createError(
|
|
928
|
+
`Invalid XML tag name '${nameAttr}' - must start with letter/underscore, contain only letters, digits, underscores, hyphens, or periods, and not start with 'xml'`,
|
|
929
|
+
node
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
const attributes = {};
|
|
933
|
+
for (const attr of openingElement.getAttributes()) {
|
|
934
|
+
if (Node.isJsxAttribute(attr)) {
|
|
935
|
+
const attrName = attr.getNameNode().getText();
|
|
936
|
+
if (attrName !== "name") {
|
|
937
|
+
const value = getAttributeValue(openingElement, attrName);
|
|
938
|
+
if (value !== void 0) {
|
|
939
|
+
attributes[attrName] = value;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return {
|
|
945
|
+
kind: "xmlBlock",
|
|
946
|
+
name: nameAttr,
|
|
947
|
+
attributes: Object.keys(attributes).length > 0 ? attributes : void 0,
|
|
948
|
+
children
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Transform mixed children (inline + block elements)
|
|
953
|
+
* Consecutive inline elements and text are wrapped in a single paragraph
|
|
954
|
+
* Block elements are transformed normally
|
|
955
|
+
*/
|
|
956
|
+
transformMixedChildren(jsxChildren) {
|
|
957
|
+
const blocks = [];
|
|
958
|
+
let inlineAccumulator = [];
|
|
959
|
+
const flushInline = () => {
|
|
960
|
+
if (inlineAccumulator.length > 0) {
|
|
961
|
+
const inlineNodes = this.transformInlineNodes(inlineAccumulator);
|
|
962
|
+
if (inlineNodes.length > 0) {
|
|
963
|
+
blocks.push({ kind: "paragraph", children: inlineNodes });
|
|
964
|
+
}
|
|
965
|
+
inlineAccumulator = [];
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
for (const child of jsxChildren) {
|
|
969
|
+
if (Node.isJsxText(child)) {
|
|
970
|
+
const text = extractText(child);
|
|
971
|
+
if (text) {
|
|
972
|
+
inlineAccumulator.push(child);
|
|
973
|
+
}
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
if (Node.isJsxElement(child) || Node.isJsxSelfClosingElement(child)) {
|
|
977
|
+
const name = getElementName(child);
|
|
978
|
+
if (isInlineElement(name)) {
|
|
979
|
+
inlineAccumulator.push(child);
|
|
980
|
+
} else {
|
|
981
|
+
flushInline();
|
|
982
|
+
const block = this.transformToBlock(child);
|
|
983
|
+
if (block) blocks.push(block);
|
|
984
|
+
}
|
|
985
|
+
} else if (Node.isJsxExpression(child)) {
|
|
986
|
+
inlineAccumulator.push(child);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
flushInline();
|
|
990
|
+
return blocks;
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Transform a list of nodes to inline nodes
|
|
994
|
+
* Used by transformMixedChildren for inline accumulation
|
|
995
|
+
*/
|
|
996
|
+
transformInlineNodes(nodes) {
|
|
997
|
+
const result = [];
|
|
998
|
+
for (const node of nodes) {
|
|
999
|
+
if (Node.isJsxText(node)) {
|
|
1000
|
+
const text = extractText(node);
|
|
1001
|
+
if (text) {
|
|
1002
|
+
result.push({ kind: "text", value: text });
|
|
1003
|
+
}
|
|
1004
|
+
} else if (Node.isJsxElement(node)) {
|
|
1005
|
+
const name = getElementName(node);
|
|
1006
|
+
const inlineNode = this.transformInlineElement(name, node);
|
|
1007
|
+
if (inlineNode) result.push(inlineNode);
|
|
1008
|
+
} else if (Node.isJsxSelfClosingElement(node)) {
|
|
1009
|
+
const name = getElementName(node);
|
|
1010
|
+
if (name === "br") {
|
|
1011
|
+
result.push({ kind: "lineBreak" });
|
|
1012
|
+
}
|
|
1013
|
+
} else if (Node.isJsxExpression(node)) {
|
|
1014
|
+
const expr = node.getExpression();
|
|
1015
|
+
if (expr) {
|
|
1016
|
+
const text = expr.getText();
|
|
1017
|
+
const cleaned = text.replace(/^['"`]|['"`]$/g, "");
|
|
1018
|
+
if (cleaned) {
|
|
1019
|
+
result.push({ kind: "text", value: cleaned });
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
return result;
|
|
1025
|
+
}
|
|
1026
|
+
transformXmlBlock(node) {
|
|
1027
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1028
|
+
const nameAttr = getAttributeValue(openingElement, "name");
|
|
1029
|
+
if (!nameAttr) {
|
|
1030
|
+
throw this.createError("XmlBlock requires name prop", node);
|
|
1031
|
+
}
|
|
1032
|
+
if (!isValidXmlName(nameAttr)) {
|
|
1033
|
+
throw this.createError(
|
|
1034
|
+
`Invalid XML tag name '${nameAttr}' - must start with letter/underscore, contain only letters, digits, underscores, hyphens, or periods, and not start with 'xml'`,
|
|
1035
|
+
node
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1038
|
+
const children = Node.isJsxElement(node) ? this.transformBlockChildren(node.getJsxChildren()) : [];
|
|
1039
|
+
return {
|
|
1040
|
+
kind: "xmlBlock",
|
|
1041
|
+
name: nameAttr,
|
|
1042
|
+
children
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Transform Table component to TableNode IR
|
|
1047
|
+
*/
|
|
1048
|
+
transformTable(node) {
|
|
1049
|
+
const opening = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1050
|
+
const headers = getArrayAttributeValue(opening, "headers");
|
|
1051
|
+
const rows = this.parseRowsAttribute(opening);
|
|
1052
|
+
const alignRaw = getArrayAttributeValue(opening, "align");
|
|
1053
|
+
const emptyCell = getAttributeValue(opening, "emptyCell");
|
|
1054
|
+
const align = alignRaw?.map((a) => {
|
|
1055
|
+
if (a === "left" || a === "center" || a === "right") return a;
|
|
1056
|
+
return "left";
|
|
1057
|
+
});
|
|
1058
|
+
return {
|
|
1059
|
+
kind: "table",
|
|
1060
|
+
headers: headers?.length ? headers : void 0,
|
|
1061
|
+
rows,
|
|
1062
|
+
align,
|
|
1063
|
+
emptyCell: emptyCell || void 0
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* Parse rows attribute (array of arrays)
|
|
1068
|
+
*/
|
|
1069
|
+
parseRowsAttribute(opening) {
|
|
1070
|
+
const attr = opening.getAttribute("rows");
|
|
1071
|
+
if (!attr || !Node.isJsxAttribute(attr)) return [];
|
|
1072
|
+
const init = attr.getInitializer();
|
|
1073
|
+
if (!init || !Node.isJsxExpression(init)) return [];
|
|
1074
|
+
const expr = init.getExpression();
|
|
1075
|
+
if (!expr || !Node.isArrayLiteralExpression(expr)) return [];
|
|
1076
|
+
const rows = [];
|
|
1077
|
+
for (const element of expr.getElements()) {
|
|
1078
|
+
if (Node.isArrayLiteralExpression(element)) {
|
|
1079
|
+
const row = [];
|
|
1080
|
+
for (const cell of element.getElements()) {
|
|
1081
|
+
if (Node.isStringLiteral(cell)) {
|
|
1082
|
+
row.push(cell.getLiteralValue());
|
|
1083
|
+
} else if (Node.isNumericLiteral(cell)) {
|
|
1084
|
+
row.push(cell.getLiteralValue().toString());
|
|
1085
|
+
} else if (Node.isPropertyAccessExpression(cell)) {
|
|
1086
|
+
const interpolated = this.interpolatePropertyAccess(cell);
|
|
1087
|
+
row.push(interpolated ?? cell.getText());
|
|
1088
|
+
} else {
|
|
1089
|
+
row.push(cell.getText());
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
rows.push(row);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
return rows;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Interpolate a PropertyAccessExpression if it references render props context
|
|
1099
|
+
* Returns the interpolated value or null if not a context access
|
|
1100
|
+
*/
|
|
1101
|
+
interpolatePropertyAccess(expr) {
|
|
1102
|
+
const objExpr = expr.getExpression();
|
|
1103
|
+
const propName = expr.getName();
|
|
1104
|
+
if (Node.isIdentifier(objExpr) && this.renderPropsContext) {
|
|
1105
|
+
const objName = objExpr.getText();
|
|
1106
|
+
if (objName === this.renderPropsContext.paramName) {
|
|
1107
|
+
const value = this.renderPropsContext.values[propName];
|
|
1108
|
+
if (value !== void 0) {
|
|
1109
|
+
return value;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return null;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Transform List component (prop-based) to ListNode IR
|
|
1117
|
+
* This is separate from HTML <ul>/<ol> transformation
|
|
1118
|
+
*/
|
|
1119
|
+
transformPropList(node) {
|
|
1120
|
+
const opening = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1121
|
+
const items = getArrayAttributeValue(opening, "items") ?? [];
|
|
1122
|
+
const ordered = getAttributeValue(opening, "ordered") === "true" || opening.getAttribute("ordered") !== void 0;
|
|
1123
|
+
let start = void 0;
|
|
1124
|
+
const startAttr = opening.getAttribute("start");
|
|
1125
|
+
if (startAttr && Node.isJsxAttribute(startAttr)) {
|
|
1126
|
+
const init = startAttr.getInitializer();
|
|
1127
|
+
if (init && Node.isJsxExpression(init)) {
|
|
1128
|
+
const expr = init.getExpression();
|
|
1129
|
+
if (expr && Node.isNumericLiteral(expr)) {
|
|
1130
|
+
start = expr.getLiteralValue();
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
const listItems = items.map((item) => ({
|
|
1135
|
+
kind: "listItem",
|
|
1136
|
+
children: [{
|
|
1137
|
+
kind: "paragraph",
|
|
1138
|
+
children: [{ kind: "text", value: String(item) }]
|
|
1139
|
+
}]
|
|
1140
|
+
}));
|
|
1141
|
+
return {
|
|
1142
|
+
kind: "list",
|
|
1143
|
+
ordered,
|
|
1144
|
+
items: listItems,
|
|
1145
|
+
start
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
// ============================================================================
|
|
1149
|
+
// Semantic Workflow Components
|
|
1150
|
+
// ============================================================================
|
|
1151
|
+
transformExecutionContext(node) {
|
|
1152
|
+
const opening = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1153
|
+
const paths = getArrayAttributeValue(opening, "paths") ?? [];
|
|
1154
|
+
const prefix = getAttributeValue(opening, "prefix") ?? "@";
|
|
1155
|
+
const children = [];
|
|
1156
|
+
if (Node.isJsxElement(node)) {
|
|
1157
|
+
for (const child of node.getJsxChildren()) {
|
|
1158
|
+
const block = this.transformToBlock(child);
|
|
1159
|
+
if (block) children.push(block);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
return {
|
|
1163
|
+
kind: "executionContext",
|
|
1164
|
+
paths,
|
|
1165
|
+
prefix,
|
|
1166
|
+
children
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
transformSuccessCriteria(node) {
|
|
1170
|
+
const opening = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1171
|
+
const items = this.parseSuccessCriteriaItems(opening);
|
|
1172
|
+
return {
|
|
1173
|
+
kind: "successCriteria",
|
|
1174
|
+
items
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Parse items attribute for SuccessCriteria
|
|
1179
|
+
* Handles both string shorthand and {text, checked} objects
|
|
1180
|
+
*/
|
|
1181
|
+
parseSuccessCriteriaItems(opening) {
|
|
1182
|
+
const attr = opening.getAttribute("items");
|
|
1183
|
+
if (!attr || !Node.isJsxAttribute(attr)) return [];
|
|
1184
|
+
const init = attr.getInitializer();
|
|
1185
|
+
if (!init || !Node.isJsxExpression(init)) return [];
|
|
1186
|
+
const expr = init.getExpression();
|
|
1187
|
+
if (!expr || !Node.isArrayLiteralExpression(expr)) return [];
|
|
1188
|
+
const items = [];
|
|
1189
|
+
for (const element of expr.getElements()) {
|
|
1190
|
+
if (Node.isStringLiteral(element)) {
|
|
1191
|
+
items.push({ text: element.getLiteralValue(), checked: false });
|
|
1192
|
+
} else if (Node.isObjectLiteralExpression(element)) {
|
|
1193
|
+
let text = "";
|
|
1194
|
+
let checked = false;
|
|
1195
|
+
for (const prop of element.getProperties()) {
|
|
1196
|
+
if (Node.isPropertyAssignment(prop)) {
|
|
1197
|
+
const propName = prop.getName();
|
|
1198
|
+
const propInit = prop.getInitializer();
|
|
1199
|
+
if (propName === "text" && propInit && Node.isStringLiteral(propInit)) {
|
|
1200
|
+
text = propInit.getLiteralValue();
|
|
1201
|
+
} else if (propName === "checked" && propInit) {
|
|
1202
|
+
if (propInit.getKind() === 112) {
|
|
1203
|
+
checked = true;
|
|
1204
|
+
} else if (propInit.getKind() === 97) {
|
|
1205
|
+
checked = false;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
items.push({ text, checked });
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
return items;
|
|
1214
|
+
}
|
|
1215
|
+
transformOfferNext(node) {
|
|
1216
|
+
const opening = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1217
|
+
const routes = this.parseOfferNextRoutes(opening);
|
|
1218
|
+
return {
|
|
1219
|
+
kind: "offerNext",
|
|
1220
|
+
routes
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Parse routes attribute for OfferNext
|
|
1225
|
+
* Each route is an object with name, path, and optional description
|
|
1226
|
+
*/
|
|
1227
|
+
parseOfferNextRoutes(opening) {
|
|
1228
|
+
const attr = opening.getAttribute("routes");
|
|
1229
|
+
if (!attr || !Node.isJsxAttribute(attr)) return [];
|
|
1230
|
+
const init = attr.getInitializer();
|
|
1231
|
+
if (!init || !Node.isJsxExpression(init)) return [];
|
|
1232
|
+
const expr = init.getExpression();
|
|
1233
|
+
if (!expr || !Node.isArrayLiteralExpression(expr)) return [];
|
|
1234
|
+
const routes = [];
|
|
1235
|
+
for (const element of expr.getElements()) {
|
|
1236
|
+
if (Node.isObjectLiteralExpression(element)) {
|
|
1237
|
+
let name = "";
|
|
1238
|
+
let path = "";
|
|
1239
|
+
let description = void 0;
|
|
1240
|
+
for (const prop of element.getProperties()) {
|
|
1241
|
+
if (Node.isPropertyAssignment(prop)) {
|
|
1242
|
+
const propName = prop.getName();
|
|
1243
|
+
const propInit = prop.getInitializer();
|
|
1244
|
+
if (propInit && Node.isStringLiteral(propInit)) {
|
|
1245
|
+
const value = propInit.getLiteralValue();
|
|
1246
|
+
if (propName === "name") {
|
|
1247
|
+
name = value;
|
|
1248
|
+
} else if (propName === "path") {
|
|
1249
|
+
path = value;
|
|
1250
|
+
} else if (propName === "description") {
|
|
1251
|
+
description = value;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (name && path) {
|
|
1257
|
+
routes.push({ name, path, description });
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
return routes;
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Transform Step component to StepNode IR
|
|
1265
|
+
*/
|
|
1266
|
+
transformStep(node) {
|
|
1267
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1268
|
+
let stepNumber = void 0;
|
|
1269
|
+
const numberAttr = openingElement.getAttribute("number");
|
|
1270
|
+
if (numberAttr && Node.isJsxAttribute(numberAttr)) {
|
|
1271
|
+
const init = numberAttr.getInitializer();
|
|
1272
|
+
if (init) {
|
|
1273
|
+
if (Node.isStringLiteral(init)) {
|
|
1274
|
+
stepNumber = init.getLiteralValue();
|
|
1275
|
+
} else if (Node.isJsxExpression(init)) {
|
|
1276
|
+
const expr = init.getExpression();
|
|
1277
|
+
if (expr) {
|
|
1278
|
+
if (Node.isNumericLiteral(expr)) {
|
|
1279
|
+
stepNumber = String(expr.getLiteralValue());
|
|
1280
|
+
} else if (Node.isStringLiteral(expr)) {
|
|
1281
|
+
stepNumber = expr.getLiteralValue();
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
const name = getAttributeValue(openingElement, "name");
|
|
1288
|
+
if (!stepNumber) {
|
|
1289
|
+
throw this.createError("Step requires number prop", openingElement);
|
|
1290
|
+
}
|
|
1291
|
+
if (!name) {
|
|
1292
|
+
throw this.createError("Step requires name prop", openingElement);
|
|
1293
|
+
}
|
|
1294
|
+
const variantAttr = getAttributeValue(openingElement, "variant");
|
|
1295
|
+
let variant = "heading";
|
|
1296
|
+
if (variantAttr === "heading" || variantAttr === "bold" || variantAttr === "xml") {
|
|
1297
|
+
variant = variantAttr;
|
|
1298
|
+
}
|
|
1299
|
+
const children = Node.isJsxElement(node) ? this.transformBlockChildren(node.getJsxChildren()) : [];
|
|
1300
|
+
return {
|
|
1301
|
+
kind: "step",
|
|
1302
|
+
number: stepNumber,
|
|
1303
|
+
name,
|
|
1304
|
+
variant,
|
|
1305
|
+
children
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Transform <Bash> to CodeBlockNode with language 'bash'
|
|
1310
|
+
*
|
|
1311
|
+
* <Bash>ls -la</Bash>
|
|
1312
|
+
* becomes:
|
|
1313
|
+
* ```bash
|
|
1314
|
+
* ls -la
|
|
1315
|
+
* ```
|
|
1316
|
+
*/
|
|
1317
|
+
transformBash(node) {
|
|
1318
|
+
if (Node.isJsxSelfClosingElement(node)) {
|
|
1319
|
+
return { kind: "codeBlock", language: "bash", content: "" };
|
|
1320
|
+
}
|
|
1321
|
+
const content = this.extractCodeContent(node);
|
|
1322
|
+
return {
|
|
1323
|
+
kind: "codeBlock",
|
|
1324
|
+
language: "bash",
|
|
1325
|
+
content
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Transform <ReadFiles> to ReadFilesNode
|
|
1330
|
+
*
|
|
1331
|
+
* Extracts the files prop (which should be a defineFiles() result)
|
|
1332
|
+
* and creates a ReadFilesNode with file entries.
|
|
1333
|
+
*/
|
|
1334
|
+
transformReadFiles(node) {
|
|
1335
|
+
const opening = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1336
|
+
const filesAttr = opening.getAttribute("files");
|
|
1337
|
+
if (!filesAttr || !Node.isJsxAttribute(filesAttr)) {
|
|
1338
|
+
throw this.createError("ReadFiles requires files prop", node);
|
|
1339
|
+
}
|
|
1340
|
+
const init = filesAttr.getInitializer();
|
|
1341
|
+
if (!init || !Node.isJsxExpression(init)) {
|
|
1342
|
+
throw this.createError("ReadFiles files prop must be a JSX expression", node);
|
|
1343
|
+
}
|
|
1344
|
+
const expr = init.getExpression();
|
|
1345
|
+
if (!expr) {
|
|
1346
|
+
throw this.createError("ReadFiles files prop expression is empty", node);
|
|
1347
|
+
}
|
|
1348
|
+
const files = [];
|
|
1349
|
+
if (Node.isIdentifier(expr)) {
|
|
1350
|
+
const varName = expr.getText();
|
|
1351
|
+
const sourceFile = this.sourceFile;
|
|
1352
|
+
if (sourceFile) {
|
|
1353
|
+
const statements = sourceFile.getStatements();
|
|
1354
|
+
for (const stmt of statements) {
|
|
1355
|
+
if (Node.isVariableStatement(stmt)) {
|
|
1356
|
+
for (const decl of stmt.getDeclarationList().getDeclarations()) {
|
|
1357
|
+
if (decl.getName() === varName) {
|
|
1358
|
+
const initializer = decl.getInitializer();
|
|
1359
|
+
if (initializer && Node.isCallExpression(initializer)) {
|
|
1360
|
+
const callee = initializer.getExpression();
|
|
1361
|
+
if (Node.isIdentifier(callee) && callee.getText() === "defineFiles") {
|
|
1362
|
+
const args = initializer.getArguments();
|
|
1363
|
+
if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
|
|
1364
|
+
this.extractFilesFromSchema(args[0], files);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
} else if (Node.isCallExpression(expr)) {
|
|
1374
|
+
const callee = expr.getExpression();
|
|
1375
|
+
if (Node.isIdentifier(callee) && callee.getText() === "defineFiles") {
|
|
1376
|
+
const args = expr.getArguments();
|
|
1377
|
+
if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
|
|
1378
|
+
this.extractFilesFromSchema(args[0], files);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
if (files.length === 0) {
|
|
1383
|
+
throw this.createError("ReadFiles: could not extract files from defineFiles schema", node);
|
|
1384
|
+
}
|
|
1385
|
+
return {
|
|
1386
|
+
kind: "readFiles",
|
|
1387
|
+
files
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* Extract file entries from defineFiles schema object literal
|
|
1392
|
+
*/
|
|
1393
|
+
extractFilesFromSchema(obj, files) {
|
|
1394
|
+
for (const prop of obj.getProperties()) {
|
|
1395
|
+
if (Node.isPropertyAssignment(prop)) {
|
|
1396
|
+
const key = prop.getName();
|
|
1397
|
+
const value = prop.getInitializer();
|
|
1398
|
+
if (value && Node.isObjectLiteralExpression(value)) {
|
|
1399
|
+
let path;
|
|
1400
|
+
let required = true;
|
|
1401
|
+
for (const fileProp of value.getProperties()) {
|
|
1402
|
+
if (Node.isPropertyAssignment(fileProp)) {
|
|
1403
|
+
const propName = fileProp.getName();
|
|
1404
|
+
const propValue = fileProp.getInitializer();
|
|
1405
|
+
if (propName === "path" && propValue) {
|
|
1406
|
+
if (Node.isStringLiteral(propValue)) {
|
|
1407
|
+
path = propValue.getLiteralValue();
|
|
1408
|
+
} else if (Node.isNoSubstitutionTemplateLiteral(propValue)) {
|
|
1409
|
+
path = propValue.getLiteralValue();
|
|
1410
|
+
} else if (Node.isTemplateExpression(propValue)) {
|
|
1411
|
+
path = this.extractTemplatePath(propValue);
|
|
1412
|
+
}
|
|
1413
|
+
} else if (propName === "required" && propValue) {
|
|
1414
|
+
if (propValue.getText() === "false") {
|
|
1415
|
+
required = false;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
if (path) {
|
|
1421
|
+
const varName = key.replace(/([a-z])([A-Z])/g, "$1_$2").toUpperCase() + "_CONTENT";
|
|
1422
|
+
files.push({ varName, path, required });
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Extract path from template expression, preserving ${} for shell
|
|
1430
|
+
*/
|
|
1431
|
+
extractTemplatePath(tmpl) {
|
|
1432
|
+
let result = tmpl.getHead().getLiteralText();
|
|
1433
|
+
for (const span of tmpl.getTemplateSpans()) {
|
|
1434
|
+
const spanExpr = span.getExpression();
|
|
1435
|
+
result += "${" + spanExpr.getText() + "}";
|
|
1436
|
+
result += span.getLiteral().getLiteralText();
|
|
1437
|
+
}
|
|
1438
|
+
return result;
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Transform <PromptTemplate> to PromptTemplateNode
|
|
1442
|
+
*
|
|
1443
|
+
* <PromptTemplate>
|
|
1444
|
+
* <XmlBlock name="objective">...</XmlBlock>
|
|
1445
|
+
* </PromptTemplate>
|
|
1446
|
+
*
|
|
1447
|
+
* Becomes:
|
|
1448
|
+
* ```markdown
|
|
1449
|
+
* <objective>
|
|
1450
|
+
* ...
|
|
1451
|
+
* </objective>
|
|
1452
|
+
* ```
|
|
1453
|
+
*/
|
|
1454
|
+
transformPromptTemplate(node) {
|
|
1455
|
+
if (Node.isJsxSelfClosingElement(node)) {
|
|
1456
|
+
return { kind: "promptTemplate", children: [] };
|
|
1457
|
+
}
|
|
1458
|
+
const children = this.transformBlockChildren(node.getJsxChildren());
|
|
1459
|
+
return {
|
|
1460
|
+
kind: "promptTemplate",
|
|
1461
|
+
children
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
transformXmlSection(node) {
|
|
1465
|
+
const opening = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1466
|
+
const name = getAttributeValue(opening, "name") ?? "section";
|
|
1467
|
+
const children = [];
|
|
1468
|
+
if (Node.isJsxElement(node)) {
|
|
1469
|
+
for (const child of node.getJsxChildren()) {
|
|
1470
|
+
const block = this.transformToBlock(child);
|
|
1471
|
+
if (block) children.push(block);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
return {
|
|
1475
|
+
kind: "xmlBlock",
|
|
1476
|
+
name,
|
|
1477
|
+
children
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
transformXmlWrapper(componentName, node) {
|
|
1481
|
+
const tagName = toSnakeCase(componentName);
|
|
1482
|
+
const children = [];
|
|
1483
|
+
if (Node.isJsxElement(node)) {
|
|
1484
|
+
for (const child of node.getJsxChildren()) {
|
|
1485
|
+
const block = this.transformToBlock(child);
|
|
1486
|
+
if (block) children.push(block);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
return {
|
|
1490
|
+
kind: "xmlBlock",
|
|
1491
|
+
name: tagName,
|
|
1492
|
+
children
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
transformMarkdown(node) {
|
|
1496
|
+
if (Node.isJsxSelfClosingElement(node)) {
|
|
1497
|
+
return { kind: "raw", content: "" };
|
|
1498
|
+
}
|
|
1499
|
+
const parts = [];
|
|
1500
|
+
const jsxChildren = node.getJsxChildren();
|
|
1501
|
+
for (let i = 0; i < jsxChildren.length; i++) {
|
|
1502
|
+
const child = jsxChildren[i];
|
|
1503
|
+
const prev = parts[parts.length - 1];
|
|
1504
|
+
if (Node.isJsxText(child)) {
|
|
1505
|
+
let text = child.getText();
|
|
1506
|
+
if (text === "" && i > 0 && i < jsxChildren.length - 1) {
|
|
1507
|
+
const prevChild = jsxChildren[i - 1];
|
|
1508
|
+
const nextChild = jsxChildren[i + 1];
|
|
1509
|
+
if (Node.isJsxExpression(prevChild) && Node.isJsxExpression(nextChild)) {
|
|
1510
|
+
parts.push("\n");
|
|
1511
|
+
continue;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
if (prev && !/\s$/.test(prev) && !/^\s/.test(text) && text !== "") {
|
|
1515
|
+
if (/^#{1,6}\s/.test(text) || /^```/.test(text)) {
|
|
1516
|
+
parts.push("\n\n");
|
|
1517
|
+
} else if (/^\*\*/.test(text)) {
|
|
1518
|
+
parts.push("\n");
|
|
1519
|
+
} else if (/^[-*]\s/.test(text) || /^\d+\.\s/.test(text)) {
|
|
1520
|
+
parts.push("\n");
|
|
1521
|
+
} else if (/^[|]/.test(text)) {
|
|
1522
|
+
if (/[|]\s*$/.test(prev)) {
|
|
1523
|
+
parts.push("\n");
|
|
1524
|
+
} else {
|
|
1525
|
+
parts.push(" ");
|
|
1526
|
+
}
|
|
1527
|
+
} else if (!/^[.,;:!?)}\]>`"'/]/.test(text)) {
|
|
1528
|
+
parts.push(" ");
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
parts.push(text);
|
|
1532
|
+
} else if (Node.isJsxExpression(child)) {
|
|
1533
|
+
const expr = child.getExpression();
|
|
1534
|
+
if (expr) {
|
|
1535
|
+
if (Node.isStringLiteral(expr)) {
|
|
1536
|
+
parts.push(expr.getLiteralValue());
|
|
1537
|
+
} else if (Node.isNoSubstitutionTemplateLiteral(expr)) {
|
|
1538
|
+
parts.push(expr.getLiteralValue());
|
|
1539
|
+
} else if (Node.isTemplateExpression(expr)) {
|
|
1540
|
+
let result = expr.getHead().getLiteralText();
|
|
1541
|
+
for (const span of expr.getTemplateSpans()) {
|
|
1542
|
+
const spanExpr = span.getExpression();
|
|
1543
|
+
if (Node.isIdentifier(spanExpr)) {
|
|
1544
|
+
result += `\${${spanExpr.getText()}}`;
|
|
1545
|
+
} else if (Node.isStringLiteral(spanExpr)) {
|
|
1546
|
+
result += spanExpr.getLiteralValue();
|
|
1547
|
+
} else {
|
|
1548
|
+
result += `\${${spanExpr.getText()}}`;
|
|
1549
|
+
}
|
|
1550
|
+
const literal = span.getLiteral();
|
|
1551
|
+
if (Node.isTemplateMiddle(literal)) {
|
|
1552
|
+
result += literal.getLiteralText();
|
|
1553
|
+
} else if (Node.isTemplateTail(literal)) {
|
|
1554
|
+
result += literal.getLiteralText();
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
parts.push(result);
|
|
1558
|
+
} else if (Node.isIdentifier(expr)) {
|
|
1559
|
+
parts.push(`{${expr.getText()}}`);
|
|
1560
|
+
} else if (Node.isBinaryExpression(expr)) {
|
|
1561
|
+
const concat = this.evaluateStringConcatenation(expr);
|
|
1562
|
+
if (concat !== null) {
|
|
1563
|
+
parts.push(concat);
|
|
1564
|
+
}
|
|
1565
|
+
} else if (Node.isPropertyAccessExpression(expr)) {
|
|
1566
|
+
const value = this.resolvePropertyAccess(expr);
|
|
1567
|
+
if (value !== null) {
|
|
1568
|
+
parts.push(value);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
const content = parts.join("").trim();
|
|
1575
|
+
return { kind: "raw", content };
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Transform a custom component by resolving its import and inlining its JSX
|
|
1579
|
+
*
|
|
1580
|
+
* Custom components are user-defined TSX fragments that get inlined at
|
|
1581
|
+
* transpile time. Component props are NOT supported in v1 - only parameterless
|
|
1582
|
+
* composition.
|
|
1583
|
+
*/
|
|
1584
|
+
transformCustomComponent(name, node) {
|
|
1585
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1586
|
+
const attributes = openingElement.getAttributes();
|
|
1587
|
+
if (attributes.length > 0) {
|
|
1588
|
+
throw this.createError(`Component props not supported: <${name}> has ${attributes.length} prop(s)`, node);
|
|
1589
|
+
}
|
|
1590
|
+
if (!this.sourceFile) {
|
|
1591
|
+
throw this.createError(
|
|
1592
|
+
`Cannot resolve component '${name}': no source file context. Pass sourceFile to transformer.transform() for component composition.`,
|
|
1593
|
+
node
|
|
1594
|
+
);
|
|
1595
|
+
}
|
|
1596
|
+
const resolved = resolveComponentImport(name, this.sourceFile, this.visitedPaths);
|
|
1597
|
+
this.visitedPaths = resolved.visitedPaths;
|
|
1598
|
+
const previousSourceFile = this.sourceFile;
|
|
1599
|
+
this.sourceFile = resolved.sourceFile;
|
|
1600
|
+
let result = null;
|
|
1601
|
+
if (Node.isJsxFragment(resolved.jsx)) {
|
|
1602
|
+
const blocks = this.transformFragmentChildren(resolved.jsx);
|
|
1603
|
+
result = blocks[0] ?? null;
|
|
1604
|
+
} else {
|
|
1605
|
+
result = this.transformToBlock(resolved.jsx);
|
|
1606
|
+
}
|
|
1607
|
+
this.sourceFile = previousSourceFile;
|
|
1608
|
+
return result;
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* Transform a SpawnAgent element to SpawnAgentNode
|
|
1612
|
+
* SpawnAgent is a block-level element that emits Task() syntax
|
|
1613
|
+
*
|
|
1614
|
+
* Supports two modes:
|
|
1615
|
+
* 1. prompt prop (deprecated): Manual prompt string
|
|
1616
|
+
* 2. input prop (preferred): Typed input - VariableRef or object literal
|
|
1617
|
+
*
|
|
1618
|
+
* Also supports:
|
|
1619
|
+
* - agent={AgentRef} for type-safe agent references
|
|
1620
|
+
* - loadFromFile prop for "load from file" pattern
|
|
1621
|
+
*/
|
|
1622
|
+
transformSpawnAgent(node) {
|
|
1623
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
1624
|
+
const { agentName, agentPath } = this.extractAgentProp(openingElement);
|
|
1625
|
+
const model = getAttributeValue(openingElement, "model");
|
|
1626
|
+
const description = getAttributeValue(openingElement, "description");
|
|
1627
|
+
const loadFromFile = this.extractLoadFromFileProp(openingElement, agentPath);
|
|
1628
|
+
const prompt = this.extractPromptProp(openingElement);
|
|
1629
|
+
const promptVariable = getAttributeValue(openingElement, "promptVariable");
|
|
1630
|
+
const input = this.extractInputProp(openingElement);
|
|
1631
|
+
const extraInstructions = Node.isJsxElement(node) ? this.extractExtraInstructions(node) : void 0;
|
|
1632
|
+
if (!agentName) {
|
|
1633
|
+
throw this.createError("SpawnAgent requires agent prop", openingElement);
|
|
1634
|
+
}
|
|
1635
|
+
if (!model) {
|
|
1636
|
+
throw this.createError("SpawnAgent requires model prop", openingElement);
|
|
1637
|
+
}
|
|
1638
|
+
if (!description) {
|
|
1639
|
+
throw this.createError("SpawnAgent requires description prop", openingElement);
|
|
1640
|
+
}
|
|
1641
|
+
const promptProps = [prompt, promptVariable, input].filter(Boolean).length;
|
|
1642
|
+
if (promptProps > 1) {
|
|
1643
|
+
throw this.createError(
|
|
1644
|
+
"Cannot use multiple prompt props on SpawnAgent. Use one of: prompt, promptVariable, or input.",
|
|
1645
|
+
openingElement
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1648
|
+
if (promptProps === 0) {
|
|
1649
|
+
throw this.createError(
|
|
1650
|
+
"SpawnAgent requires either prompt, promptVariable, or input prop",
|
|
1651
|
+
openingElement
|
|
1652
|
+
);
|
|
1653
|
+
}
|
|
1654
|
+
const typeArgs = extractTypeArguments(node);
|
|
1655
|
+
let inputType;
|
|
1656
|
+
const typeParam = typeArgs && typeArgs.length > 0 ? typeArgs[0] : void 0;
|
|
1657
|
+
if (typeParam) {
|
|
1658
|
+
inputType = {
|
|
1659
|
+
kind: "typeReference",
|
|
1660
|
+
name: typeParam,
|
|
1661
|
+
resolved: false
|
|
1662
|
+
// Will be resolved in validation phase
|
|
1663
|
+
};
|
|
1664
|
+
}
|
|
1665
|
+
if (input) {
|
|
1666
|
+
this.validateInputAgainstInterface(input, typeParam, openingElement);
|
|
1667
|
+
}
|
|
1668
|
+
return {
|
|
1669
|
+
kind: "spawnAgent",
|
|
1670
|
+
agent: agentName,
|
|
1671
|
+
model,
|
|
1672
|
+
description,
|
|
1673
|
+
...prompt && { prompt },
|
|
1674
|
+
...promptVariable && { promptVariable },
|
|
1675
|
+
...input && { input },
|
|
1676
|
+
...extraInstructions && { extraInstructions },
|
|
1677
|
+
...inputType && { inputType },
|
|
1678
|
+
...loadFromFile && { loadFromFile }
|
|
1679
|
+
};
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* Extract agent prop - handles string OR AgentRef identifier
|
|
1683
|
+
*
|
|
1684
|
+
* Returns:
|
|
1685
|
+
* - agentName: The agent name string (required)
|
|
1686
|
+
* - agentPath: The agent's file path (if AgentRef with path)
|
|
1687
|
+
*/
|
|
1688
|
+
extractAgentProp(element) {
|
|
1689
|
+
const attr = element.getAttribute("agent");
|
|
1690
|
+
if (!attr || !Node.isJsxAttribute(attr)) {
|
|
1691
|
+
return { agentName: void 0, agentPath: void 0 };
|
|
1692
|
+
}
|
|
1693
|
+
const init = attr.getInitializer();
|
|
1694
|
+
if (init && Node.isStringLiteral(init)) {
|
|
1695
|
+
return { agentName: init.getLiteralValue(), agentPath: void 0 };
|
|
1696
|
+
}
|
|
1697
|
+
if (init && Node.isJsxExpression(init)) {
|
|
1698
|
+
const expr = init.getExpression();
|
|
1699
|
+
if (expr && Node.isIdentifier(expr)) {
|
|
1700
|
+
const identName = expr.getText();
|
|
1701
|
+
const agentRef = this.resolveAgentRef(identName);
|
|
1702
|
+
if (agentRef) {
|
|
1703
|
+
return { agentName: agentRef.name, agentPath: agentRef.path };
|
|
1704
|
+
}
|
|
1705
|
+
return { agentName: identName, agentPath: void 0 };
|
|
1706
|
+
}
|
|
1707
|
+
if (expr && Node.isStringLiteral(expr)) {
|
|
1708
|
+
return { agentName: expr.getLiteralValue(), agentPath: void 0 };
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
return { agentName: void 0, agentPath: void 0 };
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Try to resolve an identifier to an AgentRef definition
|
|
1715
|
+
*
|
|
1716
|
+
* Looks for:
|
|
1717
|
+
* 1. Imported AgentRef (from defineAgent call in source file)
|
|
1718
|
+
* 2. Local AgentRef constant
|
|
1719
|
+
*/
|
|
1720
|
+
resolveAgentRef(identName) {
|
|
1721
|
+
if (!this.sourceFile) return void 0;
|
|
1722
|
+
const symbol = this.sourceFile.getLocal(identName);
|
|
1723
|
+
if (!symbol) return void 0;
|
|
1724
|
+
const declarations = symbol.getDeclarations();
|
|
1725
|
+
if (!declarations || declarations.length === 0) return void 0;
|
|
1726
|
+
for (const decl of declarations) {
|
|
1727
|
+
if (Node.isImportSpecifier(decl)) {
|
|
1728
|
+
const resolved = this.resolveImportedAgentRef(decl, identName);
|
|
1729
|
+
if (resolved) return resolved;
|
|
1730
|
+
continue;
|
|
1731
|
+
}
|
|
1732
|
+
if (Node.isVariableDeclaration(decl)) {
|
|
1733
|
+
const init = decl.getInitializer();
|
|
1734
|
+
if (init && Node.isCallExpression(init)) {
|
|
1735
|
+
const callExpr = init.getExpression();
|
|
1736
|
+
if (callExpr && callExpr.getText() === "defineAgent") {
|
|
1737
|
+
const args = init.getArguments();
|
|
1738
|
+
if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
|
|
1739
|
+
return this.extractAgentRefFromObject(args[0]);
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
return void 0;
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Resolve an imported AgentRef by tracing to its source file
|
|
1749
|
+
*/
|
|
1750
|
+
resolveImportedAgentRef(importSpec, identName) {
|
|
1751
|
+
let current = importSpec;
|
|
1752
|
+
while (current && !Node.isImportDeclaration(current)) {
|
|
1753
|
+
current = current.getParent();
|
|
1754
|
+
}
|
|
1755
|
+
if (!current || !Node.isImportDeclaration(current)) {
|
|
1756
|
+
return void 0;
|
|
1757
|
+
}
|
|
1758
|
+
const importDecl = current;
|
|
1759
|
+
const resolvedSourceFile = importDecl.getModuleSpecifierSourceFile();
|
|
1760
|
+
if (!resolvedSourceFile) {
|
|
1761
|
+
return void 0;
|
|
1762
|
+
}
|
|
1763
|
+
const exportedVar = resolvedSourceFile.getVariableDeclaration(identName);
|
|
1764
|
+
if (!exportedVar) {
|
|
1765
|
+
return void 0;
|
|
1766
|
+
}
|
|
1767
|
+
const init = exportedVar.getInitializer();
|
|
1768
|
+
if (init && Node.isCallExpression(init)) {
|
|
1769
|
+
const callExpr = init.getExpression();
|
|
1770
|
+
if (callExpr && callExpr.getText() === "defineAgent") {
|
|
1771
|
+
const args = init.getArguments();
|
|
1772
|
+
if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
|
|
1773
|
+
return this.extractAgentRefFromObject(args[0]);
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
return void 0;
|
|
1778
|
+
}
|
|
1779
|
+
/**
|
|
1780
|
+
* Extract AgentRef properties from defineAgent config object
|
|
1781
|
+
*/
|
|
1782
|
+
extractAgentRefFromObject(obj) {
|
|
1783
|
+
let name;
|
|
1784
|
+
let path;
|
|
1785
|
+
for (const prop of obj.getProperties()) {
|
|
1786
|
+
if (Node.isPropertyAssignment(prop)) {
|
|
1787
|
+
const propName = prop.getName();
|
|
1788
|
+
const init = prop.getInitializer();
|
|
1789
|
+
if (propName === "name" && init && Node.isStringLiteral(init)) {
|
|
1790
|
+
name = init.getLiteralValue();
|
|
1791
|
+
}
|
|
1792
|
+
if (propName === "path" && init && Node.isStringLiteral(init)) {
|
|
1793
|
+
path = init.getLiteralValue();
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
if (name) {
|
|
1798
|
+
return { name, path };
|
|
1799
|
+
}
|
|
1800
|
+
return void 0;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Extract loadFromFile prop
|
|
1804
|
+
*
|
|
1805
|
+
* Supports:
|
|
1806
|
+
* - loadFromFile (boolean true shorthand)
|
|
1807
|
+
* - loadFromFile={true}
|
|
1808
|
+
* - loadFromFile="explicit/path.md"
|
|
1809
|
+
*
|
|
1810
|
+
* When true, uses agentPath from AgentRef.
|
|
1811
|
+
* Returns resolved path string or undefined.
|
|
1812
|
+
*/
|
|
1813
|
+
extractLoadFromFileProp(element, agentPath) {
|
|
1814
|
+
const attr = element.getAttribute("loadFromFile");
|
|
1815
|
+
if (!attr || !Node.isJsxAttribute(attr)) {
|
|
1816
|
+
return void 0;
|
|
1817
|
+
}
|
|
1818
|
+
const init = attr.getInitializer();
|
|
1819
|
+
if (!init) {
|
|
1820
|
+
if (!agentPath) {
|
|
1821
|
+
throw this.createError(
|
|
1822
|
+
'loadFromFile={true} requires an AgentRef with a path property. Either use agent={AgentRef} where AgentRef has a path, or provide an explicit path: loadFromFile="path/to/agent.md"',
|
|
1823
|
+
element
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
return agentPath;
|
|
1827
|
+
}
|
|
1828
|
+
if (Node.isStringLiteral(init)) {
|
|
1829
|
+
return init.getLiteralValue();
|
|
1830
|
+
}
|
|
1831
|
+
if (Node.isJsxExpression(init)) {
|
|
1832
|
+
const expr = init.getExpression();
|
|
1833
|
+
if (expr && expr.getText() === "true") {
|
|
1834
|
+
if (!agentPath) {
|
|
1835
|
+
throw this.createError(
|
|
1836
|
+
'loadFromFile={true} requires an AgentRef with a path property. Either use agent={AgentRef} where AgentRef has a path, or provide an explicit path: loadFromFile="path/to/agent.md"',
|
|
1837
|
+
element
|
|
1838
|
+
);
|
|
1839
|
+
}
|
|
1840
|
+
return agentPath;
|
|
1841
|
+
}
|
|
1842
|
+
if (expr && expr.getText() === "false") {
|
|
1843
|
+
return void 0;
|
|
1844
|
+
}
|
|
1845
|
+
if (expr && Node.isStringLiteral(expr)) {
|
|
1846
|
+
return expr.getLiteralValue();
|
|
1847
|
+
}
|
|
1848
|
+
if (expr && Node.isPropertyAccessExpression(expr)) {
|
|
1849
|
+
const resolvedPath = this.resolvePropertyAccess(expr);
|
|
1850
|
+
if (resolvedPath) {
|
|
1851
|
+
return resolvedPath;
|
|
1852
|
+
}
|
|
1853
|
+
throw this.createError(
|
|
1854
|
+
`Cannot resolve property access ${expr.getText()} for loadFromFile. Make sure the object is a const with string literal values.`,
|
|
1855
|
+
element
|
|
1856
|
+
);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
throw this.createError(
|
|
1860
|
+
"loadFromFile must be a boolean or string path",
|
|
1861
|
+
element
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
/**
|
|
1865
|
+
* Extract input prop - handles VariableRef identifier or object literal
|
|
1866
|
+
*
|
|
1867
|
+
* Supports:
|
|
1868
|
+
* - input={varRef} - Reference to useVariable result
|
|
1869
|
+
* - input={{ key: "value" }} - Object literal with properties
|
|
1870
|
+
*/
|
|
1871
|
+
extractInputProp(element) {
|
|
1872
|
+
const attr = element.getAttribute("input");
|
|
1873
|
+
if (!attr || !Node.isJsxAttribute(attr)) return void 0;
|
|
1874
|
+
const init = attr.getInitializer();
|
|
1875
|
+
if (!init || !Node.isJsxExpression(init)) return void 0;
|
|
1876
|
+
const expr = init.getExpression();
|
|
1877
|
+
if (!expr) return void 0;
|
|
1878
|
+
if (Node.isIdentifier(expr)) {
|
|
1879
|
+
const variable = this.variables.get(expr.getText());
|
|
1880
|
+
if (variable) {
|
|
1881
|
+
return { type: "variable", varName: variable.envName };
|
|
1882
|
+
}
|
|
1883
|
+
throw this.createError(
|
|
1884
|
+
`Input '${expr.getText()}' not found. Use useVariable() or object literal.`,
|
|
1885
|
+
element
|
|
1886
|
+
);
|
|
1887
|
+
}
|
|
1888
|
+
if (Node.isObjectLiteralExpression(expr)) {
|
|
1889
|
+
const properties = extractInputObjectLiteral(expr, this.variables);
|
|
1890
|
+
return { type: "object", properties };
|
|
1891
|
+
}
|
|
1892
|
+
throw this.createError("Input must be a VariableRef or object literal", element);
|
|
1893
|
+
}
|
|
1894
|
+
/**
|
|
1895
|
+
* Extract extra instructions from SpawnAgent children
|
|
1896
|
+
*
|
|
1897
|
+
* Treats children as raw text content (like Markdown component).
|
|
1898
|
+
* Returns undefined if no children or only whitespace.
|
|
1899
|
+
*/
|
|
1900
|
+
extractExtraInstructions(node) {
|
|
1901
|
+
const parts = [];
|
|
1902
|
+
for (const child of node.getJsxChildren()) {
|
|
1903
|
+
if (Node.isJsxText(child)) {
|
|
1904
|
+
const text = child.getText();
|
|
1905
|
+
if (text.trim()) {
|
|
1906
|
+
parts.push(text);
|
|
1907
|
+
}
|
|
1908
|
+
} else if (Node.isJsxExpression(child)) {
|
|
1909
|
+
const expr = child.getExpression();
|
|
1910
|
+
if (expr) {
|
|
1911
|
+
if (Node.isStringLiteral(expr)) {
|
|
1912
|
+
parts.push(expr.getLiteralValue());
|
|
1913
|
+
} else if (Node.isNoSubstitutionTemplateLiteral(expr)) {
|
|
1914
|
+
parts.push(expr.getLiteralValue());
|
|
1915
|
+
} else if (Node.isTemplateExpression(expr)) {
|
|
1916
|
+
parts.push(this.extractTemplateText(expr));
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
const content = parts.join("").trim();
|
|
1922
|
+
return content || void 0;
|
|
1923
|
+
}
|
|
1924
|
+
/**
|
|
1925
|
+
* Extract type argument from SpawnAgent<T> syntax
|
|
1926
|
+
*
|
|
1927
|
+
* Returns the type name string (e.g., "ResearcherInput") or undefined
|
|
1928
|
+
* if no type argument is present.
|
|
1929
|
+
*/
|
|
1930
|
+
extractSpawnAgentTypeParam(element) {
|
|
1931
|
+
const parent = element.getParent();
|
|
1932
|
+
if (!parent) return void 0;
|
|
1933
|
+
if (Node.isJsxElement(parent)) {
|
|
1934
|
+
const typeArgs = extractTypeArguments(parent);
|
|
1935
|
+
return typeArgs && typeArgs.length > 0 ? typeArgs[0] : void 0;
|
|
1936
|
+
}
|
|
1937
|
+
if (Node.isJsxSelfClosingElement(element)) {
|
|
1938
|
+
const typeArgs = extractTypeArguments(element);
|
|
1939
|
+
return typeArgs && typeArgs.length > 0 ? typeArgs[0] : void 0;
|
|
1940
|
+
}
|
|
1941
|
+
return void 0;
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1944
|
+
* Validate input object properties against SpawnAgent<T> type parameter.
|
|
1945
|
+
*
|
|
1946
|
+
* Throws compile error if required interface properties are missing.
|
|
1947
|
+
* Only validates object literal inputs (VariableRef is runtime-checked).
|
|
1948
|
+
*
|
|
1949
|
+
* @param input - The parsed SpawnAgentInput (may be variable or object)
|
|
1950
|
+
* @param typeParam - The type parameter name (e.g., "ResearcherInput")
|
|
1951
|
+
* @param element - The JSX element for error reporting
|
|
1952
|
+
*/
|
|
1953
|
+
validateInputAgainstInterface(input, typeParam, element) {
|
|
1954
|
+
if (input.type !== "object") return;
|
|
1955
|
+
if (!typeParam) return;
|
|
1956
|
+
if (!this.sourceFile) {
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
const resolved = resolveTypeImport(typeParam, this.sourceFile);
|
|
1960
|
+
if (!resolved?.interface) {
|
|
1961
|
+
return;
|
|
1962
|
+
}
|
|
1963
|
+
const interfaceProps = extractInterfaceProperties(resolved.interface);
|
|
1964
|
+
const requiredProps = interfaceProps.filter((p) => p.required);
|
|
1965
|
+
const inputPropNames = input.properties.map((p) => p.name);
|
|
1966
|
+
const missing = requiredProps.filter((p) => !inputPropNames.includes(p.name));
|
|
1967
|
+
if (missing.length > 0) {
|
|
1968
|
+
const missingNames = missing.map((p) => p.name).join(", ");
|
|
1969
|
+
const requiredNames = requiredProps.map((p) => p.name).join(", ");
|
|
1970
|
+
throw this.createError(
|
|
1971
|
+
`SpawnAgent input missing required properties: ${missingNames}. Interface '${typeParam}' requires: ${requiredNames}`,
|
|
1972
|
+
element
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
/**
|
|
1977
|
+
* Transform an If element to IfNode
|
|
1978
|
+
*
|
|
1979
|
+
* NOTE: V1 control flow is deprecated. Use V3 transformer with useRuntimeVar and condition-based If.
|
|
1980
|
+
*/
|
|
1981
|
+
transformIf(node) {
|
|
1982
|
+
throw this.createError(
|
|
1983
|
+
"V1 If control flow is deprecated. Use V3 transformer with useRuntimeVar and condition-based If.",
|
|
1984
|
+
node
|
|
1985
|
+
);
|
|
1986
|
+
}
|
|
1987
|
+
/**
|
|
1988
|
+
* Transform an Else element to ElseNode
|
|
1989
|
+
*
|
|
1990
|
+
* NOTE: V1 control flow is deprecated. Use V3 transformer with useRuntimeVar and condition-based If/Else.
|
|
1991
|
+
*/
|
|
1992
|
+
transformElse(node) {
|
|
1993
|
+
throw this.createError(
|
|
1994
|
+
"V1 Else control flow is deprecated. Use V3 transformer with useRuntimeVar and condition-based Else.",
|
|
1995
|
+
node
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Transform Loop component to LoopNode IR
|
|
2000
|
+
*
|
|
2001
|
+
* NOTE: V1 control flow is deprecated. Use V3 transformer with useRuntimeVar and max-based Loop.
|
|
2002
|
+
*/
|
|
2003
|
+
transformLoop(node) {
|
|
2004
|
+
throw this.createError(
|
|
2005
|
+
"V1 Loop control flow is deprecated. Use V3 transformer with useRuntimeVar and max-based Loop.",
|
|
2006
|
+
node
|
|
2007
|
+
);
|
|
2008
|
+
}
|
|
2009
|
+
/**
|
|
2010
|
+
* Extract useOutput declarations from source file
|
|
2011
|
+
* Returns map of identifier name -> agent name
|
|
2012
|
+
*
|
|
2013
|
+
* Uses forEachDescendant to find declarations inside function bodies,
|
|
2014
|
+
* following the same pattern as extractVariableDeclarations in parser.ts
|
|
2015
|
+
*/
|
|
2016
|
+
extractOutputDeclarations(sourceFile) {
|
|
2017
|
+
const outputs = /* @__PURE__ */ new Map();
|
|
2018
|
+
sourceFile.forEachDescendant((node) => {
|
|
2019
|
+
if (!Node.isVariableDeclaration(node)) return;
|
|
2020
|
+
const init = node.getInitializer();
|
|
2021
|
+
if (!init || !Node.isCallExpression(init)) return;
|
|
2022
|
+
const expr = init.getExpression();
|
|
2023
|
+
if (!Node.isIdentifier(expr) || expr.getText() !== "useOutput") return;
|
|
2024
|
+
const args = init.getArguments();
|
|
2025
|
+
if (args.length < 1) return;
|
|
2026
|
+
const agentArg = args[0];
|
|
2027
|
+
if (Node.isStringLiteral(agentArg)) {
|
|
2028
|
+
const agentName = agentArg.getLiteralValue();
|
|
2029
|
+
const identName = node.getName();
|
|
2030
|
+
outputs.set(identName, agentName);
|
|
2031
|
+
}
|
|
2032
|
+
});
|
|
2033
|
+
return outputs;
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Extract useStateRef declarations from source file
|
|
2037
|
+
* Returns map of identifier name -> state key
|
|
2038
|
+
*
|
|
2039
|
+
* Uses forEachDescendant to find declarations inside function bodies,
|
|
2040
|
+
* following the same pattern as extractOutputDeclarations
|
|
2041
|
+
*/
|
|
2042
|
+
extractStateRefDeclarations(sourceFile) {
|
|
2043
|
+
const stateRefs = /* @__PURE__ */ new Map();
|
|
2044
|
+
sourceFile.forEachDescendant((node) => {
|
|
2045
|
+
if (!Node.isVariableDeclaration(node)) return;
|
|
2046
|
+
const init = node.getInitializer();
|
|
2047
|
+
if (!init || !Node.isCallExpression(init)) return;
|
|
2048
|
+
const expr = init.getExpression();
|
|
2049
|
+
if (!Node.isIdentifier(expr) || expr.getText() !== "useStateRef") return;
|
|
2050
|
+
const args = init.getArguments();
|
|
2051
|
+
if (args.length < 1) return;
|
|
2052
|
+
const keyArg = args[0];
|
|
2053
|
+
if (Node.isStringLiteral(keyArg)) {
|
|
2054
|
+
const stateKey = keyArg.getLiteralValue();
|
|
2055
|
+
const identName = node.getName();
|
|
2056
|
+
stateRefs.set(identName, stateKey);
|
|
2057
|
+
}
|
|
2058
|
+
});
|
|
2059
|
+
return stateRefs;
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Transform ReadState JSX element into IR node
|
|
2063
|
+
*
|
|
2064
|
+
* Extracts:
|
|
2065
|
+
* - state: StateRef with key property
|
|
2066
|
+
* - into: VariableRef with name property
|
|
2067
|
+
* - field: optional nested path string
|
|
2068
|
+
*/
|
|
2069
|
+
transformReadState(node) {
|
|
2070
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
2071
|
+
const stateAttr = openingElement.getAttribute("state");
|
|
2072
|
+
if (!stateAttr || !Node.isJsxAttribute(stateAttr)) {
|
|
2073
|
+
throw this.createError("ReadState requires state prop", openingElement);
|
|
2074
|
+
}
|
|
2075
|
+
const stateInit = stateAttr.getInitializer();
|
|
2076
|
+
if (!stateInit || !Node.isJsxExpression(stateInit)) {
|
|
2077
|
+
throw this.createError("ReadState state prop must be JSX expression", openingElement);
|
|
2078
|
+
}
|
|
2079
|
+
const stateExpr = stateInit.getExpression();
|
|
2080
|
+
if (!stateExpr) {
|
|
2081
|
+
throw this.createError("ReadState state prop expression is empty", openingElement);
|
|
2082
|
+
}
|
|
2083
|
+
const stateKey = this.extractStateKey(stateExpr, openingElement);
|
|
2084
|
+
const intoAttr = openingElement.getAttribute("into");
|
|
2085
|
+
if (!intoAttr || !Node.isJsxAttribute(intoAttr)) {
|
|
2086
|
+
throw this.createError("ReadState requires into prop", openingElement);
|
|
2087
|
+
}
|
|
2088
|
+
const intoInit = intoAttr.getInitializer();
|
|
2089
|
+
if (!intoInit || !Node.isJsxExpression(intoInit)) {
|
|
2090
|
+
throw this.createError("ReadState into prop must be JSX expression", openingElement);
|
|
2091
|
+
}
|
|
2092
|
+
const intoExpr = intoInit.getExpression();
|
|
2093
|
+
if (!intoExpr) {
|
|
2094
|
+
throw this.createError("ReadState into prop expression is empty", openingElement);
|
|
2095
|
+
}
|
|
2096
|
+
const variableName = this.extractVariableName(intoExpr, openingElement);
|
|
2097
|
+
const fieldAttr = openingElement.getAttribute("field");
|
|
2098
|
+
let field;
|
|
2099
|
+
if (fieldAttr && Node.isJsxAttribute(fieldAttr)) {
|
|
2100
|
+
const fieldInit = fieldAttr.getInitializer();
|
|
2101
|
+
if (fieldInit && Node.isStringLiteral(fieldInit)) {
|
|
2102
|
+
field = fieldInit.getLiteralText();
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
return {
|
|
2106
|
+
kind: "readState",
|
|
2107
|
+
stateKey,
|
|
2108
|
+
variableName,
|
|
2109
|
+
field
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* Extract state key from StateRef expression
|
|
2114
|
+
* Handles: identifier pointing to useStateRef result
|
|
2115
|
+
*/
|
|
2116
|
+
extractStateKey(expr, element) {
|
|
2117
|
+
if (Node.isIdentifier(expr)) {
|
|
2118
|
+
const name = expr.getText();
|
|
2119
|
+
const tracked = this.stateRefs.get(name);
|
|
2120
|
+
if (tracked) return tracked;
|
|
2121
|
+
throw this.createError(
|
|
2122
|
+
`State reference '${name}' not found. Did you declare it with useStateRef()?`,
|
|
2123
|
+
element
|
|
2124
|
+
);
|
|
2125
|
+
}
|
|
2126
|
+
throw this.createError(`Cannot extract state key from: ${expr.getText()}`, element);
|
|
2127
|
+
}
|
|
2128
|
+
/**
|
|
2129
|
+
* Extract variable name from VariableRef expression
|
|
2130
|
+
* Handles: identifier pointing to useVariable result
|
|
2131
|
+
*/
|
|
2132
|
+
extractVariableName(expr, element) {
|
|
2133
|
+
if (Node.isIdentifier(expr)) {
|
|
2134
|
+
const name = expr.getText();
|
|
2135
|
+
const tracked = this.variables.get(name);
|
|
2136
|
+
if (tracked) return tracked.envName;
|
|
2137
|
+
throw this.createError(
|
|
2138
|
+
`Variable '${name}' not found. Did you declare it with useVariable()?`,
|
|
2139
|
+
element
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
throw this.createError(`Cannot extract variable name from: ${expr.getText()}`, element);
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* Transform WriteState JSX element into IR node
|
|
2146
|
+
*
|
|
2147
|
+
* Two modes:
|
|
2148
|
+
* 1. Field mode: field="path" value={val}
|
|
2149
|
+
* 2. Merge mode: merge={partial}
|
|
2150
|
+
*/
|
|
2151
|
+
transformWriteState(node) {
|
|
2152
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
2153
|
+
const stateAttr = openingElement.getAttribute("state");
|
|
2154
|
+
if (!stateAttr || !Node.isJsxAttribute(stateAttr)) {
|
|
2155
|
+
throw this.createError("WriteState requires state prop", openingElement);
|
|
2156
|
+
}
|
|
2157
|
+
const stateInit = stateAttr.getInitializer();
|
|
2158
|
+
if (!stateInit || !Node.isJsxExpression(stateInit)) {
|
|
2159
|
+
throw this.createError("WriteState state prop must be JSX expression", openingElement);
|
|
2160
|
+
}
|
|
2161
|
+
const stateExpr = stateInit.getExpression();
|
|
2162
|
+
if (!stateExpr) {
|
|
2163
|
+
throw this.createError("WriteState state prop expression is empty", openingElement);
|
|
2164
|
+
}
|
|
2165
|
+
const stateKey = this.extractStateKey(stateExpr, openingElement);
|
|
2166
|
+
const fieldAttr = openingElement.getAttribute("field");
|
|
2167
|
+
const mergeAttr = openingElement.getAttribute("merge");
|
|
2168
|
+
if (fieldAttr && Node.isJsxAttribute(fieldAttr)) {
|
|
2169
|
+
const fieldInit = fieldAttr.getInitializer();
|
|
2170
|
+
if (!fieldInit || !Node.isStringLiteral(fieldInit)) {
|
|
2171
|
+
throw this.createError("WriteState field prop must be string literal", openingElement);
|
|
2172
|
+
}
|
|
2173
|
+
const field = fieldInit.getLiteralText();
|
|
2174
|
+
const valueAttr = openingElement.getAttribute("value");
|
|
2175
|
+
if (!valueAttr || !Node.isJsxAttribute(valueAttr)) {
|
|
2176
|
+
throw this.createError("WriteState with field requires value prop", openingElement);
|
|
2177
|
+
}
|
|
2178
|
+
const valueInit = valueAttr.getInitializer();
|
|
2179
|
+
if (!valueInit) {
|
|
2180
|
+
throw this.createError("WriteState value prop is empty", openingElement);
|
|
2181
|
+
}
|
|
2182
|
+
let value;
|
|
2183
|
+
if (Node.isStringLiteral(valueInit)) {
|
|
2184
|
+
value = { type: "literal", content: valueInit.getLiteralText() };
|
|
2185
|
+
} else if (Node.isJsxExpression(valueInit)) {
|
|
2186
|
+
const valueExpr = valueInit.getExpression();
|
|
2187
|
+
if (!valueExpr) {
|
|
2188
|
+
throw this.createError("WriteState value expression is empty", openingElement);
|
|
2189
|
+
}
|
|
2190
|
+
if (Node.isIdentifier(valueExpr)) {
|
|
2191
|
+
const varName = valueExpr.getText();
|
|
2192
|
+
const tracked = this.variables.get(varName);
|
|
2193
|
+
if (tracked) {
|
|
2194
|
+
value = { type: "variable", content: tracked.envName };
|
|
2195
|
+
} else {
|
|
2196
|
+
value = { type: "literal", content: valueExpr.getText() };
|
|
2197
|
+
}
|
|
2198
|
+
} else {
|
|
2199
|
+
value = { type: "literal", content: valueExpr.getText() };
|
|
2200
|
+
}
|
|
2201
|
+
} else {
|
|
2202
|
+
throw this.createError("WriteState value must be string or expression", openingElement);
|
|
2203
|
+
}
|
|
2204
|
+
return {
|
|
2205
|
+
kind: "writeState",
|
|
2206
|
+
stateKey,
|
|
2207
|
+
mode: "field",
|
|
2208
|
+
field,
|
|
2209
|
+
value
|
|
2210
|
+
};
|
|
2211
|
+
} else if (mergeAttr && Node.isJsxAttribute(mergeAttr)) {
|
|
2212
|
+
const mergeInit = mergeAttr.getInitializer();
|
|
2213
|
+
if (!mergeInit || !Node.isJsxExpression(mergeInit)) {
|
|
2214
|
+
throw this.createError("WriteState merge prop must be JSX expression", openingElement);
|
|
2215
|
+
}
|
|
2216
|
+
const mergeExpr = mergeInit.getExpression();
|
|
2217
|
+
if (!mergeExpr) {
|
|
2218
|
+
throw this.createError("WriteState merge expression is empty", openingElement);
|
|
2219
|
+
}
|
|
2220
|
+
const content = mergeExpr.getText();
|
|
2221
|
+
return {
|
|
2222
|
+
kind: "writeState",
|
|
2223
|
+
stateKey,
|
|
2224
|
+
mode: "merge",
|
|
2225
|
+
value: { type: "literal", content }
|
|
2226
|
+
};
|
|
2227
|
+
} else {
|
|
2228
|
+
throw this.createError("WriteState requires either field+value or merge prop", openingElement);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
/**
|
|
2232
|
+
* Transform an OnStatus element to OnStatusNode
|
|
2233
|
+
* OnStatus is a block-level element that emits status-based conditionals
|
|
2234
|
+
*/
|
|
2235
|
+
transformOnStatus(node) {
|
|
2236
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
2237
|
+
const outputAttr = openingElement.getAttribute("output");
|
|
2238
|
+
if (!outputAttr || !Node.isJsxAttribute(outputAttr)) {
|
|
2239
|
+
throw this.createError("OnStatus requires output prop", openingElement);
|
|
2240
|
+
}
|
|
2241
|
+
const outputInit = outputAttr.getInitializer();
|
|
2242
|
+
if (!outputInit || !Node.isJsxExpression(outputInit)) {
|
|
2243
|
+
throw this.createError("OnStatus output must be a JSX expression: output={outputRef}", openingElement);
|
|
2244
|
+
}
|
|
2245
|
+
const outputExpr = outputInit.getExpression();
|
|
2246
|
+
if (!outputExpr || !Node.isIdentifier(outputExpr)) {
|
|
2247
|
+
throw this.createError("OnStatus output must reference a useOutput result", openingElement);
|
|
2248
|
+
}
|
|
2249
|
+
const outputIdentifier = outputExpr.getText();
|
|
2250
|
+
const agentName = this.outputs.get(outputIdentifier);
|
|
2251
|
+
if (!agentName) {
|
|
2252
|
+
throw this.createError(
|
|
2253
|
+
`Output '${outputIdentifier}' not found. Did you declare it with useOutput()?`,
|
|
2254
|
+
openingElement
|
|
2255
|
+
);
|
|
2256
|
+
}
|
|
2257
|
+
const status = getAttributeValue(openingElement, "status");
|
|
2258
|
+
if (!status) {
|
|
2259
|
+
throw this.createError("OnStatus requires status prop", openingElement);
|
|
2260
|
+
}
|
|
2261
|
+
const validStatuses = ["SUCCESS", "BLOCKED", "NOT_FOUND", "ERROR", "CHECKPOINT"];
|
|
2262
|
+
if (!validStatuses.includes(status)) {
|
|
2263
|
+
throw this.createError(
|
|
2264
|
+
`OnStatus status must be one of: ${validStatuses.join(", ")}. Got: ${status}`,
|
|
2265
|
+
openingElement
|
|
2266
|
+
);
|
|
2267
|
+
}
|
|
2268
|
+
const children = Node.isJsxElement(node) ? this.transformBlockChildren(node.getJsxChildren()) : [];
|
|
2269
|
+
return {
|
|
2270
|
+
kind: "onStatus",
|
|
2271
|
+
outputRef: {
|
|
2272
|
+
kind: "outputReference",
|
|
2273
|
+
agent: agentName
|
|
2274
|
+
},
|
|
2275
|
+
status,
|
|
2276
|
+
children
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
// ============================================================================
|
|
2280
|
+
// MCP Configuration Transformation
|
|
2281
|
+
// ============================================================================
|
|
2282
|
+
/**
|
|
2283
|
+
* Transform an MCPConfig element to MCPConfigDocumentNode
|
|
2284
|
+
* MCPConfig wraps multiple MCPServer elements into a single document
|
|
2285
|
+
* Delegates to document.ts transformMCPConfig()
|
|
2286
|
+
*/
|
|
2287
|
+
transformMCPConfig(node) {
|
|
2288
|
+
return transformMCPConfig(node, this.buildContext());
|
|
2289
|
+
}
|
|
2290
|
+
/**
|
|
2291
|
+
* Transform JSX children to BlockNodes, handling If/Else sibling pairs
|
|
2292
|
+
*/
|
|
2293
|
+
transformBlockChildren(jsxChildren) {
|
|
2294
|
+
const blocks = [];
|
|
2295
|
+
let i = 0;
|
|
2296
|
+
while (i < jsxChildren.length) {
|
|
2297
|
+
const child = jsxChildren[i];
|
|
2298
|
+
if (Node.isJsxText(child)) {
|
|
2299
|
+
const text = extractText(child);
|
|
2300
|
+
if (!text) {
|
|
2301
|
+
i++;
|
|
2302
|
+
continue;
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
if (Node.isJsxElement(child) || Node.isJsxSelfClosingElement(child)) {
|
|
2306
|
+
const childName = getElementName(child);
|
|
2307
|
+
if (childName === "If") {
|
|
2308
|
+
const ifNode = this.transformIf(child);
|
|
2309
|
+
blocks.push(ifNode);
|
|
2310
|
+
let nextIndex = i + 1;
|
|
2311
|
+
while (nextIndex < jsxChildren.length) {
|
|
2312
|
+
const sibling = jsxChildren[nextIndex];
|
|
2313
|
+
if (Node.isJsxText(sibling)) {
|
|
2314
|
+
const text = extractText(sibling);
|
|
2315
|
+
if (!text) {
|
|
2316
|
+
nextIndex++;
|
|
2317
|
+
continue;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
if ((Node.isJsxElement(sibling) || Node.isJsxSelfClosingElement(sibling)) && getElementName(sibling) === "Else") {
|
|
2321
|
+
const elseNode = this.transformElse(sibling);
|
|
2322
|
+
blocks.push(elseNode);
|
|
2323
|
+
i = nextIndex;
|
|
2324
|
+
}
|
|
2325
|
+
break;
|
|
2326
|
+
}
|
|
2327
|
+
} else {
|
|
2328
|
+
const block = this.transformToBlock(child);
|
|
2329
|
+
if (block) blocks.push(block);
|
|
2330
|
+
}
|
|
2331
|
+
} else {
|
|
2332
|
+
const block = this.transformToBlock(child);
|
|
2333
|
+
if (block) blocks.push(block);
|
|
2334
|
+
}
|
|
2335
|
+
i++;
|
|
2336
|
+
}
|
|
2337
|
+
return blocks;
|
|
2338
|
+
}
|
|
2339
|
+
/**
|
|
2340
|
+
* Transform an Assign element to AssignNode
|
|
2341
|
+
* Assign emits a bash code block with variable assignment
|
|
2342
|
+
*
|
|
2343
|
+
* Supports three assignment types (exactly one required):
|
|
2344
|
+
* - bash: VAR=$(command)
|
|
2345
|
+
* - value: VAR=value (quoted if spaces)
|
|
2346
|
+
* - env: VAR=$ENV_VAR
|
|
2347
|
+
*/
|
|
2348
|
+
transformAssign(node) {
|
|
2349
|
+
const openingElement = Node.isJsxElement(node) ? node.getOpeningElement() : node;
|
|
2350
|
+
const varAttr = openingElement.getAttribute("var");
|
|
2351
|
+
if (!varAttr || !Node.isJsxAttribute(varAttr)) {
|
|
2352
|
+
throw this.createError("Assign requires var prop", openingElement);
|
|
2353
|
+
}
|
|
2354
|
+
const init = varAttr.getInitializer();
|
|
2355
|
+
if (!init || !Node.isJsxExpression(init)) {
|
|
2356
|
+
throw this.createError("Assign var must be a JSX expression: var={variableName}", openingElement);
|
|
2357
|
+
}
|
|
2358
|
+
const expr = init.getExpression();
|
|
2359
|
+
if (!expr) {
|
|
2360
|
+
throw this.createError("Assign var must reference a useVariable or defineVars result", openingElement);
|
|
2361
|
+
}
|
|
2362
|
+
let localName;
|
|
2363
|
+
if (Node.isIdentifier(expr)) {
|
|
2364
|
+
localName = expr.getText();
|
|
2365
|
+
} else if (Node.isPropertyAccessExpression(expr)) {
|
|
2366
|
+
localName = expr.getText();
|
|
2367
|
+
} else {
|
|
2368
|
+
throw this.createError("Assign var must reference a useVariable or defineVars result", openingElement);
|
|
2369
|
+
}
|
|
2370
|
+
const variable = this.variables.get(localName);
|
|
2371
|
+
if (!variable) {
|
|
2372
|
+
throw this.createError(
|
|
2373
|
+
`Variable '${localName}' not found. Did you declare it with useVariable() or defineVars()?`,
|
|
2374
|
+
openingElement
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
2377
|
+
const bashProp = this.extractAssignPropValue(openingElement, "bash");
|
|
2378
|
+
const valueProp = this.extractAssignPropValue(openingElement, "value");
|
|
2379
|
+
const envProp = this.extractAssignPropValue(openingElement, "env");
|
|
2380
|
+
const propCount = [bashProp, valueProp, envProp].filter((p) => p !== void 0).length;
|
|
2381
|
+
if (propCount === 0) {
|
|
2382
|
+
throw this.createError(
|
|
2383
|
+
"Assign requires one of: bash, value, or env prop",
|
|
2384
|
+
openingElement
|
|
2385
|
+
);
|
|
2386
|
+
}
|
|
2387
|
+
if (propCount > 1) {
|
|
2388
|
+
throw this.createError(
|
|
2389
|
+
"Assign accepts only one of: bash, value, or env prop",
|
|
2390
|
+
openingElement
|
|
2391
|
+
);
|
|
2392
|
+
}
|
|
2393
|
+
let assignment;
|
|
2394
|
+
if (bashProp !== void 0) {
|
|
2395
|
+
assignment = { type: "bash", content: bashProp };
|
|
2396
|
+
} else if (valueProp !== void 0) {
|
|
2397
|
+
assignment = { type: "value", content: valueProp };
|
|
2398
|
+
} else {
|
|
2399
|
+
assignment = { type: "env", content: envProp };
|
|
2400
|
+
}
|
|
2401
|
+
const commentProp = this.extractAssignPropValue(openingElement, "comment");
|
|
2402
|
+
return {
|
|
2403
|
+
kind: "assign",
|
|
2404
|
+
variableName: variable.envName,
|
|
2405
|
+
assignment,
|
|
2406
|
+
...commentProp && { comment: commentProp }
|
|
2407
|
+
};
|
|
2408
|
+
}
|
|
2409
|
+
/**
|
|
2410
|
+
* Transform an AssignGroup element to AssignGroupNode
|
|
2411
|
+
* AssignGroup collects Assign children into a single bash code block
|
|
2412
|
+
*/
|
|
2413
|
+
transformAssignGroup(node) {
|
|
2414
|
+
if (Node.isJsxSelfClosingElement(node)) {
|
|
2415
|
+
throw this.createError("AssignGroup must have Assign children", node);
|
|
2416
|
+
}
|
|
2417
|
+
const children = node.getJsxChildren();
|
|
2418
|
+
const assignments = [];
|
|
2419
|
+
let pendingBlankBefore = false;
|
|
2420
|
+
for (const child of children) {
|
|
2421
|
+
if (Node.isJsxText(child)) {
|
|
2422
|
+
const text = child.getText().trim();
|
|
2423
|
+
if (text === "") continue;
|
|
2424
|
+
throw this.createError("AssignGroup can only contain Assign or br elements, not text", child);
|
|
2425
|
+
}
|
|
2426
|
+
if (!Node.isJsxElement(child) && !Node.isJsxSelfClosingElement(child)) {
|
|
2427
|
+
throw this.createError("AssignGroup can only contain Assign or br elements", child);
|
|
2428
|
+
}
|
|
2429
|
+
const opening = Node.isJsxElement(child) ? child.getOpeningElement() : child;
|
|
2430
|
+
const tagNameNode = opening.getTagNameNode();
|
|
2431
|
+
const name = tagNameNode.getText();
|
|
2432
|
+
if (name === "br") {
|
|
2433
|
+
pendingBlankBefore = true;
|
|
2434
|
+
continue;
|
|
2435
|
+
}
|
|
2436
|
+
if (name !== "Assign") {
|
|
2437
|
+
throw this.createError(`AssignGroup can only contain Assign or br elements, found: ${name}`, child);
|
|
2438
|
+
}
|
|
2439
|
+
const assignNode = this.transformAssign(child);
|
|
2440
|
+
if (pendingBlankBefore) {
|
|
2441
|
+
assignNode.blankBefore = true;
|
|
2442
|
+
pendingBlankBefore = false;
|
|
2443
|
+
}
|
|
2444
|
+
assignments.push(assignNode);
|
|
2445
|
+
}
|
|
2446
|
+
if (assignments.length === 0) {
|
|
2447
|
+
throw this.createError("AssignGroup must contain at least one Assign element", node);
|
|
2448
|
+
}
|
|
2449
|
+
return {
|
|
2450
|
+
kind: "assignGroup",
|
|
2451
|
+
assignments
|
|
2452
|
+
};
|
|
2453
|
+
}
|
|
2454
|
+
/**
|
|
2455
|
+
* Extract assignment prop value from Assign element
|
|
2456
|
+
* Handles string literals, JSX expressions with strings, and template literals
|
|
2457
|
+
*/
|
|
2458
|
+
extractAssignPropValue(element, propName) {
|
|
2459
|
+
const attr = element.getAttribute(propName);
|
|
2460
|
+
if (!attr || !Node.isJsxAttribute(attr)) return void 0;
|
|
2461
|
+
const init = attr.getInitializer();
|
|
2462
|
+
if (!init) return void 0;
|
|
2463
|
+
if (Node.isStringLiteral(init)) {
|
|
2464
|
+
return init.getLiteralValue();
|
|
2465
|
+
}
|
|
2466
|
+
if (Node.isJsxExpression(init)) {
|
|
2467
|
+
const expr = init.getExpression();
|
|
2468
|
+
if (!expr) return void 0;
|
|
2469
|
+
if (Node.isStringLiteral(expr)) {
|
|
2470
|
+
return expr.getLiteralValue();
|
|
2471
|
+
}
|
|
2472
|
+
if (Node.isNoSubstitutionTemplateLiteral(expr)) {
|
|
2473
|
+
return expr.getLiteralValue();
|
|
2474
|
+
}
|
|
2475
|
+
if (Node.isTemplateExpression(expr)) {
|
|
2476
|
+
return this.extractBashTemplate(expr);
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
return void 0;
|
|
2480
|
+
}
|
|
2481
|
+
/**
|
|
2482
|
+
* Extract template literal content preserving ${VAR} syntax for bash
|
|
2483
|
+
*/
|
|
2484
|
+
extractBashTemplate(expr) {
|
|
2485
|
+
const parts = [];
|
|
2486
|
+
parts.push(expr.getHead().getLiteralText());
|
|
2487
|
+
for (const span of expr.getTemplateSpans()) {
|
|
2488
|
+
const spanExpr = span.getExpression();
|
|
2489
|
+
parts.push(`\${${spanExpr.getText()}}`);
|
|
2490
|
+
parts.push(span.getLiteral().getLiteralText());
|
|
2491
|
+
}
|
|
2492
|
+
return parts.join("");
|
|
2493
|
+
}
|
|
2494
|
+
/**
|
|
2495
|
+
* Extract prompt prop value, preserving multi-line content and {variable} placeholders
|
|
2496
|
+
* Supports: prompt="string", prompt={"string"}, prompt={`template`}
|
|
2497
|
+
*/
|
|
2498
|
+
extractPromptProp(element) {
|
|
2499
|
+
const attr = element.getAttribute("prompt");
|
|
2500
|
+
if (!attr || !Node.isJsxAttribute(attr)) {
|
|
2501
|
+
return void 0;
|
|
2502
|
+
}
|
|
2503
|
+
const init = attr.getInitializer();
|
|
2504
|
+
if (!init) {
|
|
2505
|
+
return void 0;
|
|
2506
|
+
}
|
|
2507
|
+
if (Node.isStringLiteral(init)) {
|
|
2508
|
+
return init.getLiteralValue();
|
|
2509
|
+
}
|
|
2510
|
+
if (Node.isJsxExpression(init)) {
|
|
2511
|
+
const expr = init.getExpression();
|
|
2512
|
+
if (!expr) {
|
|
2513
|
+
return void 0;
|
|
2514
|
+
}
|
|
2515
|
+
if (Node.isStringLiteral(expr)) {
|
|
2516
|
+
return expr.getLiteralValue();
|
|
2517
|
+
}
|
|
2518
|
+
if (Node.isNoSubstitutionTemplateLiteral(expr)) {
|
|
2519
|
+
return expr.getLiteralValue();
|
|
2520
|
+
}
|
|
2521
|
+
if (Node.isTemplateExpression(expr)) {
|
|
2522
|
+
return this.extractTemplateText(expr);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
return void 0;
|
|
2526
|
+
}
|
|
2527
|
+
/**
|
|
2528
|
+
* Extract text from a template expression, converting ${var} to {var}
|
|
2529
|
+
* This preserves GSD's {variable} placeholder syntax
|
|
2530
|
+
*/
|
|
2531
|
+
extractTemplateText(expr) {
|
|
2532
|
+
const parts = [];
|
|
2533
|
+
parts.push(expr.getHead().getLiteralText());
|
|
2534
|
+
for (const span of expr.getTemplateSpans()) {
|
|
2535
|
+
const spanExpr = span.getExpression();
|
|
2536
|
+
parts.push(`{${spanExpr.getText()}}`);
|
|
2537
|
+
parts.push(span.getLiteral().getLiteralText());
|
|
2538
|
+
}
|
|
2539
|
+
return parts.join("");
|
|
2540
|
+
}
|
|
2541
|
+
// ============================================================================
|
|
2542
|
+
// State Document Transformation
|
|
2543
|
+
// ============================================================================
|
|
2544
|
+
/**
|
|
2545
|
+
* Transform a State component into StateDocumentNode
|
|
2546
|
+
* Delegates to document.ts transformState()
|
|
2547
|
+
*/
|
|
2548
|
+
transformState(node) {
|
|
2549
|
+
return transformState(node, this.buildContext());
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Evaluate a binary expression that represents string concatenation.
|
|
2553
|
+
* Handles chains like: `text ` + AGENT_PATHS.researcher + ` more`
|
|
2554
|
+
* Returns the concatenated string or null if not evaluable.
|
|
2555
|
+
*/
|
|
2556
|
+
evaluateStringConcatenation(expr) {
|
|
2557
|
+
const operator = expr.getOperatorToken().getText();
|
|
2558
|
+
if (operator !== "+") {
|
|
2559
|
+
return null;
|
|
2560
|
+
}
|
|
2561
|
+
const left = expr.getLeft();
|
|
2562
|
+
const right = expr.getRight();
|
|
2563
|
+
const leftValue = this.evaluateStringExpression(left);
|
|
2564
|
+
const rightValue = this.evaluateStringExpression(right);
|
|
2565
|
+
if (leftValue === null || rightValue === null) {
|
|
2566
|
+
return null;
|
|
2567
|
+
}
|
|
2568
|
+
return leftValue + rightValue;
|
|
2569
|
+
}
|
|
2570
|
+
/**
|
|
2571
|
+
* Evaluate an expression that should resolve to a string value.
|
|
2572
|
+
* Handles: string literals, template literals, property access, binary expressions.
|
|
2573
|
+
*/
|
|
2574
|
+
evaluateStringExpression(expr) {
|
|
2575
|
+
if (Node.isStringLiteral(expr)) {
|
|
2576
|
+
return expr.getLiteralValue();
|
|
2577
|
+
}
|
|
2578
|
+
if (Node.isNoSubstitutionTemplateLiteral(expr)) {
|
|
2579
|
+
return expr.getLiteralValue();
|
|
2580
|
+
}
|
|
2581
|
+
if (Node.isTemplateExpression(expr)) {
|
|
2582
|
+
let result = expr.getHead().getLiteralText();
|
|
2583
|
+
for (const span of expr.getTemplateSpans()) {
|
|
2584
|
+
const spanExpr = span.getExpression();
|
|
2585
|
+
const spanValue = this.evaluateStringExpression(spanExpr);
|
|
2586
|
+
if (spanValue !== null) {
|
|
2587
|
+
result += spanValue;
|
|
2588
|
+
} else if (Node.isIdentifier(spanExpr)) {
|
|
2589
|
+
result += `\${${spanExpr.getText()}}`;
|
|
2590
|
+
} else {
|
|
2591
|
+
result += `\${${spanExpr.getText()}}`;
|
|
2592
|
+
}
|
|
2593
|
+
const literal = span.getLiteral();
|
|
2594
|
+
if (Node.isTemplateMiddle(literal)) {
|
|
2595
|
+
result += literal.getLiteralText();
|
|
2596
|
+
} else if (Node.isTemplateTail(literal)) {
|
|
2597
|
+
result += literal.getLiteralText();
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2600
|
+
return result;
|
|
2601
|
+
}
|
|
2602
|
+
if (Node.isPropertyAccessExpression(expr)) {
|
|
2603
|
+
return this.resolvePropertyAccess(expr);
|
|
2604
|
+
}
|
|
2605
|
+
if (Node.isBinaryExpression(expr)) {
|
|
2606
|
+
return this.evaluateStringConcatenation(expr);
|
|
2607
|
+
}
|
|
2608
|
+
if (Node.isParenthesizedExpression(expr)) {
|
|
2609
|
+
return this.evaluateStringExpression(expr.getExpression());
|
|
2610
|
+
}
|
|
2611
|
+
return null;
|
|
2612
|
+
}
|
|
2613
|
+
/**
|
|
2614
|
+
* Resolve a property access expression (e.g., AGENT_PATHS.researcher) to its value.
|
|
2615
|
+
* Only works for const declarations with object literals.
|
|
2616
|
+
*/
|
|
2617
|
+
resolvePropertyAccess(expr) {
|
|
2618
|
+
const objectExpr = expr.getExpression();
|
|
2619
|
+
const propertyName = expr.getName();
|
|
2620
|
+
if (!Node.isIdentifier(objectExpr)) {
|
|
2621
|
+
return null;
|
|
2622
|
+
}
|
|
2623
|
+
const objectName = objectExpr.getText();
|
|
2624
|
+
const sourceFile = expr.getSourceFile();
|
|
2625
|
+
const varDecls = sourceFile.getVariableDeclarations();
|
|
2626
|
+
for (const varDecl of varDecls) {
|
|
2627
|
+
if (varDecl.getName() === objectName) {
|
|
2628
|
+
let initializer = varDecl.getInitializer();
|
|
2629
|
+
if (initializer && Node.isAsExpression(initializer)) {
|
|
2630
|
+
initializer = initializer.getExpression();
|
|
2631
|
+
}
|
|
2632
|
+
if (initializer && Node.isObjectLiteralExpression(initializer)) {
|
|
2633
|
+
for (const prop of initializer.getProperties()) {
|
|
2634
|
+
if (Node.isPropertyAssignment(prop) && prop.getName() === propertyName) {
|
|
2635
|
+
const propInit = prop.getInitializer();
|
|
2636
|
+
if (propInit && Node.isStringLiteral(propInit)) {
|
|
2637
|
+
return propInit.getLiteralValue();
|
|
2638
|
+
}
|
|
2639
|
+
if (propInit && Node.isNoSubstitutionTemplateLiteral(propInit)) {
|
|
2640
|
+
return propInit.getLiteralValue();
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
break;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
return null;
|
|
2649
|
+
}
|
|
2650
|
+
};
|
|
2651
|
+
function transform(node, sourceFile) {
|
|
2652
|
+
const transformer = new Transformer();
|
|
2653
|
+
return transformer.transform(node, sourceFile);
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
// src/primitives/schema.ts
|
|
2657
|
+
function defineVars(schema) {
|
|
2658
|
+
const result = {};
|
|
2659
|
+
for (const key of Object.keys(schema)) {
|
|
2660
|
+
result[key] = { name: key, ref: key };
|
|
2661
|
+
}
|
|
2662
|
+
return result;
|
|
2663
|
+
}
|
|
2664
|
+
function defineFiles(schema) {
|
|
2665
|
+
const result = {};
|
|
2666
|
+
const refs = [];
|
|
2667
|
+
for (const key of Object.keys(schema)) {
|
|
2668
|
+
const def = schema[key];
|
|
2669
|
+
const varName = key.replace(/([a-z])([A-Z])/g, "$1_$2").toUpperCase() + "_CONTENT";
|
|
2670
|
+
const pathValue = typeof def.path === "function" ? def.path({}) : def.path;
|
|
2671
|
+
const fileRef = {
|
|
2672
|
+
varName,
|
|
2673
|
+
key,
|
|
2674
|
+
path: pathValue,
|
|
2675
|
+
required: def.required !== false
|
|
2676
|
+
// Default true
|
|
2677
|
+
};
|
|
2678
|
+
result[key] = fileRef;
|
|
2679
|
+
refs.push(fileRef);
|
|
2680
|
+
}
|
|
2681
|
+
return {
|
|
2682
|
+
...result,
|
|
2683
|
+
_refs: refs
|
|
2684
|
+
};
|
|
2685
|
+
}
|
|
2686
|
+
function defineContext(def) {
|
|
2687
|
+
const agents = {};
|
|
2688
|
+
if (def.agents) {
|
|
2689
|
+
for (const [key, value] of Object.entries(def.agents)) {
|
|
2690
|
+
if (typeof value === "string") {
|
|
2691
|
+
agents[key] = { path: value };
|
|
2692
|
+
} else {
|
|
2693
|
+
agents[key] = value;
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
return {
|
|
2698
|
+
agents,
|
|
2699
|
+
vars: def.vars || {},
|
|
2700
|
+
files: def.files || { _refs: [] }
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
// src/workflow/sections/semantic.ts
|
|
2705
|
+
function ExecutionContext(_props) {
|
|
2706
|
+
return null;
|
|
2707
|
+
}
|
|
2708
|
+
export {
|
|
2709
|
+
ASK_USER_MARKER,
|
|
2710
|
+
Agent,
|
|
2711
|
+
AskUser,
|
|
2712
|
+
BREAK_MARKER,
|
|
2713
|
+
Break,
|
|
2714
|
+
Command,
|
|
2715
|
+
ELSE_MARKER,
|
|
2716
|
+
Else,
|
|
2717
|
+
ExecutionContext,
|
|
2718
|
+
IF_MARKER,
|
|
2719
|
+
If,
|
|
2720
|
+
Indent,
|
|
2721
|
+
LOOP_MARKER,
|
|
2722
|
+
List,
|
|
2723
|
+
Loop,
|
|
2724
|
+
Markdown,
|
|
2725
|
+
OnStatus,
|
|
2726
|
+
RETURN_MARKER,
|
|
2727
|
+
Return,
|
|
2728
|
+
RuntimeMarkdownEmitter,
|
|
2729
|
+
SpawnAgent,
|
|
2730
|
+
Table,
|
|
2731
|
+
Transformer,
|
|
2732
|
+
XmlBlock,
|
|
2733
|
+
assertNever,
|
|
2734
|
+
buildRuntimeFile,
|
|
2735
|
+
bundleCodeSplit,
|
|
2736
|
+
bundleSingleEntryRuntime,
|
|
2737
|
+
clearRuntimeFnRegistry,
|
|
2738
|
+
createProject,
|
|
2739
|
+
createRuntimeContext,
|
|
2740
|
+
defineAgent,
|
|
2741
|
+
defineContext,
|
|
2742
|
+
defineFiles,
|
|
2743
|
+
defineVars,
|
|
2744
|
+
detectRuntime,
|
|
2745
|
+
emit,
|
|
2746
|
+
emitAgent,
|
|
2747
|
+
emitDocument,
|
|
2748
|
+
emitRuntime,
|
|
2749
|
+
emitSettings,
|
|
2750
|
+
emitSkill,
|
|
2751
|
+
emitSkillFile,
|
|
2752
|
+
extractExportedFunctionNames,
|
|
2753
|
+
extractExternalComponentDeclarations,
|
|
2754
|
+
extractFunctions,
|
|
2755
|
+
extractInputObjectLiteral,
|
|
2756
|
+
extractInterfaceProperties,
|
|
2757
|
+
extractLocalComponentDeclarations,
|
|
2758
|
+
extractPromptPlaceholders,
|
|
2759
|
+
extractRuntimeFnDeclarations,
|
|
2760
|
+
extractRuntimeVarDeclarations,
|
|
2761
|
+
extractText,
|
|
2762
|
+
extractTypeArguments,
|
|
2763
|
+
extractVariableDeclarations,
|
|
2764
|
+
findRootJsxElement,
|
|
2765
|
+
generateRuntime,
|
|
2766
|
+
getAgentName,
|
|
2767
|
+
getAgentPath,
|
|
2768
|
+
getArrayAttributeValue,
|
|
2769
|
+
getAttributeValue,
|
|
2770
|
+
getElementName,
|
|
2771
|
+
getJsxChildren,
|
|
2772
|
+
getRuntimeFn,
|
|
2773
|
+
getRuntimeFnRegistry,
|
|
2774
|
+
getRuntimeFunctionNames,
|
|
2775
|
+
getRuntimeImportPaths,
|
|
2776
|
+
getRuntimeVarInfo,
|
|
2777
|
+
hasRuntimeImports,
|
|
2778
|
+
isAgentRef,
|
|
2779
|
+
isDocument,
|
|
2780
|
+
isRuntimeFile,
|
|
2781
|
+
isRuntimeFn,
|
|
2782
|
+
isRuntimeNode,
|
|
2783
|
+
isRuntimeVar,
|
|
2784
|
+
isWhitespaceOnlyText,
|
|
2785
|
+
mergeSettings,
|
|
2786
|
+
normalizeWhitespace,
|
|
2787
|
+
parseFile,
|
|
2788
|
+
parseSource,
|
|
2789
|
+
resolveTypeImport,
|
|
2790
|
+
runtimeFn,
|
|
2791
|
+
toJqExpression,
|
|
2792
|
+
toJqPath,
|
|
2793
|
+
transform,
|
|
2794
|
+
transformRuntimeBlockChildren,
|
|
2795
|
+
transformRuntimeCommand,
|
|
2796
|
+
transformToRuntimeBlock,
|
|
2797
|
+
useOutput,
|
|
2798
|
+
useRuntimeVar
|
|
2799
|
+
};
|
|
2800
|
+
//# sourceMappingURL=index.js.map
|