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/skill/SKILL.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentforcepmd
|
|
3
|
+
description: Use this skill whenever working with the sf-agentpmd SF CLI plugin — discovering its commands, installing or upgrading it, running it against an Agentforce / AgentScript project, or interpreting its text / JSON / Markdown / SARIF / CSV outputs. Triggers on mentions of `sf agentpmd`, "AgentScript cyclomatic complexity", "Agent CC", "McCabe analysis of .agent files", "agent PMD", or any request to compute or report complexity / action-reference inventory for AgentScript bundles and the Apex backing logic they invoke.
|
|
4
|
+
metadata:
|
|
5
|
+
type: skill
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
last_updated: "2026-05-19"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# sf-agentpmd
|
|
11
|
+
|
|
12
|
+
`sf-agentpmd` is an SF CLI plugin that computes **standard McCabe
|
|
13
|
+
cyclomatic complexity** for AgentScript (`.agent`) bundles and the Apex
|
|
14
|
+
classes they invoke through `apex://` action targets. It also inventories
|
|
15
|
+
action declarations and references, and emits a "CC by location"
|
|
16
|
+
roll-up (AgentScript vs. Apex vs. Combined) suitable for posture analysis
|
|
17
|
+
or static-analysis CI gates.
|
|
18
|
+
|
|
19
|
+
## What it does at a glance
|
|
20
|
+
|
|
21
|
+
- Walks every `.agent` file under a source directory (or auto-discovers
|
|
22
|
+
`sfdx-project.json` and uses its `packageDirectories`).
|
|
23
|
+
- For each `before_reasoning:`, `after_reasoning:`, and
|
|
24
|
+
`reasoning.instructions:` block, computes McCabe CC.
|
|
25
|
+
- For each `actions:` declaration, classifies the `target:` URI
|
|
26
|
+
(`apex://`, `flow://`, `prompt://`).
|
|
27
|
+
- For every `apex://ClassName` target, resolves the `.cls` file and
|
|
28
|
+
computes per-method McCabe CC with the same convention SonarQube / PMD
|
|
29
|
+
use for Apex.
|
|
30
|
+
- Renders the result as **text** (TTY-aware), **JSON** (SF CLI envelope),
|
|
31
|
+
**markdown** (with a Mermaid by-location chart), **SARIF** (for GitHub
|
|
32
|
+
Code Scanning), or **CSV** (for spreadsheet pivots).
|
|
33
|
+
|
|
34
|
+
## Task domains
|
|
35
|
+
|
|
36
|
+
Identify which of the four common questions the user is asking and read
|
|
37
|
+
the matching reference file before answering.
|
|
38
|
+
|
|
39
|
+
### "What commands does this plugin offer?"
|
|
40
|
+
|
|
41
|
+
Read [`references/command-structure.md`](references/command-structure.md).
|
|
42
|
+
Covers the topic / command tree, every flag, defaults, and short aliases.
|
|
43
|
+
|
|
44
|
+
### "How do I install it?"
|
|
45
|
+
|
|
46
|
+
Read [`references/install.md`](references/install.md). Covers both:
|
|
47
|
+
- **Today (pre-publication):** clone + `npm install` + `npm run build` +
|
|
48
|
+
`sf plugins link`.
|
|
49
|
+
- **Future (after npm publish):** `sf plugins install sf-agentpmd`.
|
|
50
|
+
|
|
51
|
+
### "How do I upgrade it?"
|
|
52
|
+
|
|
53
|
+
Read [`references/upgrade.md`](references/upgrade.md). Covers the
|
|
54
|
+
linked-checkout refresh path (`git pull && npm run build`) and the
|
|
55
|
+
published-plugin path (`sf plugins update` or
|
|
56
|
+
`sf plugins install <name>@latest`).
|
|
57
|
+
|
|
58
|
+
### "How do I make sense of the output?"
|
|
59
|
+
|
|
60
|
+
Read [`references/output-formats.md`](references/output-formats.md).
|
|
61
|
+
Covers every format the plugin emits, what each column / field means,
|
|
62
|
+
how to read the "CC by location" roll-up, and which format to pick for
|
|
63
|
+
which downstream consumer (terminal, PR comment, CI gate, spreadsheet).
|
|
64
|
+
|
|
65
|
+
## Rules that always apply
|
|
66
|
+
|
|
67
|
+
1. **Always include `--json`** when programmatically consuming output
|
|
68
|
+
(CI, follow-on `jq` pipelines, another plugin). Non-JSON formats are
|
|
69
|
+
for humans.
|
|
70
|
+
2. **Prefer auto-discovery.** When run from inside an sfdx project,
|
|
71
|
+
omit `--source-dir`. The plugin will walk up to `sfdx-project.json`
|
|
72
|
+
and use its `packageDirectories`. Print the resolved root from the
|
|
73
|
+
header line to confirm.
|
|
74
|
+
3. **Apex CC follow-through happens for free.** Any `apex://` target
|
|
75
|
+
referenced by an analyzed `.agent` file resolves to a sibling
|
|
76
|
+
`classes/<ClassName>.cls` and gets walked automatically — no flag
|
|
77
|
+
needed. Override with `--apex-source <dir>` only when the layout
|
|
78
|
+
differs from the standard sfdx convention.
|
|
79
|
+
4. **`--fail-on N` thresholds on combined CC** (agent + Apex), not
|
|
80
|
+
agent-only. This is intentional for CI gates: a posture that pushes
|
|
81
|
+
complexity from AgentScript into Apex shouldn't slip past the gate.
|
|
82
|
+
|
|
83
|
+
## Common workflows
|
|
84
|
+
|
|
85
|
+
| You want to… | Run |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| Inspect a whole sfdx project | `sf agentpmd analyze` (inside the project) |
|
|
88
|
+
| Inspect a specific bundle | `sf agentpmd analyze -n <DeveloperName>` |
|
|
89
|
+
| Generate a PR / whitepaper appendix | `sf agentpmd analyze --format markdown > report.md` |
|
|
90
|
+
| Gate a PR in CI | `sf agentpmd analyze --format sarif > out.sarif` (upload to Code Scanning) or `--fail-on 50` |
|
|
91
|
+
| Pipe into another sf tool | `sf agentpmd analyze --json \| jq '.result.apexClasses[].classComplexity'` |
|
|
92
|
+
|
|
93
|
+
## When *not* to use this plugin
|
|
94
|
+
|
|
95
|
+
- **General Apex static analysis.** That's PMD / sfdx-scanner /
|
|
96
|
+
`@salesforce/code-analyzer`. sf-agentpmd's Apex pass only walks classes
|
|
97
|
+
reachable via `apex://` targets from an `.agent` file.
|
|
98
|
+
- **Old Bot Builder XML or GenAiPlannerBundle XML.** Currently unsupported
|
|
99
|
+
(see the project's `TODO.md`). The plugin will skip them silently and
|
|
100
|
+
may dramatically under-report the implementation surface of agents
|
|
101
|
+
that store actions in a sibling planner bundle.
|
|
102
|
+
- **Flow CC.** Not implemented; tracked in `TODO.md` § 9 / Flow
|
|
103
|
+
incorporation.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Command structure
|
|
2
|
+
|
|
3
|
+
`sf-agentpmd` registers the topic `agentpmd` with one command:
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
sf agentpmd analyze [flags]
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Discover the command surface yourself with `sf agentpmd --help` or
|
|
10
|
+
`sf agentpmd analyze --help`.
|
|
11
|
+
|
|
12
|
+
## The one command — `sf agentpmd analyze`
|
|
13
|
+
|
|
14
|
+
Compute McCabe cyclomatic complexity and action-reference inventory for
|
|
15
|
+
AgentScript bundles and their Apex backing logic.
|
|
16
|
+
|
|
17
|
+
### Flags
|
|
18
|
+
|
|
19
|
+
| Flag | Short | Type | Default | Purpose |
|
|
20
|
+
| --- | --- | --- | --- | --- |
|
|
21
|
+
| `--source-dir` | `-d` | path | _auto_ | Directory or single `.agent` file to analyze. When omitted, walks up from cwd looking for `sfdx-project.json` and uses its `packageDirectories`. |
|
|
22
|
+
| `--api-name` | `-n` | string (repeatable) | _all_ | Filter to specific bundles by api-name. Matches against the bundle directory name **or** `config.developer_name` inside the `.agent`. Pass multiple times to union: `-n A -n B`. |
|
|
23
|
+
| `--apex-source` | — | path | _auto_ | Override directory for resolving `apex://` targets. Default: walks up from each `.agent` looking for a sibling `classes/` directory. |
|
|
24
|
+
| `--format` | — | enum | `text` | Non-JSON output: `text`, `markdown`, `sarif`, `csv`. Ignored when `--json` is set. |
|
|
25
|
+
| `--width` | — | integer | `60` | Rule width for the text renderer. |
|
|
26
|
+
| `--ascii` | — | boolean | _auto_ | Force ASCII-only output (no emoji / Unicode box chars). Auto-enabled when stdout isn't a TTY (e.g. piped). |
|
|
27
|
+
| `--no-color` | — | boolean | `false` | Disable ANSI color in the text renderer. `NO_COLOR` env var also disables. |
|
|
28
|
+
| `--sarif-warning` | — | integer | `10` | SARIF "warning" level threshold (per-method/per-procedure CC). |
|
|
29
|
+
| `--sarif-error` | — | integer | `20` | SARIF "error" level threshold. |
|
|
30
|
+
| `--fail-on` | — | integer | _off_ | Exit non-zero (code 2) if **combined** (agent + Apex) CC ≥ N. CI gate. |
|
|
31
|
+
| `--json` | — | boolean | `false` | Emit SF CLI JSON envelope. Takes precedence over `--format`. |
|
|
32
|
+
| `--flags-dir` | — | path | — | Standard SF CLI flag — import flag values from a directory. Inherited from `@salesforce/sf-plugins-core`. |
|
|
33
|
+
|
|
34
|
+
### Auto-discovery rules
|
|
35
|
+
|
|
36
|
+
When `--source-dir` is omitted, the plugin walks up from `process.cwd()`
|
|
37
|
+
looking for `sfdx-project.json`. If found, it uses the project's
|
|
38
|
+
`packageDirectories` as source roots and prints
|
|
39
|
+
`Analyzing sfdx project <root> (N package director{y|ies}).` as the
|
|
40
|
+
first line of human output. If no project file is found, it errors with
|
|
41
|
+
`No --source-dir was provided and no sfdx-project.json was found …`.
|
|
42
|
+
|
|
43
|
+
This matches the standard SF CLI ergonomics (`sf project deploy start`,
|
|
44
|
+
`sf project retrieve start`, etc.).
|
|
45
|
+
|
|
46
|
+
### Filter semantics for `--api-name`
|
|
47
|
+
|
|
48
|
+
A bundle matches a `-n <X>` value if **either**:
|
|
49
|
+
|
|
50
|
+
1. The bundle's directory name equals `<X>` (fast path, no parse).
|
|
51
|
+
2. The bundle's `config.developer_name:` value equals `<X>` (slow path,
|
|
52
|
+
used only when (1) misses).
|
|
53
|
+
|
|
54
|
+
If multiple `-n` values are supplied, the union is included. When none
|
|
55
|
+
match anything discovered, the command errors with the list of
|
|
56
|
+
available bundle names so the user can correct.
|
|
57
|
+
|
|
58
|
+
The slow path means `--api-name` works even when the bundle's developer
|
|
59
|
+
name has been edited away from the directory name — common after a
|
|
60
|
+
manual rename.
|
|
61
|
+
|
|
62
|
+
### Exit codes
|
|
63
|
+
|
|
64
|
+
| Code | Meaning |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| 0 | Success. Report rendered to stdout. |
|
|
67
|
+
| 1 | Standard usage / configuration error (missing flag, unknown bundle, no project found, invalid path). |
|
|
68
|
+
| 2 | `--fail-on N` was set and combined CC reached or exceeded N. |
|
|
69
|
+
|
|
70
|
+
### What "combined CC" includes
|
|
71
|
+
|
|
72
|
+
- Sum of CC of every analyzed `.agent` procedure body
|
|
73
|
+
(`before_reasoning`, `after_reasoning`, `reasoning.instructions:->`).
|
|
74
|
+
- Sum of CC of every method/constructor body in every Apex class reached
|
|
75
|
+
through an `apex://` action target.
|
|
76
|
+
- Apex classes referenced by multiple bundles are counted **once** in the
|
|
77
|
+
combined total (de-duplicated by class path).
|
|
78
|
+
|
|
79
|
+
### What the plugin does NOT count
|
|
80
|
+
|
|
81
|
+
- `else` clauses, `when else` arms, `finally` blocks, `try` itself
|
|
82
|
+
(per standard McCabe).
|
|
83
|
+
- AgentScript constructs the language doesn't have (loops, switch on AS
|
|
84
|
+
side — the AS grammar has no `for`/`while`/`case`).
|
|
85
|
+
- Methods without a body (interface methods, abstract methods).
|
|
86
|
+
- Apex methods reachable only through `flow://` or `prompt://` targets
|
|
87
|
+
(those URIs aren't followed yet).
|
|
88
|
+
- Old-style Bot dialogs or GenAiPlannerBundle action declarations
|
|
89
|
+
(tracked as TODO).
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Install
|
|
2
|
+
|
|
3
|
+
There are two install paths depending on the plugin's distribution
|
|
4
|
+
state. As of the date this skill was last updated (2026-05-19), the
|
|
5
|
+
plugin is **not yet published to npm**, so the from-source path is the
|
|
6
|
+
only one that works today.
|
|
7
|
+
|
|
8
|
+
## Path A — From source (today, pre-publication)
|
|
9
|
+
|
|
10
|
+
The plugin lives at `~/projects/AgentForcePMD/` (or wherever the user
|
|
11
|
+
cloned it). To install it into the `sf` CLI:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cd ~/projects/AgentForcePMD
|
|
15
|
+
npm install
|
|
16
|
+
npm run build
|
|
17
|
+
sf plugins link "$(pwd)"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The link survives across `sf` invocations. You only need to rebuild
|
|
21
|
+
(`npm run build`) when source under `src/` changes; the link itself
|
|
22
|
+
remains. See [`upgrade.md`](upgrade.md) for the refresh dance.
|
|
23
|
+
|
|
24
|
+
### Verify the install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
sf plugins # should list 'sf-agentpmd X.Y.Z (link)'
|
|
28
|
+
sf agentpmd analyze --help # should render the flag reference
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`sf` will emit a one-time warning per process the first time you
|
|
32
|
+
invoke a linked ESM plugin:
|
|
33
|
+
|
|
34
|
+
> Warning: sf-agentpmd is a linked ESM module and cannot be
|
|
35
|
+
> auto-transpiled. Existing compiled source will be used instead.
|
|
36
|
+
|
|
37
|
+
This is benign. It's telling you `sf` is reading `lib/` (the build
|
|
38
|
+
output), not running TypeScript directly. Just remember to
|
|
39
|
+
`npm run build` after `src/` edits.
|
|
40
|
+
|
|
41
|
+
### Where the linked plugin lives
|
|
42
|
+
|
|
43
|
+
`sf plugins link` records the absolute path under
|
|
44
|
+
`~/.local/share/sf/client/<version>/`. Inspecting:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
sf plugins --core # nothing — not a core plugin
|
|
48
|
+
sf plugins # sf-agentpmd appears here under its link path
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Path B — From npm (future, post-publication)
|
|
52
|
+
|
|
53
|
+
When the plugin is published to the npm registry, the standard SF CLI
|
|
54
|
+
install path applies:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
sf plugins install sf-agentpmd
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Verify the same way:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
sf plugins # should list 'sf-agentpmd X.Y.Z'
|
|
64
|
+
sf agentpmd analyze --help
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
No build step, no link. Plain npm install under the hood.
|
|
68
|
+
|
|
69
|
+
## Install the Claude Code skill
|
|
70
|
+
|
|
71
|
+
The plugin bundles this Claude Code skill. After the plugin is installed
|
|
72
|
+
(Path A or Path B), copy the skill tree into `~/.claude/skills/` with:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
sf agentpmd install-skill
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This recursively copies the bundled `skill/` tree (SKILL.md plus the
|
|
79
|
+
`references/` pages) to `~/.claude/skills/agentforcepmd/`. Restart Claude
|
|
80
|
+
Code (or reload skills) to activate it.
|
|
81
|
+
|
|
82
|
+
For an npm install, the bundled source lives at
|
|
83
|
+
`node_modules/sf-agentpmd/skill/`; local-dev contributors can instead
|
|
84
|
+
symlink the in-repo `skill/` directory:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
ln -sfn ~/projects/AgentForcePMD/skill ~/.claude/skills/agentforcepmd
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Prerequisites
|
|
91
|
+
|
|
92
|
+
- **Node.js ≥ 20** (the plugin declares `"engines": { "node": ">=20" }`).
|
|
93
|
+
- **`sf` CLI v2.131+** (older versions don't load linked ESM plugins
|
|
94
|
+
reliably).
|
|
95
|
+
- **`@apexdevtools/apex-parser` runtime deps** — auto-installed by `npm
|
|
96
|
+
install`. Includes `antlr4` as a peer.
|
|
97
|
+
|
|
98
|
+
## Uninstall
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
sf plugins unlink sf-agentpmd # Path A — removes the link, source repo untouched
|
|
102
|
+
sf plugins uninstall sf-agentpmd # Path B — removes the npm-installed copy
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Common install issues
|
|
106
|
+
|
|
107
|
+
| Symptom | Cause | Fix |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| `Command sf agentpmd not found` after link | `npm run build` not run, so `lib/` is empty / stale | `cd ~/projects/AgentForcePMD && npm run build` |
|
|
110
|
+
| `Cannot find module '@agentscript/parser-javascript'` | Vendored deps missing — `vendor/` wasn't installed | `cd ~/projects/AgentForcePMD && npm install` (the `file:./vendor/...` deps re-symlink) |
|
|
111
|
+
| `sf plugins link` reports "linked" but command absent | sf CLI cache | `rm -rf ~/.local/share/sf/client/*/node_modules/.cache 2>/dev/null && sf plugins link "$(pwd)"` |
|
|
112
|
+
| Warning about ESM transpilation | Expected — see above | Ignore. |
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Making sense of the output
|
|
2
|
+
|
|
3
|
+
The plugin emits one of five surfaces depending on flags. Pick by
|
|
4
|
+
downstream consumer.
|
|
5
|
+
|
|
6
|
+
## The five surfaces
|
|
7
|
+
|
|
8
|
+
| Surface | Triggered by | Audience |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| Text | default | Terminal eyeballs |
|
|
11
|
+
| JSON envelope | `--json` | Other SF plugins / `jq` pipelines |
|
|
12
|
+
| Markdown | `--format markdown` | PR descriptions, gists, whitepaper appendices |
|
|
13
|
+
| SARIF | `--format sarif` | GitHub Code Scanning, IDE annotations |
|
|
14
|
+
| CSV | `--format csv` | Spreadsheet pivots |
|
|
15
|
+
|
|
16
|
+
`--json` is special: it wraps the data in the standard SF CLI envelope
|
|
17
|
+
(`{ status, result, warnings }`) and takes precedence over `--format`.
|
|
18
|
+
Use it whenever something other than a human is reading.
|
|
19
|
+
|
|
20
|
+
## Text output
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Analyzing sfdx project /path/to/proj (1 package directory).
|
|
24
|
+
AgentForce PMD — Cyclomatic Complexity (McCabe)
|
|
25
|
+
============================================================
|
|
26
|
+
|
|
27
|
+
[agent] aiAuthoringBundles/Foo/Foo.agent CC=19
|
|
28
|
+
------------------------------------------------------------
|
|
29
|
+
start_agent play subtotal CC=19
|
|
30
|
+
reasoning.instructions CC=19 if=5 and=9 or=4
|
|
31
|
+
|
|
32
|
+
Action references
|
|
33
|
+
----------------------------------------------------------
|
|
34
|
+
pickRandomChoice [apex ] used 1x → apex://Foo_Random
|
|
35
|
+
|
|
36
|
+
Apex backing logic (resolved via apex:// targets)
|
|
37
|
+
============================================================
|
|
38
|
+
|
|
39
|
+
[apex] classes/Foo_Random.cls class CC=12
|
|
40
|
+
referenced by: aiAuthoringBundles/Foo/Foo.agent
|
|
41
|
+
------------------------------------------------------------
|
|
42
|
+
List<Result> execute(List<Request> requests) CC=8 ternary=2 ||=1 for=1 &&=2 catch=1
|
|
43
|
+
String freshCookie() CC=1 (base only)
|
|
44
|
+
String abbreviate(String s) CC=3 if=2
|
|
45
|
+
|
|
46
|
+
============================================================
|
|
47
|
+
CC by location (whitepaper § 7)
|
|
48
|
+
AgentScript: 19 Apex: 12 Combined: 31
|
|
49
|
+
Action declarations: 1 (apex 1, flow 0, prompt 0, unknown 0)
|
|
50
|
+
Action references: 2
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### How to read it
|
|
54
|
+
|
|
55
|
+
- **Header line** confirms what was analyzed (auto-discovered project or
|
|
56
|
+
explicit `--source-dir`). If you see this when you didn't expect
|
|
57
|
+
auto-discovery, you forgot `--source-dir`.
|
|
58
|
+
- **`[agent]` blocks**: one per `.agent` file. The bundle's CC and a
|
|
59
|
+
per-scope breakdown (`start_agent` and each `topic`).
|
|
60
|
+
- Each procedure line:
|
|
61
|
+
`<kind> CC=<n> <contributor breakdown>`
|
|
62
|
+
where contributor breakdown is something like `if=3 and=1`. The CC
|
|
63
|
+
number is the McCabe value (`1 + sum(contributors)`). `(base only)`
|
|
64
|
+
means no control flow; CC = 1.
|
|
65
|
+
- **Action references** lists each declared action with its target kind
|
|
66
|
+
(apex/flow/prompt/unknown) and a usage count (`used Nx`). A `used 0x`
|
|
67
|
+
declaration means the action is defined but not invoked — usually a
|
|
68
|
+
red flag (dead code) unless it's a planner-only action.
|
|
69
|
+
- **`[apex]` blocks**: one per `.cls` file resolved via `apex://`. Lists
|
|
70
|
+
every method and constructor with its signature, CC, and contributor
|
|
71
|
+
breakdown using Apex-flavored short names (`for`, `while`, `do-while`,
|
|
72
|
+
`when`, `catch`, `ternary`, `&&`, `||`).
|
|
73
|
+
- **`CC by location`** is the headline number: `AgentScript`,
|
|
74
|
+
`Apex`, `Combined`. This maps to the whitepaper § 7 framing — same
|
|
75
|
+
agent measured in two different layers, summed for the gross posture.
|
|
76
|
+
|
|
77
|
+
### TTY-aware rendering
|
|
78
|
+
|
|
79
|
+
When stdout isn't a TTY (piped, redirected, captured by CI), the text
|
|
80
|
+
renderer auto-degrades:
|
|
81
|
+
- Emoji prefixes (`📄`, `📜`) become `[agent]` / `[apex]`.
|
|
82
|
+
- Unicode rules (`═`, `─`) become `=` / `-`.
|
|
83
|
+
- ANSI color is disabled.
|
|
84
|
+
|
|
85
|
+
Force ASCII even on a TTY with `--ascii`. Force color off with
|
|
86
|
+
`--no-color` or `NO_COLOR=1`.
|
|
87
|
+
|
|
88
|
+
## JSON envelope (`--json`)
|
|
89
|
+
|
|
90
|
+
Standard SF CLI shape:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"status": 0,
|
|
95
|
+
"result": {
|
|
96
|
+
"files": [ { "path": "...", "procedures": [...], "fileComplexity": 19, ... } ],
|
|
97
|
+
"totalComplexity": 19,
|
|
98
|
+
"totalDeclarations": 1,
|
|
99
|
+
"totalReferences": 2,
|
|
100
|
+
"byTargetKind": { "apex": 1, "flow": 0, "prompt": 0, "utils": 0, "unknown": 0 },
|
|
101
|
+
"apexClasses": [ { "className": "...", "path": "...", "methods": [...], "classComplexity": 12, ... } ],
|
|
102
|
+
"totalApexComplexity": 12,
|
|
103
|
+
"unresolvedApexTargets": []
|
|
104
|
+
},
|
|
105
|
+
"warnings": []
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Useful `jq` recipes:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Combined CC for a CI gate
|
|
113
|
+
sf agentpmd analyze --json | jq '.result.totalComplexity + .result.totalApexComplexity'
|
|
114
|
+
|
|
115
|
+
# List apex:// targets that couldn't be resolved
|
|
116
|
+
sf agentpmd analyze --json | jq -r '.result.unresolvedApexTargets[]'
|
|
117
|
+
|
|
118
|
+
# Per-bundle CC table
|
|
119
|
+
sf agentpmd analyze --json | jq -r '.result.files[] | "\(.fileComplexity)\t\(.path)"'
|
|
120
|
+
|
|
121
|
+
# Methods exceeding CC 10
|
|
122
|
+
sf agentpmd analyze --json \
|
|
123
|
+
| jq -r '.result.apexClasses[].methods[] | select(.complexity >= 10) | "\(.complexity)\t\(.signature)"'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Markdown (`--format markdown`)
|
|
127
|
+
|
|
128
|
+
Designed for embedding in PR descriptions, gists, Slack snippets,
|
|
129
|
+
whitepaper appendices.
|
|
130
|
+
|
|
131
|
+
- Top: a Mermaid `xychart-beta` bar chart with one bar per `.agent`
|
|
132
|
+
bundle, split into AgentScript CC (red — whitepaper "Reasoning
|
|
133
|
+
Logic") and Apex CC (green — "Deterministic Logic"). Renders
|
|
134
|
+
natively in GitHub, GitLab, and most modern markdown previewers.
|
|
135
|
+
- Followed by a per-bundle table (procedure-by-procedure).
|
|
136
|
+
- Followed by a per-Apex-class table (method-by-method).
|
|
137
|
+
- Final "CC by location" totals row.
|
|
138
|
+
|
|
139
|
+
GFM pipe escaping is applied automatically — `||` short-circuit
|
|
140
|
+
operators in the Apex breakdown render as `\|\|` in cells so they don't
|
|
141
|
+
break the row.
|
|
142
|
+
|
|
143
|
+
Typical use:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
sf agentpmd analyze --format markdown > report.md
|
|
147
|
+
gh pr comment <pr-number> --body-file report.md
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## SARIF (`--format sarif`)
|
|
151
|
+
|
|
152
|
+
SARIF 2.1.0. One result per procedure + per Apex method. Severity
|
|
153
|
+
driven by `--sarif-warning` (default 10) and `--sarif-error` (default
|
|
154
|
+
20), matching PMD's `methodReportLevel` convention.
|
|
155
|
+
|
|
156
|
+
Upload to GitHub Code Scanning:
|
|
157
|
+
|
|
158
|
+
```yaml
|
|
159
|
+
# .github/workflows/agentpmd.yml
|
|
160
|
+
- name: Analyze
|
|
161
|
+
run: sf agentpmd analyze --format sarif > agentpmd.sarif
|
|
162
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
163
|
+
with:
|
|
164
|
+
sarif_file: agentpmd.sarif
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Each result carries `properties.complexity` (numeric) and
|
|
168
|
+
`properties.kind` (`method` / `constructor` for Apex, `before_reasoning`
|
|
169
|
+
/ `after_reasoning` / `reasoning_instructions` for AgentScript) so
|
|
170
|
+
follow-on tooling can re-band severity without re-running.
|
|
171
|
+
|
|
172
|
+
Row origins are normalized to 1-based in SARIF regardless of source
|
|
173
|
+
parser (AgentScript CST is 0-based; ANTLR is 1-based for line, 0-based
|
|
174
|
+
for column — the renderer adjusts).
|
|
175
|
+
|
|
176
|
+
## CSV (`--format csv`)
|
|
177
|
+
|
|
178
|
+
RFC-4180 quoted. One header row + one row per procedure / per Apex
|
|
179
|
+
method.
|
|
180
|
+
|
|
181
|
+
Columns:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
type, file, scope_or_class, name, complexity, start_row, start_col, contributors
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`type` is either `agent_procedure` or `apex_method`. `contributors`
|
|
188
|
+
is a semicolon-separated `kind=count` list (e.g.
|
|
189
|
+
`if_statement=3;short_circuit_and=1`).
|
|
190
|
+
|
|
191
|
+
Pivot in your favorite spreadsheet on `type` × `file` for a posture
|
|
192
|
+
matrix, or on `kind` (parsed from `contributors`) for a contributor
|
|
193
|
+
breakdown.
|
|
194
|
+
|
|
195
|
+
## Picking a format — the cheat sheet
|
|
196
|
+
|
|
197
|
+
| Question | Best surface |
|
|
198
|
+
| --- | --- |
|
|
199
|
+
| "What's the CC of this file right now in my terminal?" | text |
|
|
200
|
+
| "I want to gate the PR if combined CC ≥ 80." | `--fail-on 80` (uses text or `--json` for visibility) |
|
|
201
|
+
| "I want PR annotations on the specific high-CC methods." | sarif |
|
|
202
|
+
| "I want to drop a CC table into a PR description." | markdown |
|
|
203
|
+
| "I want to share the numbers in a quick gist." | markdown |
|
|
204
|
+
| "I want to feed the per-method numbers into a spreadsheet." | csv |
|
|
205
|
+
| "I want another tool / script to consume the output." | `--json` |
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Upgrade
|
|
2
|
+
|
|
3
|
+
## Path A — From source (linked checkout)
|
|
4
|
+
|
|
5
|
+
When `sf-agentpmd` is installed via `sf plugins link <repo>`, upgrading
|
|
6
|
+
means pulling new commits and rebuilding `lib/`. The link itself does
|
|
7
|
+
not need to be re-established.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd ~/projects/AgentForcePMD
|
|
11
|
+
git pull --ff-only
|
|
12
|
+
npm install # if dependencies changed
|
|
13
|
+
npm run build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
That's it. The next `sf agentpmd analyze` invocation picks up the new
|
|
17
|
+
`lib/`. No `sf plugins link` re-run is needed because the link points
|
|
18
|
+
at the on-disk directory, not at a specific build.
|
|
19
|
+
|
|
20
|
+
If `npm install` reports dependency tree changes that don't match
|
|
21
|
+
`package-lock.json`, that's fine — it usually means upstream patched a
|
|
22
|
+
transitive. To enforce a clean install matching the lockfile:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm ci # exact install per package-lock.json
|
|
26
|
+
npm run build
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### When to also `npm install`
|
|
30
|
+
|
|
31
|
+
| Trigger | Action |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| Only `src/` changed | `npm run build` |
|
|
34
|
+
| `package.json` or `package-lock.json` changed | `npm install && npm run build` |
|
|
35
|
+
| `vendor/` changed (e.g. agentscript parser refresh) | `npm install && npm run build` |
|
|
36
|
+
| `tsconfig.json` changed | `npm run clean && npm run build` |
|
|
37
|
+
|
|
38
|
+
## Path B — From npm (published plugin)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
sf plugins update # bumps every installed sf plugin
|
|
42
|
+
# or, to target this one:
|
|
43
|
+
sf plugins install sf-agentpmd@latest # explicit
|
|
44
|
+
sf plugins install sf-agentpmd@0.3.1 # pin to a specific version
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`sf plugins update` is idempotent and safe to run at any time. It
|
|
48
|
+
respects the version range declared at install (defaults to `latest`).
|
|
49
|
+
|
|
50
|
+
To check whether you're on the latest:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
sf plugins # shows installed version
|
|
54
|
+
npm view sf-agentpmd version # shows current published version
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Downgrade
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Path B: pin to an earlier version
|
|
61
|
+
sf plugins install sf-agentpmd@0.2.0
|
|
62
|
+
|
|
63
|
+
# Path A: git checkout the desired tag, then rebuild
|
|
64
|
+
cd ~/projects/AgentForcePMD
|
|
65
|
+
git checkout v0.2.0
|
|
66
|
+
npm install
|
|
67
|
+
npm run build
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Switching between linked source and published npm
|
|
71
|
+
|
|
72
|
+
To move from a linked checkout to the published version:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
sf plugins unlink sf-agentpmd
|
|
76
|
+
sf plugins install sf-agentpmd
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
To move from the published version back to a linked checkout:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
sf plugins uninstall sf-agentpmd
|
|
83
|
+
cd ~/projects/AgentForcePMD
|
|
84
|
+
sf plugins link "$(pwd)"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Refreshing the Claude Code skill
|
|
88
|
+
|
|
89
|
+
The bundled skill ships inside the plugin, so a plugin upgrade may carry
|
|
90
|
+
new skill content. After upgrading, re-copy the skill tree:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
sf agentpmd install-skill # re-copies skill/ to ~/.claude/skills/agentforcepmd/
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Restart Claude Code (or reload skills) to pick up the new content. If you
|
|
97
|
+
use a local-dev symlink (`~/.claude/skills/agentforcepmd` -> the repo's
|
|
98
|
+
`skill/` directory), no re-copy is needed — a `git pull` updates the
|
|
99
|
+
skill in place.
|
|
100
|
+
|
|
101
|
+
## Verifying the upgrade
|
|
102
|
+
|
|
103
|
+
Always sanity-check after upgrading:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
sf agentpmd analyze --help # confirm new flags / removed flags
|
|
107
|
+
sf agentpmd --version 2>/dev/null \
|
|
108
|
+
|| sf plugins | grep agentpmd # confirm version bump
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
If the plugin gained new commands, they appear under the `agentpmd`
|
|
112
|
+
topic. `sf agentpmd` (no subcommand) prompts to pick one.
|