@ryanstark24/sfgraph-skills 1.1.3 → 1.2.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/dist/__tests__/installer.test.js +8 -8
- package/package.json +1 -1
- package/skills/sf-cross-layer-trace/SKILL.md +5 -8
- package/skills/sf-cross-org-diff/SKILL.md +5 -5
- package/skills/sf-dead-code-audit/SKILL.md +3 -2
- package/skills/sf-debug-log-analysis/SKILL.md +103 -0
- package/skills/sf-debug-root-cause/SKILL.md +96 -0
- package/skills/sf-explain-code/SKILL.md +20 -4
- package/skills/sf-find-similar/SKILL.md +99 -0
- package/skills/sf-governor-risk-fix/SKILL.md +26 -4
- package/skills/sf-graph-router/SKILL.md +104 -0
- package/skills/sf-impact-from-diff/SKILL.md +7 -5
- package/skills/sf-security-audit/SKILL.md +4 -2
- package/skills/sf-snapshot-compare/SKILL.md +4 -4
- package/skills/sf-what-broke/SKILL.md +3 -3
- package/skills/sf-wip-impact/SKILL.md +5 -5
|
@@ -11,11 +11,11 @@ afterEach(() => {
|
|
|
11
11
|
rmSync(home, { recursive: true, force: true });
|
|
12
12
|
});
|
|
13
13
|
describe("skills installer", () => {
|
|
14
|
-
it("installs all
|
|
14
|
+
it("installs all 20 skills to the claude target", async () => {
|
|
15
15
|
const results = await install("claude", { homeOverride: home });
|
|
16
16
|
const skillNames = await listSkillsBundled();
|
|
17
|
-
expect(skillNames.length).toBe(
|
|
18
|
-
expect(results.length).toBe(
|
|
17
|
+
expect(skillNames.length).toBe(20);
|
|
18
|
+
expect(results.length).toBe(20);
|
|
19
19
|
for (const r of results) {
|
|
20
20
|
expect(r.target).toBe("claude");
|
|
21
21
|
expect(r.action).toBe("created");
|
|
@@ -26,11 +26,11 @@ describe("skills installer", () => {
|
|
|
26
26
|
});
|
|
27
27
|
it("installs to the cursor target as .mdc files in Cursor's frontmatter shape", async () => {
|
|
28
28
|
const results = await install("cursor", { homeOverride: home });
|
|
29
|
-
expect(results.length).toBe(
|
|
29
|
+
expect(results.length).toBe(20);
|
|
30
30
|
const cursorDir = join(home, ".cursor", "rules");
|
|
31
31
|
const files = readdirSync(cursorDir);
|
|
32
32
|
expect(files.every((f) => f.endsWith(".mdc"))).toBe(true);
|
|
33
|
-
expect(files.length).toBe(
|
|
33
|
+
expect(files.length).toBe(20);
|
|
34
34
|
// Cursor-shaped frontmatter (the three keys Cursor's rule loader reads).
|
|
35
35
|
const sample = readFileSync(join(cursorDir, files[0] ?? ""), "utf8");
|
|
36
36
|
expect(sample).toMatch(/^description:/m);
|
|
@@ -48,9 +48,9 @@ describe("skills installer", () => {
|
|
|
48
48
|
const claudeCount = results.filter((r) => r.target === "claude").length;
|
|
49
49
|
const cursorCount = results.filter((r) => r.target === "cursor").length;
|
|
50
50
|
const vscodeCount = results.filter((r) => r.target === "vscode").length;
|
|
51
|
-
expect(claudeCount).toBe(
|
|
52
|
-
expect(cursorCount).toBe(
|
|
53
|
-
expect(vscodeCount).toBe(
|
|
51
|
+
expect(claudeCount).toBe(20);
|
|
52
|
+
expect(cursorCount).toBe(20);
|
|
53
|
+
expect(vscodeCount).toBe(20);
|
|
54
54
|
expect(existsSync(join(home, ".claude", "skills"))).toBe(true);
|
|
55
55
|
expect(existsSync(join(home, ".cursor", "rules"))).toBe(true);
|
|
56
56
|
});
|
package/package.json
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-cross-layer-trace
|
|
3
|
-
description: Trace a field, component, or method end-to-end across
|
|
3
|
+
description: Trace a Salesforce field, LWC/Aura/VF component, or method end-to-end across UI → Apex → Flow → SObject. Use when the user asks "where is X used" or wants the full call chain across layers. For a plain-English explanation of one code unit only, prefer sf-explain-code. For schema/ERD views of objects, prefer sf-schema-overview. May be offered as a follow-up after sf-explain-code completes on a UI artifact, but do not auto-invoke alongside it — let the user opt in.
|
|
4
4
|
triggers:
|
|
5
5
|
- "UI to DB"
|
|
6
6
|
- "trace this LWC"
|
|
7
7
|
- "end-to-end"
|
|
8
8
|
- "where is this field used"
|
|
9
9
|
- "where does this come from"
|
|
10
|
-
- "explain this LWC"
|
|
11
|
-
- "explain this component"
|
|
12
|
-
- "what does this component do"
|
|
13
|
-
- "what does this LWC do"
|
|
14
|
-
- "explain this Aura"
|
|
15
|
-
- "explain this VisualForce"
|
|
16
|
-
- "explain this ApexPage"
|
|
17
10
|
- "where is this component used"
|
|
18
11
|
- "what pages embed"
|
|
19
12
|
- "which pages use"
|
|
@@ -72,6 +65,10 @@ flowchart TD
|
|
|
72
65
|
|
|
73
66
|
If the resolved trace has >30 nodes, ask the user to narrow to a single layer-pair before rendering — a sprawling layered diagram is more misleading than no diagram.
|
|
74
67
|
|
|
68
|
+
## Trace-tool noise defaults
|
|
69
|
+
|
|
70
|
+
If you drop down to `trace_upstream` / `trace_downstream` for a raw dependency walk, note they **hide security-grant and inferred edges by default**. A class granted to 100+ profiles, or a Vlocity node with reflection-walker string-name matches, would otherwise drown the real dependencies. The response tells you "N edges hidden". Only pass `include_security: true` for an access-centric question, or `include_inferred: true` when the user explicitly wants low-confidence reflection links. Use `rel_types: [...]` to pin a walk to specific relationships (e.g. `["CALLS","IS_TEST_FOR"]`). `cross_layer_flow_map` is unaffected — it already follows curated layer edges.
|
|
71
|
+
|
|
75
72
|
## Staleness check
|
|
76
73
|
|
|
77
74
|
Before calling `cross_layer_flow_map`, invoke `staleness_check` for the target org. If the report says stale, surface a warning to the user:
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-cross-org-diff
|
|
3
|
-
description: Compare metadata between
|
|
3
|
+
description: Compare metadata between TWO DIFFERENT ORGS (sandbox vs prod, sandbox vs sandbox) and summarise configuration drift between them. Use only when the user names two orgs or clearly contrasts environments. For "what changed since deploy" in a single org use sf-what-broke; for comparing point-in-time snapshots of one org use sf-snapshot-compare.
|
|
4
4
|
triggers:
|
|
5
5
|
- "sandbox vs prod"
|
|
6
|
-
- "
|
|
7
|
-
- "org diff"
|
|
8
|
-
- "
|
|
9
|
-
- "
|
|
6
|
+
- "compare these two orgs"
|
|
7
|
+
- "org-to-org diff"
|
|
8
|
+
- "drift between orgs"
|
|
9
|
+
- "what's different between <orgA> and <orgB>"
|
|
10
10
|
tools_used:
|
|
11
11
|
- cross_org_diff
|
|
12
12
|
- point_in_time_diff
|
|
@@ -12,6 +12,7 @@ tools_used:
|
|
|
12
12
|
- freshness_report
|
|
13
13
|
- trace_upstream
|
|
14
14
|
- staleness_check
|
|
15
|
+
- find_similar
|
|
15
16
|
---
|
|
16
17
|
|
|
17
18
|
# sf-dead-code-audit
|
|
@@ -20,9 +21,9 @@ Use when the user wants to inventory metadata that appears unreferenced. Output
|
|
|
20
21
|
|
|
21
22
|
## Playbook
|
|
22
23
|
|
|
23
|
-
1. Call `dead_code_audit`
|
|
24
|
+
1. Call `dead_code_audit` for the org. The tool **summarizes by confidence (`high`/`medium`/`low`) and by metadata type**, then renders a capped list (`limit`, default 50). On a large org there can be thousands of candidates — do NOT try to retrieve them all inline; work from the summary counts and drill in with `confidence: "high"` (most-likely-dead first) or raise `limit`. For the complete machine-readable set, use `export_sarif`. Each row carries a score + reasons (`no_incoming_edges`, `stale_freshness`).
|
|
24
25
|
2. Call `freshness_report` to layer last-touched timestamps onto each candidate. Stale + unreferenced is stronger evidence than unreferenced alone.
|
|
25
|
-
3. For any candidate the user names interactively, call `trace_upstream` to confirm absence of indirect callers (dynamic Apex, Flow lookups, callable interfaces).
|
|
26
|
+
3. For any candidate the user names interactively, call `trace_upstream` to confirm absence of indirect callers (dynamic Apex, Flow lookups, callable interfaces). Optionally call `find_similar(qname=<candidate>, k=5)` — if the candidate has near-neighbours (similarity > 0.6) that ARE referenced, the candidate may be a copy-paste duplicate of live code and worth deleting; if every neighbour is also in the dead list, you've found a whole disused subsystem worth flagging as a group.
|
|
26
27
|
4. Sort candidates into three buckets:
|
|
27
28
|
- **confident-dead** — no incoming edges, no dynamic-invocation signature match, freshness > 12 months, no inclusion in active permission sets / page layouts.
|
|
28
29
|
- **likely-dead** — no incoming edges, but at least one weak signal (recently modified, referenced from a managed package boundary, or named in a metadata file we don't parse fully).
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-debug-log-analysis
|
|
3
|
+
description: Read and analyse a Salesforce Apex debug log — exceptions/FATAL_ERROR, governor-limit consumption (SOQL/DML/CPU/heap), the execution call tree, and slow or repeated code units — then ground every finding in the org graph (map the log's code units/methods to qnames and explain WHY with trace/governor/analyze_field). Use when the user pastes or points to a debug log, an `sf apex get log` output, or asks to interpret a System.debug / stack trace / "Too many SOQL queries" / CPU-time log. Pairs with sf-debug-root-cause (log = symptom, graph = cause).
|
|
4
|
+
triggers:
|
|
5
|
+
- "debug log"
|
|
6
|
+
- "read this log"
|
|
7
|
+
- "analyze this log"
|
|
8
|
+
- "apex log"
|
|
9
|
+
- "Too many SOQL queries"
|
|
10
|
+
- "Apex CPU time limit"
|
|
11
|
+
- "System.debug output"
|
|
12
|
+
- "FATAL_ERROR"
|
|
13
|
+
- "LIMIT_USAGE"
|
|
14
|
+
- "sf apex get log"
|
|
15
|
+
- "stack trace from the log"
|
|
16
|
+
tools_used:
|
|
17
|
+
- find_nodes
|
|
18
|
+
- explain_code
|
|
19
|
+
- trace_upstream
|
|
20
|
+
- trace_downstream
|
|
21
|
+
- analyze_field
|
|
22
|
+
- governor_risk_check
|
|
23
|
+
- staleness_check
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# sf-debug-log-analysis
|
|
27
|
+
|
|
28
|
+
A Salesforce debug log is the ground truth of what *actually executed* — but on its own
|
|
29
|
+
it's a wall of pipe-delimited lines and it can't tell you *why* (what other code calls the
|
|
30
|
+
slow method, where the in-loop SOQL is declared, what writes the field that reverted).
|
|
31
|
+
This skill reads the log, extracts the signal, and **grounds each finding in the org graph**
|
|
32
|
+
so the answer is "the CPU went here because `OrderTriggerHandler.recalc` runs a SOQL inside
|
|
33
|
+
a `for` over `Trigger.new` — here are its 3 callers", not "looks like a CPU issue".
|
|
34
|
+
|
|
35
|
+
Format reference: <https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_debugging_debug_log.htm>
|
|
36
|
+
|
|
37
|
+
## Getting the log (if the user hasn't supplied one)
|
|
38
|
+
|
|
39
|
+
- Salesforce CLI: `sf apex list log` → `sf apex get log --log-id <id> > debug.log`, or live: `sf apex tail log --color none`.
|
|
40
|
+
- Setup → Debug Logs (trace flags on the user), then download.
|
|
41
|
+
- Tell the user the log level matters: `Apex Code = FINE`/`FINER` captures method entry/exit and SOQL; `Apex Profiling`/`System = FINE` captures the `CUMULATIVE_LIMIT_USAGE` block. `FINEST` is huge and often truncated at the 20 MB cap — prefer `FINE`/`FINER` unless you need variable-level detail.
|
|
42
|
+
|
|
43
|
+
## Reading the log (format)
|
|
44
|
+
|
|
45
|
+
The header line lists the API version + per-category log levels. Every subsequent line is
|
|
46
|
+
`HH:mm:ss.SSS (elapsedNanos)|EVENT_TYPE|details`. The event types that carry signal:
|
|
47
|
+
|
|
48
|
+
| Event | What it tells you |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `CODE_UNIT_STARTED` / `_FINISHED` | The unit boundaries — triggers, `Class.method`, flows, VF, anonymous. Top of the call tree. |
|
|
51
|
+
| `METHOD_ENTRY` / `METHOD_EXIT` | Method call tree (needs Apex Code ≥ FINER). Indentation/elapsed time = where time goes. |
|
|
52
|
+
| `SOQL_EXECUTE_BEGIN` / `_END` | Each query + `Rows:` returned + aggregations. **Count them** — repeated identical SOQL = in-loop. |
|
|
53
|
+
| `SOSL_EXECUTE_*`, `DML_BEGIN` / `_END` | SOSL and DML operations + row counts. |
|
|
54
|
+
| `CALLOUT_REQUEST` / `_RESPONSE` | HTTP callouts + endpoints + timing. |
|
|
55
|
+
| `EXCEPTION_THROWN` | The thrown exception + type + the offending `Class.method: line`. |
|
|
56
|
+
| `FATAL_ERROR` | The uncaught error + full Apex stack trace — the prime anchor for a failure. |
|
|
57
|
+
| `USER_DEBUG` | `System.debug()` output the developer planted. |
|
|
58
|
+
| `LIMIT_USAGE_FOR_NS` / `CUMULATIVE_LIMIT_USAGE` | **The governor scorecard** — SOQL queries, query rows, DML statements/rows, CPU time, heap, callouts used vs limit. |
|
|
59
|
+
| `HEAP_ALLOCATE`, `STATEMENT_EXECUTE`, `VARIABLE_*` | FINEST-only, very noisy — skip unless chasing a heap/variable bug. |
|
|
60
|
+
| `FLOW_*` / `WF_*` | Flow elements and Workflow-rule evaluation (order-of-execution bugs). |
|
|
61
|
+
|
|
62
|
+
## Method
|
|
63
|
+
|
|
64
|
+
1. **If the log is large, filter before reading.** Don't load a 20 MB log into context. Grep for the signal first:
|
|
65
|
+
`grep -nE 'FATAL_ERROR|EXCEPTION_THROWN|CUMULATIVE_LIMIT_USAGE|LIMIT_USAGE_FOR_NS' debug.log` for failures + limits;
|
|
66
|
+
`grep -c 'SOQL_EXECUTE_BEGIN' debug.log` for query count;
|
|
67
|
+
`grep -E 'CODE_UNIT_(STARTED|FINISHED)' debug.log` for the unit skeleton.
|
|
68
|
+
Read only the relevant slices.
|
|
69
|
+
2. **Classify the problem** from the evidence: an uncaught failure (`FATAL_ERROR`), a governor breach (limit at/over 100% in the cumulative block, or a `System.LimitException`), a performance issue (one `CODE_UNIT` dominating elapsed time), or just `USER_DEBUG` tracing.
|
|
70
|
+
3. **Extract the anchor:**
|
|
71
|
+
- Failure → the exception type + the top in-org frame `Class.method: line` from the stack trace.
|
|
72
|
+
- Governor → which limit, the count vs cap, and the `CODE_UNIT`/method where consumption spiked (repeated SOQL/DML lines under one unit).
|
|
73
|
+
- Performance → the `CODE_UNIT`/method with the largest elapsed delta.
|
|
74
|
+
4. **Ground it in the graph** (the part a log reader alone can't do):
|
|
75
|
+
- `find_nodes ApexClass:<Name>` / `ApexMethod:<Name>.*` to resolve the anchor to a qname; `explain_code` on the method to read the offending source.
|
|
76
|
+
- `trace_upstream` — who invokes this unit, and in what context (trigger vs batch vs LWC). Order-of-execution and "why was this even called" answers live here.
|
|
77
|
+
- `trace_downstream` — what it calls/reads/writes; a NullPointer or limit usually originates in a callee.
|
|
78
|
+
- Governor breach → `governor_risk_check` scoped to the class to pinpoint the SOQL/DML-in-loop **source line** the log proved is hot.
|
|
79
|
+
- Field misbehaviour seen in the log → `analyze_field` for every trigger/Flow/validation that fires on that field (competing automation).
|
|
80
|
+
5. **State a single root-cause hypothesis** backed by *both* the log evidence and the graph evidence, then hand the fix to the right design skill (`sf-architect-apex` / `sf-architect-performance` / `sf-governor-risk-fix`) — grounded, never generic.
|
|
81
|
+
|
|
82
|
+
## Staleness
|
|
83
|
+
|
|
84
|
+
If you'll ground in the graph, call `staleness_check` first. A stale graph maps the log's
|
|
85
|
+
code units to outdated source — warn and recommend `sfgraph ingest --org <alias>`. The log
|
|
86
|
+
itself is always current; the mismatch is on the graph side.
|
|
87
|
+
|
|
88
|
+
## Response shape
|
|
89
|
+
|
|
90
|
+
- **Verdict** — one line: failure / governor breach / performance / trace-only, with the anchor `Class.method:line`.
|
|
91
|
+
- **Log evidence** — the decisive lines (exception, the cumulative-limit row that breached, the repeated SOQL count, the dominant code unit) — quote them, don't paraphrase.
|
|
92
|
+
- **Graph grounding** — callers, callees, competing automation, or the in-loop source line that explains the log.
|
|
93
|
+
- **Root cause** — one hypothesis, confidence, tied to both evidence sources.
|
|
94
|
+
- **Fix** — described and handed off to a design skill; not auto-applied.
|
|
95
|
+
- **Mermaid** — optional call-tree or caller→unit→callee path when it clarifies.
|
|
96
|
+
|
|
97
|
+
## Don't
|
|
98
|
+
|
|
99
|
+
- Don't load a multi-MB log wholesale — filter with grep first, then read slices. Say what you filtered so nothing looks silently dropped.
|
|
100
|
+
- Don't stop at the log. The log shows *what*; grounding in the graph shows *why* — that's the value. A log-only answer is a guess about the cause.
|
|
101
|
+
- Don't trust `FINEST` noise (`STATEMENT_EXECUTE`/`VARIABLE_ASSIGNMENT`) as signal — anchor on CODE_UNIT/SOQL/DML/limit/exception events.
|
|
102
|
+
- Don't edit code here — produce evidence + root cause; design hands off.
|
|
103
|
+
- Don't confuse a logged, *caught* `EXCEPTION_THROWN` with the actual failure — the uncaught `FATAL_ERROR` (if present) is the one that ended the transaction.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-debug-root-cause
|
|
3
|
+
description: Root-cause a SPECIFIC Salesforce failure — an Apex exception or stack trace, a failing test, a flow fault, or "this field/record isn't behaving right" — by grounding the symptom in the org graph (callers, callees, recent changes, automation on the object, test coverage). Use when the user reports a concrete error/symptom and wants to know WHY. For "what changed since deploy" broadly use sf-what-broke; for pre-commit blast radius use sf-wip-impact.
|
|
4
|
+
triggers:
|
|
5
|
+
- "why is this failing"
|
|
6
|
+
- "debug this error"
|
|
7
|
+
- "this test fails"
|
|
8
|
+
- "stack trace"
|
|
9
|
+
- "NullPointerException"
|
|
10
|
+
- "System.LimitException"
|
|
11
|
+
- "this trigger isn't firing"
|
|
12
|
+
- "field isn't updating"
|
|
13
|
+
- "flow fault"
|
|
14
|
+
- "root cause"
|
|
15
|
+
tools_used:
|
|
16
|
+
- find_nodes
|
|
17
|
+
- explain_code
|
|
18
|
+
- trace_upstream
|
|
19
|
+
- trace_downstream
|
|
20
|
+
- analyze_field
|
|
21
|
+
- what_broke
|
|
22
|
+
- test_gap_intelligence_from_git_diff
|
|
23
|
+
- staleness_check
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# sf-debug-root-cause
|
|
27
|
+
|
|
28
|
+
Use when the user has a **concrete failure** and wants the cause, not a guess. Salesforce
|
|
29
|
+
failures are rarely in the one method that threw — they come from another trigger on the
|
|
30
|
+
same object, a recent change upstream, an order-of-execution surprise, or automation the
|
|
31
|
+
developer forgot exists. The graph makes those visible. Debug by narrowing with evidence,
|
|
32
|
+
never by pattern-matching the error message to a generic fix.
|
|
33
|
+
|
|
34
|
+
## Method (scientific, evidence-first)
|
|
35
|
+
|
|
36
|
+
0. **If a debug log is available, start there.** A debug log is the strongest anchor — it
|
|
37
|
+
has the exact `FATAL_ERROR` stack frame and the real governor scorecard. Hand the log to
|
|
38
|
+
**`sf-debug-log-analysis`** to extract the anchor + limit evidence, then continue this
|
|
39
|
+
playbook from step 2 with that anchor. Without a log, anchor from the error text/symptom:
|
|
40
|
+
|
|
41
|
+
1. **Anchor the symptom to a node.** Parse the error / test name / symptom for the failing
|
|
42
|
+
unit and resolve its qname:
|
|
43
|
+
- Apex class/method in the trace → `find_nodes ApexClass:<Name>` / `ApexMethod:<Name>.*`.
|
|
44
|
+
- Failing test → the test method, then its `IS_TEST_FOR` target.
|
|
45
|
+
- "Field X isn't updating" → `analyze_field` on `<Object>.<Field>`.
|
|
46
|
+
If you can't anchor it, ask the user for the class/object name — don't guess.
|
|
47
|
+
|
|
48
|
+
2. **Read the failing unit.** `explain_code(qname=<ApexMethod>)` — get the source + branch
|
|
49
|
+
annotation. Confirm the line in the trace maps to a real branch (SOQL, DML, deref).
|
|
50
|
+
|
|
51
|
+
3. **Look outward for the real cause — this is where graphs beat grep:**
|
|
52
|
+
- `trace_downstream(qname)` — what it calls / reads / writes. A `System.NullPointer` or
|
|
53
|
+
`LimitException` usually originates in a callee or a SOQL/DML it triggers.
|
|
54
|
+
- `trace_upstream(qname)` — who invokes it, and with what context (trigger vs batch vs
|
|
55
|
+
LWC). Order-of-execution bugs hide here.
|
|
56
|
+
- For an object symptom: `sf-flow-impact` / `analyze_field` — every trigger, Flow,
|
|
57
|
+
Process Builder, and validation rule that fires on the object. "Trigger isn't firing"
|
|
58
|
+
and "field reverts" are almost always a competing automation.
|
|
59
|
+
- Governor `LimitException` → hand to `sf-governor-risk-fix` scoped to the class to find
|
|
60
|
+
the SOQL/DML-in-loop.
|
|
61
|
+
|
|
62
|
+
4. **Check what recently changed.** `sf-what-broke` (or `what_broke`) for the org since the
|
|
63
|
+
last deploy/ingest — if the failing node or any node it depends on changed recently,
|
|
64
|
+
that's your prime suspect. Correlate the failure's first-seen time with the change.
|
|
65
|
+
|
|
66
|
+
5. **Check test coverage of the suspect path** — `test_gap_intelligence_from_git_diff` (if a
|
|
67
|
+
diff exists) or the `IS_TEST_FOR` edges — a path with no test is where regressions live.
|
|
68
|
+
|
|
69
|
+
6. **State a single hypothesis, then confirm it** against the graph before recommending a
|
|
70
|
+
fix. "I think X because the graph shows Y." If the evidence doesn't support it, form a
|
|
71
|
+
new hypothesis — don't stack speculative fixes.
|
|
72
|
+
|
|
73
|
+
## Staleness check
|
|
74
|
+
|
|
75
|
+
Call `staleness_check` first. A stale graph misleads root-cause analysis (the change that
|
|
76
|
+
caused the bug may not be ingested yet). If stale, warn and recommend
|
|
77
|
+
`sfgraph ingest --org <alias>` before trusting the upstream/recent-change steps.
|
|
78
|
+
|
|
79
|
+
## Response shape
|
|
80
|
+
|
|
81
|
+
- **Symptom** — the error/test/behaviour, anchored to a qname.
|
|
82
|
+
- **Evidence chain** — the graph facts that narrow the cause (callers, callees, competing
|
|
83
|
+
automation, recent changes, coverage gaps), each tied to the tool that surfaced it.
|
|
84
|
+
- **Root-cause hypothesis** — one, with the supporting evidence. Confidence level.
|
|
85
|
+
- **Recommended fix** — described, not auto-applied; hand to `sf-architect-apex` /
|
|
86
|
+
`sf-architect-ui` / `sf-governor-risk-fix` to design it, grounded in this evidence.
|
|
87
|
+
- **Mermaid** — optional: the failing path (caller → unit → callee/field) when it clarifies.
|
|
88
|
+
|
|
89
|
+
## Don't
|
|
90
|
+
|
|
91
|
+
- Don't propose a fix before anchoring the symptom to a real node and reading its source.
|
|
92
|
+
- Don't ignore competing automation — on object symptoms it's the most common root cause and
|
|
93
|
+
the thing a stack trace alone never shows.
|
|
94
|
+
- Don't stack multiple speculative fixes; one hypothesis, confirmed, at a time.
|
|
95
|
+
- Don't edit code here — root-cause + evidence is the deliverable; design hands off.
|
|
96
|
+
- Don't trust a stale graph for "what recently changed" without flagging it.
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-explain-code
|
|
3
|
-
description: Explain
|
|
3
|
+
description: Explain a single Salesforce code unit (Apex method/class/trigger, LWC handler, Aura controller method) in plain English with conditional-branch annotation, then cache the explanation back to the sfgraph store. Salesforce metadata only — do NOT use for non-Salesforce code (e.g. Node, Python, ingest pipeline scripts) even when asked inside this repo. Scope is one named code unit; for end-to-end UI→DB tracing across layers use sf-cross-layer-trace, for whole-object schema views use sf-schema-overview.
|
|
4
4
|
triggers:
|
|
5
|
-
- "explain this method"
|
|
6
|
-
- "
|
|
5
|
+
- "explain this Apex method"
|
|
6
|
+
- "explain this trigger"
|
|
7
|
+
- "explain this LWC handler"
|
|
8
|
+
- "what does <ApexClass.method> do"
|
|
7
9
|
- "walk me through <qname>"
|
|
8
10
|
- "annotate the conditionals"
|
|
9
11
|
tools_used:
|
|
@@ -11,6 +13,7 @@ tools_used:
|
|
|
11
13
|
- trace_upstream
|
|
12
14
|
- trace_downstream
|
|
13
15
|
- staleness_check
|
|
16
|
+
- find_similar
|
|
14
17
|
---
|
|
15
18
|
|
|
16
19
|
# sf-explain-code
|
|
@@ -19,7 +22,7 @@ Use this skill when the user wants a plain-English explanation of a specific cod
|
|
|
19
22
|
|
|
20
23
|
## Playbook
|
|
21
24
|
|
|
22
|
-
1. **Resolve the target qname.**
|
|
25
|
+
1. **Resolve the target qname — it must be METHOD-level.** Snippets are stored only for Apex methods, so `explain_code` needs `ApexMethod:AccountSvc.calculate(N)` (N = arity), **not** a class qname like `ApexClass:AccountSvc` (that returns "No snippet stored"). If the user names a class, first enumerate its methods with `find_nodes(pattern="ApexMethod:AccountSvc.*")` and either pick the method they meant or explain each in turn. For declarative metadata (fields, objects, Flows) there is no snippet — redirect to `analyze_field` / `sf-cross-layer-trace` instead. If the arity is unknown or the name is ambiguous, use `find_nodes` to enumerate candidates and confirm with the user.
|
|
23
26
|
2. **`staleness_check`** for the linked org. If stale, surface a warning so the user knows the cached source may not reflect production.
|
|
24
27
|
3. **`explain_code(qname=X)`** — pull the stored snippet and any prior cached explanation. The tool returns the source text in a fenced code block.
|
|
25
28
|
4. **Generate the explanation**, structured as:
|
|
@@ -58,9 +61,22 @@ Continue the playbook either way; just flag the risk.
|
|
|
58
61
|
- **Mermaid** — only when conditional structure justifies it.
|
|
59
62
|
- **Cached** — confirm the explanation was cached back, with the qname.
|
|
60
63
|
|
|
64
|
+
## Follow-up: "what else is like this?"
|
|
65
|
+
|
|
66
|
+
After delivering the explanation, offer a one-line follow-up:
|
|
67
|
+
|
|
68
|
+
> _Want me to find semantically similar code? I can run `find_similar` on this qname._
|
|
69
|
+
|
|
70
|
+
If the user says yes, hand off to `sf-find-similar` with mode=qname and the same qname. Don't pre-emptively run it — the embedding query takes a moment and the user may not want it. The chain is most useful when:
|
|
71
|
+
|
|
72
|
+
- The user is reviewing legacy code and wants to spot duplicates.
|
|
73
|
+
- The method does something domain-specific (taxes, compliance, pricing) and the user wants to find every place that handles the same concept.
|
|
74
|
+
- The agent already produced an explanation but the user wonders "is this the only place this logic lives?".
|
|
75
|
+
|
|
61
76
|
## Don't
|
|
62
77
|
|
|
63
78
|
- Don't modify the source. This skill is read-only against the local graph.
|
|
64
79
|
- Don't write anything to Salesforce.
|
|
65
80
|
- Always render the source inside a fenced code block tagged with the `sourceFormat` returned by `explain_code` (`apex`, `js`, `html`, etc.).
|
|
66
81
|
- Don't fabricate behaviour — if the source is empty or stubbed, say so plainly.
|
|
82
|
+
- Don't pass a class/trigger/field qname expecting source — only `ApexMethod:...(N)` has a snippet. On "No snippet stored", resolve to a method qname rather than reporting failure.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-find-similar
|
|
3
|
+
description: Find Salesforce metadata that is semantically similar to an existing node OR a free-text concept. Two modes — pass a qname to anchor on an existing node (e.g. "show me other Apex methods like BillingSvc.run"), or pass free text to discover code by meaning when no name fits (e.g. "find code that handles order cancellation"). Use when exact-name search misses, when an agent wants to surface near-misses for review, or when the user describes a concept rather than a node. Powered by the MiniLM-L6 embeddings produced during ingest and the `vec0` SQLite KNN index. Filter by label to restrict to one node type. Do NOT use for structural edge traversal — for "what does X call" / "who reads field Y" use trace_downstream / analyze_field, which give exact answers; this skill is for fuzzy / conceptual matches.
|
|
4
|
+
triggers:
|
|
5
|
+
- "find similar"
|
|
6
|
+
- "show me code like"
|
|
7
|
+
- "what else is like"
|
|
8
|
+
- "find nodes similar to"
|
|
9
|
+
- "semantically similar"
|
|
10
|
+
- "find code that handles"
|
|
11
|
+
- "where do we"
|
|
12
|
+
- "anything related to"
|
|
13
|
+
- "fuzzy search"
|
|
14
|
+
- "more like this"
|
|
15
|
+
tools_used:
|
|
16
|
+
- find_similar
|
|
17
|
+
- explain_code
|
|
18
|
+
- trace_downstream
|
|
19
|
+
- analyze_field
|
|
20
|
+
- staleness_check
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# sf-find-similar
|
|
24
|
+
|
|
25
|
+
Use this skill when the user wants discovery rather than exact lookup: *"what other Apex methods are like this one"*, *"find code that handles order cancellation"*, *"is there anything similar to `accountTile`?"*. Powered by the in-process MiniLM-L6 embeddings sfgraph produces during every ingest.
|
|
26
|
+
|
|
27
|
+
## When to choose this vs. the other tools
|
|
28
|
+
|
|
29
|
+
| Question shape | Use |
|
|
30
|
+
|---|---|
|
|
31
|
+
| "What does X call?" / "Who reads field Y?" | `trace_downstream` / `analyze_field` — exact graph edges |
|
|
32
|
+
| "Explain method X" | `sf-explain-code` |
|
|
33
|
+
| "What else is like X?" / "Find code that does Y" | **`sf-find-similar`** |
|
|
34
|
+
| "What changed?" / "What broke?" | `sf-what-broke`, `sf-cross-org-diff`, `sf-impact-from-diff` |
|
|
35
|
+
|
|
36
|
+
If the user mentions an exact qname *and* asks for relationships, prefer the structural tool. Reach for `find_similar` when names don't match or the user is describing a concept.
|
|
37
|
+
|
|
38
|
+
## Two modes
|
|
39
|
+
|
|
40
|
+
### Mode A — anchored on an existing node (`qname`)
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
find_similar(org="my-org", qname="ApexClass:BillingSvc", k=10, label="ApexClass")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Use when the user names a node and wants "more like this." Pass `label` when restricting matters (e.g. "other LWCs like accountTile" — set `label="LWC"`).
|
|
47
|
+
|
|
48
|
+
### Mode B — free-text concept (`text`)
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
find_similar(org="my-org", text="code that computes compliance fees", k=10)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Use when the user describes the *what* but not the *which*. The query is embedded on the fly with the same MiniLM-L6 pipeline the ingest uses. Most useful when:
|
|
55
|
+
|
|
56
|
+
- The user couldn't recall an exact class/method name.
|
|
57
|
+
- The concept spans multiple classes — semantic match surfaces them all.
|
|
58
|
+
- The user explicitly says "find code that does X" / "where do we Y".
|
|
59
|
+
|
|
60
|
+
## Playbook
|
|
61
|
+
|
|
62
|
+
1. **Pick the mode** based on whether the user named a node or described a concept.
|
|
63
|
+
2. **`staleness_check`** for the org. If stale, warn — embeddings may not reflect production code.
|
|
64
|
+
3. **`find_similar`** with the chosen mode. Use `k=10` by default; raise to 20–30 only if the user asks "more results."
|
|
65
|
+
4. **Read the response** — it returns a ranked table of `(qname, label, similarity, distance)`. Similarity is 0–1, higher is closer.
|
|
66
|
+
5. **Filter the noise.** Similarity < ~0.4 is usually unrelated text overlap, not real semantic match. Drop those before surfacing to the user unless they explicitly asked for everything.
|
|
67
|
+
6. **Offer to drill in.** For each hit the user seems interested in, propose chaining to `sf-explain-code` (what does this one do?) or `trace_downstream` (where does it flow?).
|
|
68
|
+
|
|
69
|
+
## Visualization
|
|
70
|
+
|
|
71
|
+
When the result set has 5+ hits, render a horizontal bar chart (Mermaid `xychart-beta`) of similarity scores so the user can eyeball the cluster vs. tail. For ≤4 hits the table alone is fine.
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
xychart-beta
|
|
75
|
+
title "Similarity to BillingSvc"
|
|
76
|
+
x-axis [OrderInvoiceSvc, CreditMemoSvc, TaxCalcSvc, RebateSvc]
|
|
77
|
+
y-axis "similarity" 0 --> 1
|
|
78
|
+
bar [0.82, 0.79, 0.71, 0.55]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Common failure modes & how to handle them
|
|
82
|
+
|
|
83
|
+
- **`reason: vector_index_unavailable`** — the org's graph was ingested before embeddings were wired up, or the optional `@ryanstark24/sfgraph-models` install was skipped. Tell the user verbatim what the tool's markdown suggests: re-install with `npm install -g @ryanstark24/sfgraph` and re-ingest with `--rebuild`.
|
|
84
|
+
- **`reason: no_focal_vector`** (qname mode) — the qname is wrong or its label isn't embedded. Confirm the qname spelling. If correct, suggest re-trying with `text` mode using the user's description of the node.
|
|
85
|
+
- **`reason: embedder_unavailable`** (text mode) — the MiniLM runtime isn't present. Fall back to qname mode if the user can name a similar node.
|
|
86
|
+
- **`reason: no_neighbours`** — genuinely no similar nodes. Suggest dropping the `label` filter, or running structural `trace_upstream` / `trace_downstream` instead.
|
|
87
|
+
|
|
88
|
+
## Response shape
|
|
89
|
+
|
|
90
|
+
- **TL;DR** — "Top N matches for `<focal>`."
|
|
91
|
+
- **Ranked table** — qname, label, similarity (3 decimal places), distance.
|
|
92
|
+
- **Drop-low note** — if you filtered out scores <0.4, say so: "Skipped 3 results below the 0.4 noise floor."
|
|
93
|
+
- **Follow-ups** — propose `explain_code` / `trace_downstream` for the top hit.
|
|
94
|
+
|
|
95
|
+
## Don't
|
|
96
|
+
|
|
97
|
+
- Don't claim semantic match implies a structural edge. If the user wants "who actually calls X", route to `trace_upstream`. Similarity ≠ dependency.
|
|
98
|
+
- Don't surface scores below ~0.4 unless the user explicitly asked for a wider net. They are usually statistical noise from the embedding space.
|
|
99
|
+
- Don't use this for "what changed" / "what broke" questions — those need diff-style tools, not semantic neighbours.
|
|
@@ -17,11 +17,32 @@ tools_used:
|
|
|
17
17
|
|
|
18
18
|
Use when the user wants to find Apex code that risks hitting governor limits at scale. The skill produces a prioritised remediation checklist; it never rewrites Apex automatically.
|
|
19
19
|
|
|
20
|
+
## What the tool actually emits
|
|
21
|
+
|
|
22
|
+
`governor_risk_check` reports only the risk types the analyzer can prove from
|
|
23
|
+
the graph. As of the edge-based detector these are:
|
|
24
|
+
|
|
25
|
+
- **`soql_in_loop`** — a SOQL query whose `EXECUTES_SOQL` edge is tagged
|
|
26
|
+
`inLoop` (AST-verified: the query sits inside a for/while/do-while body).
|
|
27
|
+
- **`dml_in_loop`** — same, for DML statements.
|
|
28
|
+
- **`no_bulk`** — a trigger that doesn't iterate `Trigger.new` (body-scan path).
|
|
29
|
+
|
|
30
|
+
Do **not** promise `UNBOUNDED_QUERY`, `NON_SELECTIVE_QUERY`, `CALLOUT_IN_LOOP`,
|
|
31
|
+
`LARGE_HEAP`, or `RECURSIVE_TRIGGER` — the tool does not produce them. (Unbounded-
|
|
32
|
+
query was removed: on a real org ~100% of SOQL has no WHERE/LIMIT in the captured
|
|
33
|
+
query head, so it was pure noise.)
|
|
34
|
+
|
|
35
|
+
**Live-ingest prerequisite:** `inLoop` tagging comes from the Apex AST parser. A
|
|
36
|
+
graph ingested before that parser change has zero `inLoop` edges, so the check
|
|
37
|
+
returns nothing. If `governor_risk_check` returns empty on an org you believe has
|
|
38
|
+
in-loop SOQL, the fix is a re-ingest (`sfgraph ingest --org <alias> --rebuild`),
|
|
39
|
+
not "the org is clean" — say so explicitly rather than reporting a false all-clear.
|
|
40
|
+
|
|
20
41
|
## Playbook
|
|
21
42
|
|
|
22
|
-
1. Call `governor_risk_check` over the requested scope (single class, namespace, or full org). The tool returns risk records
|
|
23
|
-
2. Group findings by
|
|
24
|
-
3. For each finding, describe the canonical fix pattern (e.g. "extract the SOQL above the loop and key the result by `Id`") in one or two sentences — do not write the code.
|
|
43
|
+
1. Call `governor_risk_check` over the requested scope (single class, namespace, or full org). The tool returns risk records keyed on the **method** qname (`ApexMethod:Class.method(n)`) with `risk_type` (`soql_in_loop` / `dml_in_loop` / `no_bulk`) and evidence (the query text or DML target).
|
|
44
|
+
2. Group findings by `risk_type`; within each group, sort by call-site fan-in (more callers = higher blast radius). Use `trace_upstream` on the owning class to get fan-in.
|
|
45
|
+
3. For each finding, describe the canonical fix pattern (e.g. "extract the SOQL above the loop and key the result by `Id`") in one or two sentences — do not write the code. To actually design the bulkified fix, hand off to **`sf-architect-apex`** (or **`sf-architect-performance`** for LDV/query-plan work) with these call sites as grounding, so the rewrite respects the org's real selectors and trigger framework rather than a generic template.
|
|
25
46
|
4. Render the Mermaid heat-map (class-by-rule) from the tool response.
|
|
26
47
|
5. Produce a checklist the user can copy into a ticket: `- [ ] ClassName.methodName:line — rule — recommended pattern`.
|
|
27
48
|
6. Recommend `sf-impact-from-diff` after the user applies fixes, to verify nothing downstream regressed.
|
|
@@ -60,5 +81,6 @@ Then continue with the playbook.
|
|
|
60
81
|
|
|
61
82
|
- **Never auto-apply fixes.** This skill does not edit Apex.
|
|
62
83
|
- Do not flatten severities — the bucket ordering matters.
|
|
63
|
-
- Do not invent additional rules; only report what `governor_risk_check` returns.
|
|
84
|
+
- Do not invent additional rules; only report what `governor_risk_check` returns (`soql_in_loop`, `dml_in_loop`, `no_bulk`).
|
|
85
|
+
- Do not report "no governor risks" without first checking staleness — an empty result on a pre-AST-parser ingest means the graph lacks `inLoop` tags, not that the code is clean. Recommend a re-ingest.
|
|
64
86
|
- Do not silently exclude managed-package code; mention it was filtered out if so.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sf-graph-router
|
|
3
|
+
description: Start here for ANY Salesforce development, design, or debugging task on an org sfgraph has ingested. Routes intent to the right sfgraph skill + MCP tool, and enforces the grounding-first rule — query the org graph for real schema / dependencies / security / governor facts BEFORE generating or changing Apex, LWC, Flow, or config. Use when the user asks to build, design, refactor, review, or debug Salesforce metadata and you are unsure which skill or tool applies, or when about to write Salesforce code from memory.
|
|
4
|
+
triggers:
|
|
5
|
+
- "help me build"
|
|
6
|
+
- "design a"
|
|
7
|
+
- "write a trigger"
|
|
8
|
+
- "write apex"
|
|
9
|
+
- "create an LWC"
|
|
10
|
+
- "refactor this"
|
|
11
|
+
- "review my"
|
|
12
|
+
- "is this safe to deploy"
|
|
13
|
+
- "which sfgraph tool"
|
|
14
|
+
- "where do I start"
|
|
15
|
+
- "debug this"
|
|
16
|
+
- "why is this failing"
|
|
17
|
+
tools_used:
|
|
18
|
+
- find_nodes
|
|
19
|
+
- analyze_field
|
|
20
|
+
- find_similar
|
|
21
|
+
- staleness_check
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# sf-graph-router — start here
|
|
25
|
+
|
|
26
|
+
sfgraph has a **local, queryable graph of the real org** (every Apex class, LWC, Flow,
|
|
27
|
+
field, profile, Vlocity/OmniStudio component, and the edges between them). That graph is
|
|
28
|
+
the antidote to the #1 failure of LLM-assisted Salesforce work: **hallucinating field
|
|
29
|
+
names, classes, and call chains that don't exist in this org.** This skill decides which
|
|
30
|
+
specialised skill/tool to use, and enforces one rule above all.
|
|
31
|
+
|
|
32
|
+
## The grounding-first rule (non-negotiable)
|
|
33
|
+
|
|
34
|
+
**Before you generate or modify any Salesforce metadata — Apex, LWC, Flow, validation
|
|
35
|
+
rule, permission set — query the graph to ground yourself in what the org actually
|
|
36
|
+
contains.** Designing from training data alone is how you invent `Account.Tier__c` when
|
|
37
|
+
the org has `Account.Customer_Tier__c`, call a method arity that doesn't exist, or write a
|
|
38
|
+
trigger that ignores the three triggers already on the object.
|
|
39
|
+
|
|
40
|
+
Minimum grounding before writing code that touches object/field `X` or class `Y`:
|
|
41
|
+
|
|
42
|
+
1. `find_nodes` — confirm the qnames exist (`CustomField:Account.*`, `ApexClass:*Order*`).
|
|
43
|
+
2. `analyze_field` — for any field you'll read/write: who already reads/writes it, its type.
|
|
44
|
+
3. `find_similar` — is there existing code that already does this? Reuse beats regenerate.
|
|
45
|
+
4. For changes to existing Apex: `trace_upstream` (callers / blast radius) + `explain_code`.
|
|
46
|
+
|
|
47
|
+
If `staleness_check` says the ingest is old, say so — your grounding may be out of date —
|
|
48
|
+
and recommend `sfgraph ingest --org <alias>`. If the org isn't ingested at all, say the
|
|
49
|
+
grounding step is unavailable and proceed with explicit low-confidence caveats.
|
|
50
|
+
|
|
51
|
+
Only after grounding do you hand off to a design/knowledge skill (`sf-architect-*`) to
|
|
52
|
+
write the code. Ground → design → verify. Never design → hope.
|
|
53
|
+
|
|
54
|
+
## Route by intent
|
|
55
|
+
|
|
56
|
+
### DEVELOPMENT — writing or changing code
|
|
57
|
+
| Intent | Ground with | Then design with |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| "Write/extend Apex on `<Object>`" | `sf-schema-overview` (`<Object>`) + `find_nodes ApexClass:*<Object>*` + `find_similar` | `sf-architect-apex` |
|
|
60
|
+
| "Build an LWC for `<feature>`" | `find_similar` (existing LWCs) + `analyze_field` (bound fields) | `sf-architect-ui` |
|
|
61
|
+
| "Add an integration / callout" | `find_nodes NamedCredential:*` + `find_similar` | `sf-architect-integrations` |
|
|
62
|
+
| "Reuse — is this already built?" | `sf-find-similar` (free-text concept mode) | — |
|
|
63
|
+
| "Explain this method/class" | `sf-explain-code` (needs `ApexMethod:Class.m(n)`) | — |
|
|
64
|
+
|
|
65
|
+
### DESIGN — architecture & data model
|
|
66
|
+
| Intent | Skill |
|
|
67
|
+
|---|---|
|
|
68
|
+
| "Show the data model / ERD for `<Object>`" | `sf-schema-overview` |
|
|
69
|
+
| "Trace `<field/LWC/method>` UI → DB" | `sf-cross-layer-trace` |
|
|
70
|
+
| "Where is `<field>` used / what writes it" | `sf-flow-impact` (Flow/automation) or `analyze_field` (all layers) |
|
|
71
|
+
| "Find duplicate / similar logic to consolidate" | `sf-find-similar` |
|
|
72
|
+
|
|
73
|
+
### DEBUGGING — something is wrong
|
|
74
|
+
| Intent | Skill |
|
|
75
|
+
|---|---|
|
|
76
|
+
| "This Apex/test fails / this error — why" | `sf-debug-root-cause` |
|
|
77
|
+
| "Read/interpret this debug log / stack trace / 'Too many SOQL' / CPU-time log" | `sf-debug-log-analysis` |
|
|
78
|
+
| "What broke after the last deploy" | `sf-what-broke` |
|
|
79
|
+
| "Will my uncommitted change break anything" | `sf-wip-impact` |
|
|
80
|
+
| "Blast radius + test gaps of this PR/branch" | `sf-impact-from-diff` |
|
|
81
|
+
| "Compare two points in time / snapshots" | `sf-snapshot-compare` |
|
|
82
|
+
|
|
83
|
+
### QUALITY / GOVERNANCE — review before ship
|
|
84
|
+
| Intent | Skill |
|
|
85
|
+
|---|---|
|
|
86
|
+
| "Governor-limit risks (SOQL/DML in loops)" | `sf-governor-risk-fix` |
|
|
87
|
+
| "FLS / sharing / who-has-access audit" | `sf-security-audit` |
|
|
88
|
+
| "What's unused / safe to delete" | `sf-dead-code-audit` |
|
|
89
|
+
| "Generate a deployment manifest" | `sf-deployment-manifest` |
|
|
90
|
+
| "Diff two orgs (sandbox vs prod)" | `sf-cross-org-diff` |
|
|
91
|
+
| "Vlocity ↔ OmniStudio migration inventory" | `sf-omnistudio-migration-audit` |
|
|
92
|
+
| "Is the graph fresh / how do I refresh" | `sf-metadata-refresh` |
|
|
93
|
+
| "Show me the graph visually" | `sf-web-explorer` |
|
|
94
|
+
|
|
95
|
+
## Disambiguation (commonly confused)
|
|
96
|
+
- **Committed vs uncommitted vs post-deploy change analysis:** PR/branch/commit → `sf-impact-from-diff`; uncommitted working tree → `sf-wip-impact`; already deployed, something regressed → `sf-what-broke`.
|
|
97
|
+
- **Two orgs vs two snapshots vs one org over time:** different orgs → `sf-cross-org-diff`; named snapshots of one org → `sf-snapshot-compare`; "since last deploy" → `sf-what-broke`.
|
|
98
|
+
- **Explain one unit vs trace across layers:** plain-English of one method → `sf-explain-code`; full UI→DB chain → `sf-cross-layer-trace`.
|
|
99
|
+
|
|
100
|
+
## Don't
|
|
101
|
+
- Don't generate Salesforce code before grounding when the org is ingested — that's the whole point of the graph.
|
|
102
|
+
- Don't re-implement the routing logic in prose every turn; pick the skill and go.
|
|
103
|
+
- Don't block on grounding if the org isn't ingested — degrade gracefully with a stated caveat.
|
|
104
|
+
- Don't treat this skill as a destination; it hands off. Its job is selection + the grounding rule.
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-impact-from-diff
|
|
3
|
-
description: Compute downstream blast radius and test-coverage gaps for a git diff before merge.
|
|
3
|
+
description: Compute downstream blast radius and test-coverage gaps for a COMMITTED git diff (a PR, a branch, a commit range) before merge. Requires the changes to already exist in git history. For uncommitted working-tree changes, use sf-wip-impact instead.
|
|
4
4
|
triggers:
|
|
5
5
|
- "what does this PR break"
|
|
6
|
-
- "impact of this
|
|
7
|
-
- "
|
|
8
|
-
- "
|
|
9
|
-
- "
|
|
6
|
+
- "impact of this PR"
|
|
7
|
+
- "blast radius of this branch"
|
|
8
|
+
- "before I merge this PR"
|
|
9
|
+
- "test gaps for this diff"
|
|
10
10
|
tools_used:
|
|
11
11
|
- impact_from_git_diff
|
|
12
12
|
- test_gap_intelligence_from_git_diff
|
|
13
13
|
- staleness_check
|
|
14
|
+
- find_similar
|
|
14
15
|
---
|
|
15
16
|
|
|
16
17
|
# sf-impact-from-diff
|
|
@@ -25,6 +26,7 @@ Use when the user wants to understand the downstream consequences of a pending c
|
|
|
25
26
|
4. Group findings by risk tier — **direct edits**, **first-degree dependents**, **transitive (depth ≥ 2)** — and call out anything that crosses metadata layers (LWC -> Apex -> Flow).
|
|
26
27
|
5. Render the Mermaid impact graph returned by the tool. If the impact set is large (>40 nodes), summarise by category and offer a follow-up call scoped to a single changed file.
|
|
27
28
|
6. If test gaps exist, list the specific impacted classes + methods that lack assertions, not just totals.
|
|
29
|
+
7. **Semantic-sibling check (optional).** For each top-level changed file, call `find_similar(qname=<changed-node>, k=5)` and surface any near-neighbour (similarity > 0.6) that is NOT in the structural impact set. Rationale: copy-paste duplicates of the changed logic often live elsewhere in the codebase without a structural edge linking them. The diff doesn't touch them, but a behaviour change to the original probably should propagate. Flag these as "siblings worth reviewing" — don't add them to the at-risk list automatically (similarity ≠ dependency), but offer them for the user to scan.
|
|
28
30
|
|
|
29
31
|
## Visualization
|
|
30
32
|
|
|
@@ -20,8 +20,10 @@ Use when the user asks about who can read or write a field/object, what sharing
|
|
|
20
20
|
|
|
21
21
|
## Playbook
|
|
22
22
|
|
|
23
|
-
1. Resolve the target. Call `analyze_field` if the user gave `SObject.Field`; otherwise treat as SObject-level.
|
|
24
|
-
2. Call `security_audit` with the resolved target
|
|
23
|
+
1. Resolve the target. Call `analyze_field` if the user gave `SObject.Field`; otherwise treat as SObject-level. `analyze_field` takes **separate `object` and `field`** params (not a single `Account.Status` string) — split before calling.
|
|
24
|
+
2. Call `security_audit` with the resolved target (`object` / `field` to narrow; whole-org if neither). Capture full-access sharing rules and the FLS gap list.
|
|
25
|
+
- **FLS gaps are pre-filtered** to FLS-relevant fields: Custom Metadata Type (`__mdt`), platform-event (`__e`), big-object (`__b`), and standard system/audit fields (Id, CreatedById, SystemModstamp, …) are excluded as noise. The response notes `+N CMDT/system fields hidden`. Only pass `include_non_fls_fields: true` if the user explicitly wants that raw set — never lead with it.
|
|
26
|
+
- The inline gap list is capped (`limit`, default 30). Narrow with `object`, or raise `limit`, rather than dumping thousands of rows.
|
|
25
27
|
3. Build the access matrix: Profile/PSet -> Read / Edit / Delete / View All / Modify All.
|
|
26
28
|
4. Identify sharing exposure: OWD setting, sharing rules expanding access, role-hierarchy inheritance toggles.
|
|
27
29
|
5. Flag risks: `without sharing` Apex selectors, missing `stripInaccessible` / `WITH SECURITY_ENFORCED`, guest user access, Experience Cloud profile reach.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-snapshot-compare
|
|
3
|
-
description: Compare two sfgraph
|
|
3
|
+
description: Compare two named sfgraph SNAPSHOTS of the same org (or one snapshot against current) for arbitrary point-in-time analysis. Use when the user explicitly references snapshots by name/id, wants to "rewind" to a prior state, or compare arbitrary points in time. For post-deploy regressions use sf-what-broke; for comparing two different orgs use sf-cross-org-diff.
|
|
4
4
|
triggers:
|
|
5
5
|
- "compare snapshots"
|
|
6
|
-
- "
|
|
6
|
+
- "diff snapshot <a> and <b>"
|
|
7
7
|
- "point in time diff"
|
|
8
|
-
- "rewind"
|
|
9
|
-
- "show me the state before"
|
|
8
|
+
- "rewind to snapshot"
|
|
9
|
+
- "show me the state before <snapshot>"
|
|
10
10
|
tools_used:
|
|
11
11
|
- snapshot_list
|
|
12
12
|
- snapshot_create
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-what-broke
|
|
3
|
-
description: Identify what regressed in
|
|
3
|
+
description: Identify what regressed in a SINGLE org since a recent deploy or sync — post-deployment regression triage. Use when the user reports something stopped working after a deploy, or asks what changed since the last ingest. For comparing two distinct orgs use sf-cross-org-diff; for arbitrary point-in-time snapshot comparison use sf-snapshot-compare.
|
|
4
4
|
triggers:
|
|
5
|
-
- "what broke"
|
|
5
|
+
- "what broke after the deploy"
|
|
6
6
|
- "post-deploy regression"
|
|
7
|
-
- "since deploy"
|
|
7
|
+
- "since the last deploy"
|
|
8
8
|
- "what changed since last sync"
|
|
9
9
|
- "regression triage"
|
|
10
10
|
tools_used:
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sf-wip-impact
|
|
3
|
-
description: Dry-run the
|
|
3
|
+
description: Dry-run the blast radius and test gaps for UNCOMMITTED local working-tree changes against the org graph — use before you commit. For committed PR/branch diffs use sf-impact-from-diff instead.
|
|
4
4
|
triggers:
|
|
5
|
-
- "dry-run
|
|
6
|
-
- "
|
|
7
|
-
- "local impact"
|
|
8
|
-
- "uncommitted changes"
|
|
5
|
+
- "dry-run my local changes"
|
|
6
|
+
- "impact of my uncommitted changes"
|
|
9
7
|
- "wip impact"
|
|
8
|
+
- "before I commit"
|
|
9
|
+
- "what would my working-tree changes affect"
|
|
10
10
|
tools_used:
|
|
11
11
|
- wip_impact
|
|
12
12
|
- wip_test_gap
|