sf-agentpmd 0.1.0

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 (109) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +26 -0
  3. package/README.md +204 -0
  4. package/bin/dev.js +5 -0
  5. package/bin/run.js +3 -0
  6. package/dist/analyzer/action-references.d.ts +21 -0
  7. package/dist/analyzer/action-references.js +130 -0
  8. package/dist/analyzer/action-references.js.map +1 -0
  9. package/dist/analyzer/analyze.d.ts +43 -0
  10. package/dist/analyzer/analyze.js +222 -0
  11. package/dist/analyzer/analyze.js.map +1 -0
  12. package/dist/analyzer/apex-analyze.d.ts +14 -0
  13. package/dist/analyzer/apex-analyze.js +60 -0
  14. package/dist/analyzer/apex-analyze.js.map +1 -0
  15. package/dist/analyzer/apex-complexity.d.ts +27 -0
  16. package/dist/analyzer/apex-complexity.js +133 -0
  17. package/dist/analyzer/apex-complexity.js.map +1 -0
  18. package/dist/analyzer/apex-parse.d.ts +39 -0
  19. package/dist/analyzer/apex-parse.js +32 -0
  20. package/dist/analyzer/apex-parse.js.map +1 -0
  21. package/dist/analyzer/apex-resolve.d.ts +32 -0
  22. package/dist/analyzer/apex-resolve.js +59 -0
  23. package/dist/analyzer/apex-resolve.js.map +1 -0
  24. package/dist/analyzer/complexity.d.ts +30 -0
  25. package/dist/analyzer/complexity.js +126 -0
  26. package/dist/analyzer/complexity.js.map +1 -0
  27. package/dist/analyzer/parse.d.ts +51 -0
  28. package/dist/analyzer/parse.js +143 -0
  29. package/dist/analyzer/parse.js.map +1 -0
  30. package/dist/analyzer/project.d.ts +12 -0
  31. package/dist/analyzer/project.js +51 -0
  32. package/dist/analyzer/project.js.map +1 -0
  33. package/dist/analyzer/types.d.ts +76 -0
  34. package/dist/analyzer/types.js +2 -0
  35. package/dist/analyzer/types.js.map +1 -0
  36. package/dist/commands/agentpmd/analyze.d.ts +20 -0
  37. package/dist/commands/agentpmd/analyze.js +122 -0
  38. package/dist/commands/agentpmd/analyze.js.map +1 -0
  39. package/dist/commands/agentpmd/install-skill.d.ts +11 -0
  40. package/dist/commands/agentpmd/install-skill.js +33 -0
  41. package/dist/commands/agentpmd/install-skill.js.map +1 -0
  42. package/dist/index.d.ts +3 -0
  43. package/dist/index.js +3 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/renderers/csv.d.ts +6 -0
  46. package/dist/renderers/csv.js +78 -0
  47. package/dist/renderers/csv.js.map +1 -0
  48. package/dist/renderers/index.d.ts +8 -0
  49. package/dist/renderers/index.js +25 -0
  50. package/dist/renderers/index.js.map +1 -0
  51. package/dist/renderers/markdown.d.ts +12 -0
  52. package/dist/renderers/markdown.js +233 -0
  53. package/dist/renderers/markdown.js.map +1 -0
  54. package/dist/renderers/options.d.ts +20 -0
  55. package/dist/renderers/options.js +2 -0
  56. package/dist/renderers/options.js.map +1 -0
  57. package/dist/renderers/sarif.d.ts +3 -0
  58. package/dist/renderers/sarif.js +131 -0
  59. package/dist/renderers/sarif.js.map +1 -0
  60. package/dist/renderers/text.d.ts +3 -0
  61. package/dist/renderers/text.js +243 -0
  62. package/dist/renderers/text.js.map +1 -0
  63. package/oclif.manifest.json +168 -0
  64. package/package.json +97 -0
  65. package/skill/SKILL.md +103 -0
  66. package/skill/references/command-structure.md +89 -0
  67. package/skill/references/install.md +112 -0
  68. package/skill/references/output-formats.md +205 -0
  69. package/skill/references/upgrade.md +112 -0
  70. package/vendor/agentscript-parser-javascript/dist/cst-node.d.ts +83 -0
  71. package/vendor/agentscript-parser-javascript/dist/cst-node.js +238 -0
  72. package/vendor/agentscript-parser-javascript/dist/errors.d.ts +34 -0
  73. package/vendor/agentscript-parser-javascript/dist/errors.js +74 -0
  74. package/vendor/agentscript-parser-javascript/dist/expressions.d.ts +36 -0
  75. package/vendor/agentscript-parser-javascript/dist/expressions.js +682 -0
  76. package/vendor/agentscript-parser-javascript/dist/highlighter.d.ts +24 -0
  77. package/vendor/agentscript-parser-javascript/dist/highlighter.js +260 -0
  78. package/vendor/agentscript-parser-javascript/dist/index.d.ts +29 -0
  79. package/vendor/agentscript-parser-javascript/dist/index.js +35 -0
  80. package/vendor/agentscript-parser-javascript/dist/lexer.d.ts +60 -0
  81. package/vendor/agentscript-parser-javascript/dist/lexer.js +630 -0
  82. package/vendor/agentscript-parser-javascript/dist/parse-mapping.d.ts +46 -0
  83. package/vendor/agentscript-parser-javascript/dist/parse-mapping.js +549 -0
  84. package/vendor/agentscript-parser-javascript/dist/parse-sequence.d.ts +10 -0
  85. package/vendor/agentscript-parser-javascript/dist/parse-sequence.js +118 -0
  86. package/vendor/agentscript-parser-javascript/dist/parse-statements.d.ts +15 -0
  87. package/vendor/agentscript-parser-javascript/dist/parse-statements.js +519 -0
  88. package/vendor/agentscript-parser-javascript/dist/parse-templates.d.ts +15 -0
  89. package/vendor/agentscript-parser-javascript/dist/parse-templates.js +323 -0
  90. package/vendor/agentscript-parser-javascript/dist/parser.d.ts +65 -0
  91. package/vendor/agentscript-parser-javascript/dist/parser.js +163 -0
  92. package/vendor/agentscript-parser-javascript/dist/recovery.d.ts +51 -0
  93. package/vendor/agentscript-parser-javascript/dist/recovery.js +199 -0
  94. package/vendor/agentscript-parser-javascript/dist/token.d.ts +58 -0
  95. package/vendor/agentscript-parser-javascript/dist/token.js +62 -0
  96. package/vendor/agentscript-parser-javascript/package.json +19 -0
  97. package/vendor/agentscript-types/dist/comment.d.ts +11 -0
  98. package/vendor/agentscript-types/dist/comment.js +10 -0
  99. package/vendor/agentscript-types/dist/cst.d.ts +7 -0
  100. package/vendor/agentscript-types/dist/cst.js +8 -0
  101. package/vendor/agentscript-types/dist/diagnostic.d.ts +34 -0
  102. package/vendor/agentscript-types/dist/diagnostic.js +23 -0
  103. package/vendor/agentscript-types/dist/index.d.ts +9 -0
  104. package/vendor/agentscript-types/dist/index.js +10 -0
  105. package/vendor/agentscript-types/dist/position.d.ts +11 -0
  106. package/vendor/agentscript-types/dist/position.js +16 -0
  107. package/vendor/agentscript-types/dist/syntax-node.d.ts +39 -0
  108. package/vendor/agentscript-types/dist/syntax-node.js +8 -0
  109. package/vendor/agentscript-types/package.json +15 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bobby White
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,26 @@
1
+ sf-agentpmd
2
+ Copyright (c) 2026 Bobby White
3
+
4
+ This product is licensed under the MIT License (see LICENSE).
5
+
6
+ ------------------------------------------------------------------------
7
+ Third-party components
8
+ ------------------------------------------------------------------------
9
+
10
+ This product bundles components from the AgentScript project by
11
+ Salesforce, Inc., which are licensed under the Apache License, Version 2.0.
12
+ The MIT license of this product does NOT apply to these vendored components;
13
+ they remain governed by their original Apache-2.0 license.
14
+
15
+ Project: AgentScript (https://github.com/salesforce/agentscript)
16
+ Copyright: Copyright (c) 2026 Salesforce, Inc.
17
+ License: Apache License, Version 2.0
18
+ (https://www.apache.org/licenses/LICENSE-2.0)
19
+
20
+ Vendored packages and on-disk locations:
21
+ - @agentscript/types@0.2.1
22
+ vendor/agentscript-types/
23
+ - @agentscript/parser-javascript@2.4.0
24
+ vendor/agentscript-parser-javascript/
25
+
26
+ A copy of the Apache License, Version 2.0 is available at the URL above.
package/README.md ADDED
@@ -0,0 +1,204 @@
1
+ # sf-agentpmd
2
+
3
+ SF CLI plugin that computes **standard McCabe cyclomatic complexity** for
4
+ [AgentScript](https://github.com/salesforce/agentscript) (`.agent`) files,
5
+ along with an inventory of declared and referenced agent actions.
6
+
7
+ The intent (per `docs/agent-loc-categorization-skill-v2.md` § 7) is the
8
+ by-the-book number a SonarQube / PMD / Checkstyle run would produce — but
9
+ applied to the AgentScript surface that those tools don't cover today.
10
+
11
+ ## Current scope (v2)
12
+
13
+ `sf agentpmd analyze [--source-dir <dir|file>] [--apex-source <dir>] [--fail-on N]`
14
+
15
+ If `--source-dir` is omitted, the plugin walks up from cwd looking for
16
+ `sfdx-project.json` and uses its `packageDirectories` as the source roots.
17
+ Run it from anywhere inside an sfdx project and it just works.
18
+
19
+ - Walks every `.agent` file under the resolved source roots.
20
+ - For each `before_reasoning:`, `after_reasoning:`, and
21
+ `reasoning.instructions:` block, computes McCabe CC:
22
+
23
+ ```
24
+ CC = 1
25
+ + count(if_statement)
26
+ + count(elif_clause)
27
+ + count(ternary_expression)
28
+ + count(binary_expression where operator ∈ {and, or})
29
+ ```
30
+
31
+ - Reports CC per procedure, per scope (`topic` / `start_agent` / `subagent`),
32
+ per file, and a total across files.
33
+ - Collects all `actions:` declarations and classifies their `target:` URI
34
+ (`apex://`, `flow://`, `prompt://`, …).
35
+ - Counts how many times each declared action is referenced from
36
+ `reasoning.actions`, `reasoning.instructions`, `before_reasoning`,
37
+ `after_reasoning`, and `transition` statements.
38
+ - For every `apex://ClassName` target, resolves the `.cls` file by walking
39
+ up from the `.agent` location looking for a sibling `classes/` directory
40
+ (or honors `--apex-source <dir>`), parses it with
41
+ `@apexdevtools/apex-parser`, and computes per-method McCabe CC for every
42
+ method and constructor with a body:
43
+
44
+ ```
45
+ CC = 1
46
+ + count(if)
47
+ + count(for) // includes enhanced-for
48
+ + count(while)
49
+ + count(do-while)
50
+ + count(when arm) // each switch `when X { ... }`; `when else` excluded
51
+ + count(catch)
52
+ + count(ternary ?:)
53
+ + count(&&)
54
+ + count(||)
55
+ ```
56
+
57
+ - Emits a **CC by location** rollup (AgentScript vs. Apex vs. Combined),
58
+ matching the whitepaper § 7 framing.
59
+
60
+ ### Flags
61
+
62
+ | Flag | Purpose |
63
+ | --- | --- |
64
+ | `-d, --source-dir <path>` | Directory or single `.agent` file. Optional. Defaults to the `packageDirectories` of the nearest `sfdx-project.json`. |
65
+ | `-n, --api-name <X>` | Filter to a specific bundle. Matches the bundle directory name **or** `config.developer_name:` inside the `.agent`. Repeat for multiple bundles. |
66
+ | `--apex-source <path>` | Override directory for resolving `apex://` targets. Default: walk up from each `.agent` looking for a `classes/` sibling. |
67
+ | `--format <fmt>` | Non-JSON output format: `text` (default), `markdown`, `sarif`, `csv`. Ignored when `--json` is set. |
68
+ | `--width <N>` | Rule width for the text renderer. Default 60. |
69
+ | `--ascii` | Force ASCII-only output in the text renderer (no emoji / box chars). Auto-enabled on non-TTY stdout. |
70
+ | `--no-color` | Disable ANSI color. `NO_COLOR` env var also disables. |
71
+ | `--sarif-warning <N>` / `--sarif-error <N>` | Override the SARIF level thresholds. Defaults 10 / 20. |
72
+ | `--fail-on <N>` | Exit non-zero (code 2) if **combined** (agent + Apex) CC ≥ N. Useful in CI. |
73
+ | `--json` | Machine-readable SF CLI envelope on stdout. Takes precedence over `--format`. |
74
+
75
+ ### Output formats at a glance
76
+
77
+ | Format | When to use | Surface |
78
+ | --- | --- | --- |
79
+ | `text` (default) | Terminal eyeballs. | Color-coded, palette-aligned (red/yellow/green/gray by CC band). Auto-degrades to ASCII on non-TTY. |
80
+ | `markdown` | PR descriptions, gists, whitepaper appendices. | Mermaid `xychart-beta` bar chart at top (AgentScript red vs Apex green) + per-bundle and per-class tables. |
81
+ | `sarif` | GitHub Code Scanning / IDE annotations / CI. | SARIF 2.1.0 with one result per procedure / per method. Level driven by complexity thresholds. |
82
+ | `csv` | Spreadsheet pivots, posture-comparison matrices. | One row per procedure or Apex method. RFC-4180 quoted. |
83
+ | `--json` | Machine consumers (e.g. another sf plugin). | SF CLI envelope around the full `AnalysisReport`. |
84
+
85
+ ### Example
86
+
87
+ ```
88
+ $ sf agentpmd analyze -d ./force-app/main/default/aiAuthoringBundles
89
+ AgentForce PMD — Cyclomatic Complexity (McCabe)
90
+ ════════════════════════════════════════════════════════════
91
+
92
+ 📄 case_escalation_bot.agent CC=31
93
+ ────────────────────────────────────────────────────────────
94
+ start_agent customer_verification subtotal CC=8
95
+ before_reasoning CC=2 if=1
96
+ after_reasoning CC=5 if=3 and=1
97
+ reasoning.instructions CC=1 (base only)
98
+
99
+ ```
100
+
101
+ ## Roadmap
102
+
103
+ - **v3** — implement the four-category LOC rule from
104
+ `docs/agent-loc-categorization-skill-v2.md` (Scaffolding, Deterministic
105
+ Logic, Reasoning Logic, Conversation Surface) as a separate sub-command
106
+ (`sf agentpmd categorize-loc`).
107
+ - **future** — Flow incorporation (§ 9 of the whitepaper) once a CC analog
108
+ for Flow elements is settled.
109
+
110
+ ## How it parses
111
+
112
+ We do **not** use heuristic regex scanners. Two real parsers do the work:
113
+
114
+ - **AgentScript** — the hand-written TypeScript parser in
115
+ [`@agentscript/parser-javascript`](https://github.com/salesforce/agentscript/tree/main/packages/parser-javascript),
116
+ vendored under `vendor/` because the upstream package isn't published to
117
+ npm yet.
118
+ - **Apex** — [`@apexdevtools/apex-parser`](https://github.com/apex-dev-tools/apex-parser)
119
+ v5.0.0, an actively-maintained ANTLR4 TypeScript port. Pure-Node, no JVM.
120
+
121
+ To resync the vendor copies after pulling new upstream commits:
122
+
123
+ ```
124
+ ./scripts/sync-vendor.sh
125
+ ```
126
+
127
+ That copies the freshly-built `dist/` from
128
+ `$AGENTSCRIPT_REPO/packages/{types,parser-javascript}` into
129
+ `vendor/agentscript-{types,parser-javascript}/dist/`.
130
+
131
+ ## Layout
132
+
133
+ ```
134
+ src/
135
+ commands/agentpmd/analyze.ts # sf agentpmd analyze
136
+ analyzer/
137
+ parse.ts # AgentScript CST helpers
138
+ complexity.ts # AgentScript McCabe CC walker
139
+ action-references.ts # @actions.X declarations & references
140
+ apex-parse.ts # @apexdevtools/apex-parser wrappers
141
+ apex-complexity.ts # Apex McCabe CC walker
142
+ apex-resolve.ts # apex://ClassName → .cls path resolver
143
+ apex-analyze.ts # orchestrator for the Apex pass
144
+ analyze.ts # file discovery + top-level orchestrator
145
+ report.ts # text/json rendering (incl. § 7 split)
146
+ types.ts # public types
147
+ index.ts # programmatic entry
148
+ test/
149
+ fixtures/ # synthetic + gametwo fixtures
150
+ analyzer/*.spec.ts # vitest unit + integration tests
151
+ vendor/
152
+ agentscript-types/ # vendored from agentscript monorepo
153
+ agentscript-parser-javascript/
154
+ scripts/
155
+ sync-vendor.sh
156
+ docs/
157
+ agent-loc-categorization-skill-v2.md # the categorization rule
158
+ ```
159
+
160
+ ## Development
161
+
162
+ ```
163
+ npm install
164
+ npm run build
165
+ npm test
166
+ node bin/dev.js agentpmd analyze --source-dir test/fixtures
167
+ ```
168
+
169
+ The plugin uses ESM throughout and targets Node ≥ 20.
170
+
171
+ ## Claude Code skill
172
+
173
+ The plugin ships with a bundled Claude Code skill (at `skill/` in the repo)
174
+ that wraps the plugin from an adopter's point of view — discovery,
175
+ install, upgrade, and output interpretation. It auto-triggers when a
176
+ Claude session mentions `sf agentpmd`, "AgentScript cyclomatic
177
+ complexity", or related phrases.
178
+
179
+ **Activate the skill.** After installing the plugin, run:
180
+
181
+ ```bash
182
+ sf agentpmd install-skill
183
+ ```
184
+
185
+ This recursively copies the bundled skill tree to
186
+ `~/.claude/skills/agentforcepmd/`. Restart Claude Code (or reload skills)
187
+ to activate it.
188
+
189
+ Local-dev contributors can instead symlink the in-repo `skill/` directory
190
+ (it moved from `.claude/skills/agentforcepmd/` to `skill/`) so edits show
191
+ up live:
192
+
193
+ ```bash
194
+ ln -sfn "$(pwd)/skill" ~/.claude/skills/agentforcepmd
195
+ ```
196
+
197
+ The skill's `SKILL.md` indexes four reference pages:
198
+
199
+ - `references/command-structure.md` — every flag, defaults, exit codes
200
+ - `references/install.md` — both pre- and post-publication install paths
201
+ - `references/upgrade.md` — refresh dance for a linked checkout, plus
202
+ `sf plugins update` for the published case
203
+ - `references/output-formats.md` — text / JSON / markdown / SARIF / CSV
204
+ surface with examples, plus a "pick a format" cheat sheet
package/bin/dev.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env -S node --loader ts-node/esm --disable-warning=ExperimentalWarning
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({development: true, dir: import.meta.url})
package/bin/run.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { execute } from '@oclif/core';
3
+ await execute({ dir: import.meta.url });
@@ -0,0 +1,21 @@
1
+ import type { AgentScope } from './complexity.js';
2
+ import type { ActionDeclaration, ActionReference } from './types.js';
3
+ /**
4
+ * Within a scope body (the value of a `topic` or `start_agent`/`subagent`
5
+ * mapping_element), the `actions:` entry holds a mapping of named action
6
+ * declarations. Each declaration is itself a mapping with metadata fields
7
+ * like `target:`, `label:`, `inputs:`, `outputs:`.
8
+ */
9
+ export declare function collectDeclarations(scope: AgentScope): ActionDeclaration[];
10
+ /**
11
+ * Collect every member_expression of the form `@actions.X` *outside* the
12
+ * `actions:` declaration block. We treat them as references — i.e. usages of
13
+ * the declared actions in reasoning / before / after blocks.
14
+ *
15
+ * Context discrimination:
16
+ * • inside reasoning > actions → 'reasoning_actions'
17
+ * • inside after_reasoning → 'after_reasoning_run'
18
+ * • inside before_reasoning → 'before_reasoning_run'
19
+ * • inside transition_statement → 'transition'
20
+ */
21
+ export declare function collectReferences(scope: AgentScope): ActionReference[];
@@ -0,0 +1,130 @@
1
+ import { descendants, extractStringLiteral, findMappingEntry, locOf, mappingKeyHeader, mappingValue, } from './parse.js';
2
+ const TARGET_SCHEME = /^([a-z][a-z0-9+.-]*):\/\//i;
3
+ function classifyTarget(uri) {
4
+ if (!uri)
5
+ return 'unknown';
6
+ const m = TARGET_SCHEME.exec(uri);
7
+ if (!m)
8
+ return 'unknown';
9
+ const scheme = m[1].toLowerCase();
10
+ if (scheme === 'apex')
11
+ return 'apex';
12
+ if (scheme === 'flow')
13
+ return 'flow';
14
+ if (scheme.startsWith('prompt'))
15
+ return 'prompt';
16
+ return 'unknown';
17
+ }
18
+ /**
19
+ * Within a scope body (the value of a `topic` or `start_agent`/`subagent`
20
+ * mapping_element), the `actions:` entry holds a mapping of named action
21
+ * declarations. Each declaration is itself a mapping with metadata fields
22
+ * like `target:`, `label:`, `inputs:`, `outputs:`.
23
+ */
24
+ export function collectDeclarations(scope) {
25
+ const decls = [];
26
+ const actionsBlock = findMappingEntry(scope.body, 'actions');
27
+ if (!actionsBlock)
28
+ return decls;
29
+ for (const child of actionsBlock.namedChildren) {
30
+ if (child.type !== 'mapping_element')
31
+ continue;
32
+ const h = mappingKeyHeader(child);
33
+ if (!h)
34
+ continue;
35
+ const declName = h.kind;
36
+ const declBody = mappingValue(child);
37
+ if (!declBody) {
38
+ decls.push({
39
+ location: locOf(child),
40
+ name: declName,
41
+ scope: scope.label,
42
+ target: undefined,
43
+ targetKind: 'unknown',
44
+ });
45
+ continue;
46
+ }
47
+ const targetVal = findMappingEntry(declBody, 'target');
48
+ const targetStr = targetVal ? extractStringLiteral(targetVal) : undefined;
49
+ decls.push({
50
+ location: locOf(child),
51
+ name: declName,
52
+ scope: scope.label,
53
+ target: targetStr,
54
+ targetKind: classifyTarget(targetStr),
55
+ });
56
+ }
57
+ return decls;
58
+ }
59
+ /**
60
+ * Collect every member_expression of the form `@actions.X` *outside* the
61
+ * `actions:` declaration block. We treat them as references — i.e. usages of
62
+ * the declared actions in reasoning / before / after blocks.
63
+ *
64
+ * Context discrimination:
65
+ * • inside reasoning > actions → 'reasoning_actions'
66
+ * • inside after_reasoning → 'after_reasoning_run'
67
+ * • inside before_reasoning → 'before_reasoning_run'
68
+ * • inside transition_statement → 'transition'
69
+ */
70
+ export function collectReferences(scope) {
71
+ const refs = [];
72
+ const explore = (body, context) => {
73
+ if (!body)
74
+ return;
75
+ for (const n of descendants(body)) {
76
+ if (n.type !== 'member_expression')
77
+ continue;
78
+ // member_expression text is the full chain ("@actions.Foo[.Bar]");
79
+ // text matching is more robust than peeking through the wrapper
80
+ // chain (expression → atom → at_id).
81
+ if (!n.text.startsWith('@actions.'))
82
+ continue;
83
+ const name = actionNameFromMember(n);
84
+ if (!name)
85
+ continue;
86
+ // Differentiate when we're inside a transition_statement.
87
+ const ctx = isInsideTransition(n) ? 'transition' : context;
88
+ refs.push({
89
+ context: ctx,
90
+ location: locOf(n),
91
+ name,
92
+ scope: scope.label,
93
+ });
94
+ }
95
+ };
96
+ explore(findMappingEntry(scope.body, 'before_reasoning'), 'before_reasoning_run');
97
+ explore(findMappingEntry(scope.body, 'after_reasoning'), 'after_reasoning_run');
98
+ const reasoning = findMappingEntry(scope.body, 'reasoning');
99
+ if (reasoning) {
100
+ // `reasoning.actions:` — the declarative action contract block;
101
+ // refs here describe what the LLM is allowed to call.
102
+ explore(findMappingEntry(reasoning, 'actions'), 'reasoning_actions');
103
+ // `reasoning.instructions: ->` — refs here are `run @actions.X`
104
+ // invocations the LLM evaluates as part of its instructions.
105
+ // Per the whitepaper, these execute non-deterministically.
106
+ explore(findMappingEntry(reasoning, 'instructions'), 'reasoning_instructions_run');
107
+ }
108
+ return refs;
109
+ }
110
+ function actionNameFromMember(n) {
111
+ // member_expression text is "@actions.Foo_Bar" — strip the prefix.
112
+ const t = n.text;
113
+ const dot = t.indexOf('.');
114
+ if (dot === -1)
115
+ return undefined;
116
+ const rest = t.slice(dot + 1);
117
+ // Take the leading identifier, in case of further chained access.
118
+ const m = /^([A-Za-z_][A-Za-z0-9_]*)/.exec(rest);
119
+ return m?.[1];
120
+ }
121
+ function isInsideTransition(n) {
122
+ let p = n.parent;
123
+ while (p) {
124
+ if (p.type === 'transition_statement')
125
+ return true;
126
+ p = p.parent;
127
+ }
128
+ return false;
129
+ }
130
+ //# sourceMappingURL=action-references.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-references.js","sourceRoot":"","sources":["../../src/analyzer/action-references.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,gBAAgB,EAChB,KAAK,EACL,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,MAAM,aAAa,GAAG,4BAA4B,CAAC;AAEnD,SAAS,cAAc,CAAC,GAAuB;IAC7C,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAClC,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACrC,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACrC,IAAI,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IACjD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAiB;IACnD,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,MAAM,YAAY,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC7D,IAAI,CAAC,YAAY;QAAE,OAAO,KAAK,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,aAAa,EAAE,CAAC;QAC/C,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB;YAAE,SAAS;QAC/C,MAAM,CAAC,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC;QACxB,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,KAAK,CAAC,IAAI,CAAC;gBACT,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;gBACtB,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,MAAM,EAAE,SAAS;gBACjB,UAAU,EAAE,SAAS;aACtB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,KAAK,CAAC,IAAI,CAAC;YACT,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;YACtB,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,cAAc,CAAC,SAAS,CAAC;SACtC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAiB;IACjD,MAAM,IAAI,GAAsB,EAAE,CAAC;IAEnC,MAAM,OAAO,GAAG,CAAC,IAA4B,EAAE,OAAmC,EAAE,EAAE;QACpF,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB;gBAAE,SAAS;YAC7C,mEAAmE;YACnE,gEAAgE;YAChE,qCAAqC;YACrC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;gBAAE,SAAS;YAC9C,MAAM,IAAI,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,0DAA0D;YAC1D,MAAM,GAAG,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3D,IAAI,CAAC,IAAI,CAAC;gBACR,OAAO,EAAE,GAAG;gBACZ,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;gBAClB,IAAI;gBACJ,KAAK,EAAE,KAAK,CAAC,KAAK;aACnB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,EAAE,sBAAsB,CAAC,CAAC;IAClF,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,iBAAiB,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAChF,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC5D,IAAI,SAAS,EAAE,CAAC;QACd,gEAAgE;QAChE,sDAAsD;QACtD,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,mBAAmB,CAAC,CAAC;QACrE,gEAAgE;QAChE,6DAA6D;QAC7D,2DAA2D;QAC3D,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,4BAA4B,CAAC,CAAC;IACrF,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,oBAAoB,CAAC,CAAa;IACzC,mEAAmE;IACnE,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACjB,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAC9B,kEAAkE;IAClE,MAAM,CAAC,GAAG,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB,CAAC,CAAa;IACvC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC;QACT,IAAI,CAAC,CAAC,IAAI,KAAK,sBAAsB;YAAE,OAAO,IAAI,CAAC;QACnD,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACf,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { AnalysisReport, FileReport } from './types.js';
2
+ export interface AnalyzeOptions {
3
+ /** Override location for apex:// resolution. Optional. */
4
+ apexSourceOverride?: string;
5
+ /**
6
+ * Filter to specific agent bundles by API name. Each entry is matched
7
+ * against (a) the bundle directory name and (b) `config.developer_name`
8
+ * inside the .agent file. When omitted or empty, all discovered bundles
9
+ * are analyzed.
10
+ */
11
+ apiNames?: string[];
12
+ /**
13
+ * Base directory for relative paths in the report. Defaults to the source
14
+ * root (or, when multiple roots are supplied, the longest common ancestor).
15
+ */
16
+ reportBase?: string;
17
+ }
18
+ /**
19
+ * Error thrown when --api-name filters produce no matches. Carries the
20
+ * candidate list so callers can show a useful hint.
21
+ */
22
+ export declare class NoMatchingBundlesError extends Error {
23
+ readonly requested: string[];
24
+ readonly available: BundleIdentity[];
25
+ constructor(requested: string[], available: BundleIdentity[]);
26
+ }
27
+ export interface BundleIdentity {
28
+ /** The config.developer_name value, if present. */
29
+ developerName: string | undefined;
30
+ /** The bundle's directory name (parent of the .agent file). */
31
+ dirName: string;
32
+ /** Absolute path of the .agent file. */
33
+ path: string;
34
+ }
35
+ /**
36
+ * Analyze AgentScript bundles under one or more source roots.
37
+ *
38
+ * Backward-compatible: pass a single path (string) for the legacy
39
+ * single-root case. Pass an array of paths for multi-root analysis
40
+ * (e.g. multiple `packageDirectories` in an sfdx project).
41
+ */
42
+ export declare function analyzeSource(rootPathOrPaths: string | string[], options?: AnalyzeOptions): Promise<AnalysisReport>;
43
+ export declare function analyzeFile(absPath: string, base: string): Promise<FileReport>;