sf-agentpmd 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/NOTICE +7 -5
  2. package/dist/commands/agentpmd/analyze.js +4141 -109
  3. package/dist/commands/agentpmd/analyze.js.map +7 -1
  4. package/dist/commands/agentpmd/install-skill.js +27 -30
  5. package/dist/commands/agentpmd/install-skill.js.map +7 -1
  6. package/dist/index.js +4155 -3
  7. package/dist/index.js.map +7 -1
  8. package/oclif.manifest.json +1 -1
  9. package/package.json +7 -8
  10. package/dist/analyzer/action-references.d.ts +0 -21
  11. package/dist/analyzer/action-references.js +0 -130
  12. package/dist/analyzer/action-references.js.map +0 -1
  13. package/dist/analyzer/analyze.d.ts +0 -43
  14. package/dist/analyzer/analyze.js +0 -222
  15. package/dist/analyzer/analyze.js.map +0 -1
  16. package/dist/analyzer/apex-analyze.d.ts +0 -14
  17. package/dist/analyzer/apex-analyze.js +0 -60
  18. package/dist/analyzer/apex-analyze.js.map +0 -1
  19. package/dist/analyzer/apex-complexity.d.ts +0 -27
  20. package/dist/analyzer/apex-complexity.js +0 -133
  21. package/dist/analyzer/apex-complexity.js.map +0 -1
  22. package/dist/analyzer/apex-parse.d.ts +0 -39
  23. package/dist/analyzer/apex-parse.js +0 -32
  24. package/dist/analyzer/apex-parse.js.map +0 -1
  25. package/dist/analyzer/apex-resolve.d.ts +0 -32
  26. package/dist/analyzer/apex-resolve.js +0 -59
  27. package/dist/analyzer/apex-resolve.js.map +0 -1
  28. package/dist/analyzer/complexity.d.ts +0 -30
  29. package/dist/analyzer/complexity.js +0 -126
  30. package/dist/analyzer/complexity.js.map +0 -1
  31. package/dist/analyzer/parse.d.ts +0 -51
  32. package/dist/analyzer/parse.js +0 -143
  33. package/dist/analyzer/parse.js.map +0 -1
  34. package/dist/analyzer/project.d.ts +0 -12
  35. package/dist/analyzer/project.js +0 -51
  36. package/dist/analyzer/project.js.map +0 -1
  37. package/dist/analyzer/types.d.ts +0 -76
  38. package/dist/analyzer/types.js +0 -2
  39. package/dist/analyzer/types.js.map +0 -1
  40. package/dist/commands/agentpmd/analyze.d.ts +0 -20
  41. package/dist/commands/agentpmd/install-skill.d.ts +0 -11
  42. package/dist/index.d.ts +0 -3
  43. package/dist/renderers/csv.d.ts +0 -6
  44. package/dist/renderers/csv.js +0 -78
  45. package/dist/renderers/csv.js.map +0 -1
  46. package/dist/renderers/index.d.ts +0 -8
  47. package/dist/renderers/index.js +0 -25
  48. package/dist/renderers/index.js.map +0 -1
  49. package/dist/renderers/markdown.d.ts +0 -12
  50. package/dist/renderers/markdown.js +0 -233
  51. package/dist/renderers/markdown.js.map +0 -1
  52. package/dist/renderers/options.d.ts +0 -20
  53. package/dist/renderers/options.js +0 -2
  54. package/dist/renderers/options.js.map +0 -1
  55. package/dist/renderers/sarif.d.ts +0 -3
  56. package/dist/renderers/sarif.js +0 -131
  57. package/dist/renderers/sarif.js.map +0 -1
  58. package/dist/renderers/text.d.ts +0 -3
  59. package/dist/renderers/text.js +0 -243
  60. package/dist/renderers/text.js.map +0 -1
  61. package/vendor/agentscript-parser-javascript/dist/cst-node.d.ts +0 -83
  62. package/vendor/agentscript-parser-javascript/dist/cst-node.js +0 -238
  63. package/vendor/agentscript-parser-javascript/dist/errors.d.ts +0 -34
  64. package/vendor/agentscript-parser-javascript/dist/errors.js +0 -74
  65. package/vendor/agentscript-parser-javascript/dist/expressions.d.ts +0 -36
  66. package/vendor/agentscript-parser-javascript/dist/expressions.js +0 -682
  67. package/vendor/agentscript-parser-javascript/dist/highlighter.d.ts +0 -24
  68. package/vendor/agentscript-parser-javascript/dist/highlighter.js +0 -260
  69. package/vendor/agentscript-parser-javascript/dist/index.d.ts +0 -29
  70. package/vendor/agentscript-parser-javascript/dist/index.js +0 -35
  71. package/vendor/agentscript-parser-javascript/dist/lexer.d.ts +0 -60
  72. package/vendor/agentscript-parser-javascript/dist/lexer.js +0 -630
  73. package/vendor/agentscript-parser-javascript/dist/parse-mapping.d.ts +0 -46
  74. package/vendor/agentscript-parser-javascript/dist/parse-mapping.js +0 -549
  75. package/vendor/agentscript-parser-javascript/dist/parse-sequence.d.ts +0 -10
  76. package/vendor/agentscript-parser-javascript/dist/parse-sequence.js +0 -118
  77. package/vendor/agentscript-parser-javascript/dist/parse-statements.d.ts +0 -15
  78. package/vendor/agentscript-parser-javascript/dist/parse-statements.js +0 -519
  79. package/vendor/agentscript-parser-javascript/dist/parse-templates.d.ts +0 -15
  80. package/vendor/agentscript-parser-javascript/dist/parse-templates.js +0 -323
  81. package/vendor/agentscript-parser-javascript/dist/parser.d.ts +0 -65
  82. package/vendor/agentscript-parser-javascript/dist/parser.js +0 -163
  83. package/vendor/agentscript-parser-javascript/dist/recovery.d.ts +0 -51
  84. package/vendor/agentscript-parser-javascript/dist/recovery.js +0 -199
  85. package/vendor/agentscript-parser-javascript/dist/token.d.ts +0 -58
  86. package/vendor/agentscript-parser-javascript/dist/token.js +0 -62
  87. package/vendor/agentscript-parser-javascript/package.json +0 -19
  88. package/vendor/agentscript-types/dist/comment.d.ts +0 -11
  89. package/vendor/agentscript-types/dist/comment.js +0 -10
  90. package/vendor/agentscript-types/dist/cst.d.ts +0 -7
  91. package/vendor/agentscript-types/dist/cst.js +0 -8
  92. package/vendor/agentscript-types/dist/diagnostic.d.ts +0 -34
  93. package/vendor/agentscript-types/dist/diagnostic.js +0 -23
  94. package/vendor/agentscript-types/dist/index.d.ts +0 -9
  95. package/vendor/agentscript-types/dist/index.js +0 -10
  96. package/vendor/agentscript-types/dist/position.d.ts +0 -11
  97. package/vendor/agentscript-types/dist/position.js +0 -16
  98. package/vendor/agentscript-types/dist/syntax-node.d.ts +0 -39
  99. package/vendor/agentscript-types/dist/syntax-node.js +0 -8
  100. package/vendor/agentscript-types/package.json +0 -15
@@ -1,10 +1,4038 @@
1
- import { Flags, SfCommand } from '@salesforce/sf-plugins-core';
2
- import { analyzeSource } from '../../analyzer/analyze.js';
3
- import { discoverSfdxProject } from '../../analyzer/project.js';
4
- import { render } from '../../renderers/index.js';
5
- const FORMATS = ['text', 'markdown', 'sarif', 'csv'];
6
- export default class AgentpmdAnalyze extends SfCommand {
7
- static description = `Walks .agent source files under --source-dir and emits per-procedure
1
+ // src/commands/agentpmd/analyze.ts
2
+ import { Flags, SfCommand } from "@salesforce/sf-plugins-core";
3
+
4
+ // src/analyzer/analyze.ts
5
+ import { readdir, readFile as readFile2, stat as stat2 } from "node:fs/promises";
6
+ import { basename as basename2, dirname as dirname2, join as join2, relative as relative2, resolve as resolve2 } from "node:path";
7
+
8
+ // vendor/agentscript-parser-javascript/dist/cst-node.js
9
+ var EMPTY_CHILDREN = Object.freeze([]);
10
+ var CSTNode = class {
11
+ type;
12
+ /** Whether this is a "named" node (true) or anonymous punctuation/keyword (false). */
13
+ isNamed;
14
+ isError;
15
+ isMissing;
16
+ startOffset;
17
+ endOffset;
18
+ // Flat position storage — avoids object allocations per node.
19
+ // Also exposed as startPosition/endPosition getters for compat.
20
+ startRow;
21
+ startCol;
22
+ endRow;
23
+ endCol;
24
+ /** Lazy children array — null for leaf nodes, allocated on first appendChild. */
25
+ _children = null;
26
+ parent = null;
27
+ /** Index of this node within its parent's children array. -1 if no parent. */
28
+ _childIndex = -1;
29
+ /** Field name → child indices. Lazy: null until first field is added. */
30
+ _fields = null;
31
+ /** Reverse map: child index → field name. Built lazily. */
32
+ _childFieldNames = null;
33
+ /** Cached named children. */
34
+ _namedChildren = null;
35
+ /** The original source string, shared across all nodes in a tree. */
36
+ _source;
37
+ constructor(type, source, startOffset, endOffset, startPosition, endPosition, isNamed = true, isError = false, isMissing = false) {
38
+ this.type = type;
39
+ this._source = source;
40
+ this.startOffset = startOffset;
41
+ this.endOffset = endOffset;
42
+ this.startRow = startPosition.row;
43
+ this.startCol = startPosition.column;
44
+ this.endRow = endPosition.row;
45
+ this.endCol = endPosition.column;
46
+ this.isNamed = isNamed;
47
+ this.isError = isError;
48
+ this.isMissing = isMissing;
49
+ }
50
+ get text() {
51
+ return this._source.slice(this.startOffset, this.endOffset);
52
+ }
53
+ get startPosition() {
54
+ return { row: this.startRow, column: this.startCol };
55
+ }
56
+ set startPosition(pos) {
57
+ this.startRow = pos.row;
58
+ this.startCol = pos.column;
59
+ }
60
+ get endPosition() {
61
+ return { row: this.endRow, column: this.endCol };
62
+ }
63
+ set endPosition(pos) {
64
+ this.endRow = pos.row;
65
+ this.endCol = pos.column;
66
+ }
67
+ get children() {
68
+ return this._children ?? EMPTY_CHILDREN;
69
+ }
70
+ set children(value) {
71
+ this._children = value;
72
+ }
73
+ get namedChildren() {
74
+ if (!this._namedChildren) {
75
+ this._namedChildren = this.children.filter((c) => c.isNamed);
76
+ }
77
+ return this._namedChildren;
78
+ }
79
+ get previousSibling() {
80
+ if (!this.parent || this._childIndex <= 0)
81
+ return null;
82
+ return this.parent.children[this._childIndex - 1];
83
+ }
84
+ get nextSibling() {
85
+ if (!this.parent)
86
+ return null;
87
+ const siblings = this.parent.children;
88
+ return this._childIndex < siblings.length - 1 ? siblings[this._childIndex + 1] : null;
89
+ }
90
+ childForFieldName(name) {
91
+ if (!this._fields)
92
+ return null;
93
+ const indices = this._fields.get(name);
94
+ if (!indices || indices.length === 0)
95
+ return null;
96
+ return this.children[indices[0]] ?? null;
97
+ }
98
+ childrenForFieldName(name) {
99
+ if (!this._fields)
100
+ return [];
101
+ const indices = this._fields.get(name);
102
+ if (!indices)
103
+ return [];
104
+ return indices.map((i) => this.children[i]).filter(Boolean);
105
+ }
106
+ /** True if this node or any descendant has an error or missing node. */
107
+ get hasError() {
108
+ if (this.isError || this.isMissing)
109
+ return true;
110
+ return this.children.some((c) => c.hasError);
111
+ }
112
+ /** Get the field name for a child at a given index. */
113
+ fieldNameForChild(index) {
114
+ if (!this._fields)
115
+ return null;
116
+ if (!this._childFieldNames) {
117
+ this._childFieldNames = /* @__PURE__ */ new Map();
118
+ for (const [fieldName, indices] of this._fields) {
119
+ for (const idx of indices) {
120
+ this._childFieldNames.set(idx, fieldName);
121
+ }
122
+ }
123
+ }
124
+ return this._childFieldNames.get(index) ?? null;
125
+ }
126
+ /** Add a child node, optionally associating it with a field name. */
127
+ appendChild(child, fieldName) {
128
+ if (!this._children)
129
+ this._children = [];
130
+ const idx = this._children.length;
131
+ child.parent = this;
132
+ child._childIndex = idx;
133
+ this._children.push(child);
134
+ this.endRow = child.endRow;
135
+ this.endCol = child.endCol;
136
+ this.endOffset = child.endOffset;
137
+ if (fieldName) {
138
+ if (!this._fields)
139
+ this._fields = /* @__PURE__ */ new Map();
140
+ let arr = this._fields.get(fieldName);
141
+ if (!arr) {
142
+ arr = [];
143
+ this._fields.set(fieldName, arr);
144
+ }
145
+ arr.push(idx);
146
+ }
147
+ }
148
+ /** @deprecated No-op: appendChild() tracks end position incrementally. */
149
+ finalize() {
150
+ }
151
+ /** Serialize to s-expression format for testing (named nodes only, no text). */
152
+ toSExp() {
153
+ return nodeToSExp(this);
154
+ }
155
+ /**
156
+ * Serialize to verbose s-expression format that includes ALL nodes
157
+ * (both named and anonymous) with truncated text content.
158
+ * Matches the source-of-truth format in sot/source.s-expression.
159
+ */
160
+ toVerboseSExp() {
161
+ return nodeToVerboseSExp(this, 0);
162
+ }
163
+ };
164
+ function nodeToSExp(node) {
165
+ const parts = [];
166
+ for (let i = 0; i < node.children.length; i++) {
167
+ const child = node.children[i];
168
+ if (!child.isNamed && !child.isError && !child.isMissing)
169
+ continue;
170
+ const fieldName = node.fieldNameForChild(i);
171
+ const childStr = child.children.length > 0 || child.isError ? nodeToSExp(child) : child.isMissing ? `(MISSING ${child.type})` : `(${child.type})`;
172
+ if (fieldName) {
173
+ parts.push(`${fieldName}: ${childStr}`);
174
+ } else {
175
+ parts.push(childStr);
176
+ }
177
+ }
178
+ if (node.isError) {
179
+ if (parts.length === 0) {
180
+ return `(ERROR)`;
181
+ }
182
+ return `(ERROR ${parts.join(" ")})`;
183
+ }
184
+ if (node.isMissing) {
185
+ return `(MISSING ${node.type})`;
186
+ }
187
+ if (parts.length === 0) {
188
+ return `(${node.type})`;
189
+ }
190
+ return `(${node.type} ${parts.join(" ")})`;
191
+ }
192
+ function nodeToVerboseSExp(node, depth) {
193
+ const indent = " ".repeat(depth);
194
+ if (node.isMissing) {
195
+ return `${indent}(MISSING ${JSON.stringify(node.type)})`;
196
+ }
197
+ if (node.isError && node.children.length === 0) {
198
+ return `${indent}(ERROR)`;
199
+ }
200
+ if (node.children.length === 0) {
201
+ const rawText = node.text;
202
+ const truncated = rawText.length > 20 ? rawText.slice(0, 20) + "\u2026" : rawText;
203
+ const escaped = JSON.stringify(truncated);
204
+ return `${indent}(${node.type} ${escaped})`;
205
+ }
206
+ const childLines = [];
207
+ for (const child of node.children) {
208
+ childLines.push(nodeToVerboseSExp(child, depth + 1));
209
+ }
210
+ return `${indent}(${node.type}
211
+ ${childLines.join("\n")})`;
212
+ }
213
+
214
+ // vendor/agentscript-parser-javascript/dist/token.js
215
+ var TokenKind;
216
+ (function(TokenKind2) {
217
+ TokenKind2["NEWLINE"] = "NEWLINE";
218
+ TokenKind2["INDENT"] = "INDENT";
219
+ TokenKind2["DEDENT"] = "DEDENT";
220
+ TokenKind2["EOF"] = "EOF";
221
+ TokenKind2["ID"] = "ID";
222
+ TokenKind2["NUMBER"] = "NUMBER";
223
+ TokenKind2["STRING"] = "STRING";
224
+ TokenKind2["STRING_CONTENT"] = "STRING_CONTENT";
225
+ TokenKind2["ESCAPE_SEQUENCE"] = "ESCAPE_SEQUENCE";
226
+ TokenKind2["DATETIME"] = "DATETIME";
227
+ TokenKind2["TEMPLATE_CONTENT"] = "TEMPLATE_CONTENT";
228
+ TokenKind2["PLUS"] = "PLUS";
229
+ TokenKind2["MINUS"] = "MINUS";
230
+ TokenKind2["STAR"] = "STAR";
231
+ TokenKind2["SLASH"] = "SLASH";
232
+ TokenKind2["DOT"] = "DOT";
233
+ TokenKind2["COMMA"] = "COMMA";
234
+ TokenKind2["COLON"] = "COLON";
235
+ TokenKind2["EQ"] = "EQ";
236
+ TokenKind2["EQEQ"] = "EQEQ";
237
+ TokenKind2["NEQ"] = "NEQ";
238
+ TokenKind2["LT"] = "LT";
239
+ TokenKind2["GT"] = "GT";
240
+ TokenKind2["LTE"] = "LTE";
241
+ TokenKind2["GTE"] = "GTE";
242
+ TokenKind2["ARROW"] = "ARROW";
243
+ TokenKind2["ELLIPSIS"] = "ELLIPSIS";
244
+ TokenKind2["PERCENT"] = "PERCENT";
245
+ TokenKind2["PIPE"] = "PIPE";
246
+ TokenKind2["AT"] = "AT";
247
+ TokenKind2["LPAREN"] = "LPAREN";
248
+ TokenKind2["RPAREN"] = "RPAREN";
249
+ TokenKind2["LBRACKET"] = "LBRACKET";
250
+ TokenKind2["RBRACKET"] = "RBRACKET";
251
+ TokenKind2["LBRACE"] = "LBRACE";
252
+ TokenKind2["RBRACE"] = "RBRACE";
253
+ TokenKind2["TEMPLATE_EXPR_START"] = "TEMPLATE_EXPR_START";
254
+ TokenKind2["DASH_SPACE"] = "DASH_SPACE";
255
+ TokenKind2["DQUOTE"] = "DQUOTE";
256
+ TokenKind2["COMMENT"] = "COMMENT";
257
+ TokenKind2["ERROR_TOKEN"] = "ERROR_TOKEN";
258
+ })(TokenKind || (TokenKind = {}));
259
+ function isTokenKind(token, kind) {
260
+ return token.kind === kind;
261
+ }
262
+
263
+ // node_modules/tiny-invariant/dist/esm/tiny-invariant.js
264
+ var isProduction = process.env.NODE_ENV === "production";
265
+ var prefix = "Invariant failed";
266
+ function invariant(condition, message) {
267
+ if (condition) {
268
+ return;
269
+ }
270
+ if (isProduction) {
271
+ throw new Error(prefix);
272
+ }
273
+ var provided = typeof message === "function" ? message() : message;
274
+ var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
275
+ throw new Error(value);
276
+ }
277
+
278
+ // vendor/agentscript-parser-javascript/dist/lexer.js
279
+ var CH_TAB = 9;
280
+ var CH_LF = 10;
281
+ var CH_CR = 13;
282
+ var CH_SPACE = 32;
283
+ var CH_BANG = 33;
284
+ var CH_DQUOTE = 34;
285
+ var CH_HASH = 35;
286
+ var CH_DASH = 45;
287
+ var CH_DOT = 46;
288
+ var CH_0 = 48;
289
+ var CH_9 = 57;
290
+ var CH_LT = 60;
291
+ var CH_EQ = 61;
292
+ var CH_GT = 62;
293
+ var CH_A = 65;
294
+ var CH_Z = 90;
295
+ var CH_BACKSLASH = 92;
296
+ var CH_UNDERSCORE = 95;
297
+ var CH_a = 97;
298
+ var CH_z = 122;
299
+ var CH_LBRACE = 123;
300
+ var CH_NUL = 0;
301
+ function isIdStart(c) {
302
+ return c >= CH_A && c <= CH_Z || c >= CH_a && c <= CH_z || c === CH_UNDERSCORE;
303
+ }
304
+ function isIdCont(c) {
305
+ return isIdStart(c) || c >= CH_0 && c <= CH_9;
306
+ }
307
+ function isDigit(c) {
308
+ return c >= CH_0 && c <= CH_9;
309
+ }
310
+ function isHorizontalWs(c) {
311
+ return c === CH_SPACE || c === CH_TAB;
312
+ }
313
+ var SINGLE_CHAR_TOKENS = new Array(128).fill(0);
314
+ SINGLE_CHAR_TOKENS[43] = TokenKind.PLUS;
315
+ SINGLE_CHAR_TOKENS[CH_DASH] = TokenKind.MINUS;
316
+ SINGLE_CHAR_TOKENS[42] = TokenKind.STAR;
317
+ SINGLE_CHAR_TOKENS[47] = TokenKind.SLASH;
318
+ SINGLE_CHAR_TOKENS[CH_DOT] = TokenKind.DOT;
319
+ SINGLE_CHAR_TOKENS[44] = TokenKind.COMMA;
320
+ SINGLE_CHAR_TOKENS[58] = TokenKind.COLON;
321
+ SINGLE_CHAR_TOKENS[61] = TokenKind.EQ;
322
+ SINGLE_CHAR_TOKENS[60] = TokenKind.LT;
323
+ SINGLE_CHAR_TOKENS[CH_GT] = TokenKind.GT;
324
+ SINGLE_CHAR_TOKENS[124] = TokenKind.PIPE;
325
+ SINGLE_CHAR_TOKENS[64] = TokenKind.AT;
326
+ SINGLE_CHAR_TOKENS[40] = TokenKind.LPAREN;
327
+ SINGLE_CHAR_TOKENS[41] = TokenKind.RPAREN;
328
+ SINGLE_CHAR_TOKENS[91] = TokenKind.LBRACKET;
329
+ SINGLE_CHAR_TOKENS[93] = TokenKind.RBRACKET;
330
+ SINGLE_CHAR_TOKENS[CH_LBRACE] = TokenKind.LBRACE;
331
+ SINGLE_CHAR_TOKENS[125] = TokenKind.RBRACE;
332
+ var Lexer = class {
333
+ source;
334
+ offset = 0;
335
+ row = 0;
336
+ col = 0;
337
+ tokens = [];
338
+ indentStack = [0];
339
+ /** True when the current line started with `|` (template line). */
340
+ onTemplateLine = false;
341
+ /** Indent level of the line containing `|`. Content deeper than this is template content. */
342
+ templateBaseIndent = -1;
343
+ /** Nested brace depth inside a template expression (for `{` inside `{!...}`). -1 means not inside a template expression. */
344
+ templateExprBraceDepth = -1;
345
+ get inTemplateExpr() {
346
+ return this.templateExprBraceDepth >= 0;
347
+ }
348
+ /** Parenthesis depth — suppresses INDENT/DEDENT/NEWLINE when > 0 to support multi-line call expressions. */
349
+ bracketDepth = 0;
350
+ constructor(source) {
351
+ this.source = source;
352
+ }
353
+ tokenize() {
354
+ this.tokens = [];
355
+ const estimate = this.source.length / 8 | 0;
356
+ if (estimate > 64) {
357
+ this.tokens.length = estimate;
358
+ this.tokens.length = 0;
359
+ }
360
+ this.offset = 0;
361
+ this.row = 0;
362
+ this.col = 0;
363
+ this.indentStack = [0];
364
+ this.bracketDepth = 0;
365
+ while (this.hasMore) {
366
+ this.tokenizeLine();
367
+ }
368
+ while (this.indentStack.length > 1) {
369
+ this.indentStack.pop();
370
+ this.emitVirtual(TokenKind.DEDENT);
371
+ }
372
+ this.emitVirtual(TokenKind.EOF);
373
+ return this.tokens;
374
+ }
375
+ tokenizeLine() {
376
+ const indentLength = this.consumeIndentation();
377
+ if (this.consumeNewline()) {
378
+ return;
379
+ }
380
+ const c = this.peekCharCode();
381
+ if (c === CH_HASH && (!this.onTemplateLine || indentLength <= this.templateBaseIndent)) {
382
+ const currentIndent2 = this.indentStack[this.indentStack.length - 1];
383
+ if (indentLength > currentIndent2) {
384
+ const nextContentIndent = this.peekNextContentIndent();
385
+ if (nextContentIndent < indentLength) {
386
+ this.emitIndentation(currentIndent2);
387
+ return this.tokenizeComment();
388
+ }
389
+ } else if (indentLength < currentIndent2) {
390
+ const nextContentIndent = this.peekNextContentIndent();
391
+ if (nextContentIndent > indentLength) {
392
+ this.emitIndentation(nextContentIndent);
393
+ return this.tokenizeComment();
394
+ }
395
+ } else {
396
+ const nextContentIndent = this.peekNextContentIndent();
397
+ if (nextContentIndent > indentLength) {
398
+ return this.tokenizeComment();
399
+ }
400
+ }
401
+ this.emitIndentation(indentLength);
402
+ return this.tokenizeComment();
403
+ }
404
+ const currentIndent = this.indentStack[this.indentStack.length - 1];
405
+ if (this.onTemplateLine && indentLength > this.templateBaseIndent && currentIndent > this.templateBaseIndent && indentLength !== currentIndent) {
406
+ this.emitIndentation(currentIndent);
407
+ } else {
408
+ this.emitIndentation(indentLength);
409
+ }
410
+ if (this.bracketDepth === 0 && c === CH_DASH) {
411
+ const nc = this.peekCharCode(1);
412
+ const atEOF = this.offset + 1 >= this.source.length;
413
+ if (nc === CH_SPACE || this.atNewline(1) || atEOF) {
414
+ this.emit(TokenKind.DASH_SPACE, nc === CH_SPACE ? "- " : "-");
415
+ }
416
+ }
417
+ while (this.hasMore) {
418
+ const c2 = this.peekCharCode();
419
+ if (this.consumeNewline()) {
420
+ return;
421
+ }
422
+ if (c2 === CH_CR) {
423
+ invariant(!this.atNewline());
424
+ this.advance();
425
+ continue;
426
+ }
427
+ if (isHorizontalWs(c2)) {
428
+ this.advance();
429
+ continue;
430
+ }
431
+ if (c2 === CH_BACKSLASH) {
432
+ if (this.atNewline(1)) {
433
+ this.advance();
434
+ invariant(this.consumeNewline());
435
+ while (isHorizontalWs(this.peekCharCode())) {
436
+ this.advance();
437
+ }
438
+ continue;
439
+ }
440
+ }
441
+ if (c2 === CH_HASH && !this.onTemplateLine) {
442
+ return this.tokenizeComment();
443
+ }
444
+ this.tokenizeToken();
445
+ }
446
+ }
447
+ emitIndentation(indentLength) {
448
+ if (this.bracketDepth > 0)
449
+ return;
450
+ const currentIndent = this.indentStack[this.indentStack.length - 1];
451
+ if (indentLength > currentIndent) {
452
+ this.indentStack.push(indentLength);
453
+ this.emitVirtual(TokenKind.INDENT);
454
+ } else if (indentLength < currentIndent) {
455
+ if (indentLength <= this.templateBaseIndent) {
456
+ this.onTemplateLine = false;
457
+ this.templateExprBraceDepth = -1;
458
+ }
459
+ while (this.indentStack.length > 1 && this.indentStack[this.indentStack.length - 1] > indentLength) {
460
+ this.indentStack.pop();
461
+ this.emitVirtual(TokenKind.DEDENT);
462
+ }
463
+ this.emitVirtual(TokenKind.NEWLINE);
464
+ } else {
465
+ if (indentLength <= this.templateBaseIndent) {
466
+ this.onTemplateLine = false;
467
+ this.templateExprBraceDepth = -1;
468
+ }
469
+ if (this.tokens.length > 0) {
470
+ this.emitVirtual(TokenKind.NEWLINE);
471
+ }
472
+ }
473
+ }
474
+ tokenizeToken() {
475
+ const c = this.peekCharCode();
476
+ if (isDigit(c)) {
477
+ if (this.tryDatetime()) {
478
+ return;
479
+ }
480
+ this.tokenizeNumber();
481
+ return;
482
+ }
483
+ if (isIdStart(c)) {
484
+ this.tokenizeId();
485
+ return;
486
+ }
487
+ if (!this.onTemplateLine || this.inTemplateExpr) {
488
+ if (c === CH_DQUOTE) {
489
+ this.tokenizeString();
490
+ return;
491
+ }
492
+ }
493
+ if (c === CH_LBRACE && this.peekCharCode(1) === CH_BANG) {
494
+ this.templateExprBraceDepth = 0;
495
+ this.emit(TokenKind.TEMPLATE_EXPR_START, "{!");
496
+ return;
497
+ }
498
+ if (c === CH_DOT) {
499
+ if (this.peekCharCode(1) === CH_DOT && this.peekCharCode(2) === CH_DOT) {
500
+ this.emit(TokenKind.ELLIPSIS, "...");
501
+ return;
502
+ }
503
+ if (isDigit(this.peekCharCode(1))) {
504
+ const prev = this.tokens[this.tokens.length - 1];
505
+ const isMemberAccess = prev !== void 0 && (prev.kind === TokenKind.ID || prev.kind === TokenKind.NUMBER || prev.kind === TokenKind.RPAREN || prev.kind === TokenKind.RBRACKET);
506
+ if (!isMemberAccess) {
507
+ this.tokenizeNumber();
508
+ return;
509
+ }
510
+ }
511
+ }
512
+ if (c === CH_DASH) {
513
+ if (this.peekCharCode(1) === CH_GT) {
514
+ return this.emit(TokenKind.ARROW, "->");
515
+ }
516
+ }
517
+ const nc = this.peekCharCode(1);
518
+ if (nc === CH_EQ) {
519
+ if (c === CH_EQ) {
520
+ return this.emit(TokenKind.EQEQ, "==");
521
+ }
522
+ if (c === CH_BANG) {
523
+ return this.emit(TokenKind.NEQ, "!=");
524
+ }
525
+ if (c === CH_LT) {
526
+ return this.emit(TokenKind.LTE, "<=");
527
+ }
528
+ if (c === CH_GT) {
529
+ return this.emit(TokenKind.GTE, ">=");
530
+ }
531
+ }
532
+ const kind = c < 128 ? SINGLE_CHAR_TOKENS[c] : 0;
533
+ if (kind) {
534
+ this.emitSpan(kind, 1);
535
+ switch (kind) {
536
+ // Track template lines: `|` starts a template context for this line
537
+ // and continuation lines indented deeper than this level.
538
+ case TokenKind.PIPE:
539
+ this.onTemplateLine = true;
540
+ this.templateBaseIndent = this.indentStack[this.indentStack.length - 1];
541
+ break;
542
+ // Track parenthesis depth to suppress structural tokens inside
543
+ // multi-line call expressions. Skip when inside a template line —
544
+ // parens in template content are literal text and must not suppress
545
+ // INDENT/DEDENT emission (unmatched parens would eat the rest of
546
+ // the file).
547
+ case TokenKind.LPAREN:
548
+ if (!this.onTemplateLine)
549
+ this.bracketDepth++;
550
+ break;
551
+ case TokenKind.RPAREN:
552
+ if (!this.onTemplateLine)
553
+ this.bracketDepth--;
554
+ break;
555
+ // Track brace depth inside {!...} template expressions so that nested
556
+ // braces (e.g. JSON objects) don't prematurely close the expression.
557
+ case TokenKind.LBRACE:
558
+ if (this.inTemplateExpr) {
559
+ this.templateExprBraceDepth++;
560
+ }
561
+ break;
562
+ case TokenKind.RBRACE:
563
+ if (this.inTemplateExpr) {
564
+ this.templateExprBraceDepth--;
565
+ }
566
+ break;
567
+ }
568
+ return;
569
+ }
570
+ this.emitSpan(TokenKind.ERROR_TOKEN, 1);
571
+ }
572
+ tokenizeId() {
573
+ let i = 0;
574
+ for (; ; i++) {
575
+ const c = this.peekCharCode(i);
576
+ if (!isIdCont(c))
577
+ break;
578
+ }
579
+ this.emitSpan(TokenKind.ID, i);
580
+ }
581
+ tokenizeNumber() {
582
+ let tokenLength = 0;
583
+ const leadingDot = this.peekCharCode(tokenLength) === CH_DOT;
584
+ if (leadingDot) {
585
+ tokenLength++;
586
+ }
587
+ while (isDigit(this.peekCharCode(tokenLength))) {
588
+ tokenLength++;
589
+ }
590
+ if (!leadingDot && this.peekCharCode(tokenLength) === CH_DOT) {
591
+ tokenLength++;
592
+ }
593
+ while (isDigit(this.peekCharCode(tokenLength))) {
594
+ tokenLength++;
595
+ }
596
+ this.emitSpan(TokenKind.NUMBER, tokenLength);
597
+ }
598
+ tryDatetime() {
599
+ const remaining = this.source.length - this.offset;
600
+ if (remaining < 10)
601
+ return false;
602
+ if (this.source.charCodeAt(this.offset + 4) !== CH_DASH || this.source.charCodeAt(this.offset + 7) !== CH_DASH) {
603
+ return false;
604
+ }
605
+ const slice = this.source.slice(this.offset, this.offset + 30);
606
+ const match = slice.match(/^\d{4}-\d{2}-\d{2}(T\d{1,2}(:\d{2})?(:\d{2})?(\.\d+)?Z?)?/);
607
+ if (!match)
608
+ return false;
609
+ const matchText = match[0];
610
+ if (matchText.length < 10)
611
+ return false;
612
+ this.emit(TokenKind.DATETIME, matchText);
613
+ return true;
614
+ }
615
+ tokenizeString() {
616
+ const start = this.position;
617
+ const startOffset = this.offset;
618
+ const quoteCode = this.peekCharCode();
619
+ this.advance();
620
+ while (this.hasMore) {
621
+ const c = this.peekCharCode();
622
+ if (c === quoteCode) {
623
+ this.advance();
624
+ const text2 = this.source.slice(startOffset, this.offset);
625
+ this.tokens.push(this.makeToken(TokenKind.STRING, text2, start, this.position, startOffset));
626
+ return;
627
+ }
628
+ if (c === CH_BACKSLASH) {
629
+ this.advance(2);
630
+ continue;
631
+ }
632
+ if (this.atNewline()) {
633
+ break;
634
+ }
635
+ if (c === CH_CR) {
636
+ invariant(!this.atNewline());
637
+ this.advance();
638
+ continue;
639
+ }
640
+ if (c === CH_NUL) {
641
+ break;
642
+ }
643
+ this.advance();
644
+ }
645
+ const text = this.source.slice(startOffset, this.offset);
646
+ this.tokens.push(this.makeToken(TokenKind.STRING, text, start, this.position, startOffset));
647
+ }
648
+ tokenizeComment() {
649
+ const start = this.position;
650
+ const startOffset = this.offset;
651
+ while (this.hasMore && !this.atNewline()) {
652
+ this.advance();
653
+ }
654
+ const text = this.source.slice(startOffset, this.offset);
655
+ this.tokens.push(this.makeToken(TokenKind.COMMENT, text, start, this.position, startOffset));
656
+ this.consumeNewline();
657
+ }
658
+ consumeIndentation() {
659
+ let indentLength = 0;
660
+ while (this.hasMore) {
661
+ const c = this.peekCharCode();
662
+ if (c === CH_SPACE) {
663
+ indentLength += 1;
664
+ this.advance();
665
+ } else if (c === CH_TAB) {
666
+ indentLength += 3;
667
+ this.advance();
668
+ } else if (c === CH_CR) {
669
+ indentLength = 0;
670
+ this.advance();
671
+ } else {
672
+ break;
673
+ }
674
+ }
675
+ return indentLength;
676
+ }
677
+ /**
678
+ * Scan ahead (without advancing) past comment/blank lines to find the indent
679
+ * of the next line with real (non-comment) content. Returns -1 if only
680
+ * comments, blanks, or EOF remain. Matches tree-sitter scanner behavior which
681
+ * skips past comment-only lines when computing INDENT/DEDENT.
682
+ */
683
+ peekNextContentIndent() {
684
+ const startPosition = this.position;
685
+ const startOffset = this.offset;
686
+ while (this.hasMore) {
687
+ if (this.consumeNewline())
688
+ break;
689
+ this.advance();
690
+ }
691
+ while (this.hasMore) {
692
+ const lineIndent = this.consumeIndentation();
693
+ if (this.consumeNewline())
694
+ continue;
695
+ const c = this.peekCharCode();
696
+ if (c === CH_HASH) {
697
+ while (this.hasMore) {
698
+ if (this.consumeNewline())
699
+ break;
700
+ this.advance();
701
+ }
702
+ continue;
703
+ }
704
+ this.offset = startOffset;
705
+ this.row = startPosition.row;
706
+ this.col = startPosition.column;
707
+ return lineIndent;
708
+ }
709
+ this.offset = startOffset;
710
+ this.row = startPosition.row;
711
+ this.col = startPosition.column;
712
+ return -1;
713
+ }
714
+ // --- Utility methods ---
715
+ peekCharCode(additiveOffset = 0) {
716
+ return this.source.charCodeAt(this.offset + additiveOffset);
717
+ }
718
+ get hasMore() {
719
+ return this.offset < this.source.length && this.offset >= 0;
720
+ }
721
+ /**
722
+ * Attempt to advance n characters.
723
+ * @returns how many characters were advanced.
724
+ */
725
+ advance(n = 1) {
726
+ n = Math.max(0, Math.min(n, this.source.length - this.offset));
727
+ this.col += n;
728
+ for (let i = 0; i < n; i++) {
729
+ if (this.peekCharCode(i) === CH_LF) {
730
+ this.row++;
731
+ this.col = n - i - 1;
732
+ }
733
+ }
734
+ this.offset += n;
735
+ return n;
736
+ }
737
+ /**
738
+ * Attempt to consume a newline.
739
+ * @returns whether a newline was consumed.
740
+ */
741
+ consumeNewline() {
742
+ const newChars = this.atNewline();
743
+ if (newChars > 0) {
744
+ invariant(this.advance(newChars));
745
+ return true;
746
+ }
747
+ return false;
748
+ }
749
+ /**
750
+ * Checks if the current position is at a newline.
751
+ * @param additiveOffset
752
+ * @returns 0 if not at a newline, 1 if at an LF newline, 2 if at a CR LF newline.
753
+ */
754
+ atNewline(additiveOffset = 0) {
755
+ const firstChar = this.peekCharCode(additiveOffset);
756
+ if (firstChar === CH_LF)
757
+ return 1;
758
+ if (firstChar === CH_CR && this.peekCharCode(additiveOffset + 1) === CH_LF)
759
+ return 2;
760
+ return 0;
761
+ }
762
+ get position() {
763
+ return { row: this.row, column: this.col };
764
+ }
765
+ emitSpan(kind, length) {
766
+ const text = this.source.slice(this.offset, this.offset + length);
767
+ return this.emit(kind, text);
768
+ }
769
+ emit(kind, text) {
770
+ const startPosition = this.position;
771
+ const startOffset = this.offset;
772
+ invariant(text === this.source.slice(startOffset, startOffset + text.length), `expected '${text}' but got ${this.source.slice(startOffset, startOffset + text.length)} at offset ${startOffset}`);
773
+ this.advance(text.length);
774
+ this.tokens.push(this.makeToken(kind, text, startPosition, this.position, startOffset));
775
+ }
776
+ emitVirtual(kind) {
777
+ return this.emit(kind, "");
778
+ }
779
+ makeToken(kind, text, start, end, startOffset) {
780
+ return { kind, text, start, end, startOffset };
781
+ }
782
+ };
783
+
784
+ // vendor/agentscript-parser-javascript/dist/errors.js
785
+ function makeErrorNode(source, children, startOffset, endOffset, startPosition, endPosition) {
786
+ const node = new CSTNode("ERROR", source, startOffset, endOffset, startPosition, endPosition, true, true);
787
+ for (const child of children) {
788
+ node.appendChild(child);
789
+ }
790
+ return node;
791
+ }
792
+ function tokenToLeaf(token, source, isNamed, offset) {
793
+ return new CSTNode(tokenTypeToNodeType(token), source, offset, offset + token.text.length, token.start, token.end, isNamed);
794
+ }
795
+ var NAMED_TOKEN_KINDS = /* @__PURE__ */ new Set([
796
+ TokenKind.ID,
797
+ TokenKind.NUMBER,
798
+ TokenKind.STRING,
799
+ TokenKind.DATETIME,
800
+ TokenKind.COMMENT,
801
+ TokenKind.ELLIPSIS
802
+ ]);
803
+ function tokenToAutoLeaf(token, source, offset) {
804
+ return tokenToLeaf(token, source, NAMED_TOKEN_KINDS.has(token.kind), offset);
805
+ }
806
+ function tokenTypeToNodeType(token) {
807
+ switch (token.kind) {
808
+ case TokenKind.ID:
809
+ return "id";
810
+ case TokenKind.NUMBER:
811
+ return "number";
812
+ case TokenKind.STRING:
813
+ return "string";
814
+ case TokenKind.DATETIME:
815
+ return "datetime_literal";
816
+ case TokenKind.COMMENT:
817
+ return "comment";
818
+ case TokenKind.ELLIPSIS:
819
+ return "ellipsis";
820
+ default:
821
+ return token.text;
822
+ }
823
+ }
824
+ function isSyncPoint(kind) {
825
+ return kind === TokenKind.NEWLINE || kind === TokenKind.DEDENT || kind === TokenKind.EOF;
826
+ }
827
+
828
+ // vendor/agentscript-parser-javascript/dist/recovery.js
829
+ function makeEmptyError(ctx) {
830
+ const offset = ctx.peekOffset();
831
+ const pos = ctx.peek().start;
832
+ return new CSTNode("ERROR", ctx.source, offset, offset, pos, pos, true, true);
833
+ }
834
+ function addMissingTarget(ctx, node) {
835
+ const errAtom = makeEmptyError(ctx);
836
+ const atom = new CSTNode("atom", ctx.source, errAtom.startOffset, errAtom.endOffset, errAtom.startPosition, errAtom.endPosition);
837
+ atom.appendChild(errAtom);
838
+ const expr = new CSTNode("expression", ctx.source, atom.startOffset, atom.endOffset, atom.startPosition, atom.endPosition);
839
+ expr.appendChild(atom);
840
+ node.appendChild(expr, "target");
841
+ }
842
+ function makeMissing(ctx, type) {
843
+ const offset = ctx.peekOffset();
844
+ const pos = ctx.peek().start;
845
+ return new CSTNode(type, ctx.source, offset, offset, pos, pos, true, false, true);
846
+ }
847
+ function parseOrphanBlock(ctx, parseProcedure2) {
848
+ const startOffset = ctx.peekOffset();
849
+ const startPos = ctx.peek().start;
850
+ const children = [];
851
+ const keywordTok = ctx.consume();
852
+ const kwOffset = ctx.currentOffset();
853
+ children.push(new CSTNode(keywordTok.text, ctx.source, kwOffset, kwOffset + keywordTok.text.length, keywordTok.start, keywordTok.end, false));
854
+ while (!ctx.isAtSyncPoint() && !isAtEnd(ctx) && ctx.peekKind() !== TokenKind.COLON) {
855
+ ctx.consume();
856
+ }
857
+ if (ctx.peekKind() === TokenKind.COLON)
858
+ ctx.consume();
859
+ if (ctx.peekKind() === TokenKind.INDENT) {
860
+ ctx.consume();
861
+ const proc = parseProcedure2(ctx);
862
+ if (proc) {
863
+ for (const child of proc.namedChildren) {
864
+ children.push(child);
865
+ }
866
+ }
867
+ while (ctx.peekKind() === TokenKind.COMMENT || ctx.peekKind() === TokenKind.NEWLINE) {
868
+ if (ctx.peekKind() === TokenKind.COMMENT) {
869
+ children.push(ctx.consumeNamed("comment"));
870
+ } else {
871
+ ctx.consume();
872
+ }
873
+ }
874
+ if (ctx.peekKind() === TokenKind.DEDENT)
875
+ ctx.consume();
876
+ }
877
+ if (ctx.peekKind() === TokenKind.NEWLINE)
878
+ ctx.consume();
879
+ const endOffset = children.length > 0 ? children[children.length - 1].endOffset : ctx.peekOffset();
880
+ const endPos = children.length > 0 ? children[children.length - 1].endPosition : ctx.peek().start;
881
+ return makeErrorNode(ctx.source, children, startOffset, endOffset, startPos, endPos);
882
+ }
883
+ function recoverToBlockEnd(ctx, parent) {
884
+ while (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {
885
+ if (ctx.peekKind() === TokenKind.NEWLINE) {
886
+ ctx.consume();
887
+ continue;
888
+ }
889
+ if (ctx.peekKind() === TokenKind.INDENT) {
890
+ ctx.consume();
891
+ recoverToBlockEnd(ctx, parent);
892
+ if (ctx.peekKind() === TokenKind.DEDENT)
893
+ ctx.consume();
894
+ continue;
895
+ }
896
+ const err = synchronize(ctx);
897
+ if (err) {
898
+ parent.appendChild(err);
899
+ } else {
900
+ break;
901
+ }
902
+ }
903
+ }
904
+ function synchronizeUntil(ctx, extraStop) {
905
+ if (ctx.isAtSyncPoint() || isAtEnd(ctx))
906
+ return null;
907
+ if (extraStop && extraStop(ctx.peekKind(), ctx.peek().start.row))
908
+ return null;
909
+ const startOffset = ctx.peekOffset();
910
+ const startPos = ctx.peek().start;
911
+ const children = [];
912
+ while (!ctx.isAtSyncPoint() && !isAtEnd(ctx) && !(extraStop && extraStop(ctx.peekKind(), ctx.peek().start.row))) {
913
+ const tok = ctx.consume();
914
+ children.push(tokenToAutoLeaf(tok, ctx.source, ctx.currentOffset()));
915
+ }
916
+ if (children.length === 0)
917
+ return null;
918
+ const last = children[children.length - 1];
919
+ return makeErrorNode(ctx.source, children, startOffset, last.endOffset, startPos, last.endPosition);
920
+ }
921
+ function synchronizeRowUntilColon(ctx, row) {
922
+ return synchronizeUntil(ctx, (kind, r) => kind === TokenKind.INDENT || kind === TokenKind.COLON || r !== row);
923
+ }
924
+ function synchronizeRow(ctx, row) {
925
+ return synchronizeUntil(ctx, (kind, r) => kind === TokenKind.INDENT || r !== row);
926
+ }
927
+ function synchronize(ctx) {
928
+ return synchronizeUntil(ctx);
929
+ }
930
+ function skipNewlines(ctx) {
931
+ while (ctx.peekKind() === TokenKind.NEWLINE) {
932
+ ctx.consume();
933
+ }
934
+ }
935
+ function consumeCommentsAndSkipNewlines(ctx, parent) {
936
+ while (true) {
937
+ if (ctx.peekKind() === TokenKind.COMMENT) {
938
+ parent.appendChild(ctx.consumeNamed("comment"));
939
+ } else if (ctx.peekKind() === TokenKind.NEWLINE) {
940
+ ctx.consume();
941
+ } else {
942
+ break;
943
+ }
944
+ }
945
+ }
946
+ function isAtEnd(ctx) {
947
+ return ctx.peekKind() === TokenKind.EOF;
948
+ }
949
+ function isTrailingCommentOnly(ctx) {
950
+ let i = 0;
951
+ while (i < 50) {
952
+ const tok = ctx.peekAt(i);
953
+ if (tok.kind === TokenKind.EOF || tok.kind === TokenKind.DEDENT)
954
+ return true;
955
+ if (tok.kind === TokenKind.COMMENT || tok.kind === TokenKind.NEWLINE) {
956
+ i++;
957
+ continue;
958
+ }
959
+ return false;
960
+ }
961
+ return false;
962
+ }
963
+
964
+ // vendor/agentscript-parser-javascript/dist/expressions.js
965
+ var VALID_ESCAPES = /* @__PURE__ */ new Set(['"', "'", "\\", "n", "r", "t", "0"]);
966
+ var KEY_STOP_KEYWORDS = /* @__PURE__ */ new Set([
967
+ "if",
968
+ "elif",
969
+ "else",
970
+ "run",
971
+ "set",
972
+ "with",
973
+ "to",
974
+ "transition",
975
+ "available",
976
+ "and",
977
+ "or",
978
+ "not",
979
+ "is",
980
+ "True",
981
+ "False",
982
+ "None",
983
+ "mutable",
984
+ "linked",
985
+ "empty"
986
+ ]);
987
+ function makeMissingArgument(ctx) {
988
+ const offset = ctx.peekOffset();
989
+ const pos = ctx.peek().start;
990
+ const missingId = new CSTNode("id", ctx.source, offset, offset, pos, pos, true, false, true);
991
+ const atom = new CSTNode("atom", ctx.source, offset, offset, pos, pos);
992
+ atom.appendChild(missingId);
993
+ const expr = new CSTNode("expression", ctx.source, offset, offset, pos, pos);
994
+ expr.appendChild(atom);
995
+ return expr;
996
+ }
997
+ function makeEmptyError2(ctx) {
998
+ const tok = ctx.peek();
999
+ const offset = ctx.peekOffset();
1000
+ return new CSTNode("ERROR", ctx.source, offset, offset, tok.start, tok.start, true, true);
1001
+ }
1002
+ function parseExpression(ctx, minPrec = 0) {
1003
+ let left = parsePrefix(ctx);
1004
+ if (!left)
1005
+ return null;
1006
+ while (true) {
1007
+ const nextKind = ctx.peekKind();
1008
+ if (nextKind === TokenKind.NEWLINE || nextKind === TokenKind.DEDENT || nextKind === TokenKind.EOF)
1009
+ break;
1010
+ const prec = infixPrecedence(ctx);
1011
+ if (prec < minPrec)
1012
+ break;
1013
+ const result = parseInfix(ctx, left, prec);
1014
+ if (!result)
1015
+ break;
1016
+ left = result;
1017
+ }
1018
+ return left;
1019
+ }
1020
+ function parsePrefix(ctx) {
1021
+ const tok = ctx.peek();
1022
+ if (tok.kind === TokenKind.ID && tok.text === "not") {
1023
+ return parseUnary(ctx, "not", 3);
1024
+ }
1025
+ if (tok.kind === TokenKind.PLUS || tok.kind === TokenKind.MINUS) {
1026
+ const op = tok.text;
1027
+ return parseUnary(ctx, op, 7);
1028
+ }
1029
+ if (tok.kind === TokenKind.STAR) {
1030
+ return parseSpread(ctx);
1031
+ }
1032
+ if (tok.kind === TokenKind.LPAREN) {
1033
+ return parseParenthesized(ctx);
1034
+ }
1035
+ return parseAtom(ctx);
1036
+ }
1037
+ function parseUnary(ctx, _op, prec) {
1038
+ const startTok = ctx.peek();
1039
+ const node = ctx.startNode("unary_expression");
1040
+ ctx.addAnonymousChild(node, ctx.consume());
1041
+ const operand = parseExpression(ctx, prec + 1);
1042
+ if (operand) {
1043
+ node.appendChild(wrapExpression(ctx, operand));
1044
+ }
1045
+ ctx.finishNode(node, startTok);
1046
+ return node;
1047
+ }
1048
+ function parseSpread(ctx) {
1049
+ const startTok = ctx.peek();
1050
+ const node = ctx.startNode("spread_expression");
1051
+ ctx.addAnonymousChild(node, ctx.consume());
1052
+ const operand = parseExpression(ctx, 8);
1053
+ if (operand) {
1054
+ node.appendChild(wrapExpression(ctx, operand), "expression");
1055
+ }
1056
+ ctx.finishNode(node, startTok);
1057
+ return node;
1058
+ }
1059
+ function parseParenthesized(ctx) {
1060
+ const startTok = ctx.peek();
1061
+ const node = ctx.startNode("parenthesized_expression");
1062
+ ctx.addAnonymousChild(node, ctx.consume());
1063
+ const expr = parseExpression(ctx, 0);
1064
+ if (expr) {
1065
+ node.appendChild(wrapExpression(ctx, expr), "expression");
1066
+ } else if (ctx.peekKind() === TokenKind.RPAREN) {
1067
+ node.appendChild(makeMissingArgument(ctx), "expression");
1068
+ }
1069
+ if (ctx.peekKind() === TokenKind.RPAREN) {
1070
+ ctx.addAnonymousChild(node, ctx.consume());
1071
+ } else {
1072
+ node.appendChild(makeEmptyError2(ctx));
1073
+ }
1074
+ ctx.finishNode(node, startTok);
1075
+ return node;
1076
+ }
1077
+ function parseAtom(ctx) {
1078
+ const tok = ctx.peek();
1079
+ if (tok.kind === TokenKind.ID && (tok.text === "True" || tok.text === "False" || tok.text === "None")) {
1080
+ const node = ctx.startNode("atom");
1081
+ ctx.addAnonymousChild(node, ctx.consume());
1082
+ ctx.finishNode(node, tok);
1083
+ return node;
1084
+ }
1085
+ if (tok.kind === TokenKind.ID && tok.text === "empty") {
1086
+ const node = ctx.startNode("empty_keyword");
1087
+ ctx.addAnonymousChild(node, ctx.consume());
1088
+ ctx.finishNode(node, tok);
1089
+ return node;
1090
+ }
1091
+ if (tok.kind === TokenKind.AT) {
1092
+ return parseAtId(ctx);
1093
+ }
1094
+ if (tok.kind === TokenKind.ID) {
1095
+ return ctx.consumeNamed("id");
1096
+ }
1097
+ if (tok.kind === TokenKind.NUMBER) {
1098
+ return ctx.consumeNamed("number");
1099
+ }
1100
+ if (tok.kind === TokenKind.DATETIME) {
1101
+ return ctx.consumeNamed("datetime_literal");
1102
+ }
1103
+ if (tok.kind === TokenKind.STRING) {
1104
+ return parseString(ctx);
1105
+ }
1106
+ if (tok.kind === TokenKind.ELLIPSIS) {
1107
+ return ctx.consumeNamed("ellipsis");
1108
+ }
1109
+ if (tok.kind === TokenKind.LBRACKET) {
1110
+ return parseList(ctx);
1111
+ }
1112
+ if (tok.kind === TokenKind.LBRACE) {
1113
+ return parseDictionary(ctx);
1114
+ }
1115
+ return null;
1116
+ }
1117
+ function parseAtId(ctx) {
1118
+ const startTok = ctx.peek();
1119
+ const node = ctx.startNode("at_id");
1120
+ ctx.addAnonymousChild(node, ctx.consume());
1121
+ if (ctx.peekKind() === TokenKind.ID) {
1122
+ node.appendChild(ctx.consumeNamed("id"));
1123
+ } else {
1124
+ node.appendChild(makeEmptyError2(ctx));
1125
+ }
1126
+ ctx.finishNode(node, startTok);
1127
+ return node;
1128
+ }
1129
+ function parseString(ctx) {
1130
+ const tok = ctx.peek();
1131
+ const startTok = tok;
1132
+ const node = ctx.startNode("string");
1133
+ const text = tok.text;
1134
+ const tokenOffset = ctx.peekOffset();
1135
+ ctx.consume();
1136
+ const baseRow = startTok.start.row;
1137
+ const baseCol = startTok.start.column;
1138
+ node.appendChild(new CSTNode('"', ctx.source, tokenOffset, tokenOffset + 1, { row: baseRow, column: baseCol }, { row: baseRow, column: baseCol + 1 }, false));
1139
+ let i = 1;
1140
+ const quoteChar = text[0];
1141
+ const hasClosingQuote = text.length > 1 && text[text.length - 1] === quoteChar;
1142
+ const contentEnd = hasClosingQuote ? text.length - 1 : text.length;
1143
+ let contentStart = i;
1144
+ while (i < contentEnd) {
1145
+ if (text[i] === "\\" && i + 1 < contentEnd && VALID_ESCAPES.has(text[i + 1])) {
1146
+ if (i > contentStart) {
1147
+ node.appendChild(new CSTNode("string_content", ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));
1148
+ }
1149
+ const escLen = 2;
1150
+ node.appendChild(new CSTNode("escape_sequence", ctx.source, tokenOffset + i, tokenOffset + i + escLen, { row: baseRow, column: baseCol + i }, { row: baseRow, column: baseCol + i + escLen }));
1151
+ i += escLen;
1152
+ contentStart = i;
1153
+ } else if (text[i] === "\\" && i + 1 < contentEnd && !VALID_ESCAPES.has(text[i + 1])) {
1154
+ if (i > contentStart) {
1155
+ node.appendChild(new CSTNode("string_content", ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));
1156
+ }
1157
+ const escStart = i;
1158
+ i += 2;
1159
+ while (i < contentEnd && /[a-zA-Z0-9_]/.test(text[i])) {
1160
+ i++;
1161
+ }
1162
+ const errNode = new CSTNode("ERROR", ctx.source, tokenOffset + escStart, tokenOffset + i, { row: baseRow, column: baseCol + escStart }, { row: baseRow, column: baseCol + i }, true, true);
1163
+ node.appendChild(errNode);
1164
+ contentStart = i;
1165
+ } else {
1166
+ i++;
1167
+ }
1168
+ }
1169
+ if (i > contentStart) {
1170
+ node.appendChild(new CSTNode("string_content", ctx.source, tokenOffset + contentStart, tokenOffset + i, { row: baseRow, column: baseCol + contentStart }, { row: baseRow, column: baseCol + i }));
1171
+ }
1172
+ if (hasClosingQuote) {
1173
+ node.appendChild(new CSTNode(quoteChar, ctx.source, tokenOffset + text.length - 1, tokenOffset + text.length, { row: baseRow, column: baseCol + text.length - 1 }, { row: baseRow, column: baseCol + text.length }, false));
1174
+ } else {
1175
+ const missingOffset = tokenOffset + text.length;
1176
+ const missingPos = { row: baseRow, column: baseCol + text.length };
1177
+ node.appendChild(new CSTNode(quoteChar, ctx.source, missingOffset, missingOffset, missingPos, missingPos, false, false, true));
1178
+ }
1179
+ ctx.finishNode(node, startTok);
1180
+ return node;
1181
+ }
1182
+ function parseList(ctx) {
1183
+ const startTok = ctx.peek();
1184
+ const node = ctx.startNode("list");
1185
+ ctx.addAnonymousChild(node, ctx.consume());
1186
+ let _listIndentDepth = 0;
1187
+ while (ctx.peekKind() !== TokenKind.RBRACKET && ctx.peekKind() !== TokenKind.EOF) {
1188
+ if (ctx.peekKind() === TokenKind.NEWLINE) {
1189
+ ctx.consume();
1190
+ continue;
1191
+ }
1192
+ if (ctx.peekKind() === TokenKind.INDENT) {
1193
+ _listIndentDepth++;
1194
+ ctx.consume();
1195
+ continue;
1196
+ }
1197
+ if (ctx.peekKind() === TokenKind.DEDENT) {
1198
+ _listIndentDepth--;
1199
+ ctx.consume();
1200
+ continue;
1201
+ }
1202
+ const expr = parseExpression(ctx, 0);
1203
+ if (expr) {
1204
+ node.appendChild(wrapExpression(ctx, expr));
1205
+ } else {
1206
+ break;
1207
+ }
1208
+ if (ctx.peekKind() === TokenKind.COMMA) {
1209
+ ctx.addAnonymousChild(node, ctx.consume());
1210
+ } else {
1211
+ break;
1212
+ }
1213
+ }
1214
+ while (ctx.peekKind() === TokenKind.NEWLINE || ctx.peekKind() === TokenKind.INDENT || ctx.peekKind() === TokenKind.DEDENT) {
1215
+ ctx.consume();
1216
+ }
1217
+ if (ctx.peekKind() === TokenKind.RBRACKET) {
1218
+ ctx.addAnonymousChild(node, ctx.consume());
1219
+ } else {
1220
+ node.appendChild(makeEmptyError2(ctx));
1221
+ }
1222
+ ctx.finishNode(node, startTok);
1223
+ return node;
1224
+ }
1225
+ function parseDictionary(ctx) {
1226
+ const startTok = ctx.peek();
1227
+ const node = ctx.startNode("dictionary");
1228
+ ctx.addAnonymousChild(node, ctx.consume());
1229
+ while (ctx.peekKind() !== TokenKind.RBRACE && ctx.peekKind() !== TokenKind.EOF) {
1230
+ if (ctx.peekKind() === TokenKind.NEWLINE || ctx.peekKind() === TokenKind.INDENT || ctx.peekKind() === TokenKind.DEDENT) {
1231
+ ctx.consume();
1232
+ continue;
1233
+ }
1234
+ const pair = parseDictionaryPair(ctx);
1235
+ if (pair) {
1236
+ node.appendChild(pair);
1237
+ } else {
1238
+ break;
1239
+ }
1240
+ if (ctx.peekKind() === TokenKind.COMMA) {
1241
+ ctx.addAnonymousChild(node, ctx.consume());
1242
+ } else {
1243
+ break;
1244
+ }
1245
+ }
1246
+ if (ctx.peekKind() === TokenKind.RBRACE) {
1247
+ ctx.addAnonymousChild(node, ctx.consume());
1248
+ } else {
1249
+ node.appendChild(makeEmptyError2(ctx));
1250
+ }
1251
+ ctx.finishNode(node, startTok);
1252
+ return node;
1253
+ }
1254
+ function parseDictionaryPair(ctx) {
1255
+ const startTok = ctx.peek();
1256
+ if (!isKeyStart(ctx))
1257
+ return null;
1258
+ const node = ctx.startNode("dictionary_pair");
1259
+ const key = parseKey(ctx);
1260
+ if (key)
1261
+ node.appendChild(key, "key");
1262
+ if (ctx.peekKind() === TokenKind.COLON) {
1263
+ ctx.addAnonymousChild(node, ctx.consume());
1264
+ }
1265
+ const value = parseExpression(ctx, 0);
1266
+ if (value)
1267
+ node.appendChild(wrapExpression(ctx, value), "value");
1268
+ ctx.finishNode(node, startTok);
1269
+ return node;
1270
+ }
1271
+ var INFIX_PREC_BY_KIND = /* @__PURE__ */ new Map([
1272
+ [TokenKind.LPAREN, 8],
1273
+ [TokenKind.DOT, 8],
1274
+ [TokenKind.LBRACKET, 8],
1275
+ [TokenKind.EQEQ, 4],
1276
+ [TokenKind.NEQ, 4],
1277
+ [TokenKind.LT, 4],
1278
+ [TokenKind.GT, 4],
1279
+ [TokenKind.LTE, 4],
1280
+ [TokenKind.GTE, 4],
1281
+ [TokenKind.PLUS, 5],
1282
+ [TokenKind.MINUS, 5],
1283
+ [TokenKind.STAR, 6],
1284
+ [TokenKind.SLASH, 6]
1285
+ ]);
1286
+ var INFIX_KEYWORD_PREC = /* @__PURE__ */ new Map([
1287
+ ["if", 0],
1288
+ ["or", 1],
1289
+ ["and", 2],
1290
+ ["is", 4]
1291
+ ]);
1292
+ function infixPrecedence(ctx) {
1293
+ const tok = ctx.peek();
1294
+ if (tok.kind === TokenKind.ID)
1295
+ return INFIX_KEYWORD_PREC.get(tok.text) ?? -2;
1296
+ return INFIX_PREC_BY_KIND.get(tok.kind) ?? -2;
1297
+ }
1298
+ function parseInfix(ctx, left, prec) {
1299
+ const tok = ctx.peek();
1300
+ if (tok.kind === TokenKind.LPAREN && prec === 8) {
1301
+ return parseCall(ctx, left);
1302
+ }
1303
+ if (tok.kind === TokenKind.DOT && prec === 8) {
1304
+ return parseMember(ctx, left);
1305
+ }
1306
+ if (tok.kind === TokenKind.LBRACKET && prec === 8) {
1307
+ return parseSubscript(ctx, left);
1308
+ }
1309
+ if (tok.kind === TokenKind.ID && tok.text === "if") {
1310
+ return parseTernary(ctx, left);
1311
+ }
1312
+ if (tok.kind === TokenKind.ID && tok.text === "is") {
1313
+ return parseIsExpression(ctx, left);
1314
+ }
1315
+ return parseBinaryOrComparison(ctx, left, prec);
1316
+ }
1317
+ function parseCall(ctx, func) {
1318
+ const startTok = ctx.peek();
1319
+ const node = ctx.startNodeAt("call_expression", func);
1320
+ node.appendChild(wrapExpression(ctx, func), "function");
1321
+ ctx.addAnonymousChild(node, ctx.consume());
1322
+ while (ctx.peekKind() !== TokenKind.RPAREN && !ctx.isAtSyncPoint()) {
1323
+ const arg = parseExpression(ctx, 0);
1324
+ if (arg) {
1325
+ node.appendChild(wrapExpression(ctx, arg), "argument");
1326
+ } else {
1327
+ break;
1328
+ }
1329
+ if (ctx.peekKind() === TokenKind.COMMA) {
1330
+ ctx.addAnonymousChild(node, ctx.consume());
1331
+ if (ctx.peekKind() === TokenKind.RPAREN) {
1332
+ node.appendChild(makeMissingArgument(ctx), "argument");
1333
+ break;
1334
+ }
1335
+ } else {
1336
+ break;
1337
+ }
1338
+ }
1339
+ if (ctx.peekKind() === TokenKind.RPAREN) {
1340
+ ctx.addAnonymousChild(node, ctx.consume());
1341
+ } else {
1342
+ node.appendChild(makeEmptyError2(ctx));
1343
+ }
1344
+ ctx.finishNode(node, startTok);
1345
+ return node;
1346
+ }
1347
+ function parseMember(ctx, object) {
1348
+ const startTok = ctx.peek();
1349
+ const node = ctx.startNodeAt("member_expression", object);
1350
+ node.appendChild(wrapExpression(ctx, object));
1351
+ ctx.addAnonymousChild(node, ctx.consume());
1352
+ if (ctx.peekKind() === TokenKind.ID) {
1353
+ node.appendChild(ctx.consumeNamed("id"));
1354
+ } else if (ctx.peekKind() === TokenKind.NUMBER) {
1355
+ const numNode = ctx.consumeNamed("number");
1356
+ const errNode = new CSTNode("ERROR", ctx.source, numNode.startOffset, numNode.endOffset, numNode.startPosition, numNode.endPosition, true, true);
1357
+ errNode.appendChild(numNode);
1358
+ node.appendChild(errNode);
1359
+ } else {
1360
+ node.appendChild(makeEmptyError2(ctx));
1361
+ }
1362
+ ctx.finishNode(node, startTok);
1363
+ return node;
1364
+ }
1365
+ function parseSubscript(ctx, object) {
1366
+ const startTok = ctx.peek();
1367
+ const node = ctx.startNodeAt("subscript_expression", object);
1368
+ node.appendChild(wrapExpression(ctx, object));
1369
+ ctx.addAnonymousChild(node, ctx.consume());
1370
+ const index = parseExpression(ctx, 0);
1371
+ if (index) {
1372
+ node.appendChild(wrapExpression(ctx, index));
1373
+ }
1374
+ if (ctx.peekKind() === TokenKind.RBRACKET) {
1375
+ ctx.addAnonymousChild(node, ctx.consume());
1376
+ } else {
1377
+ node.appendChild(makeEmptyError2(ctx));
1378
+ }
1379
+ ctx.finishNode(node, startTok);
1380
+ return node;
1381
+ }
1382
+ function parseTernary(ctx, consequence) {
1383
+ const startTok = ctx.peek();
1384
+ const node = ctx.startNodeAt("ternary_expression", consequence);
1385
+ node.appendChild(wrapExpression(ctx, consequence), "consequence");
1386
+ ctx.addAnonymousChild(node, ctx.consume());
1387
+ const condition = parseExpression(ctx, 1);
1388
+ if (condition) {
1389
+ node.appendChild(wrapExpression(ctx, condition), "condition");
1390
+ }
1391
+ if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === "else") {
1392
+ ctx.addAnonymousChild(node, ctx.consume());
1393
+ const alt = parseExpression(ctx, 0);
1394
+ if (alt) {
1395
+ node.appendChild(wrapExpression(ctx, alt), "alternative");
1396
+ }
1397
+ } else {
1398
+ node.appendChild(makeEmptyError2(ctx));
1399
+ }
1400
+ ctx.finishNode(node, startTok);
1401
+ return node;
1402
+ }
1403
+ function parseIsExpression(ctx, left) {
1404
+ const startTok = ctx.peek();
1405
+ const isNot = ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === "not";
1406
+ const nodeType = "comparison_expression";
1407
+ const node = ctx.startNodeAt(nodeType, left);
1408
+ node.appendChild(wrapExpression(ctx, left));
1409
+ ctx.addAnonymousChild(node, ctx.consume());
1410
+ if (isNot) {
1411
+ ctx.addAnonymousChild(node, ctx.consume());
1412
+ }
1413
+ const right = parseExpression(ctx, 5);
1414
+ if (right) {
1415
+ node.appendChild(wrapExpression(ctx, right));
1416
+ }
1417
+ ctx.finishNode(node, startTok);
1418
+ return node;
1419
+ }
1420
+ function parseBinaryOrComparison(ctx, left, prec) {
1421
+ const tok = ctx.peek();
1422
+ const startTok = tok;
1423
+ const isComparison = tok.kind === TokenKind.EQEQ || tok.kind === TokenKind.NEQ || tok.kind === TokenKind.LT || tok.kind === TokenKind.GT || tok.kind === TokenKind.LTE || tok.kind === TokenKind.GTE || tok.kind === TokenKind.EQ;
1424
+ const nodeType = isComparison ? "comparison_expression" : "binary_expression";
1425
+ const node = ctx.startNodeAt(nodeType, left);
1426
+ node.appendChild(wrapExpression(ctx, left));
1427
+ ctx.addAnonymousChild(node, ctx.consume());
1428
+ const right = parseExpression(ctx, prec + 1);
1429
+ if (right) {
1430
+ node.appendChild(wrapExpression(ctx, right));
1431
+ } else {
1432
+ node.appendChild(makeEmptyError2(ctx));
1433
+ }
1434
+ ctx.finishNode(node, startTok);
1435
+ return node;
1436
+ }
1437
+ var SKIP_WRAP_TYPES = /* @__PURE__ */ new Set(["expression", "ERROR"]);
1438
+ var ATOM_TYPES = /* @__PURE__ */ new Set([
1439
+ "id",
1440
+ "number",
1441
+ "string",
1442
+ "datetime_literal",
1443
+ "at_id",
1444
+ "list",
1445
+ "dictionary",
1446
+ "ellipsis"
1447
+ ]);
1448
+ function wrapExpression(ctx, inner) {
1449
+ if (SKIP_WRAP_TYPES.has(inner.type)) {
1450
+ return inner;
1451
+ }
1452
+ let wrapped = inner;
1453
+ if (ATOM_TYPES.has(inner.type)) {
1454
+ const atom = new CSTNode("atom", ctx.source, inner.startOffset, inner.endOffset, inner.startPosition, inner.endPosition);
1455
+ atom.appendChild(inner);
1456
+ wrapped = atom;
1457
+ }
1458
+ const expr = new CSTNode("expression", ctx.source, wrapped.startOffset, wrapped.endOffset, wrapped.startPosition, wrapped.endPosition);
1459
+ expr.appendChild(wrapped);
1460
+ return expr;
1461
+ }
1462
+ function isKeyStart(ctx) {
1463
+ const tok = ctx.peek();
1464
+ return isKeyTokenStart(tok.kind);
1465
+ }
1466
+ function isKeyTokenStart(kind) {
1467
+ return kind === TokenKind.ID || kind === TokenKind.STRING || kind === TokenKind.NUMBER;
1468
+ }
1469
+ function isKeyTokenContinuation(kind) {
1470
+ return isKeyTokenStart(kind) || kind === TokenKind.MINUS || kind === TokenKind.DOT;
1471
+ }
1472
+ function parseKey(ctx) {
1473
+ if (!isKeyStart(ctx))
1474
+ return null;
1475
+ const startTok = ctx.peek();
1476
+ const node = ctx.startNode("key");
1477
+ if (ctx.peekKind() === TokenKind.NUMBER) {
1478
+ const numNode = ctx.consumeNamed("number");
1479
+ const errNode = new CSTNode("ERROR", ctx.source, numNode.startOffset, numNode.endOffset, numNode.startPosition, numNode.endPosition, true, true);
1480
+ node.appendChild(errNode);
1481
+ if (ctx.peekKind() === TokenKind.ID) {
1482
+ node.appendChild(ctx.consumeNamed("id"));
1483
+ }
1484
+ } else if (ctx.peekKind() === TokenKind.STRING) {
1485
+ node.appendChild(parseString(ctx));
1486
+ } else {
1487
+ node.appendChild(ctx.consumeNamed("id"));
1488
+ }
1489
+ if (ctx.peekKind() === TokenKind.ID && !ctx.isAtSyncPoint() && ctx.peek().start.row === startTok.start.row) {
1490
+ const nextText = ctx.peek().text;
1491
+ if (!KEY_STOP_KEYWORDS.has(nextText)) {
1492
+ node.appendChild(ctx.consumeNamed("id"));
1493
+ }
1494
+ }
1495
+ ctx.finishNode(node, startTok);
1496
+ return node;
1497
+ }
1498
+
1499
+ // vendor/agentscript-parser-javascript/dist/parse-statements.js
1500
+ function isStatementStart(ctx) {
1501
+ const tok = ctx.peek();
1502
+ if (tok.kind !== TokenKind.ID)
1503
+ return false;
1504
+ switch (tok.text) {
1505
+ case "if":
1506
+ case "run":
1507
+ case "set":
1508
+ case "transition":
1509
+ return true;
1510
+ case "with":
1511
+ return ctx.peekAt(1).kind !== TokenKind.COLON;
1512
+ case "available":
1513
+ return ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === "when";
1514
+ default:
1515
+ return false;
1516
+ }
1517
+ }
1518
+ function parseProcedure(ctx, parseTemplate2) {
1519
+ const startTok = ctx.peek();
1520
+ const node = ctx.startNode("procedure");
1521
+ while (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {
1522
+ skipNewlines(ctx);
1523
+ if (isAtEnd(ctx) || ctx.peekKind() === TokenKind.DEDENT)
1524
+ break;
1525
+ if (ctx.peekKind() === TokenKind.COMMENT && isTrailingCommentOnly(ctx)) {
1526
+ break;
1527
+ }
1528
+ const stmt = parseStatement(ctx, parseTemplate2);
1529
+ if (stmt) {
1530
+ node.appendChild(stmt);
1531
+ } else {
1532
+ const err = synchronize(ctx);
1533
+ if (err) {
1534
+ node.appendChild(err);
1535
+ } else if (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {
1536
+ ctx.consume();
1537
+ }
1538
+ }
1539
+ }
1540
+ if (node.namedChildren.length === 0) {
1541
+ node.appendChild(makeEmptyError(ctx));
1542
+ }
1543
+ ctx.finishNode(node, startTok);
1544
+ return node;
1545
+ }
1546
+ function parseStatement(ctx, parseTemplate2) {
1547
+ const tok = ctx.peek();
1548
+ if (tok.kind === TokenKind.ID) {
1549
+ switch (tok.text) {
1550
+ case "if":
1551
+ return parseIfStatement(ctx, parseTemplate2);
1552
+ case "run":
1553
+ return parseRunStatement(ctx, parseTemplate2);
1554
+ case "set":
1555
+ return parseSetStatement(ctx);
1556
+ case "transition":
1557
+ return parseTransitionStatement(ctx);
1558
+ case "with":
1559
+ return parseWithStatement(ctx);
1560
+ case "available": {
1561
+ if (ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === "when") {
1562
+ return parseAvailableWhenStatement(ctx);
1563
+ }
1564
+ break;
1565
+ }
1566
+ case "else":
1567
+ case "elif":
1568
+ case "for":
1569
+ return parseOrphanBlock(ctx, (c) => parseProcedure(c, parseTemplate2));
1570
+ }
1571
+ }
1572
+ if (tok.kind === TokenKind.PIPE && parseTemplate2) {
1573
+ return parseTemplate2(ctx);
1574
+ }
1575
+ if (tok.kind === TokenKind.COMMENT) {
1576
+ const comment = ctx.consumeNamed("comment");
1577
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1578
+ ctx.consume();
1579
+ return comment;
1580
+ }
1581
+ const expr = parseExpression(ctx, 0);
1582
+ if (expr) {
1583
+ const wrapped = wrapExpression(ctx, expr);
1584
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1585
+ ctx.consume();
1586
+ return wrapped;
1587
+ }
1588
+ return null;
1589
+ }
1590
+ function parseColonAndProcedureBody(ctx, node, row, errorOnMissingBody, parseTemplate2) {
1591
+ if (ctx.peekKind() === TokenKind.COLON) {
1592
+ ctx.addAnonymousChild(node, ctx.consume());
1593
+ } else if (errorOnMissingBody) {
1594
+ node.appendChild(makeEmptyError(ctx));
1595
+ }
1596
+ if (ctx.peekKind() === TokenKind.COMMENT) {
1597
+ node.appendChild(ctx.consumeNamed("comment"));
1598
+ }
1599
+ const inlineErr = synchronizeRow(ctx, row);
1600
+ if (inlineErr)
1601
+ node.appendChild(inlineErr);
1602
+ if (ctx.peekKind() === TokenKind.INDENT) {
1603
+ ctx.consume();
1604
+ const proc = parseProcedure(ctx, parseTemplate2);
1605
+ if (proc)
1606
+ node.appendChild(proc, "consequence");
1607
+ consumeCommentsAndSkipNewlines(ctx, node);
1608
+ if (ctx.peekKind() === TokenKind.DEDENT)
1609
+ ctx.consume();
1610
+ } else if (errorOnMissingBody && (ctx.peekKind() === TokenKind.NEWLINE || ctx.isAtSyncPoint())) {
1611
+ node.appendChild(makeEmptyError(ctx));
1612
+ }
1613
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1614
+ ctx.consume();
1615
+ }
1616
+ function parseIfStatement(ctx, parseTemplate2) {
1617
+ const startTok = ctx.peek();
1618
+ const node = ctx.startNode("if_statement");
1619
+ ctx.addAnonymousChild(node, ctx.consume());
1620
+ let condition = parseExpression(ctx, 0);
1621
+ if (condition && ctx.peekKind() === TokenKind.EQ) {
1622
+ const eqTok = ctx.consume();
1623
+ const right = parseExpression(ctx, 5);
1624
+ if (right) {
1625
+ const cmp = ctx.startNodeAt("comparison_expression", condition);
1626
+ cmp.appendChild(wrapExpression(ctx, condition));
1627
+ const eqChild = new CSTNode("=", ctx.source, eqTok.startOffset, eqTok.startOffset + 1, eqTok.start, eqTok.end, false);
1628
+ const eqErr = makeErrorNode(ctx.source, [eqChild], eqTok.startOffset, eqTok.startOffset + 1, eqTok.start, eqTok.end);
1629
+ cmp.appendChild(eqErr);
1630
+ cmp.appendChild(wrapExpression(ctx, right));
1631
+ cmp.finalize();
1632
+ condition = cmp;
1633
+ }
1634
+ }
1635
+ if (condition)
1636
+ node.appendChild(wrapExpression(ctx, condition), "condition");
1637
+ if (condition && ctx.peekKind() !== TokenKind.COLON && !ctx.isAtSyncPoint() && ctx.peekKind() !== TokenKind.INDENT) {
1638
+ const condRow = startTok.start.row;
1639
+ const err = synchronizeRowUntilColon(ctx, condRow);
1640
+ if (err)
1641
+ node.appendChild(err);
1642
+ }
1643
+ parseColonAndProcedureBody(ctx, node, startTok.start.row, true, parseTemplate2);
1644
+ while (ctx.peekKind() === TokenKind.ID && (ctx.peek().text === "elif" || ctx.peek().text === "elseif")) {
1645
+ const elif = parseElifClause(ctx, parseTemplate2);
1646
+ if (elif)
1647
+ node.appendChild(elif, "alternative");
1648
+ }
1649
+ if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === "else") {
1650
+ const elseClause = parseElseClause(ctx, parseTemplate2);
1651
+ if (elseClause)
1652
+ node.appendChild(elseClause, "alternative");
1653
+ }
1654
+ ctx.finishNode(node, startTok);
1655
+ return node;
1656
+ }
1657
+ function parseElifClause(ctx, parseTemplate2) {
1658
+ const startTok = ctx.peek();
1659
+ const node = ctx.startNode("elif_clause");
1660
+ const kw = ctx.consume();
1661
+ if (kw.text === "elseif") {
1662
+ const kwEnd = kw.startOffset + kw.text.length;
1663
+ const leaf = tokenToAutoLeaf(kw, ctx.source, kw.startOffset);
1664
+ const errNode = makeErrorNode(ctx.source, [leaf], kw.startOffset, kwEnd, kw.start, kw.end);
1665
+ node.appendChild(errNode);
1666
+ } else {
1667
+ ctx.addAnonymousChild(node, kw);
1668
+ }
1669
+ const condition = parseExpression(ctx, 0);
1670
+ if (condition)
1671
+ node.appendChild(wrapExpression(ctx, condition), "condition");
1672
+ if (condition && ctx.peekKind() !== TokenKind.COLON && !ctx.isAtSyncPoint() && ctx.peekKind() !== TokenKind.INDENT) {
1673
+ const condRow = startTok.start.row;
1674
+ const err = synchronizeRowUntilColon(ctx, condRow);
1675
+ if (err)
1676
+ node.appendChild(err);
1677
+ }
1678
+ parseColonAndProcedureBody(ctx, node, startTok.start.row, false, parseTemplate2);
1679
+ ctx.finishNode(node, startTok);
1680
+ return node;
1681
+ }
1682
+ function parseElseClause(ctx, parseTemplate2) {
1683
+ const startTok = ctx.peek();
1684
+ const node = ctx.startNode("else_clause");
1685
+ ctx.addAnonymousChild(node, ctx.consume());
1686
+ parseColonAndProcedureBody(ctx, node, startTok.start.row, false, parseTemplate2);
1687
+ ctx.finishNode(node, startTok);
1688
+ return node;
1689
+ }
1690
+ function parseRunStatement(ctx, parseTemplate2) {
1691
+ const startTok = ctx.peek();
1692
+ const node = ctx.startNode("run_statement");
1693
+ ctx.addAnonymousChild(node, ctx.consume());
1694
+ if (!ctx.isAtSyncPoint()) {
1695
+ const target = parseExpression(ctx, 0);
1696
+ if (target) {
1697
+ node.appendChild(wrapExpression(ctx, target), "target");
1698
+ } else {
1699
+ addMissingTarget(ctx, node);
1700
+ }
1701
+ } else {
1702
+ addMissingTarget(ctx, node);
1703
+ }
1704
+ if (ctx.peekKind() === TokenKind.INDENT) {
1705
+ ctx.consume();
1706
+ consumeCommentsAndSkipNewlines(ctx, node);
1707
+ const proc = parseProcedure(ctx, parseTemplate2);
1708
+ if (proc) {
1709
+ const hasWithError = proc.namedChildren.some((c) => c.isError && c.children.some((cc) => cc.type === "with"));
1710
+ if (hasWithError) {
1711
+ for (const child of proc.namedChildren) {
1712
+ node.appendChild(child);
1713
+ }
1714
+ } else {
1715
+ node.appendChild(proc, "block_value");
1716
+ }
1717
+ }
1718
+ consumeCommentsAndSkipNewlines(ctx, node);
1719
+ if (ctx.peekKind() === TokenKind.DEDENT)
1720
+ ctx.consume();
1721
+ }
1722
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1723
+ ctx.consume();
1724
+ ctx.finishNode(node, startTok);
1725
+ return node;
1726
+ }
1727
+ function parseSetStatement(ctx) {
1728
+ const startTok = ctx.peek();
1729
+ const node = ctx.startNode("set_statement");
1730
+ ctx.addAnonymousChild(node, ctx.consume());
1731
+ const target = parseExpression(ctx, 5);
1732
+ if (ctx.peekKind() === TokenKind.EQEQ) {
1733
+ const eqTok = ctx.consume();
1734
+ const rhs = parseExpression(ctx, 0);
1735
+ if (target && rhs) {
1736
+ const cmp = ctx.startNodeAt("comparison_expression", wrapExpression(ctx, target));
1737
+ cmp.appendChild(wrapExpression(ctx, target));
1738
+ cmp.appendChild(new CSTNode(eqTok.text, ctx.source, eqTok.startOffset, eqTok.startOffset + 2, eqTok.start, eqTok.end, false));
1739
+ cmp.appendChild(wrapExpression(ctx, rhs));
1740
+ cmp.finalize();
1741
+ const wrappedCmp = wrapExpression(ctx, cmp);
1742
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1743
+ ctx.consume();
1744
+ return makeErrorNode(ctx.source, [wrappedCmp], wrappedCmp.startOffset, wrappedCmp.endOffset, wrappedCmp.startPosition, wrappedCmp.endPosition);
1745
+ }
1746
+ }
1747
+ if (target)
1748
+ node.appendChild(wrapExpression(ctx, target), "target");
1749
+ if (ctx.peekKind() === TokenKind.EQ) {
1750
+ ctx.addAnonymousChild(node, ctx.consume());
1751
+ const value = parseExpression(ctx, 0);
1752
+ if (value)
1753
+ node.appendChild(wrapExpression(ctx, value), "value");
1754
+ }
1755
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1756
+ ctx.consume();
1757
+ ctx.finishNode(node, startTok);
1758
+ return node;
1759
+ }
1760
+ function parseTransitionStatement(ctx) {
1761
+ const startTok = ctx.peek();
1762
+ const node = ctx.startNode("transition_statement");
1763
+ ctx.addAnonymousChild(node, ctx.consume());
1764
+ const withToList = tryParseWithToStatementList(ctx);
1765
+ if (withToList) {
1766
+ node.appendChild(withToList, "with_to_statement_list");
1767
+ } else if (!ctx.isAtSyncPoint() && ctx.peekKind() !== TokenKind.NEWLINE && ctx.peekKind() !== TokenKind.EOF) {
1768
+ const listNode = ctx.startNode("with_to_statement_list");
1769
+ const toNode = ctx.startNode("to_statement");
1770
+ toNode.appendChild(makeMissing(ctx, "to"));
1771
+ const target = parseExpression(ctx, 0);
1772
+ if (target)
1773
+ toNode.appendChild(wrapExpression(ctx, target), "target");
1774
+ toNode.finalize();
1775
+ listNode.appendChild(toNode);
1776
+ listNode.finalize();
1777
+ node.appendChild(listNode, "with_to_statement_list");
1778
+ }
1779
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1780
+ ctx.consume();
1781
+ ctx.finishNode(node, startTok);
1782
+ return node;
1783
+ }
1784
+ function parseWithStatement(ctx) {
1785
+ const startTok = ctx.peek();
1786
+ if (ctx.peekAt(1).kind !== TokenKind.ID && ctx.peekAt(1).kind !== TokenKind.STRING) {
1787
+ const withTok = ctx.consume();
1788
+ const kwOffset = ctx.currentOffset();
1789
+ const withChild = new CSTNode("with", ctx.source, kwOffset, kwOffset + 4, withTok.start, withTok.end, false);
1790
+ return makeErrorNode(ctx.source, [withChild], kwOffset, kwOffset + 4, withTok.start, withTok.end);
1791
+ }
1792
+ const node = ctx.startNode("with_statement");
1793
+ ctx.addAnonymousChild(node, ctx.consume());
1794
+ parseWithParams(ctx, node);
1795
+ if (ctx.peekKind() === TokenKind.COMMENT) {
1796
+ node.appendChild(ctx.consumeNamed("comment"));
1797
+ }
1798
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1799
+ ctx.consume();
1800
+ ctx.finishNode(node, startTok);
1801
+ return node;
1802
+ }
1803
+ function parseWithParams(ctx, node) {
1804
+ while (!ctx.isAtSyncPoint()) {
1805
+ if (ctx.peekKind() === TokenKind.ID || ctx.peekKind() === TokenKind.STRING) {
1806
+ if (ctx.peekKind() === TokenKind.STRING) {
1807
+ node.appendChild(parseString(ctx), "param");
1808
+ } else {
1809
+ node.appendChild(ctx.consumeNamed("id"), "param");
1810
+ }
1811
+ } else {
1812
+ const err = synchronize(ctx);
1813
+ if (err)
1814
+ node.appendChild(err);
1815
+ return;
1816
+ }
1817
+ if (ctx.peekKind() === TokenKind.EQ) {
1818
+ ctx.addAnonymousChild(node, ctx.consume());
1819
+ } else {
1820
+ node.appendChild(makeMissing(ctx, "="));
1821
+ }
1822
+ const value = parseExpression(ctx, 0);
1823
+ if (value)
1824
+ node.appendChild(wrapExpression(ctx, value), "value");
1825
+ if (ctx.peekKind() === TokenKind.COMMA) {
1826
+ ctx.addAnonymousChild(node, ctx.consume());
1827
+ } else {
1828
+ break;
1829
+ }
1830
+ }
1831
+ }
1832
+ function parseAvailableWhenStatement(ctx) {
1833
+ const startTok = ctx.peek();
1834
+ const node = ctx.startNode("available_when_statement");
1835
+ ctx.addAnonymousChild(node, ctx.consume());
1836
+ ctx.addAnonymousChild(node, ctx.consume());
1837
+ const condition = parseExpression(ctx, 0);
1838
+ if (condition)
1839
+ node.appendChild(wrapExpression(ctx, condition), "condition");
1840
+ if (ctx.peekKind() === TokenKind.NEWLINE)
1841
+ ctx.consume();
1842
+ ctx.finishNode(node, startTok);
1843
+ return node;
1844
+ }
1845
+ function tryParseWithToStatementList(ctx) {
1846
+ const tok = ctx.peek();
1847
+ if (!isTokenKind(tok, TokenKind.ID))
1848
+ return null;
1849
+ if (!["with", "to"].includes(tok.text))
1850
+ return null;
1851
+ const startTok = tok;
1852
+ const node = ctx.startNode("with_to_statement_list");
1853
+ while (!ctx.isAtSyncPoint()) {
1854
+ if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === "with") {
1855
+ node.appendChild(parseInlineWithStatement(ctx));
1856
+ } else if (ctx.peekKind() === TokenKind.ID && ctx.peek().text === "to") {
1857
+ node.appendChild(parseToStatement(ctx));
1858
+ } else {
1859
+ break;
1860
+ }
1861
+ if (ctx.peekKind() === TokenKind.COMMA) {
1862
+ ctx.addAnonymousChild(node, ctx.consume());
1863
+ } else {
1864
+ break;
1865
+ }
1866
+ }
1867
+ if (node.children.length === 0)
1868
+ return null;
1869
+ ctx.finishNode(node, startTok);
1870
+ return node;
1871
+ }
1872
+ function parseInlineWithStatement(ctx) {
1873
+ const startTok = ctx.peek();
1874
+ const node = ctx.startNode("with_statement");
1875
+ ctx.addAnonymousChild(node, ctx.consume());
1876
+ parseWithParams(ctx, node);
1877
+ ctx.finishNode(node, startTok);
1878
+ return node;
1879
+ }
1880
+ function parseToStatement(ctx) {
1881
+ const startTok = ctx.peek();
1882
+ const node = ctx.startNode("to_statement");
1883
+ ctx.addAnonymousChild(node, ctx.consume());
1884
+ const target = parseExpression(ctx, 0);
1885
+ if (target) {
1886
+ node.appendChild(wrapExpression(ctx, target), "target");
1887
+ } else {
1888
+ node.appendChild(makeEmptyError(ctx));
1889
+ }
1890
+ ctx.finishNode(node, startTok);
1891
+ return node;
1892
+ }
1893
+
1894
+ // vendor/agentscript-parser-javascript/dist/parse-templates.js
1895
+ function parseTemplate(ctx) {
1896
+ const startTok = ctx.peek();
1897
+ const node = ctx.startNode("template");
1898
+ const pipeOffset = ctx.peekOffset();
1899
+ let lineStart = pipeOffset;
1900
+ while (lineStart > 0 && ctx.source.charCodeAt(lineStart - 1) !== 10) {
1901
+ lineStart--;
1902
+ }
1903
+ let templateOuterIndent = 0;
1904
+ for (let i = lineStart; i < pipeOffset; i++) {
1905
+ const ch = ctx.source.charCodeAt(i);
1906
+ if (ch === 32)
1907
+ templateOuterIndent += 1;
1908
+ else if (ch === 9)
1909
+ templateOuterIndent += 3;
1910
+ else
1911
+ break;
1912
+ }
1913
+ const pipeToken = ctx.consume();
1914
+ ctx.addAnonymousChild(node, pipeToken);
1915
+ const hasContentOnSameLine = !isAtEnd(ctx) && ctx.peekKind() !== TokenKind.NEWLINE && ctx.peekKind() !== TokenKind.INDENT && ctx.peekKind() !== TokenKind.DEDENT;
1916
+ if (hasContentOnSameLine) {
1917
+ const afterPipeOffset = pipeToken.startOffset + 1;
1918
+ gatherTemplateContentLine(ctx, node, afterPipeOffset);
1919
+ }
1920
+ if (ctx.peekKind() === TokenKind.NEWLINE) {
1921
+ ctx.consume();
1922
+ }
1923
+ if (ctx.peekKind() === TokenKind.INDENT) {
1924
+ ctx.consume();
1925
+ let indentDepth = 1;
1926
+ while (!isAtEnd(ctx)) {
1927
+ const tok = ctx.peek();
1928
+ if (tok.kind === TokenKind.DEDENT) {
1929
+ indentDepth--;
1930
+ ctx.consume();
1931
+ if (indentDepth <= 0) {
1932
+ if (templateContinues(ctx, templateOuterIndent)) {
1933
+ indentDepth = 0;
1934
+ continue;
1935
+ }
1936
+ break;
1937
+ }
1938
+ } else if (tok.kind === TokenKind.INDENT) {
1939
+ indentDepth++;
1940
+ ctx.consume();
1941
+ } else if (tok.kind === TokenKind.NEWLINE) {
1942
+ ctx.consume();
1943
+ } else {
1944
+ if (indentDepth <= 0 && !templateContinues(ctx, templateOuterIndent)) {
1945
+ break;
1946
+ }
1947
+ const lastChild = node.children.length > 0 ? node.children[node.children.length - 1] : null;
1948
+ const gapOffset = lastChild && lastChild.endOffset < ctx.peekOffset() ? lastChild.endOffset : void 0;
1949
+ const gapPos = gapOffset !== void 0 ? lastChild.endPosition : void 0;
1950
+ gatherTemplateContentLine(ctx, node, gapOffset, gapPos);
1951
+ }
1952
+ }
1953
+ }
1954
+ mergeTemplateContent(ctx, node);
1955
+ ctx.finishNode(node, startTok);
1956
+ return node;
1957
+ }
1958
+ function parseTemplateAsColinear(ctx) {
1959
+ return parseTemplate(ctx);
1960
+ }
1961
+ function templateContinues(ctx, templateOuterIndent) {
1962
+ let i = 0;
1963
+ while (ctx.peekAt(i).kind === TokenKind.NEWLINE)
1964
+ i++;
1965
+ const tok = ctx.peekAt(i);
1966
+ if (tok.kind === TokenKind.EOF || tok.kind === TokenKind.DEDENT)
1967
+ return false;
1968
+ if (tok.start.column > templateOuterIndent)
1969
+ return true;
1970
+ if (tok.kind === TokenKind.PIPE)
1971
+ return false;
1972
+ if (tok.kind === TokenKind.ID || tok.kind === TokenKind.STRING) {
1973
+ const after = ctx.peekAt(i + 1);
1974
+ if (after.kind === TokenKind.COLON)
1975
+ return false;
1976
+ if (after.kind === TokenKind.ID) {
1977
+ const afterAfter = ctx.peekAt(i + 2);
1978
+ if (afterAfter.kind === TokenKind.COLON)
1979
+ return false;
1980
+ }
1981
+ }
1982
+ if (tok.kind === TokenKind.ID) {
1983
+ switch (tok.text) {
1984
+ case "if":
1985
+ case "elif":
1986
+ case "else":
1987
+ case "run":
1988
+ case "set":
1989
+ case "transition":
1990
+ return false;
1991
+ case "with":
1992
+ if (ctx.peekAt(i + 1).kind !== TokenKind.COLON)
1993
+ return false;
1994
+ break;
1995
+ case "available":
1996
+ if (ctx.peekAt(i + 1).kind === TokenKind.ID && ctx.peekAt(i + 1).text === "when")
1997
+ return false;
1998
+ break;
1999
+ }
2000
+ }
2001
+ if (tok.kind === TokenKind.DASH_SPACE)
2002
+ return false;
2003
+ if (tok.kind === TokenKind.COMMENT)
2004
+ return false;
2005
+ return true;
2006
+ }
2007
+ function mergeTemplateContent(ctx, template) {
2008
+ const merged = [];
2009
+ let i = 0;
2010
+ while (i < template.children.length) {
2011
+ const child = template.children[i];
2012
+ if (child.type === "template_content") {
2013
+ let end = i + 1;
2014
+ while (end < template.children.length && template.children[end].type === "template_content") {
2015
+ end++;
2016
+ }
2017
+ if (end > i + 1) {
2018
+ const first = template.children[i];
2019
+ const last = template.children[end - 1];
2020
+ const mergedNode = new CSTNode("template_content", ctx.source, first.startOffset, last.endOffset, first.startPosition, last.endPosition);
2021
+ mergedNode.parent = template;
2022
+ merged.push(mergedNode);
2023
+ i = end;
2024
+ } else {
2025
+ merged.push(child);
2026
+ i++;
2027
+ }
2028
+ } else {
2029
+ merged.push(child);
2030
+ i++;
2031
+ }
2032
+ }
2033
+ template.children = merged;
2034
+ }
2035
+ function gatherTemplateContentLine(ctx, parent, initialOffset, initialPos) {
2036
+ let contentStartOffset = initialOffset ?? ctx.peekOffset();
2037
+ let contentStartPos = initialPos ?? ctx.peek().start;
2038
+ let lastConsumedEndOffset = contentStartOffset;
2039
+ let lastConsumedEndPos = contentStartPos;
2040
+ while (!isAtEnd(ctx)) {
2041
+ const tok = ctx.peek();
2042
+ if (tok.kind === TokenKind.NEWLINE || tok.kind === TokenKind.DEDENT || tok.kind === TokenKind.INDENT || tok.kind === TokenKind.EOF) {
2043
+ break;
2044
+ }
2045
+ if (tok.kind === TokenKind.TEMPLATE_EXPR_START) {
2046
+ const exprOffset = ctx.peekOffset();
2047
+ if (exprOffset > contentStartOffset) {
2048
+ parent.appendChild(new CSTNode("template_content", ctx.source, contentStartOffset, exprOffset, contentStartPos, tok.start));
2049
+ }
2050
+ const exprNode = parseTemplateExpression(ctx);
2051
+ parent.appendChild(exprNode);
2052
+ contentStartOffset = exprNode.endOffset;
2053
+ contentStartPos = exprNode.endPosition;
2054
+ lastConsumedEndOffset = exprNode.endOffset;
2055
+ lastConsumedEndPos = exprNode.endPosition;
2056
+ continue;
2057
+ }
2058
+ const tokOffset = ctx.peekOffset();
2059
+ lastConsumedEndOffset = tokOffset + tok.text.length;
2060
+ lastConsumedEndPos = tok.end;
2061
+ ctx.consume();
2062
+ }
2063
+ if (lastConsumedEndOffset > contentStartOffset) {
2064
+ parent.appendChild(new CSTNode("template_content", ctx.source, contentStartOffset, lastConsumedEndOffset, contentStartPos, lastConsumedEndPos));
2065
+ }
2066
+ }
2067
+ function parseTemplateExpression(ctx) {
2068
+ const startTok = ctx.peek();
2069
+ const node = ctx.startNode("template_expression");
2070
+ ctx.addAnonymousChild(node, ctx.consume());
2071
+ const expr = parseExpression(ctx, 0);
2072
+ if (expr) {
2073
+ node.appendChild(wrapExpression(ctx, expr), "expression");
2074
+ } else {
2075
+ node.appendChild(makeEmptyError(ctx));
2076
+ }
2077
+ if (ctx.peekKind() !== TokenKind.RBRACE && !ctx.isAtSyncPoint()) {
2078
+ const err = synchronize(ctx);
2079
+ if (err)
2080
+ node.appendChild(err);
2081
+ }
2082
+ if (ctx.peekKind() === TokenKind.RBRACE) {
2083
+ ctx.addAnonymousChild(node, ctx.consume());
2084
+ } else {
2085
+ node.appendChild(makeMissing(ctx, "}"));
2086
+ }
2087
+ ctx.finishNode(node, startTok);
2088
+ return node;
2089
+ }
2090
+
2091
+ // vendor/agentscript-parser-javascript/dist/parse-mapping.js
2092
+ var MAX_KEY_LOOKAHEAD = 10;
2093
+ function parseMappingOrExpression(ctx, parseSequence2) {
2094
+ if (isMappingStart(ctx)) {
2095
+ return parseMapping(ctx, parseSequence2);
2096
+ }
2097
+ const expr = parseExpression(ctx, 0);
2098
+ if (!expr)
2099
+ return null;
2100
+ if (isTokenKind(ctx.peek(), TokenKind.EQ)) {
2101
+ const node = ctx.startNodeAt("assignment_expression", expr);
2102
+ node.appendChild(wrapExpression(ctx, expr), "left");
2103
+ ctx.addAnonymousChild(node, ctx.consumeKind(TokenKind.EQ));
2104
+ const right = parseExpression(ctx, 0);
2105
+ if (right)
2106
+ node.appendChild(wrapExpression(ctx, right), "right");
2107
+ return node;
2108
+ }
2109
+ return wrapExpression(ctx, expr);
2110
+ }
2111
+ function isMappingStart(ctx) {
2112
+ const tok = ctx.peek();
2113
+ if (tok.kind === TokenKind.COMMENT)
2114
+ return true;
2115
+ if (tok.kind === TokenKind.PIPE)
2116
+ return true;
2117
+ if (tok.kind === TokenKind.ID && isStatementStart(ctx))
2118
+ return true;
2119
+ if (!isKeyTokenStart(tok.kind))
2120
+ return false;
2121
+ const startRow = tok.start.row;
2122
+ for (let i = 1; i < MAX_KEY_LOOKAHEAD; i++) {
2123
+ const t = ctx.peekAt(i);
2124
+ if (t.kind === TokenKind.COLON || t.kind === TokenKind.INDENT || t.kind === TokenKind.ARROW || t.kind === TokenKind.AT)
2125
+ return true;
2126
+ if (i === 1 && (t.kind === TokenKind.STRING || t.kind === TokenKind.NUMBER))
2127
+ return true;
2128
+ if (t.kind === TokenKind.EOF || t.start.row !== startRow)
2129
+ return false;
2130
+ if (!isKeyTokenContinuation(t.kind))
2131
+ return false;
2132
+ }
2133
+ return false;
2134
+ }
2135
+ function parseMapping(ctx, parseSequence2) {
2136
+ const node = ctx.startNode("mapping");
2137
+ while (!isAtEnd(ctx)) {
2138
+ skipNewlines(ctx);
2139
+ const tok = ctx.peek();
2140
+ if (tok.kind === TokenKind.DEDENT || tok.kind === TokenKind.EOF)
2141
+ break;
2142
+ if (tok.kind === TokenKind.COMMENT && isTrailingCommentOnly(ctx)) {
2143
+ break;
2144
+ }
2145
+ const item = parseMappingItem(ctx, parseSequence2);
2146
+ if (item) {
2147
+ node.appendChild(item);
2148
+ } else {
2149
+ const err = synchronize(ctx);
2150
+ if (err) {
2151
+ node.appendChild(err);
2152
+ } else if (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT) {
2153
+ ctx.consume();
2154
+ }
2155
+ }
2156
+ }
2157
+ return node;
2158
+ }
2159
+ function parseMappingItem(ctx, parseSequence2) {
2160
+ const tok = ctx.peek();
2161
+ if (tok.kind === TokenKind.ID) {
2162
+ switch (tok.text) {
2163
+ case "if":
2164
+ return parseIfStatement(ctx, (c) => parseTemplate(c));
2165
+ case "run":
2166
+ return parseRunStatement(ctx, (c) => parseTemplate(c));
2167
+ case "set":
2168
+ return parseSetStatement(ctx);
2169
+ case "transition":
2170
+ return parseTransitionStatement(ctx);
2171
+ case "with": {
2172
+ if (ctx.peekAt(1).kind !== TokenKind.COLON) {
2173
+ return parseWithStatement(ctx);
2174
+ }
2175
+ break;
2176
+ }
2177
+ case "available": {
2178
+ if (ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === "when") {
2179
+ return parseAvailableWhenStatement(ctx);
2180
+ }
2181
+ break;
2182
+ }
2183
+ }
2184
+ }
2185
+ if (tok.kind === TokenKind.PIPE) {
2186
+ return parseTemplate(ctx);
2187
+ }
2188
+ if (tok.kind === TokenKind.COMMENT) {
2189
+ return ctx.consumeNamed("comment");
2190
+ }
2191
+ if (tok.kind === TokenKind.ID && (tok.text === "else" || tok.text === "elif" || tok.text === "for")) {
2192
+ return parseOrphanBlock(ctx, (c) => parseProcedure(c, (c2) => parseTemplate(c2)));
2193
+ }
2194
+ if (isKeyStart(ctx)) {
2195
+ return parseMappingElement(ctx, parseSequence2);
2196
+ }
2197
+ return null;
2198
+ }
2199
+ function isColinearMappingElement(ctx) {
2200
+ if (!isKeyStart(ctx))
2201
+ return false;
2202
+ const tok = ctx.peek();
2203
+ const lookahead = 1;
2204
+ if (ctx.peekAt(lookahead).kind === TokenKind.ID && ctx.peekAt(lookahead).start.row === tok.start.row) {
2205
+ const afterSecond = ctx.peekAt(lookahead + 1);
2206
+ if (afterSecond.kind === TokenKind.COLON && afterSecond.start.row === tok.start.row) {
2207
+ return true;
2208
+ }
2209
+ }
2210
+ const next = ctx.peekAt(lookahead);
2211
+ return next.kind === TokenKind.COLON && next.start.row === tok.start.row;
2212
+ }
2213
+ function parseColinearMappingElement(ctx) {
2214
+ const startTok = ctx.peek();
2215
+ const node = ctx.startNode("mapping_element");
2216
+ const key = parseKey(ctx);
2217
+ if (key)
2218
+ node.appendChild(key, "key");
2219
+ if (ctx.peekKind() === TokenKind.COLON) {
2220
+ ctx.addAnonymousChild(node, ctx.consume());
2221
+ }
2222
+ const colinear = tryParseColinearValue(ctx);
2223
+ if (colinear) {
2224
+ if (colinear.errorPrefix)
2225
+ node.appendChild(colinear.errorPrefix);
2226
+ node.appendChild(colinear.value, "colinear_value");
2227
+ }
2228
+ ctx.finishNode(node, startTok);
2229
+ return node;
2230
+ }
2231
+ function tryParseColinearValue(ctx) {
2232
+ const tok = ctx.peek();
2233
+ if (tok.kind === TokenKind.PIPE) {
2234
+ return { value: parseTemplateAsColinear(ctx) };
2235
+ }
2236
+ if (tok.kind === TokenKind.ID && (tok.text === "mutable" || tok.text === "linked")) {
2237
+ return { value: parseVariableDeclaration(ctx) };
2238
+ }
2239
+ if (tok.kind === TokenKind.ID && isFuzzyModifier(tok.text)) {
2240
+ return { value: parseFuzzyVariableDeclaration(ctx) };
2241
+ }
2242
+ const expr = parseExpression(ctx, 0);
2243
+ if (!expr)
2244
+ return null;
2245
+ if ((expr.type === "number" || expr.type === "id" && /^[0-9]/.test(expr.text)) && ctx.peekKind() === TokenKind.ID && ctx.peek().start.row === expr.startRow) {
2246
+ const errNode = makeErrorNode(ctx.source, [wrapExpression(ctx, expr)], expr.startOffset, expr.endOffset, expr.startPosition, expr.endPosition);
2247
+ const realValue = tryParseColinearValue(ctx);
2248
+ if (realValue) {
2249
+ return { value: realValue.value, errorPrefix: errNode };
2250
+ }
2251
+ }
2252
+ const withToList = tryParseWithToStatementList(ctx);
2253
+ if (withToList) {
2254
+ const ewt2 = ctx.startNodeAt("expression_with_to", expr);
2255
+ ewt2.appendChild(wrapExpression(ctx, expr), "expression");
2256
+ ewt2.appendChild(withToList, "with_to_statement_list");
2257
+ ewt2.finalize();
2258
+ return { value: ewt2 };
2259
+ }
2260
+ if (ctx.peekKind() === TokenKind.EQ) {
2261
+ const assign = ctx.startNodeAt("assignment_expression", expr);
2262
+ assign.appendChild(wrapExpression(ctx, expr), "left");
2263
+ ctx.addAnonymousChild(assign, ctx.consume());
2264
+ const right = parseExpression(ctx, 0);
2265
+ if (right)
2266
+ assign.appendChild(wrapExpression(ctx, right), "right");
2267
+ assign.finalize();
2268
+ return { value: assign };
2269
+ }
2270
+ const ewt = ctx.startNodeAt("expression_with_to", expr);
2271
+ ewt.appendChild(wrapExpression(ctx, expr), "expression");
2272
+ return { value: ewt };
2273
+ }
2274
+ function levenshteinDistance(a, b) {
2275
+ const m = a.length;
2276
+ const n = b.length;
2277
+ const dp = Array.from({ length: m + 1 }, () => Array.from({ length: n + 1 }).fill(0));
2278
+ for (let i = 0; i <= m; i++)
2279
+ dp[i][0] = i;
2280
+ for (let j = 0; j <= n; j++)
2281
+ dp[0][j] = j;
2282
+ for (let i = 1; i <= m; i++) {
2283
+ for (let j = 1; j <= n; j++) {
2284
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
2285
+ dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + cost);
2286
+ }
2287
+ }
2288
+ return dp[m][n];
2289
+ }
2290
+ function isFuzzyModifier(text) {
2291
+ return levenshteinDistance(text, "mutable") <= 2 || levenshteinDistance(text, "linked") <= 2;
2292
+ }
2293
+ function parseFuzzyVariableDeclaration(ctx) {
2294
+ const startTok = ctx.peek();
2295
+ const node = ctx.startNode("variable_declaration");
2296
+ const misspelled = ctx.consume();
2297
+ const misspelledEnd = misspelled.startOffset + misspelled.text.length;
2298
+ const leaf = tokenToAutoLeaf(misspelled, ctx.source, misspelled.startOffset);
2299
+ const errNode = makeErrorNode(ctx.source, [leaf], misspelled.startOffset, misspelledEnd, misspelled.start, misspelled.end);
2300
+ node.appendChild(errNode);
2301
+ const typeExpr = parseExpression(ctx, 0);
2302
+ if (typeExpr)
2303
+ node.appendChild(wrapExpression(ctx, typeExpr), "type");
2304
+ if (ctx.peekKind() === TokenKind.EQ) {
2305
+ ctx.addAnonymousChild(node, ctx.consume());
2306
+ const defaultExpr = parseExpression(ctx, 0);
2307
+ if (defaultExpr)
2308
+ node.appendChild(wrapExpression(ctx, defaultExpr), "default");
2309
+ }
2310
+ ctx.finishNode(node, startTok);
2311
+ return node;
2312
+ }
2313
+ function parseMappingElement(ctx, parseSequence2) {
2314
+ const startTok = ctx.peek();
2315
+ const node = ctx.startNode("mapping_element");
2316
+ const key = parseKey(ctx);
2317
+ invariant(key != null, "We must be at a key start");
2318
+ node.appendChild(key, "key");
2319
+ if (ctx.peekKind() === TokenKind.COLON) {
2320
+ ctx.addAnonymousChild(node, ctx.consumeKind(TokenKind.COLON));
2321
+ } else if (ctx.peekKind() === TokenKind.INDENT || ctx.peekKind() === TokenKind.ARROW || ctx.peekKind() === TokenKind.ID || ctx.peekKind() === TokenKind.AT || ctx.peekKind() === TokenKind.STRING || ctx.peekKind() === TokenKind.NUMBER) {
2322
+ node.appendChild(makeMissing(ctx, ":"));
2323
+ } else {
2324
+ return node;
2325
+ }
2326
+ if (ctx.peekKind() === TokenKind.ARROW) {
2327
+ parseArrowBody(ctx, node);
2328
+ } else if (ctx.peekKind() === TokenKind.INDENT) {
2329
+ parseIndentedBlockValue(ctx, node, parseSequence2);
2330
+ } else {
2331
+ parseColinearAndBlock(ctx, node, startTok.start.row, parseSequence2);
2332
+ }
2333
+ return node;
2334
+ }
2335
+ function parseColinearAndBlock(ctx, node, startRow, parseSequence2) {
2336
+ const colinear = tryParseColinearValue(ctx);
2337
+ if (colinear) {
2338
+ if (colinear.errorPrefix)
2339
+ node.appendChild(colinear.errorPrefix);
2340
+ node.appendChild(colinear.value, "colinear_value");
2341
+ }
2342
+ if (ctx.peekKind() === TokenKind.COMMENT) {
2343
+ node.appendChild(ctx.consumeNamed("comment"));
2344
+ }
2345
+ if (colinear) {
2346
+ const err = synchronizeRow(ctx, startRow);
2347
+ if (err)
2348
+ node.appendChild(err);
2349
+ } else if (!ctx.isAtSyncPoint() && ctx.peekKind() !== TokenKind.INDENT) {
2350
+ const err = synchronize(ctx);
2351
+ if (err)
2352
+ node.appendChild(err);
2353
+ }
2354
+ if (colinear?.value.type === "expression_with_to" && !colinear.value.childForFieldName("with_to_statement_list") && ctx.peekKind() === TokenKind.INDENT && ctx.peekAt(1).kind === TokenKind.ID && ctx.peekAt(1).text === "to") {
2355
+ ctx.consumeKind(TokenKind.INDENT);
2356
+ const withToList = tryParseWithToStatementList(ctx);
2357
+ if (withToList) {
2358
+ colinear.value.appendChild(withToList, "with_to_statement_list");
2359
+ node.endOffset = colinear.value.endOffset;
2360
+ node.endPosition = colinear.value.endPosition;
2361
+ }
2362
+ ctx.consumeKind(TokenKind.DEDENT);
2363
+ } else if (ctx.peekKind() === TokenKind.INDENT) {
2364
+ parseIndentedBlockValue(ctx, node, parseSequence2);
2365
+ }
2366
+ }
2367
+ function parseArrowBody(ctx, node) {
2368
+ ctx.addAnonymousChild(node, ctx.consume());
2369
+ if (ctx.peekKind() === TokenKind.COMMENT) {
2370
+ node.appendChild(ctx.consumeNamed("comment"));
2371
+ }
2372
+ if (ctx.peekKind() === TokenKind.INDENT) {
2373
+ ctx.consume();
2374
+ consumeCommentsAndSkipNewlines(ctx, node);
2375
+ const proc = parseProcedure(ctx, (c) => parseTemplate(c));
2376
+ if (proc)
2377
+ node.appendChild(proc, "block_value");
2378
+ consumeCommentsAndSkipNewlines(ctx, node);
2379
+ if (ctx.peekKind() === TokenKind.DEDENT)
2380
+ ctx.consume();
2381
+ } else {
2382
+ const emptyProc = ctx.startNode("procedure");
2383
+ emptyProc.appendChild(makeEmptyError(ctx));
2384
+ ctx.finishNode(emptyProc, ctx.peek());
2385
+ node.appendChild(emptyProc, "block_value");
2386
+ }
2387
+ }
2388
+ function parseVariableDeclaration(ctx) {
2389
+ const startTok = ctx.peek();
2390
+ const node = ctx.startNode("variable_declaration");
2391
+ ctx.addAnonymousChild(node, ctx.consume());
2392
+ if (ctx.peekKind() === TokenKind.ID && (ctx.peek().text === "mutable" || ctx.peek().text === "linked")) {
2393
+ const errExpr = parseExpression(ctx, 0);
2394
+ if (errExpr) {
2395
+ const wrapped = wrapExpression(ctx, errExpr);
2396
+ const errNode = makeErrorNode(ctx.source, [wrapped], wrapped.startOffset, wrapped.endOffset, wrapped.startPosition, wrapped.endPosition);
2397
+ node.appendChild(errNode);
2398
+ }
2399
+ }
2400
+ const typeExpr = parseExpression(ctx, 0);
2401
+ if (typeExpr)
2402
+ node.appendChild(wrapExpression(ctx, typeExpr), "type");
2403
+ if (ctx.peekKind() === TokenKind.EQ) {
2404
+ ctx.addAnonymousChild(node, ctx.consume());
2405
+ const defaultExpr = parseExpression(ctx, 0);
2406
+ if (defaultExpr)
2407
+ node.appendChild(wrapExpression(ctx, defaultExpr), "default");
2408
+ }
2409
+ ctx.finishNode(node, startTok);
2410
+ return node;
2411
+ }
2412
+ function parseIndentedBlockValue(ctx, parent, parseSequence2) {
2413
+ ctx.consume();
2414
+ consumeCommentsAndSkipNewlines(ctx, parent);
2415
+ const blockValue = parseBlockValue(ctx, parseSequence2);
2416
+ if (blockValue)
2417
+ parent.appendChild(blockValue, "block_value");
2418
+ consumeCommentsAndSkipNewlines(ctx, parent);
2419
+ recoverToBlockEnd(ctx, parent);
2420
+ if (ctx.peekKind() === TokenKind.DEDENT)
2421
+ ctx.consume();
2422
+ }
2423
+ function parseBlockValue(ctx, parseSequence2) {
2424
+ const tok = ctx.peek();
2425
+ if (tok.kind === TokenKind.DASH_SPACE) {
2426
+ return parseSequence2(ctx);
2427
+ }
2428
+ if (tok.kind === TokenKind.ID && tok.text === "empty") {
2429
+ const emptyNode = ctx.startNode("empty_keyword");
2430
+ ctx.addAnonymousChild(emptyNode, ctx.consume());
2431
+ ctx.finishNode(emptyNode, tok);
2432
+ return emptyNode;
2433
+ }
2434
+ if (isMappingStart(ctx)) {
2435
+ return parseMapping(ctx, parseSequence2);
2436
+ }
2437
+ return parseAtomBlockValue(ctx);
2438
+ }
2439
+ function parseAtomBlockValue(ctx) {
2440
+ const expr = parseExpression(ctx, 0);
2441
+ if (!expr)
2442
+ return null;
2443
+ if (ATOM_TYPES.has(expr.type)) {
2444
+ const atom = new CSTNode("atom", ctx.source, expr.startOffset, expr.endOffset, expr.startPosition, expr.endPosition);
2445
+ atom.appendChild(expr);
2446
+ return atom;
2447
+ }
2448
+ return expr;
2449
+ }
2450
+
2451
+ // vendor/agentscript-parser-javascript/dist/parse-sequence.js
2452
+ function parseSequence(ctx) {
2453
+ const startTok = ctx.peek();
2454
+ const node = ctx.startNode("sequence");
2455
+ while (ctx.peekKind() === TokenKind.DASH_SPACE) {
2456
+ const elem = parseSequenceElement(ctx);
2457
+ if (elem)
2458
+ node.appendChild(elem);
2459
+ skipNewlines(ctx);
2460
+ }
2461
+ while (!isAtEnd(ctx) && ctx.peekKind() !== TokenKind.DEDENT && ctx.peekKind() !== TokenKind.DASH_SPACE) {
2462
+ skipNewlines(ctx);
2463
+ if (isAtEnd(ctx) || ctx.peekKind() === TokenKind.DEDENT)
2464
+ break;
2465
+ const parseSeq = (_ctx) => parseSequence(_ctx);
2466
+ const item = parseMappingItem(ctx, parseSeq);
2467
+ if (item) {
2468
+ const errNode = makeErrorNode(ctx.source, [item], item.startOffset, item.endOffset, item.startPosition, item.endPosition);
2469
+ node.appendChild(errNode);
2470
+ } else {
2471
+ const err = synchronize(ctx);
2472
+ if (err) {
2473
+ node.appendChild(err);
2474
+ } else {
2475
+ ctx.consume();
2476
+ }
2477
+ }
2478
+ }
2479
+ ctx.finishNode(node, startTok);
2480
+ return node;
2481
+ }
2482
+ function parseSequenceElement(ctx) {
2483
+ const startTok = ctx.peek();
2484
+ const node = ctx.startNode("sequence_element");
2485
+ ctx.addAnonymousChild(node, ctx.consume());
2486
+ const parseSeq = (_ctx) => parseSequence(_ctx);
2487
+ if (isColinearMappingElement(ctx)) {
2488
+ const mappingElem = parseColinearMappingElement(ctx);
2489
+ if (mappingElem)
2490
+ node.appendChild(mappingElem, "colinear_mapping_element");
2491
+ if (ctx.peekKind() === TokenKind.NEWLINE)
2492
+ ctx.consume();
2493
+ if (ctx.peekKind() === TokenKind.INDENT) {
2494
+ ctx.consume();
2495
+ const blockValue = parseMapping(ctx, parseSeq);
2496
+ if (blockValue)
2497
+ node.appendChild(blockValue, "block_value");
2498
+ if (ctx.peekKind() === TokenKind.DEDENT)
2499
+ ctx.consume();
2500
+ }
2501
+ } else if (ctx.peekKind() === TokenKind.NEWLINE || ctx.peekKind() === TokenKind.EOF || ctx.peekKind() === TokenKind.INDENT) {
2502
+ if (ctx.peekKind() === TokenKind.NEWLINE)
2503
+ ctx.consume();
2504
+ if (ctx.peekKind() === TokenKind.INDENT) {
2505
+ ctx.consume();
2506
+ const blockValue = parseMapping(ctx, parseSeq);
2507
+ if (blockValue)
2508
+ node.appendChild(blockValue, "block_value");
2509
+ if (ctx.peekKind() === TokenKind.DEDENT)
2510
+ ctx.consume();
2511
+ }
2512
+ } else {
2513
+ const colinear = tryParseColinearValue(ctx);
2514
+ if (colinear) {
2515
+ if (colinear.errorPrefix)
2516
+ node.appendChild(colinear.errorPrefix);
2517
+ node.appendChild(colinear.value, "colinear_value");
2518
+ }
2519
+ if (ctx.peekKind() === TokenKind.COMMENT) {
2520
+ node.appendChild(ctx.consumeNamed("comment"));
2521
+ }
2522
+ if (ctx.peekKind() === TokenKind.NEWLINE)
2523
+ ctx.consume();
2524
+ }
2525
+ ctx.finishNode(node, startTok);
2526
+ return node;
2527
+ }
2528
+
2529
+ // vendor/agentscript-parser-javascript/dist/parser.js
2530
+ var Parser = class {
2531
+ source;
2532
+ tokens;
2533
+ pos = 0;
2534
+ _eof;
2535
+ constructor(source) {
2536
+ this.source = source;
2537
+ const lexer = new Lexer(source);
2538
+ this.tokens = lexer.tokenize();
2539
+ }
2540
+ parse() {
2541
+ const root = this.parseSourceFile();
2542
+ return root;
2543
+ }
2544
+ // --- ParserContext implementation ---
2545
+ peek() {
2546
+ return this.peekAt(0);
2547
+ }
2548
+ peekAt(offset) {
2549
+ return this.peekAtIndex(this.pos + offset);
2550
+ }
2551
+ peekAtIndex(idx) {
2552
+ return this.tokens[idx] ?? this.eofToken();
2553
+ }
2554
+ peekKind() {
2555
+ return this.peek().kind;
2556
+ }
2557
+ consume() {
2558
+ const tok = this.peek();
2559
+ this.pos++;
2560
+ return tok;
2561
+ }
2562
+ consumeKind(kind) {
2563
+ const tok = this.peek();
2564
+ invariant(isTokenKind(tok, kind), `Expected token kind ${kind} but got ${tok.kind}`);
2565
+ this.pos++;
2566
+ return tok;
2567
+ }
2568
+ consumeNamed(type) {
2569
+ const tok = this.consume();
2570
+ const offset = tok.startOffset;
2571
+ return new CSTNode(type, this.source, offset, offset + tok.text.length, tok.start, tok.end);
2572
+ }
2573
+ currentOffset() {
2574
+ const idx = this.pos > 0 ? this.pos - 1 : 0;
2575
+ return this.peekAtIndex(idx).startOffset;
2576
+ }
2577
+ peekOffset() {
2578
+ return this.peek().startOffset;
2579
+ }
2580
+ isAtSyncPoint() {
2581
+ return isSyncPoint(this.peekKind());
2582
+ }
2583
+ startNode(type) {
2584
+ const tok = this.peek();
2585
+ const offset = tok.startOffset;
2586
+ return new CSTNode(type, this.source, offset, offset, tok.start, tok.end);
2587
+ }
2588
+ startNodeAt(type, existingChild) {
2589
+ return new CSTNode(type, this.source, existingChild.startOffset, existingChild.endOffset, existingChild.startPosition, existingChild.endPosition);
2590
+ }
2591
+ finishNode(_node, _startTok) {
2592
+ }
2593
+ addAnonymousChild(parent, token) {
2594
+ const offset = token.startOffset;
2595
+ const child = new CSTNode(token.text, this.source, offset, offset + token.text.length, token.start, token.end, false);
2596
+ parent.appendChild(child);
2597
+ }
2598
+ // --- Top-level parsing ---
2599
+ parseSourceFile() {
2600
+ const node = this.startNode("source_file");
2601
+ skipNewlines(this);
2602
+ if (this.peekKind() === TokenKind.INDENT) {
2603
+ this.consume();
2604
+ }
2605
+ consumeCommentsAndSkipNewlines(this, node);
2606
+ if (this.peekKind() === TokenKind.DASH_SPACE) {
2607
+ node.appendChild(parseSequence(this));
2608
+ } else {
2609
+ const content = parseMappingOrExpression(this, (_ctx) => parseSequence(_ctx));
2610
+ if (content)
2611
+ node.appendChild(content);
2612
+ }
2613
+ consumeCommentsAndSkipNewlines(this, node);
2614
+ while (!isAtEnd(this)) {
2615
+ if (this.peekKind() === TokenKind.NEWLINE || this.peekKind() === TokenKind.DEDENT) {
2616
+ this.consume();
2617
+ continue;
2618
+ }
2619
+ if (this.peekKind() === TokenKind.COMMENT) {
2620
+ node.appendChild(this.consumeNamed("comment"));
2621
+ continue;
2622
+ }
2623
+ const err = synchronize(this);
2624
+ if (err) {
2625
+ node.appendChild(err);
2626
+ } else {
2627
+ this.consume();
2628
+ }
2629
+ }
2630
+ node.startOffset = 0;
2631
+ node.startPosition = { row: 0, column: 0 };
2632
+ node.endOffset = this.source.length;
2633
+ node.endPosition = this.eofToken().end;
2634
+ return node;
2635
+ }
2636
+ eofToken() {
2637
+ if (!this._eof) {
2638
+ const lastToken = this.tokens[this.tokens.length - 1];
2639
+ const pos = lastToken ? lastToken.end : { row: 0, column: 0 };
2640
+ this._eof = {
2641
+ kind: TokenKind.EOF,
2642
+ text: "",
2643
+ start: pos,
2644
+ end: pos,
2645
+ startOffset: this.source.length
2646
+ };
2647
+ }
2648
+ return this._eof;
2649
+ }
2650
+ };
2651
+
2652
+ // vendor/agentscript-parser-javascript/dist/index.js
2653
+ function parse(source) {
2654
+ const parser = new Parser(source);
2655
+ return { rootNode: parser.parse() };
2656
+ }
2657
+
2658
+ // src/analyzer/parse.ts
2659
+ function parseAgentSource(source) {
2660
+ return parse(source).rootNode;
2661
+ }
2662
+ function locOf(n) {
2663
+ return {
2664
+ endCol: n.endCol,
2665
+ endRow: n.endRow,
2666
+ startCol: n.startCol,
2667
+ startRow: n.startRow
2668
+ };
2669
+ }
2670
+ function* descendants(node) {
2671
+ yield node;
2672
+ for (const c of node.namedChildren) yield* descendants(c);
2673
+ }
2674
+ function keyHeader(n) {
2675
+ if (n.type !== "key") return null;
2676
+ const head = n.text.split("\n", 1)[0];
2677
+ const colon = head.indexOf(":");
2678
+ const lhs = (colon === -1 ? head : head.slice(0, colon)).trim();
2679
+ const parts = lhs.split(/\s+/);
2680
+ return { kind: parts[0], label: parts.length > 1 ? parts.slice(1).join(" ") : void 0 };
2681
+ }
2682
+ function mappingKeyHeader(m) {
2683
+ if (m.type !== "mapping_element") return null;
2684
+ const keyNode = m.childForFieldName("key");
2685
+ if (!keyNode) {
2686
+ for (const c of m.namedChildren) {
2687
+ if (c.type === "key") return keyHeader(c);
2688
+ }
2689
+ return null;
2690
+ }
2691
+ return keyHeader(keyNode);
2692
+ }
2693
+ var NON_VALUE_NAMED_TYPES = /* @__PURE__ */ new Set(["comment", "key"]);
2694
+ function mappingValue(m) {
2695
+ if (m.type !== "mapping_element") return void 0;
2696
+ for (const c of m.namedChildren) {
2697
+ if (!NON_VALUE_NAMED_TYPES.has(c.type)) return c;
2698
+ }
2699
+ return void 0;
2700
+ }
2701
+ function findMappingEntry(parentBody, kind) {
2702
+ for (const c of parentBody.namedChildren) {
2703
+ if (c.type !== "mapping_element") continue;
2704
+ const h = mappingKeyHeader(c);
2705
+ if (h && h.kind === kind) return mappingValue(c);
2706
+ }
2707
+ return void 0;
2708
+ }
2709
+ function bodyOf(scopeKey) {
2710
+ const { parent } = scopeKey;
2711
+ if (!parent) return void 0;
2712
+ return mappingValue(parent);
2713
+ }
2714
+ function extractDeveloperName(root) {
2715
+ const topMapping = root.namedChildren.find((c) => c.type === "mapping") ?? root;
2716
+ for (const c of topMapping.namedChildren) {
2717
+ if (c.type !== "mapping_element") continue;
2718
+ const keyNode = c.childForFieldName("key") ?? c.namedChildren.find((n) => n.type === "key");
2719
+ if (!keyNode) continue;
2720
+ const h = keyHeader(keyNode);
2721
+ if (!h || h.kind !== "config") continue;
2722
+ const body = mappingValue(c);
2723
+ if (!body) return void 0;
2724
+ const devNameVal = findMappingEntry(body, "developer_name");
2725
+ if (!devNameVal) return void 0;
2726
+ return extractStringLiteral(devNameVal);
2727
+ }
2728
+ return void 0;
2729
+ }
2730
+ function extractStringLiteral(n) {
2731
+ for (const d of descendants(n)) {
2732
+ if (d.type === "string") {
2733
+ const t = d.text;
2734
+ if (t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
2735
+ if (t.startsWith("'") && t.endsWith("'")) return t.slice(1, -1);
2736
+ return t;
2737
+ }
2738
+ }
2739
+ return void 0;
2740
+ }
2741
+
2742
+ // src/analyzer/action-references.ts
2743
+ var TARGET_SCHEME = /^([a-z][a-z0-9+.-]*):\/\//i;
2744
+ function classifyTarget(uri) {
2745
+ if (!uri) return "unknown";
2746
+ const m = TARGET_SCHEME.exec(uri);
2747
+ if (!m) return "unknown";
2748
+ const scheme = m[1].toLowerCase();
2749
+ if (scheme === "apex") return "apex";
2750
+ if (scheme === "flow") return "flow";
2751
+ if (scheme.startsWith("prompt")) return "prompt";
2752
+ return "unknown";
2753
+ }
2754
+ function collectDeclarations(scope) {
2755
+ const decls = [];
2756
+ const actionsBlock = findMappingEntry(scope.body, "actions");
2757
+ if (!actionsBlock) return decls;
2758
+ for (const child of actionsBlock.namedChildren) {
2759
+ if (child.type !== "mapping_element") continue;
2760
+ const h = mappingKeyHeader(child);
2761
+ if (!h) continue;
2762
+ const declName = h.kind;
2763
+ const declBody = mappingValue(child);
2764
+ if (!declBody) {
2765
+ decls.push({
2766
+ location: locOf(child),
2767
+ name: declName,
2768
+ scope: scope.label,
2769
+ target: void 0,
2770
+ targetKind: "unknown"
2771
+ });
2772
+ continue;
2773
+ }
2774
+ const targetVal = findMappingEntry(declBody, "target");
2775
+ const targetStr = targetVal ? extractStringLiteral(targetVal) : void 0;
2776
+ decls.push({
2777
+ location: locOf(child),
2778
+ name: declName,
2779
+ scope: scope.label,
2780
+ target: targetStr,
2781
+ targetKind: classifyTarget(targetStr)
2782
+ });
2783
+ }
2784
+ return decls;
2785
+ }
2786
+ function collectReferences(scope) {
2787
+ const refs = [];
2788
+ const explore = (body, context) => {
2789
+ if (!body) return;
2790
+ for (const n of descendants(body)) {
2791
+ if (n.type !== "member_expression") continue;
2792
+ if (!n.text.startsWith("@actions.")) continue;
2793
+ const name = actionNameFromMember(n);
2794
+ if (!name) continue;
2795
+ const ctx = isInsideTransition(n) ? "transition" : context;
2796
+ refs.push({
2797
+ context: ctx,
2798
+ location: locOf(n),
2799
+ name,
2800
+ scope: scope.label
2801
+ });
2802
+ }
2803
+ };
2804
+ explore(findMappingEntry(scope.body, "before_reasoning"), "before_reasoning_run");
2805
+ explore(findMappingEntry(scope.body, "after_reasoning"), "after_reasoning_run");
2806
+ const reasoning = findMappingEntry(scope.body, "reasoning");
2807
+ if (reasoning) {
2808
+ explore(findMappingEntry(reasoning, "actions"), "reasoning_actions");
2809
+ explore(findMappingEntry(reasoning, "instructions"), "reasoning_instructions_run");
2810
+ }
2811
+ return refs;
2812
+ }
2813
+ function actionNameFromMember(n) {
2814
+ const t = n.text;
2815
+ const dot = t.indexOf(".");
2816
+ if (dot === -1) return void 0;
2817
+ const rest = t.slice(dot + 1);
2818
+ const m = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(rest);
2819
+ return m?.[1];
2820
+ }
2821
+ function isInsideTransition(n) {
2822
+ let p = n.parent;
2823
+ while (p) {
2824
+ if (p.type === "transition_statement") return true;
2825
+ p = p.parent;
2826
+ }
2827
+ return false;
2828
+ }
2829
+
2830
+ // src/analyzer/apex-analyze.ts
2831
+ import { readFile } from "node:fs/promises";
2832
+ import { basename, relative } from "node:path";
2833
+
2834
+ // src/analyzer/apex-complexity.ts
2835
+ import {
2836
+ CatchClauseContext,
2837
+ CondExpressionContext,
2838
+ ConstructorDeclarationContext,
2839
+ DoWhileStatementContext,
2840
+ ForStatementContext,
2841
+ IfStatementContext,
2842
+ LogAndExpressionContext,
2843
+ LogOrExpressionContext,
2844
+ MethodDeclarationContext,
2845
+ WhenControlContext,
2846
+ WhileStatementContext
2847
+ } from "@apexdevtools/apex-parser";
2848
+
2849
+ // src/analyzer/apex-parse.ts
2850
+ import {
2851
+ ApexParserFactory
2852
+ } from "@apexdevtools/apex-parser";
2853
+ function parseApexSource(source) {
2854
+ const parser = ApexParserFactory.createParser(source);
2855
+ return parser.compilationUnit();
2856
+ }
2857
+ function locOfCtx(ctx) {
2858
+ const { start } = ctx;
2859
+ const stop = ctx.stop ?? ctx.start;
2860
+ return {
2861
+ endCol: (stop?.column ?? 0) + (stop?.text?.length ?? 0),
2862
+ endRow: stop?.line ?? 0,
2863
+ startCol: start?.column ?? 0,
2864
+ startRow: start?.line ?? 0
2865
+ };
2866
+ }
2867
+ function walkParseTree(node, visit) {
2868
+ visit(node);
2869
+ const childCount = typeof node.getChildCount === "function" ? node.getChildCount() : 0;
2870
+ for (let i = 0; i < childCount; i++) {
2871
+ const c = node.getChild(i);
2872
+ if (c && typeof c.getChildCount === "function") {
2873
+ walkParseTree(c, visit);
2874
+ }
2875
+ }
2876
+ }
2877
+
2878
+ // src/analyzer/apex-complexity.ts
2879
+ function complexityOfMethod(methodCtx) {
2880
+ const body = methodCtx.block();
2881
+ const contributors = [];
2882
+ if (body) {
2883
+ walkParseTree(body, (node) => {
2884
+ if (node !== methodCtx && (node instanceof MethodDeclarationContext || node instanceof ConstructorDeclarationContext)) {
2885
+ return;
2886
+ }
2887
+ const kind = classifyContributor(node);
2888
+ if (kind !== void 0 && enclosingMethod(node) === methodCtx) {
2889
+ contributors.push({ kind, location: locOfCtx(node) });
2890
+ }
2891
+ });
2892
+ }
2893
+ const name = methodCtx instanceof ConstructorDeclarationContext ? methodCtx.qualifiedName()?.getText() ?? "<ctor>" : methodCtx.id()?.getText() ?? "<anon>";
2894
+ const signature = renderSignature(methodCtx, name);
2895
+ return {
2896
+ complexity: 1 + contributors.length,
2897
+ contributors,
2898
+ kind: methodCtx instanceof ConstructorDeclarationContext ? "constructor" : "method",
2899
+ location: locOfCtx(methodCtx),
2900
+ name,
2901
+ signature
2902
+ };
2903
+ }
2904
+ function classifyContributor(node) {
2905
+ if (node instanceof IfStatementContext) return "if_statement";
2906
+ if (node instanceof ForStatementContext) return "for_statement";
2907
+ if (node instanceof WhileStatementContext) return "while_statement";
2908
+ if (node instanceof DoWhileStatementContext) return "do_while_statement";
2909
+ if (node instanceof WhenControlContext) {
2910
+ const wv = node.whenValue();
2911
+ const elseTok = wv && typeof wv.ELSE === "function" ? wv.ELSE() : void 0;
2912
+ return elseTok ? void 0 : "when_arm";
2913
+ }
2914
+ if (node instanceof CatchClauseContext) return "catch_clause";
2915
+ if (node instanceof CondExpressionContext) return "ternary";
2916
+ if (node instanceof LogAndExpressionContext) return "short_circuit_and";
2917
+ if (node instanceof LogOrExpressionContext) return "short_circuit_or";
2918
+ return void 0;
2919
+ }
2920
+ function enclosingMethod(node) {
2921
+ let p = node.parentCtx;
2922
+ while (p) {
2923
+ if (p instanceof MethodDeclarationContext || p instanceof ConstructorDeclarationContext) {
2924
+ return p;
2925
+ }
2926
+ p = p.parentCtx;
2927
+ }
2928
+ return void 0;
2929
+ }
2930
+ function renderSignature(ctx, name) {
2931
+ const paramsText = renderFormalParameters(ctx.formalParameters());
2932
+ if (ctx instanceof MethodDeclarationContext) {
2933
+ const retType = ctx.typeRef()?.getText() ?? (ctx.VOID() ? "void" : "");
2934
+ return `${retType ? retType + " " : ""}${name}${paramsText}`;
2935
+ }
2936
+ return `${name}${paramsText}`;
2937
+ }
2938
+ function renderFormalParameters(params) {
2939
+ if (!params) return "()";
2940
+ const list = params.formalParameterList();
2941
+ if (!list) return "()";
2942
+ const parts = list.formalParameter_list().map((p) => {
2943
+ const type = p.typeRef()?.getText() ?? "";
2944
+ const id = p.id()?.getText() ?? "";
2945
+ return type && id ? `${type} ${id}` : type || id;
2946
+ });
2947
+ return `(${parts.join(", ")})`;
2948
+ }
2949
+ function methodsInCompilationUnit(cu) {
2950
+ const out = [];
2951
+ walkParseTree(cu, (node) => {
2952
+ if ((node instanceof MethodDeclarationContext || node instanceof ConstructorDeclarationContext) && node.block()) {
2953
+ out.push(node);
2954
+ }
2955
+ });
2956
+ return out;
2957
+ }
2958
+
2959
+ // src/analyzer/apex-resolve.ts
2960
+ import { stat } from "node:fs/promises";
2961
+ import { dirname, isAbsolute, join, resolve, sep } from "node:path";
2962
+ var APEX_SCHEME = /^apex:\/\/(.+)$/;
2963
+ function extractApexClassName(uri) {
2964
+ const m = APEX_SCHEME.exec(uri);
2965
+ if (!m) return void 0;
2966
+ const raw = m[1].trim();
2967
+ const dot = raw.lastIndexOf(".");
2968
+ return dot === -1 ? raw : raw.slice(dot + 1);
2969
+ }
2970
+ async function resolveApexClassPath(className, opts) {
2971
+ const candidates = [];
2972
+ if (opts.apexSourceOverride) {
2973
+ const override = isAbsolute(opts.apexSourceOverride) ? opts.apexSourceOverride : resolve(opts.apexSourceOverride);
2974
+ candidates.push(
2975
+ join(override, `${className}.cls`),
2976
+ join(override, "classes", `${className}.cls`)
2977
+ );
2978
+ }
2979
+ const stop = resolve(opts.sourceDirRoot);
2980
+ let dir = dirname(resolve(opts.agentFilePath));
2981
+ while (true) {
2982
+ candidates.push(join(dir, "classes", `${className}.cls`));
2983
+ if (dir === stop) break;
2984
+ const parent = dirname(dir);
2985
+ if (parent === dir) break;
2986
+ dir = parent;
2987
+ }
2988
+ for (const c of candidates) {
2989
+ const s = await stat(c).catch(() => {
2990
+ });
2991
+ if (s?.isFile()) return c;
2992
+ }
2993
+ return void 0;
2994
+ }
2995
+
2996
+ // src/analyzer/apex-analyze.ts
2997
+ async function analyzeReferencedApex(inputs) {
2998
+ const byPath = /* @__PURE__ */ new Map();
2999
+ const unresolved = /* @__PURE__ */ new Set();
3000
+ for (let i = 0; i < inputs.fileReports.length; i++) {
3001
+ const fr = inputs.fileReports[i];
3002
+ const agentAbs = inputs.agentAbsPaths[i];
3003
+ for (const decl of fr.declarations) {
3004
+ if (decl.targetKind !== "apex" || !decl.target) continue;
3005
+ const className = extractApexClassName(decl.target);
3006
+ if (!className) {
3007
+ unresolved.add(decl.target);
3008
+ continue;
3009
+ }
3010
+ const path = await resolveApexClassPath(className, {
3011
+ agentFilePath: agentAbs,
3012
+ apexSourceOverride: inputs.apexSourceOverride,
3013
+ sourceDirRoot: inputs.sourceDirRoot
3014
+ });
3015
+ if (!path) {
3016
+ unresolved.add(decl.target);
3017
+ continue;
3018
+ }
3019
+ const existing = byPath.get(path);
3020
+ if (existing) {
3021
+ if (!existing.referencedBy.includes(fr.path)) {
3022
+ existing.referencedBy.push(fr.path);
3023
+ }
3024
+ continue;
3025
+ }
3026
+ const report = await analyzeApexClass(path, className, [fr.path], inputs.sourceDirRoot);
3027
+ byPath.set(path, report);
3028
+ }
3029
+ }
3030
+ return {
3031
+ classes: [...byPath.values()].sort((a, b) => a.className.localeCompare(b.className)),
3032
+ unresolved: [...unresolved].sort()
3033
+ };
3034
+ }
3035
+ async function analyzeApexClass(absPath, className, referencedBy, sourceDirRoot) {
3036
+ const source = await readFile(absPath, "utf8");
3037
+ const cu = parseApexSource(source);
3038
+ const methodCtxs = methodsInCompilationUnit(cu);
3039
+ const methods = methodCtxs.map((m) => complexityOfMethod(m));
3040
+ const classComplexity = methods.reduce((acc, m) => acc + m.complexity, 0);
3041
+ return {
3042
+ classComplexity,
3043
+ className: className || basename(absPath, ".cls"),
3044
+ methods,
3045
+ parseErrors: [],
3046
+ path: relative(sourceDirRoot, absPath),
3047
+ referencedBy
3048
+ };
3049
+ }
3050
+
3051
+ // src/analyzer/complexity.ts
3052
+ var SHORT_CIRCUIT_OPS = /* @__PURE__ */ new Set(["and", "or"]);
3053
+ function complexityOf(body, scope, kind) {
3054
+ const contributors = [];
3055
+ for (const n of descendants(body)) {
3056
+ switch (n.type) {
3057
+ case "binary_expression": {
3058
+ const op = binaryOperator(n);
3059
+ if (op === "and") contributors.push({ kind: "short_circuit_and", location: locOf(n) });
3060
+ else if (op === "or") contributors.push({ kind: "short_circuit_or", location: locOf(n) });
3061
+ break;
3062
+ }
3063
+ case "elif_clause": {
3064
+ contributors.push({ kind: "elif_clause", location: locOf(n) });
3065
+ break;
3066
+ }
3067
+ case "if_statement": {
3068
+ contributors.push({ kind: "if_statement", location: locOf(n) });
3069
+ break;
3070
+ }
3071
+ case "ternary_expression": {
3072
+ contributors.push({ kind: "ternary_expression", location: locOf(n) });
3073
+ break;
3074
+ }
3075
+ }
3076
+ }
3077
+ return {
3078
+ complexity: 1 + contributors.length,
3079
+ contributors,
3080
+ kind,
3081
+ location: locOf(body),
3082
+ scope
3083
+ };
3084
+ }
3085
+ function binaryOperator(n) {
3086
+ for (const c of n.children) {
3087
+ if (!c.isNamed && SHORT_CIRCUIT_OPS.has(c.type)) return c.type;
3088
+ if (!c.isNamed && (c.type === "+" || c.type === "-" || c.type === "*" || c.type === "/")) return c.type;
3089
+ }
3090
+ return void 0;
3091
+ }
3092
+ function collectProcedures(scopeBody, scopeLabel) {
3093
+ const out = [];
3094
+ const before = findMappingEntry(scopeBody, "before_reasoning");
3095
+ if (before) out.push(complexityOf(before, scopeLabel, "before_reasoning"));
3096
+ const after = findMappingEntry(scopeBody, "after_reasoning");
3097
+ if (after) out.push(complexityOf(after, scopeLabel, "after_reasoning"));
3098
+ const reasoning = findMappingEntry(scopeBody, "reasoning");
3099
+ if (reasoning) {
3100
+ const instructions = findMappingEntry(reasoning, "instructions");
3101
+ if (instructions) {
3102
+ out.push(complexityOf(instructions, scopeLabel, "reasoning_instructions"));
3103
+ }
3104
+ }
3105
+ return out;
3106
+ }
3107
+ var PROCEDURE_SCOPES = /* @__PURE__ */ new Set(["start_agent", "subagent", "topic"]);
3108
+ function collectScopes(root) {
3109
+ const scopes = [];
3110
+ const topMapping = root.namedChildren.find((c) => c.type === "mapping") ?? root;
3111
+ for (const c of topMapping.namedChildren) {
3112
+ if (c.type !== "mapping_element") continue;
3113
+ const keyNode = c.childForFieldName("key") ?? c.namedChildren.find((n) => n.type === "key");
3114
+ if (!keyNode) continue;
3115
+ const h = keyHeader(keyNode);
3116
+ if (!h || !PROCEDURE_SCOPES.has(h.kind)) continue;
3117
+ const body = bodyOf(keyNode);
3118
+ if (!body) continue;
3119
+ scopes.push({ body, kind: h.kind, label: `${h.kind} ${h.label ?? ""}`.trim() });
3120
+ }
3121
+ return scopes;
3122
+ }
3123
+ function complexityForFile(root) {
3124
+ const procedures = [];
3125
+ for (const s of collectScopes(root)) {
3126
+ procedures.push(...collectProcedures(s.body, s.label));
3127
+ }
3128
+ const total = procedures.reduce((acc, p) => acc + p.complexity, 0);
3129
+ return { procedures, total };
3130
+ }
3131
+
3132
+ // src/analyzer/analyze.ts
3133
+ var NoMatchingBundlesError = class extends Error {
3134
+ constructor(requested, available) {
3135
+ super(
3136
+ `No agent bundle matched ${requested.map((n) => `'${n}'`).join(", ")}. Available: ${available.map((b) => formatBundleIdentity(b)).join(", ")}`
3137
+ );
3138
+ this.requested = requested;
3139
+ this.available = available;
3140
+ this.name = "NoMatchingBundlesError";
3141
+ }
3142
+ };
3143
+ function formatBundleIdentity(b) {
3144
+ if (b.developerName && b.developerName !== b.dirName) {
3145
+ return `${b.developerName} (dir: ${b.dirName})`;
3146
+ }
3147
+ return b.dirName;
3148
+ }
3149
+ async function analyzeSource(rootPathOrPaths, options = {}) {
3150
+ const rawRoots = Array.isArray(rootPathOrPaths) ? rootPathOrPaths : [rootPathOrPaths];
3151
+ if (rawRoots.length === 0) {
3152
+ throw new Error("analyzeSource requires at least one source path");
3153
+ }
3154
+ const absRoots = rawRoots.map((p) => resolve2(p));
3155
+ const reportBase = options.reportBase ? resolve2(options.reportBase) : absRoots.length === 1 ? absRoots[0] : longestCommonAncestor(absRoots);
3156
+ const allFiles = [];
3157
+ for (const root of absRoots) {
3158
+ const files = await findAgentFiles(root);
3159
+ for (const f of files) if (!allFiles.includes(f)) allFiles.push(f);
3160
+ }
3161
+ allFiles.sort();
3162
+ const filteredFiles = await filterByApiNames(allFiles, options.apiNames);
3163
+ const fileReports = [];
3164
+ for (const file of filteredFiles) {
3165
+ fileReports.push(await analyzeFile(file, reportBase));
3166
+ }
3167
+ const apex = await analyzeReferencedApex({
3168
+ agentAbsPaths: filteredFiles,
3169
+ apexSourceOverride: options.apexSourceOverride,
3170
+ fileReports,
3171
+ sourceDirRoot: reportBase
3172
+ });
3173
+ const report = {
3174
+ apexClasses: apex.classes,
3175
+ byTargetKind: tallyTargets(fileReports),
3176
+ files: fileReports,
3177
+ totalApexComplexity: apex.classes.reduce((acc, c) => acc + c.classComplexity, 0),
3178
+ totalComplexity: fileReports.reduce((acc, f) => acc + f.fileComplexity, 0),
3179
+ totalDeclarations: fileReports.reduce((acc, f) => acc + f.declarations.length, 0),
3180
+ totalReferences: fileReports.reduce((acc, f) => acc + f.references.length, 0),
3181
+ unresolvedApexTargets: apex.unresolved
3182
+ };
3183
+ return report;
3184
+ }
3185
+ async function analyzeFile(absPath, base) {
3186
+ const source = await readFile2(absPath, "utf8");
3187
+ const root = parseAgentSource(source);
3188
+ const cc = complexityForFile(root);
3189
+ const { procedures } = cc;
3190
+ const scopes = collectScopes(root);
3191
+ const declarations = [];
3192
+ const references = [];
3193
+ for (const s of scopes) {
3194
+ declarations.push(...collectDeclarations(s));
3195
+ references.push(...collectReferences(s));
3196
+ }
3197
+ return {
3198
+ declarations,
3199
+ fileComplexity: cc.total,
3200
+ parseErrors: [],
3201
+ // CST is error-tolerant; surface diagnostics in a later iteration.
3202
+ path: relative2(base, absPath),
3203
+ procedures,
3204
+ references
3205
+ };
3206
+ }
3207
+ async function findAgentFiles(root) {
3208
+ const s = await stat2(root).catch(() => {
3209
+ });
3210
+ if (!s) throw new Error(`source path does not exist: ${root}`);
3211
+ if (s.isFile()) return root.endsWith(".agent") ? [root] : [];
3212
+ const out = [];
3213
+ const visit = async (dir) => {
3214
+ const entries = await readdir(dir, { withFileTypes: true });
3215
+ for (const e of entries) {
3216
+ if (e.name.startsWith(".")) continue;
3217
+ if (e.name === "node_modules" || e.name === "vendor" || e.name === "lib") continue;
3218
+ const full = join2(dir, e.name);
3219
+ if (e.isDirectory()) await visit(full);
3220
+ else if (e.isFile() && e.name.endsWith(".agent")) out.push(full);
3221
+ }
3222
+ };
3223
+ await visit(root);
3224
+ out.sort();
3225
+ return out;
3226
+ }
3227
+ function tallyTargets(files) {
3228
+ const acc = {
3229
+ apex: 0,
3230
+ flow: 0,
3231
+ prompt: 0,
3232
+ unknown: 0,
3233
+ utils: 0
3234
+ };
3235
+ for (const f of files) for (const d of f.declarations) acc[d.targetKind]++;
3236
+ return acc;
3237
+ }
3238
+ async function filterByApiNames(files, apiNames) {
3239
+ if (!apiNames || apiNames.length === 0) return files;
3240
+ const wanted = new Set(apiNames);
3241
+ const matches = [];
3242
+ const unmatched = [];
3243
+ for (const file of files) {
3244
+ const dirName = basename2(dirname2(file));
3245
+ if (wanted.has(dirName)) {
3246
+ matches.push(file);
3247
+ } else {
3248
+ unmatched.push(file);
3249
+ }
3250
+ }
3251
+ if (matches.length === files.length || unmatched.length === 0) {
3252
+ return matches;
3253
+ }
3254
+ const identities = [];
3255
+ for (const file of unmatched) {
3256
+ const dirName = basename2(dirname2(file));
3257
+ const developerName = await readDeveloperName(file);
3258
+ identities.push({ developerName, dirName, path: file });
3259
+ if (developerName && wanted.has(developerName)) {
3260
+ matches.push(file);
3261
+ }
3262
+ }
3263
+ if (matches.length === 0) {
3264
+ const all = [];
3265
+ for (const file of files) {
3266
+ const existing = identities.find((i) => i.path === file);
3267
+ if (existing) {
3268
+ all.push(existing);
3269
+ } else {
3270
+ all.push({
3271
+ developerName: await readDeveloperName(file),
3272
+ dirName: basename2(dirname2(file)),
3273
+ path: file
3274
+ });
3275
+ }
3276
+ }
3277
+ all.sort((a, b) => a.dirName.localeCompare(b.dirName));
3278
+ throw new NoMatchingBundlesError(apiNames, all);
3279
+ }
3280
+ matches.sort();
3281
+ return matches;
3282
+ }
3283
+ async function readDeveloperName(file) {
3284
+ const source = await readFile2(file, "utf8");
3285
+ const root = parseAgentSource(source);
3286
+ return extractDeveloperName(root);
3287
+ }
3288
+ function longestCommonAncestor(paths) {
3289
+ if (paths.length === 0) return process.cwd();
3290
+ if (paths.length === 1) return paths[0];
3291
+ const split = paths.map((p) => p.split("/"));
3292
+ const minLen = Math.min(...split.map((s) => s.length));
3293
+ const common = [];
3294
+ for (let i = 0; i < minLen; i++) {
3295
+ const seg = split[0][i];
3296
+ if (split.every((s) => s[i] === seg)) common.push(seg);
3297
+ else break;
3298
+ }
3299
+ const joined = common.join("/") || "/";
3300
+ return joined;
3301
+ }
3302
+
3303
+ // src/analyzer/project.ts
3304
+ import { readFile as readFile3, stat as stat3 } from "node:fs/promises";
3305
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join3, resolve as resolve3 } from "node:path";
3306
+ async function discoverSfdxProject(startDir) {
3307
+ let dir = resolve3(startDir);
3308
+ while (true) {
3309
+ const candidate = join3(dir, "sfdx-project.json");
3310
+ const s = await stat3(candidate).catch(() => {
3311
+ });
3312
+ if (s?.isFile()) {
3313
+ return readProject(dir, candidate);
3314
+ }
3315
+ const parent = dirname3(dir);
3316
+ if (parent === dir) return void 0;
3317
+ dir = parent;
3318
+ }
3319
+ }
3320
+ async function readProject(root, jsonPath) {
3321
+ const raw = await readFile3(jsonPath, "utf8");
3322
+ let parsed;
3323
+ try {
3324
+ parsed = JSON.parse(raw);
3325
+ } catch (error) {
3326
+ throw new Error(
3327
+ `failed to parse ${jsonPath}: ${error.message}`
3328
+ );
3329
+ }
3330
+ const pkgs = extractPackageDirectories(parsed, root);
3331
+ return { packageDirectories: pkgs, root };
3332
+ }
3333
+ function extractPackageDirectories(parsed, root) {
3334
+ if (!parsed || typeof parsed !== "object") return [];
3335
+ const obj = parsed;
3336
+ if (!Array.isArray(obj.packageDirectories)) return [];
3337
+ const out = [];
3338
+ for (const entry of obj.packageDirectories) {
3339
+ if (!entry || typeof entry !== "object") continue;
3340
+ const pathField = entry.path;
3341
+ if (typeof pathField !== "string" || pathField.length === 0) continue;
3342
+ out.push(isAbsolute2(pathField) ? pathField : resolve3(root, pathField));
3343
+ }
3344
+ return out;
3345
+ }
3346
+
3347
+ // src/renderers/csv.ts
3348
+ function renderCsv(report) {
3349
+ const lines = [];
3350
+ lines.push(
3351
+ [
3352
+ "type",
3353
+ "file",
3354
+ "scope_or_class",
3355
+ "name",
3356
+ "complexity",
3357
+ "start_row",
3358
+ "start_col",
3359
+ "contributors"
3360
+ ].map((c) => csvCell(c)).join(",")
3361
+ );
3362
+ for (const f of report.files) {
3363
+ for (const p of f.procedures) {
3364
+ lines.push(
3365
+ [
3366
+ "agent_procedure",
3367
+ f.path,
3368
+ p.scope,
3369
+ p.kind,
3370
+ String(p.complexity),
3371
+ String(p.location.startRow),
3372
+ String(p.location.startCol),
3373
+ breakdownProc(p.contributors)
3374
+ ].map((c) => csvCell(c)).join(",")
3375
+ );
3376
+ }
3377
+ }
3378
+ for (const cls of report.apexClasses) {
3379
+ for (const m of cls.methods) {
3380
+ lines.push(
3381
+ [
3382
+ "apex_method",
3383
+ cls.path,
3384
+ cls.className,
3385
+ m.signature,
3386
+ String(m.complexity),
3387
+ String(m.location.startRow),
3388
+ String(m.location.startCol),
3389
+ breakdownApex(m.contributors)
3390
+ ].map((c) => csvCell(c)).join(",")
3391
+ );
3392
+ }
3393
+ }
3394
+ return lines.join("\n");
3395
+ }
3396
+ function csvCell(v) {
3397
+ return `"${v.replaceAll('"', '""')}"`;
3398
+ }
3399
+ function breakdownProc(contributors) {
3400
+ if (contributors.length === 0) return "base";
3401
+ const counts = {};
3402
+ for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;
3403
+ return Object.entries(counts).map(([k, n]) => `${k}=${n}`).join(";");
3404
+ }
3405
+ function breakdownApex(contributors) {
3406
+ if (contributors.length === 0) return "base";
3407
+ const counts = {};
3408
+ for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;
3409
+ return Object.entries(counts).map(([k, n]) => `${k}=${n}`).join(";");
3410
+ }
3411
+
3412
+ // src/renderers/markdown.ts
3413
+ var KIND_LABEL = {
3414
+ after_reasoning: "after_reasoning",
3415
+ available_when: "available_when",
3416
+ before_reasoning: "before_reasoning",
3417
+ other: "other",
3418
+ reasoning_instructions: "reasoning.instructions"
3419
+ };
3420
+ function renderMarkdown(report) {
3421
+ const lines = [];
3422
+ lines.push(
3423
+ "# AgentForce PMD \u2014 Cyclomatic Complexity (McCabe)",
3424
+ "",
3425
+ "Per the categorization rule \xA7 7, CC is reported by the standard McCabe convention used in SonarQube / PMD / Checkstyle for the relevant language.",
3426
+ ""
3427
+ );
3428
+ if (report.files.length === 0) {
3429
+ lines.push("_(no `.agent` files found)_");
3430
+ return lines.join("\n");
3431
+ }
3432
+ lines.push(
3433
+ "## CC by location",
3434
+ "",
3435
+ renderMermaid(report),
3436
+ "",
3437
+ `| | AgentScript | Apex | Combined |
3438
+ | --- | ---: | ---: | ---: |
3439
+ | **Totals** | ${report.totalComplexity} | ${report.totalApexComplexity} | ${report.totalComplexity + report.totalApexComplexity} |`,
3440
+ "",
3441
+ "## Per-bundle (`.agent` files)",
3442
+ ""
3443
+ );
3444
+ for (const f of report.files) {
3445
+ lines.push(`### \`${f.path}\` \u2014 CC = ${f.fileComplexity}`, "");
3446
+ if (f.procedures.length === 0) {
3447
+ lines.push("_(no procedure-bearing scopes)_");
3448
+ } else {
3449
+ lines.push("| Scope | Procedure | CC | Contributors |", "| --- | --- | ---: | --- |");
3450
+ for (const p of f.procedures) {
3451
+ lines.push(
3452
+ `| ${escapeCell(p.scope)} | ${KIND_LABEL[p.kind]} | ${p.complexity} | ${escapeCell(breakdownProc2(p.contributors))} |`
3453
+ );
3454
+ }
3455
+ }
3456
+ lines.push("");
3457
+ if (f.declarations.length > 0) {
3458
+ lines.push("**Action references**", "", "| Action | Target kind | Target | Uses |", "| --- | --- | --- | ---: |");
3459
+ const usage = countReferences(f);
3460
+ for (const d of f.declarations) {
3461
+ const used = usage.get(d.name) ?? 0;
3462
+ lines.push(
3463
+ `| \`${d.name}\` | ${d.targetKind} | ${d.target ?? "_n/a_"} | ${used} |`
3464
+ );
3465
+ }
3466
+ const undeclared = listUndeclaredRefs(f);
3467
+ if (undeclared.length > 0) {
3468
+ lines.push(
3469
+ "",
3470
+ "Referenced but not declared in-file: " + undeclared.map((u) => `\`${u}\``).join(", ")
3471
+ );
3472
+ }
3473
+ lines.push("");
3474
+ }
3475
+ }
3476
+ if (report.apexClasses.length > 0 || report.unresolvedApexTargets.length > 0) {
3477
+ lines.push("## Apex backing logic", "");
3478
+ for (const cls of report.apexClasses) {
3479
+ lines.push(
3480
+ `### \`${cls.path}\` \u2014 class CC = ${cls.classComplexity}`,
3481
+ "",
3482
+ `Referenced by: ${cls.referencedBy.map((r) => `\`${r}\``).join(", ") || "_none_"}`,
3483
+ ""
3484
+ );
3485
+ if (cls.methods.length === 0) {
3486
+ lines.push("_(no methods with bodies)_");
3487
+ } else {
3488
+ lines.push("| Method | CC | Contributors |", "| --- | ---: | --- |");
3489
+ for (const m of cls.methods) {
3490
+ lines.push(
3491
+ `| \`${escapeCell(m.signature)}\` | ${m.complexity} | ${escapeCell(breakdownApex2(m.contributors))} |`
3492
+ );
3493
+ }
3494
+ }
3495
+ lines.push("");
3496
+ }
3497
+ if (report.unresolvedApexTargets.length > 0) {
3498
+ lines.push("### Unresolved `apex://` targets", "");
3499
+ for (const u of report.unresolvedApexTargets) {
3500
+ lines.push(`- \`${u}\` \u2014 no matching \`.cls\` under \`--source-dir\` or \`--apex-source\``);
3501
+ }
3502
+ lines.push("");
3503
+ }
3504
+ }
3505
+ lines.push(
3506
+ "---",
3507
+ "",
3508
+ `Action declarations: **${report.totalDeclarations}** (apex ${report.byTargetKind.apex}, flow ${report.byTargetKind.flow}, prompt ${report.byTargetKind.prompt}, unknown ${report.byTargetKind.unknown}). Action references: **${report.totalReferences}**.`
3509
+ );
3510
+ return lines.join("\n");
3511
+ }
3512
+ function renderMermaid(report) {
3513
+ const apexByBundle = /* @__PURE__ */ new Map();
3514
+ for (const cls of report.apexClasses) {
3515
+ for (const ref of cls.referencedBy) {
3516
+ apexByBundle.set(ref, (apexByBundle.get(ref) ?? 0) + cls.classComplexity);
3517
+ }
3518
+ }
3519
+ const labels = [];
3520
+ const agentVals = [];
3521
+ const apexVals = [];
3522
+ for (const f of report.files) {
3523
+ labels.push(shortBundleLabel(f.path));
3524
+ agentVals.push(f.fileComplexity);
3525
+ apexVals.push(apexByBundle.get(f.path) ?? 0);
3526
+ }
3527
+ return [
3528
+ "```mermaid",
3529
+ '%%{init: {"theme":"base","themeVariables":{"xyChart":{"plotColorPalette":"#a82820, #6b8c52"}}}}%%',
3530
+ "xychart-beta",
3531
+ ' title "CC by location, per .agent bundle"',
3532
+ ` x-axis [${labels.map((l) => `"${l}"`).join(", ")}]`,
3533
+ ` y-axis "Cyclomatic complexity"`,
3534
+ ` bar [${agentVals.join(", ")}]`,
3535
+ ` bar [${apexVals.join(", ")}]`,
3536
+ "```",
3537
+ "",
3538
+ '<sub>Series: **AgentScript CC** (red, whitepaper "Reasoning Logic") \xB7 **Apex CC** (green, whitepaper "Deterministic Logic"). Apex CC per bundle is the sum of the CC of every `apex://` class that bundle references; classes referenced by multiple bundles contribute to each.</sub>'
3539
+ ].join("\n");
3540
+ }
3541
+ function shortBundleLabel(path) {
3542
+ const stripped = path.replace(/^.*aiAuthoringBundles\//, "").replace(/\.agent$/, "");
3543
+ const parts = stripped.split("/");
3544
+ if (parts.length === 2 && parts[0] === parts[1]) return parts[0];
3545
+ return parts.join("/");
3546
+ }
3547
+ function breakdownProc2(contributors) {
3548
+ if (contributors.length === 0) return "(base only)";
3549
+ const counts = {};
3550
+ for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;
3551
+ return Object.entries(counts).map(([k, n]) => `${shortKind(k)}=${n}`).join(" ");
3552
+ }
3553
+ function breakdownApex2(contributors) {
3554
+ if (contributors.length === 0) return "(base only)";
3555
+ const counts = {};
3556
+ for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;
3557
+ return Object.entries(counts).map(([k, n]) => `${shortApexKind(k)}=${n}`).join(" ");
3558
+ }
3559
+ function shortKind(k) {
3560
+ switch (k) {
3561
+ case "elif_clause": {
3562
+ return "elif";
3563
+ }
3564
+ case "if_statement": {
3565
+ return "if";
3566
+ }
3567
+ case "short_circuit_and": {
3568
+ return "and";
3569
+ }
3570
+ case "short_circuit_or": {
3571
+ return "or";
3572
+ }
3573
+ case "ternary_expression": {
3574
+ return "ternary";
3575
+ }
3576
+ default: {
3577
+ return k;
3578
+ }
3579
+ }
3580
+ }
3581
+ function shortApexKind(k) {
3582
+ switch (k) {
3583
+ case "catch_clause": {
3584
+ return "catch";
3585
+ }
3586
+ case "do_while_statement": {
3587
+ return "do-while";
3588
+ }
3589
+ case "for_statement": {
3590
+ return "for";
3591
+ }
3592
+ case "if_statement": {
3593
+ return "if";
3594
+ }
3595
+ case "short_circuit_and": {
3596
+ return "&&";
3597
+ }
3598
+ case "short_circuit_or": {
3599
+ return "||";
3600
+ }
3601
+ case "ternary": {
3602
+ return "ternary";
3603
+ }
3604
+ case "when_arm": {
3605
+ return "when";
3606
+ }
3607
+ case "while_statement": {
3608
+ return "while";
3609
+ }
3610
+ default: {
3611
+ return k;
3612
+ }
3613
+ }
3614
+ }
3615
+ function countReferences(f) {
3616
+ const m = /* @__PURE__ */ new Map();
3617
+ for (const r of f.references) m.set(r.name, (m.get(r.name) ?? 0) + 1);
3618
+ return m;
3619
+ }
3620
+ function listUndeclaredRefs(f) {
3621
+ const declared = new Set(f.declarations.map((d) => d.name));
3622
+ const seen = /* @__PURE__ */ new Set();
3623
+ const out = [];
3624
+ for (const r of f.references) {
3625
+ if (declared.has(r.name)) continue;
3626
+ if (seen.has(r.name)) continue;
3627
+ seen.add(r.name);
3628
+ out.push(r.name);
3629
+ }
3630
+ return out;
3631
+ }
3632
+ function escapeCell(s) {
3633
+ return s.replaceAll("|", String.raw`\|`).replaceAll("\n", "<br>");
3634
+ }
3635
+
3636
+ // src/renderers/sarif.ts
3637
+ var DEFAULT_WARNING = 10;
3638
+ var DEFAULT_ERROR = 20;
3639
+ var RULE_AGENT_CC = {
3640
+ defaultConfiguration: { level: "note" },
3641
+ fullDescription: {
3642
+ text: "Reports cyclomatic complexity (McCabe) of an AgentScript before_reasoning, after_reasoning, or reasoning.instructions block. Computed as 1 + count(if) + count(elif) + count(ternary) + count(and) + count(or)."
3643
+ },
3644
+ helpUri: "https://github.com/bobbywhitesfdc/sf-agentpmd/blob/main/docs/agent-loc-categorization-skill-v2.md#-7--cyclomatic-complexity",
3645
+ id: "AGENTPMD.AgentScriptCyclomaticComplexity",
3646
+ name: "AgentScriptCyclomaticComplexity",
3647
+ shortDescription: {
3648
+ text: "McCabe cyclomatic complexity of an AgentScript procedure."
3649
+ }
3650
+ };
3651
+ var RULE_APEX_CC = {
3652
+ defaultConfiguration: { level: "note" },
3653
+ fullDescription: {
3654
+ text: "Reports cyclomatic complexity (McCabe) of an Apex method or constructor body, mirroring SonarQube / PMD CyclomaticComplexity."
3655
+ },
3656
+ helpUri: "https://github.com/bobbywhitesfdc/sf-agentpmd/blob/main/docs/agent-loc-categorization-skill-v2.md#-7--cyclomatic-complexity",
3657
+ id: "AGENTPMD.ApexCyclomaticComplexity",
3658
+ name: "ApexCyclomaticComplexity",
3659
+ shortDescription: {
3660
+ text: "McCabe cyclomatic complexity of an Apex method or constructor."
3661
+ }
3662
+ };
3663
+ function renderSarif(report, opts) {
3664
+ const warn = opts?.sarifWarningThreshold ?? DEFAULT_WARNING;
3665
+ const err = opts?.sarifErrorThreshold ?? DEFAULT_ERROR;
3666
+ const results = [];
3667
+ for (const f of report.files) {
3668
+ for (const p of f.procedures) {
3669
+ results.push(buildAgentResult(f, p, warn, err));
3670
+ }
3671
+ }
3672
+ for (const cls of report.apexClasses) {
3673
+ for (const m of cls.methods) {
3674
+ results.push(buildApexResult(cls, m, warn, err));
3675
+ }
3676
+ }
3677
+ const log = {
3678
+ $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
3679
+ runs: [
3680
+ {
3681
+ results,
3682
+ tool: {
3683
+ driver: {
3684
+ informationUri: "https://github.com/bobbywhitesfdc/sf-agentpmd",
3685
+ name: "sf-agentpmd",
3686
+ rules: [RULE_AGENT_CC, RULE_APEX_CC],
3687
+ semanticVersion: pluginVersion()
3688
+ }
3689
+ }
3690
+ }
3691
+ ],
3692
+ version: "2.1.0"
3693
+ };
3694
+ return JSON.stringify(log, null, 2);
3695
+ }
3696
+ function buildAgentResult(f, p, warn, err) {
3697
+ return {
3698
+ level: levelFor(p.complexity, warn, err),
3699
+ locations: [
3700
+ {
3701
+ physicalLocation: {
3702
+ artifactLocation: { uri: f.path },
3703
+ // AgentScript CST locations are 0-based — bump to SARIF 1-based.
3704
+ region: regionFromZeroBased(p.location)
3705
+ }
3706
+ }
3707
+ ],
3708
+ message: {
3709
+ text: `Procedure '${p.kind}' in '${p.scope}' has cyclomatic complexity ${p.complexity}.`
3710
+ },
3711
+ properties: { complexity: p.complexity, kind: p.kind },
3712
+ ruleId: RULE_AGENT_CC.id
3713
+ };
3714
+ }
3715
+ function buildApexResult(cls, m, warn, err) {
3716
+ return {
3717
+ level: levelFor(m.complexity, warn, err),
3718
+ locations: [
3719
+ {
3720
+ physicalLocation: {
3721
+ artifactLocation: { uri: cls.path },
3722
+ // ANTLR token positions are 1-based for line, 0-based for column;
3723
+ // SARIF wants 1-based for both.
3724
+ region: regionFromAntlr(m.location)
3725
+ }
3726
+ }
3727
+ ],
3728
+ message: {
3729
+ text: `${m.kind} '${m.name}' has cyclomatic complexity ${m.complexity}.`
3730
+ },
3731
+ properties: { complexity: m.complexity, kind: m.kind },
3732
+ ruleId: RULE_APEX_CC.id
3733
+ };
3734
+ }
3735
+ function levelFor(cc, warn, err) {
3736
+ if (cc >= err) return "error";
3737
+ if (cc >= warn) return "warning";
3738
+ return "note";
3739
+ }
3740
+ function regionFromZeroBased(loc) {
3741
+ return {
3742
+ endColumn: loc.endCol + 1,
3743
+ endLine: loc.endRow + 1,
3744
+ startColumn: loc.startCol + 1,
3745
+ startLine: loc.startRow + 1
3746
+ };
3747
+ }
3748
+ function regionFromAntlr(loc) {
3749
+ return {
3750
+ endColumn: loc.endCol + 1,
3751
+ endLine: Math.max(1, loc.endRow),
3752
+ startColumn: loc.startCol + 1,
3753
+ startLine: Math.max(1, loc.startRow)
3754
+ };
3755
+ }
3756
+ function pluginVersion() {
3757
+ return "0.1.1";
3758
+ }
3759
+
3760
+ // src/renderers/text.ts
3761
+ import pc from "picocolors";
3762
+ var KIND_LABEL2 = {
3763
+ after_reasoning: "after_reasoning",
3764
+ available_when: "available_when",
3765
+ before_reasoning: "before_reasoning",
3766
+ other: "other",
3767
+ reasoning_instructions: "reasoning.instructions"
3768
+ };
3769
+ var UNICODE_GLYPHS = {
3770
+ agentFile: "\u{1F4C4}",
3771
+ apexFile: "\u{1F4DC}",
3772
+ ruleHeavy: "\u2550",
3773
+ ruleLight: "\u2500"
3774
+ };
3775
+ var ASCII_GLYPHS = {
3776
+ agentFile: "[agent]",
3777
+ apexFile: "[apex] ",
3778
+ ruleHeavy: "=",
3779
+ ruleLight: "-"
3780
+ };
3781
+ function resolveOptions(opts) {
3782
+ const stdoutIsTty = Boolean(process.stdout.isTTY);
3783
+ const noColorEnv = Boolean(process.env.NO_COLOR);
3784
+ return {
3785
+ ascii: opts?.ascii ?? !stdoutIsTty,
3786
+ color: opts?.color ?? (stdoutIsTty && !noColorEnv),
3787
+ width: opts?.width ?? 60
3788
+ };
3789
+ }
3790
+ function renderText(report, opts) {
3791
+ const r = resolveOptions(opts);
3792
+ const g = r.ascii ? ASCII_GLYPHS : UNICODE_GLYPHS;
3793
+ const c = colorize(r.color);
3794
+ const lines = [];
3795
+ lines.push(
3796
+ c.title("AgentForce PMD \u2014 Cyclomatic Complexity (McCabe)"),
3797
+ g.ruleHeavy.repeat(r.width)
3798
+ );
3799
+ if (report.files.length === 0) {
3800
+ lines.push(" (no .agent files found)");
3801
+ return lines.join("\n");
3802
+ }
3803
+ for (const f of report.files) {
3804
+ lines.push(
3805
+ "",
3806
+ `${g.agentFile} ${c.path(f.path)} CC=${c.cc(f.fileComplexity)}`,
3807
+ g.ruleLight.repeat(r.width)
3808
+ );
3809
+ if (f.procedures.length === 0) {
3810
+ lines.push(" (no procedure-bearing scopes)");
3811
+ } else {
3812
+ const scopes = groupByScope(f.procedures);
3813
+ for (const [scope, procs] of scopes) {
3814
+ const scopeTotal = procs.reduce((a, p) => a + p.complexity, 0);
3815
+ lines.push(` ${c.scope(scope)} subtotal CC=${c.cc(scopeTotal)}`);
3816
+ for (const p of procs) {
3817
+ lines.push(
3818
+ ` ${pad(KIND_LABEL2[p.kind], 24)} CC=${c.cc(p.complexity)} ` + c.breakdown(breakdownProc3(p))
3819
+ );
3820
+ }
3821
+ }
3822
+ }
3823
+ if (f.declarations.length > 0 || f.references.length > 0) {
3824
+ lines.push(
3825
+ "",
3826
+ " Action references",
3827
+ " " + g.ruleLight.repeat(Math.max(0, r.width - 2))
3828
+ );
3829
+ const usage = countReferences2(f);
3830
+ for (const d of f.declarations) {
3831
+ const used = usage.get(d.name) ?? 0;
3832
+ const tgt = d.target ?? "(no target)";
3833
+ lines.push(
3834
+ ` ${pad(d.name, 32)} [${pad(d.targetKind, 6)}] used ${used}x \u2192 ${tgt}`
3835
+ );
3836
+ }
3837
+ const undeclared = listUndeclaredRefs2(f);
3838
+ if (undeclared.length > 0) {
3839
+ lines.push("", " Referenced but not declared in-file:");
3840
+ for (const u of undeclared) {
3841
+ lines.push(` ${u}`);
3842
+ }
3843
+ }
3844
+ }
3845
+ }
3846
+ if (report.apexClasses.length > 0 || report.unresolvedApexTargets.length > 0) {
3847
+ lines.push(
3848
+ "",
3849
+ c.title("Apex backing logic (resolved via apex:// targets)"),
3850
+ g.ruleHeavy.repeat(r.width)
3851
+ );
3852
+ for (const cls of report.apexClasses) {
3853
+ lines.push(
3854
+ "",
3855
+ `${g.apexFile} ${c.path(cls.path)} class CC=${c.cc(cls.classComplexity)}`,
3856
+ ` referenced by: ${cls.referencedBy.join(", ") || "(none)"}`,
3857
+ g.ruleLight.repeat(r.width)
3858
+ );
3859
+ if (cls.methods.length === 0) {
3860
+ lines.push(" (no methods with bodies)");
3861
+ } else {
3862
+ for (const m of cls.methods) {
3863
+ lines.push(
3864
+ ` ${pad(m.signature, 44)} CC=${c.cc(m.complexity)} ${c.breakdown(breakdownApex3(m.contributors))}`
3865
+ );
3866
+ }
3867
+ }
3868
+ }
3869
+ if (report.unresolvedApexTargets.length > 0) {
3870
+ lines.push("", "Unresolved apex:// targets:");
3871
+ for (const u of report.unresolvedApexTargets) {
3872
+ lines.push(
3873
+ ` - ${u} (no matching .cls under source-dir or --apex-source)`
3874
+ );
3875
+ }
3876
+ }
3877
+ }
3878
+ lines.push(
3879
+ "",
3880
+ g.ruleHeavy.repeat(r.width),
3881
+ c.title("CC by location (whitepaper \xA7 7)"),
3882
+ ` AgentScript: ${c.cc(report.totalComplexity)} Apex: ${c.cc(report.totalApexComplexity)} Combined: ${c.cc(report.totalComplexity + report.totalApexComplexity)}`,
3883
+ `Action declarations: ${report.totalDeclarations} (apex ${report.byTargetKind.apex}, flow ${report.byTargetKind.flow}, prompt ${report.byTargetKind.prompt}, unknown ${report.byTargetKind.unknown})`,
3884
+ `Action references: ${report.totalReferences}`
3885
+ );
3886
+ return lines.join("\n");
3887
+ }
3888
+ function colorize(on) {
3889
+ if (!on) {
3890
+ return {
3891
+ breakdown: (s) => s,
3892
+ cc: String,
3893
+ path: (s) => s,
3894
+ scope: (s) => s,
3895
+ title: (s) => s
3896
+ };
3897
+ }
3898
+ return {
3899
+ breakdown: pc.gray,
3900
+ cc(n) {
3901
+ const s = String(n);
3902
+ if (n >= 20) return pc.red(s);
3903
+ if (n >= 10) return pc.yellow(s);
3904
+ if (n >= 5) return pc.green(s);
3905
+ return pc.gray(s);
3906
+ },
3907
+ path: pc.cyan,
3908
+ scope: pc.bold,
3909
+ title: pc.bold
3910
+ };
3911
+ }
3912
+ function breakdownProc3(p) {
3913
+ if (p.contributors.length === 0) return "(base only)";
3914
+ const counts = {};
3915
+ for (const c of p.contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;
3916
+ return Object.entries(counts).map(([k, n]) => `${shortKind2(k)}=${n}`).join(" ");
3917
+ }
3918
+ function breakdownApex3(contributors) {
3919
+ if (contributors.length === 0) return "(base only)";
3920
+ const counts = {};
3921
+ for (const c of contributors) counts[c.kind] = (counts[c.kind] ?? 0) + 1;
3922
+ return Object.entries(counts).map(([k, n]) => `${shortApexKind2(k)}=${n}`).join(" ");
3923
+ }
3924
+ function shortKind2(k) {
3925
+ switch (k) {
3926
+ case "elif_clause": {
3927
+ return "elif";
3928
+ }
3929
+ case "if_statement": {
3930
+ return "if";
3931
+ }
3932
+ case "short_circuit_and": {
3933
+ return "and";
3934
+ }
3935
+ case "short_circuit_or": {
3936
+ return "or";
3937
+ }
3938
+ case "ternary_expression": {
3939
+ return "ternary";
3940
+ }
3941
+ default: {
3942
+ return k;
3943
+ }
3944
+ }
3945
+ }
3946
+ function shortApexKind2(k) {
3947
+ switch (k) {
3948
+ case "catch_clause": {
3949
+ return "catch";
3950
+ }
3951
+ case "do_while_statement": {
3952
+ return "do-while";
3953
+ }
3954
+ case "for_statement": {
3955
+ return "for";
3956
+ }
3957
+ case "if_statement": {
3958
+ return "if";
3959
+ }
3960
+ case "short_circuit_and": {
3961
+ return "&&";
3962
+ }
3963
+ case "short_circuit_or": {
3964
+ return "||";
3965
+ }
3966
+ case "ternary": {
3967
+ return "ternary";
3968
+ }
3969
+ case "when_arm": {
3970
+ return "when";
3971
+ }
3972
+ case "while_statement": {
3973
+ return "while";
3974
+ }
3975
+ default: {
3976
+ return k;
3977
+ }
3978
+ }
3979
+ }
3980
+ function groupByScope(procs) {
3981
+ const m = /* @__PURE__ */ new Map();
3982
+ for (const p of procs) {
3983
+ let arr = m.get(p.scope);
3984
+ if (!arr) {
3985
+ arr = [];
3986
+ m.set(p.scope, arr);
3987
+ }
3988
+ arr.push(p);
3989
+ }
3990
+ return m;
3991
+ }
3992
+ function pad(s, n) {
3993
+ if (s.length >= n) return s;
3994
+ return s + " ".repeat(n - s.length);
3995
+ }
3996
+ function countReferences2(f) {
3997
+ const m = /* @__PURE__ */ new Map();
3998
+ for (const r of f.references) m.set(r.name, (m.get(r.name) ?? 0) + 1);
3999
+ return m;
4000
+ }
4001
+ function listUndeclaredRefs2(f) {
4002
+ const declared = new Set(f.declarations.map((d) => d.name));
4003
+ const seen = /* @__PURE__ */ new Set();
4004
+ const out = [];
4005
+ for (const r of f.references) {
4006
+ if (declared.has(r.name)) continue;
4007
+ if (seen.has(r.name)) continue;
4008
+ seen.add(r.name);
4009
+ out.push(r.name);
4010
+ }
4011
+ return out;
4012
+ }
4013
+
4014
+ // src/renderers/index.ts
4015
+ function render(format, report, options) {
4016
+ switch (format) {
4017
+ case "csv": {
4018
+ return renderCsv(report);
4019
+ }
4020
+ case "markdown": {
4021
+ return renderMarkdown(report);
4022
+ }
4023
+ case "sarif": {
4024
+ return renderSarif(report, options);
4025
+ }
4026
+ case "text": {
4027
+ return renderText(report, options);
4028
+ }
4029
+ }
4030
+ }
4031
+
4032
+ // src/commands/agentpmd/analyze.ts
4033
+ var FORMATS = ["text", "markdown", "sarif", "csv"];
4034
+ var AgentpmdAnalyze = class _AgentpmdAnalyze extends SfCommand {
4035
+ static description = `Walks .agent source files under --source-dir and emits per-procedure
8
4036
  cyclomatic complexity totals (before_reasoning, after_reasoning, and
9
4037
  reasoning.instructions blocks), plus an inventory of declared and used
10
4038
  @actions.X targets. For every apex:// target, resolves the .cls file
@@ -14,109 +4042,113 @@ Default output is human-readable text. --json emits the SF CLI envelope
14
4042
  with the full structured report. --format <markdown|sarif|csv> emits the
15
4043
  named format on stdout for piping into PR comments, GitHub Code Scanning,
16
4044
  or spreadsheet pivots.`;
17
- static examples = [
18
- '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default',
19
- '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --json',
20
- '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --format markdown > report.md',
21
- '<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --format sarif > report.sarif',
22
- ];
23
- static flags = {
24
- 'apex-source': Flags.string({
25
- summary: 'Override directory to look up apex:// targets. By default we walk up from each .agent file looking for a sibling classes/ folder.',
26
- }),
27
- 'api-name': Flags.string({
28
- char: 'n',
29
- multiple: true,
30
- summary: 'Filter to specific agent bundles. Matched against the bundle directory name and the config.developer_name field. Repeatable.',
31
- }),
32
- ascii: Flags.boolean({
33
- default: false,
34
- summary: 'Force ASCII-only output in the text renderer (no Unicode box chars, no emoji).',
35
- }),
36
- 'fail-on': Flags.integer({
37
- min: 1,
38
- summary: 'Exit non-zero if combined agent+Apex CC meets or exceeds this threshold.',
39
- }),
40
- format: Flags.string({
41
- default: 'text',
42
- options: [...FORMATS],
43
- summary: 'Non-JSON output format. --json takes precedence per SF CLI convention.',
44
- }),
45
- 'no-color': Flags.boolean({
46
- default: false,
47
- summary: 'Disable ANSI color in the text renderer. NO_COLOR env also disables.',
48
- }),
49
- 'sarif-error': Flags.integer({
50
- min: 1,
51
- summary: 'SARIF "error" level threshold. Default 20.',
52
- }),
53
- 'sarif-warning': Flags.integer({
54
- min: 1,
55
- summary: 'SARIF "warning" level threshold. Default 10.',
56
- }),
57
- 'source-dir': Flags.string({
58
- char: 'd',
59
- summary: 'Directory or single .agent file to analyze. Defaults to the packageDirectories of the nearest sfdx-project.json.',
60
- }),
61
- width: Flags.integer({
62
- default: 60,
63
- min: 20,
64
- summary: 'Rule width for the text renderer.',
65
- }),
66
- };
67
- static summary = 'Compute McCabe cyclomatic complexity and action-reference inventory for AgentScript bundles and their Apex backing logic.';
68
- async run() {
69
- const { flags } = await this.parse(AgentpmdAnalyze);
70
- const { reportBase, roots, sourceDescription } = await resolveSources(flags['source-dir']);
71
- if (!this.jsonEnabled() && sourceDescription) {
72
- this.log(sourceDescription);
73
- }
74
- const report = await analyzeSource(roots, {
75
- apexSourceOverride: flags['apex-source'],
76
- apiNames: flags['api-name'],
77
- reportBase,
78
- });
79
- if (!this.jsonEnabled()) {
80
- const format = flags.format;
81
- const text = render(format, report, {
82
- ascii: flags.ascii || undefined,
83
- color: flags['no-color'] ? false : undefined,
84
- sarifErrorThreshold: flags['sarif-error'],
85
- sarifWarningThreshold: flags['sarif-warning'],
86
- width: flags.width,
87
- });
88
- this.log(text);
89
- }
90
- const combined = report.totalComplexity + report.totalApexComplexity;
91
- if (flags['fail-on'] !== undefined && combined >= flags['fail-on']) {
92
- this.error(`Combined cyclomatic complexity ${combined} (agent ${report.totalComplexity} + apex ${report.totalApexComplexity}) ≥ threshold ${flags['fail-on']}`, { exit: 2 });
93
- }
94
- return report;
95
- }
96
- }
97
- /**
98
- * Resolve the directories we should scan. Explicit `--source-dir` wins.
99
- * Otherwise, walk up from cwd looking for `sfdx-project.json` and use its
100
- * `packageDirectories`. If neither is available, fail with a clear message.
101
- */
102
- async function resolveSources(sourceDirFlag) {
103
- if (sourceDirFlag) {
104
- return { reportBase: undefined, roots: [sourceDirFlag] };
4045
+ static examples = [
4046
+ "<%= config.bin %> <%= command.id %> --source-dir force-app/main/default",
4047
+ "<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --json",
4048
+ "<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --format markdown > report.md",
4049
+ "<%= config.bin %> <%= command.id %> --source-dir force-app/main/default --format sarif > report.sarif"
4050
+ ];
4051
+ static flags = {
4052
+ "apex-source": Flags.string({
4053
+ summary: "Override directory to look up apex:// targets. By default we walk up from each .agent file looking for a sibling classes/ folder."
4054
+ }),
4055
+ "api-name": Flags.string({
4056
+ char: "n",
4057
+ multiple: true,
4058
+ summary: "Filter to specific agent bundles. Matched against the bundle directory name and the config.developer_name field. Repeatable."
4059
+ }),
4060
+ ascii: Flags.boolean({
4061
+ default: false,
4062
+ summary: "Force ASCII-only output in the text renderer (no Unicode box chars, no emoji)."
4063
+ }),
4064
+ "fail-on": Flags.integer({
4065
+ min: 1,
4066
+ summary: "Exit non-zero if combined agent+Apex CC meets or exceeds this threshold."
4067
+ }),
4068
+ format: Flags.string({
4069
+ default: "text",
4070
+ options: [...FORMATS],
4071
+ summary: "Non-JSON output format. --json takes precedence per SF CLI convention."
4072
+ }),
4073
+ "no-color": Flags.boolean({
4074
+ default: false,
4075
+ summary: "Disable ANSI color in the text renderer. NO_COLOR env also disables."
4076
+ }),
4077
+ "sarif-error": Flags.integer({
4078
+ min: 1,
4079
+ summary: 'SARIF "error" level threshold. Default 20.'
4080
+ }),
4081
+ "sarif-warning": Flags.integer({
4082
+ min: 1,
4083
+ summary: 'SARIF "warning" level threshold. Default 10.'
4084
+ }),
4085
+ "source-dir": Flags.string({
4086
+ char: "d",
4087
+ summary: "Directory or single .agent file to analyze. Defaults to the packageDirectories of the nearest sfdx-project.json."
4088
+ }),
4089
+ width: Flags.integer({
4090
+ default: 60,
4091
+ min: 20,
4092
+ summary: "Rule width for the text renderer."
4093
+ })
4094
+ };
4095
+ static summary = "Compute McCabe cyclomatic complexity and action-reference inventory for AgentScript bundles and their Apex backing logic.";
4096
+ async run() {
4097
+ const { flags } = await this.parse(_AgentpmdAnalyze);
4098
+ const { reportBase, roots, sourceDescription } = await resolveSources(
4099
+ flags["source-dir"]
4100
+ );
4101
+ if (!this.jsonEnabled() && sourceDescription) {
4102
+ this.log(sourceDescription);
105
4103
  }
106
- const project = await discoverSfdxProject(process.cwd());
107
- if (!project) {
108
- throw new Error('No --source-dir was provided and no sfdx-project.json was found in the ' +
109
- 'current directory or any ancestor. Pass --source-dir <path> or run from ' +
110
- 'inside an sfdx project.');
4104
+ const report = await analyzeSource(roots, {
4105
+ apexSourceOverride: flags["apex-source"],
4106
+ apiNames: flags["api-name"],
4107
+ reportBase
4108
+ });
4109
+ if (!this.jsonEnabled()) {
4110
+ const format = flags.format;
4111
+ const text = render(format, report, {
4112
+ ascii: flags.ascii || void 0,
4113
+ color: flags["no-color"] ? false : void 0,
4114
+ sarifErrorThreshold: flags["sarif-error"],
4115
+ sarifWarningThreshold: flags["sarif-warning"],
4116
+ width: flags.width
4117
+ });
4118
+ this.log(text);
111
4119
  }
112
- if (project.packageDirectories.length === 0) {
113
- throw new Error(`sfdx-project.json at ${project.root} declares no packageDirectories. ` +
114
- 'Pass --source-dir <path> explicitly.');
4120
+ const combined = report.totalComplexity + report.totalApexComplexity;
4121
+ if (flags["fail-on"] !== void 0 && combined >= flags["fail-on"]) {
4122
+ this.error(
4123
+ `Combined cyclomatic complexity ${combined} (agent ${report.totalComplexity} + apex ${report.totalApexComplexity}) \u2265 threshold ${flags["fail-on"]}`,
4124
+ { exit: 2 }
4125
+ );
115
4126
  }
116
- return {
117
- reportBase: project.root,
118
- roots: project.packageDirectories,
119
- sourceDescription: `Analyzing sfdx project ${project.root} (${project.packageDirectories.length} package director${project.packageDirectories.length === 1 ? 'y' : 'ies'}).`,
120
- };
4127
+ return report;
4128
+ }
4129
+ };
4130
+ async function resolveSources(sourceDirFlag) {
4131
+ if (sourceDirFlag) {
4132
+ return { reportBase: void 0, roots: [sourceDirFlag] };
4133
+ }
4134
+ const project = await discoverSfdxProject(process.cwd());
4135
+ if (!project) {
4136
+ throw new Error(
4137
+ "No --source-dir was provided and no sfdx-project.json was found in the current directory or any ancestor. Pass --source-dir <path> or run from inside an sfdx project."
4138
+ );
4139
+ }
4140
+ if (project.packageDirectories.length === 0) {
4141
+ throw new Error(
4142
+ `sfdx-project.json at ${project.root} declares no packageDirectories. Pass --source-dir <path> explicitly.`
4143
+ );
4144
+ }
4145
+ return {
4146
+ reportBase: project.root,
4147
+ roots: project.packageDirectories,
4148
+ sourceDescription: `Analyzing sfdx project ${project.root} (${project.packageDirectories.length} package director${project.packageDirectories.length === 1 ? "y" : "ies"}).`
4149
+ };
121
4150
  }
122
- //# sourceMappingURL=analyze.js.map
4151
+ export {
4152
+ AgentpmdAnalyze as default
4153
+ };
4154
+ //# sourceMappingURL=analyze.js.map