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.
- package/LICENSE +21 -0
- package/NOTICE +26 -0
- package/README.md +204 -0
- package/bin/dev.js +5 -0
- package/bin/run.js +3 -0
- package/dist/analyzer/action-references.d.ts +21 -0
- package/dist/analyzer/action-references.js +130 -0
- package/dist/analyzer/action-references.js.map +1 -0
- package/dist/analyzer/analyze.d.ts +43 -0
- package/dist/analyzer/analyze.js +222 -0
- package/dist/analyzer/analyze.js.map +1 -0
- package/dist/analyzer/apex-analyze.d.ts +14 -0
- package/dist/analyzer/apex-analyze.js +60 -0
- package/dist/analyzer/apex-analyze.js.map +1 -0
- package/dist/analyzer/apex-complexity.d.ts +27 -0
- package/dist/analyzer/apex-complexity.js +133 -0
- package/dist/analyzer/apex-complexity.js.map +1 -0
- package/dist/analyzer/apex-parse.d.ts +39 -0
- package/dist/analyzer/apex-parse.js +32 -0
- package/dist/analyzer/apex-parse.js.map +1 -0
- package/dist/analyzer/apex-resolve.d.ts +32 -0
- package/dist/analyzer/apex-resolve.js +59 -0
- package/dist/analyzer/apex-resolve.js.map +1 -0
- package/dist/analyzer/complexity.d.ts +30 -0
- package/dist/analyzer/complexity.js +126 -0
- package/dist/analyzer/complexity.js.map +1 -0
- package/dist/analyzer/parse.d.ts +51 -0
- package/dist/analyzer/parse.js +143 -0
- package/dist/analyzer/parse.js.map +1 -0
- package/dist/analyzer/project.d.ts +12 -0
- package/dist/analyzer/project.js +51 -0
- package/dist/analyzer/project.js.map +1 -0
- package/dist/analyzer/types.d.ts +76 -0
- package/dist/analyzer/types.js +2 -0
- package/dist/analyzer/types.js.map +1 -0
- package/dist/commands/agentpmd/analyze.d.ts +20 -0
- package/dist/commands/agentpmd/analyze.js +122 -0
- package/dist/commands/agentpmd/analyze.js.map +1 -0
- package/dist/commands/agentpmd/install-skill.d.ts +11 -0
- package/dist/commands/agentpmd/install-skill.js +33 -0
- package/dist/commands/agentpmd/install-skill.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/renderers/csv.d.ts +6 -0
- package/dist/renderers/csv.js +78 -0
- package/dist/renderers/csv.js.map +1 -0
- package/dist/renderers/index.d.ts +8 -0
- package/dist/renderers/index.js +25 -0
- package/dist/renderers/index.js.map +1 -0
- package/dist/renderers/markdown.d.ts +12 -0
- package/dist/renderers/markdown.js +233 -0
- package/dist/renderers/markdown.js.map +1 -0
- package/dist/renderers/options.d.ts +20 -0
- package/dist/renderers/options.js +2 -0
- package/dist/renderers/options.js.map +1 -0
- package/dist/renderers/sarif.d.ts +3 -0
- package/dist/renderers/sarif.js +131 -0
- package/dist/renderers/sarif.js.map +1 -0
- package/dist/renderers/text.d.ts +3 -0
- package/dist/renderers/text.js +243 -0
- package/dist/renderers/text.js.map +1 -0
- package/oclif.manifest.json +168 -0
- package/package.json +97 -0
- package/skill/SKILL.md +103 -0
- package/skill/references/command-structure.md +89 -0
- package/skill/references/install.md +112 -0
- package/skill/references/output-formats.md +205 -0
- package/skill/references/upgrade.md +112 -0
- package/vendor/agentscript-parser-javascript/dist/cst-node.d.ts +83 -0
- package/vendor/agentscript-parser-javascript/dist/cst-node.js +238 -0
- package/vendor/agentscript-parser-javascript/dist/errors.d.ts +34 -0
- package/vendor/agentscript-parser-javascript/dist/errors.js +74 -0
- package/vendor/agentscript-parser-javascript/dist/expressions.d.ts +36 -0
- package/vendor/agentscript-parser-javascript/dist/expressions.js +682 -0
- package/vendor/agentscript-parser-javascript/dist/highlighter.d.ts +24 -0
- package/vendor/agentscript-parser-javascript/dist/highlighter.js +260 -0
- package/vendor/agentscript-parser-javascript/dist/index.d.ts +29 -0
- package/vendor/agentscript-parser-javascript/dist/index.js +35 -0
- package/vendor/agentscript-parser-javascript/dist/lexer.d.ts +60 -0
- package/vendor/agentscript-parser-javascript/dist/lexer.js +630 -0
- package/vendor/agentscript-parser-javascript/dist/parse-mapping.d.ts +46 -0
- package/vendor/agentscript-parser-javascript/dist/parse-mapping.js +549 -0
- package/vendor/agentscript-parser-javascript/dist/parse-sequence.d.ts +10 -0
- package/vendor/agentscript-parser-javascript/dist/parse-sequence.js +118 -0
- package/vendor/agentscript-parser-javascript/dist/parse-statements.d.ts +15 -0
- package/vendor/agentscript-parser-javascript/dist/parse-statements.js +519 -0
- package/vendor/agentscript-parser-javascript/dist/parse-templates.d.ts +15 -0
- package/vendor/agentscript-parser-javascript/dist/parse-templates.js +323 -0
- package/vendor/agentscript-parser-javascript/dist/parser.d.ts +65 -0
- package/vendor/agentscript-parser-javascript/dist/parser.js +163 -0
- package/vendor/agentscript-parser-javascript/dist/recovery.d.ts +51 -0
- package/vendor/agentscript-parser-javascript/dist/recovery.js +199 -0
- package/vendor/agentscript-parser-javascript/dist/token.d.ts +58 -0
- package/vendor/agentscript-parser-javascript/dist/token.js +62 -0
- package/vendor/agentscript-parser-javascript/package.json +19 -0
- package/vendor/agentscript-types/dist/comment.d.ts +11 -0
- package/vendor/agentscript-types/dist/comment.js +10 -0
- package/vendor/agentscript-types/dist/cst.d.ts +7 -0
- package/vendor/agentscript-types/dist/cst.js +8 -0
- package/vendor/agentscript-types/dist/diagnostic.d.ts +34 -0
- package/vendor/agentscript-types/dist/diagnostic.js +23 -0
- package/vendor/agentscript-types/dist/index.d.ts +9 -0
- package/vendor/agentscript-types/dist/index.js +10 -0
- package/vendor/agentscript-types/dist/position.d.ts +11 -0
- package/vendor/agentscript-types/dist/position.js +16 -0
- package/vendor/agentscript-types/dist/syntax-node.d.ts +39 -0
- package/vendor/agentscript-types/dist/syntax-node.js +8 -0
- 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
package/bin/run.js
ADDED
|
@@ -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":"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"}
|
|
@@ -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>;
|