@ryanstark24/sfgraph-skills 1.1.4 → 1.6.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/package.json +3 -2
- package/skills/sf-cross-layer-trace/SKILL.md +16 -5
- package/skills/sf-cross-org-diff/SKILL.md +7 -1
- package/skills/sf-dead-code-audit/SKILL.md +10 -3
- package/skills/sf-debug-log-analysis/SKILL.md +107 -0
- package/skills/sf-debug-root-cause/SKILL.md +111 -0
- package/skills/sf-deployment-manifest/SKILL.md +13 -7
- package/skills/sf-explain-code/SKILL.md +16 -1
- package/skills/sf-find-similar/SKILL.md +10 -4
- package/skills/sf-flow-impact/SKILL.md +6 -0
- package/skills/sf-governor-risk-fix/SKILL.md +50 -10
- package/skills/sf-graph-plus-source/SKILL.md +46 -0
- package/skills/sf-graph-router/SKILL.md +146 -0
- package/skills/sf-impact-from-diff/SKILL.md +11 -5
- package/skills/sf-metadata-refresh/SKILL.md +9 -3
- package/skills/sf-omnistudio-migration-audit/SKILL.md +15 -5
- package/skills/sf-schema-overview/SKILL.md +8 -2
- package/skills/sf-security-audit/SKILL.md +14 -6
- package/skills/sf-snapshot-compare/SKILL.md +6 -0
- package/skills/sf-web-explorer/SKILL.md +6 -1
- package/skills/sf-what-broke/SKILL.md +28 -22
- package/skills/sf-wip-impact/SKILL.md +8 -0
- package/dist/__tests__/cursor-format.test.d.ts +0 -2
- package/dist/__tests__/cursor-format.test.d.ts.map +0 -1
- package/dist/__tests__/cursor-format.test.js +0 -44
- package/dist/__tests__/cursor-format.test.js.map +0 -1
- package/dist/__tests__/installer.test.d.ts +0 -2
- package/dist/__tests__/installer.test.d.ts.map +0 -1
- package/dist/__tests__/installer.test.js +0 -64
- package/dist/__tests__/installer.test.js.map +0 -1
|
@@ -15,33 +15,39 @@ tools_used:
|
|
|
15
15
|
|
|
16
16
|
# sf-what-broke
|
|
17
17
|
|
|
18
|
-
Use when the user is triaging a regression and wants to know which metadata changed
|
|
18
|
+
Use when the user is triaging a regression and wants to know which metadata changed since a recent deploy/sync, and which of those changes have **untested dependents** (the likely break surface).
|
|
19
|
+
|
|
20
|
+
**What the tool actually does (and doesn't):** `what_broke(org, since?)` compares the current graph against the latest pre-sync snapshot (or the `since` you pass), finds the changed nodes, and buckets their dependents as **at-risk** (no test coverage) vs **covered**. It does NOT take a failing-test/stack "failure signal", does NOT rank by reachability to a specific failure, and does NOT emit a path-to-failure diagram. If the user has a concrete failure (a specific exception or failing test), route that to **`sf-debug-root-cause`** (symptom → graph cause) or **`sf-debug-log-analysis`** — then come back here for the "what changed in the window" picture.
|
|
21
|
+
|
|
22
|
+
## Evidence rule — say it only if something backs it
|
|
23
|
+
|
|
24
|
+
State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
|
|
19
25
|
|
|
20
26
|
## Playbook
|
|
21
27
|
|
|
22
|
-
1.
|
|
23
|
-
2. Call `
|
|
24
|
-
3.
|
|
25
|
-
4. Triage
|
|
26
|
-
5.
|
|
27
|
-
6. Recommend the smallest
|
|
28
|
+
1. **`staleness_check`** first (see below).
|
|
29
|
+
2. Call **`what_broke`** with the org (and `since` if the user has a specific baseline; otherwise it uses the latest pre-sync snapshot). If it reports no baseline snapshot, tell the user and fall back to `point_in_time_diff` / `sf-snapshot-compare` with an explicit anchor.
|
|
30
|
+
3. Read the result: the changed nodes, and their dependents split into **at-risk** (no tests — highest priority) and **covered**.
|
|
31
|
+
4. Triage at-risk first: for each, summarise what changed and what depends on it. To see the full dependency chain to a UI/test surface, hand the node to `sf-cross-layer-trace` or `trace_upstream`.
|
|
32
|
+
5. For a deeper field-level diff between two points, call **`point_in_time_diff`** (or `sf-snapshot-compare`) — that's where the detailed add/remove/modify per layer lives.
|
|
33
|
+
6. Recommend the smallest next step (revert a specific change, or add a test to an at-risk dependent before re-deploying).
|
|
28
34
|
|
|
29
35
|
## Visualization
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
`what_broke` draws a Mermaid diagram of the changed pieces and their dependents by default (`mermaid: true`; `mermaid: false` hides it). Embed the tool's diagram rather than redrawing it. If you need a different view (for example only the untested dependents), build a simple **`flowchart LR`** yourself and say you drew it.
|
|
32
38
|
|
|
33
39
|
```
|
|
34
40
|
flowchart LR
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
classDef
|
|
38
|
-
classDef
|
|
41
|
+
C1[ApexClass:AccountTrigger]:::changed --> D1[ApexClass:AccountSvc]:::atrisk
|
|
42
|
+
C1 --> D2[Flow:AccountAfterUpdate]:::atrisk
|
|
43
|
+
classDef changed fill:#fee,stroke:#c00
|
|
44
|
+
classDef atrisk fill:#fcc,stroke:#900,stroke-width:2px
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
If the suspect set is large (>15 nodes) collapse non-top suspects into a single "other changes" node — readability beats completeness.
|
|
42
|
-
|
|
43
47
|
## Staleness check
|
|
44
48
|
|
|
49
|
+
If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
|
|
50
|
+
|
|
45
51
|
Before calling `what_broke`, invoke `staleness_check` for the target org. If the report says stale, surface a warning to the user:
|
|
46
52
|
|
|
47
53
|
> Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
|
|
@@ -50,15 +56,15 @@ Then continue with the playbook.
|
|
|
50
56
|
|
|
51
57
|
## Response Shape
|
|
52
58
|
|
|
53
|
-
- **Window** —
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
57
|
-
- **Next step** — single concrete recommendation.
|
|
59
|
+
- **Window** — current vs the baseline snapshot `what_broke` used (or the `since` anchor).
|
|
60
|
+
- **At-risk changes** — changed nodes whose dependents have no test coverage, first.
|
|
61
|
+
- **Covered changes** — changed nodes whose dependents are tested, briefly.
|
|
62
|
+
- **Next step** — single concrete recommendation (revert, or add coverage to an at-risk dependent).
|
|
58
63
|
|
|
59
64
|
## Don't
|
|
60
65
|
|
|
61
|
-
- Do not
|
|
66
|
+
- Do not tell the user you passed a failing test / stack to `what_broke` — it has no such parameter. Route concrete failures to `sf-debug-root-cause`.
|
|
67
|
+
- `what_broke` DOES emit a dependency-graph Mermaid alongside its tables — embed the tool's diagram directly; don't claim it returns tables only, and don't redraw it from scratch.
|
|
68
|
+
- Do not propose a code fix without first inspecting the suspect change via `sf-cross-layer-trace`.
|
|
62
69
|
- Do not run write operations against the org. This skill only reads the local graph + snapshots.
|
|
63
|
-
- Do not
|
|
64
|
-
- Do not invent snapshots that don't exist; if the "good" anchor is unavailable, say so.
|
|
70
|
+
- Do not invent snapshots that don't exist; if no baseline is available, say so and use an explicit anchor.
|
|
@@ -18,6 +18,12 @@ tools_used:
|
|
|
18
18
|
|
|
19
19
|
Use when the user has local edits they haven't committed yet (working tree, staged or unstaged) and wants to see the downstream blast radius and test gaps before deciding whether to commit or push.
|
|
20
20
|
|
|
21
|
+
What counts as changed: the wip tools compare the local project with the ingested graph. In the default `mode: "changed-only"`, a file counts when it differs from git HEAD **or** was modified after the org's last sync, so commits made since the last ingest are included too; say so if the user expects only uncommitted edits. `mode: "full-folder"` parses every member.
|
|
22
|
+
|
|
23
|
+
## Evidence rule — say it only if something backs it
|
|
24
|
+
|
|
25
|
+
State a fact about this org or the Salesforce platform **only when evidence backs it**: a tool/graph result, source you actually read (local sfdx file or an org fetch), a live org query, or official Salesforce documentation. If you don't have that, say so plainly — "the graph doesn't show this", "unverified", "I'd need to check the org" — and either go get the evidence or stop. **Never fill the gap with a plausible-sounding guess**: an invented field/method/object name, an assumed dependency, or a governor number recalled from memory. Label each claim as **graph-confirmed** (a tool returned it), **inferred** (you reasoned it from graph facts — say which facts), or **general Salesforce knowledge**. For platform behaviour — governor limits, order of execution, sharing/FLS semantics, API rules — cite the official doc (developer.salesforce.com; fetch it if unsure) instead of asserting from memory. If the graph is stale or the org was never ingested, lead with that caveat — your grounding may be wrong.
|
|
26
|
+
|
|
21
27
|
## Playbook
|
|
22
28
|
|
|
23
29
|
1. Confirm the project root. Default to the current working directory; if the user explicitly names another, use that.
|
|
@@ -52,6 +58,8 @@ If the dependent set exceeds 40 nodes, summarise per category and skip the diagr
|
|
|
52
58
|
|
|
53
59
|
## Staleness check
|
|
54
60
|
|
|
61
|
+
If `staleness_check` is not available (the server runs with `SFGRAPH_TOOLS=core`), skip this step and say the graph's freshness was not checked.
|
|
62
|
+
|
|
55
63
|
Before calling `wip_impact`, invoke `staleness_check` for the linked org. WIP analysis depends on the existing graph being accurate; a stale graph will under-report dependents. If the report says stale, surface a warning to the user:
|
|
56
64
|
|
|
57
65
|
> Your ingest is N days old. Run `sfgraph ingest --org <alias>` to refresh, or proceed with the understanding that the graph may not reflect recent changes.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-format.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cursor-format.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { toClaudeFormat, toCursorFormat } from "../installer.js";
|
|
3
|
-
const SAMPLE = `---
|
|
4
|
-
name: foo
|
|
5
|
-
description: bar
|
|
6
|
-
triggers:
|
|
7
|
-
- "x"
|
|
8
|
-
tools_used:
|
|
9
|
-
- tool_a
|
|
10
|
-
- tool_b
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
# Body
|
|
14
|
-
|
|
15
|
-
Some content.
|
|
16
|
-
|
|
17
|
-
- bullet
|
|
18
|
-
`;
|
|
19
|
-
describe("format transforms", () => {
|
|
20
|
-
it("toCursorFormat rewrites frontmatter into Cursor's contract", () => {
|
|
21
|
-
const out = toCursorFormat(SAMPLE);
|
|
22
|
-
// Cursor-shaped frontmatter (the only three keys it understands)
|
|
23
|
-
expect(out).toMatch(/^description:.*bar/m);
|
|
24
|
-
// globs now contains the SF file patterns so the rule auto-attaches
|
|
25
|
-
// whenever the user opens any Salesforce metadata file.
|
|
26
|
-
expect(out).toMatch(/^globs:.*sfdx-project\.json.*\*\*\/\*\.cls/m);
|
|
27
|
-
expect(out).toMatch(/^alwaysApply:\s*false$/m);
|
|
28
|
-
// Trigger phrases folded into the description so the agent matches them
|
|
29
|
-
expect(out).toMatch(/Triggers:.*"?x"?/);
|
|
30
|
-
// The agent-requested hint mentions the skill name + sfgraph routing
|
|
31
|
-
expect(out).toMatch(/sfgraph MCP tools/);
|
|
32
|
-
// Body preserved verbatim
|
|
33
|
-
expect(out).toMatch(/^# Body/m);
|
|
34
|
-
expect(out).toMatch(/^- bullet/m);
|
|
35
|
-
// Old frontmatter is gone (it would confuse Cursor's parser)
|
|
36
|
-
expect(out).not.toMatch(/^name: foo/m);
|
|
37
|
-
expect(out).not.toMatch(/^triggers:/m);
|
|
38
|
-
expect(out).not.toMatch(/^tools_used:/m);
|
|
39
|
-
});
|
|
40
|
-
it("toClaudeFormat is identity", () => {
|
|
41
|
-
expect(toClaudeFormat(SAMPLE)).toBe(SAMPLE);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
//# sourceMappingURL=cursor-format.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-format.test.js","sourceRoot":"","sources":["../../src/__tests__/cursor-format.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjE,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;CAed,CAAC;AAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACnC,iEAAiE;QACjE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAC3C,oEAAoE;QACpE,wDAAwD;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC;QACnE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAC/C,wEAAwE;QACxE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACxC,qEAAqE;QACrE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QACzC,0BAA0B;QAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAClC,6DAA6D;QAC7D,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"installer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/installer.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
-
import { install, listSkillsBundled } from "../installer.js";
|
|
6
|
-
let home;
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
home = mkdtempSync(join(tmpdir(), "sfgraph-home-"));
|
|
9
|
-
});
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
rmSync(home, { recursive: true, force: true });
|
|
12
|
-
});
|
|
13
|
-
describe("skills installer", () => {
|
|
14
|
-
it("installs all 16 skills to the claude target", async () => {
|
|
15
|
-
const results = await install("claude", { homeOverride: home });
|
|
16
|
-
const skillNames = await listSkillsBundled();
|
|
17
|
-
expect(skillNames.length).toBe(16);
|
|
18
|
-
expect(results.length).toBe(16);
|
|
19
|
-
for (const r of results) {
|
|
20
|
-
expect(r.target).toBe("claude");
|
|
21
|
-
expect(r.action).toBe("created");
|
|
22
|
-
expect(existsSync(r.path)).toBe(true);
|
|
23
|
-
expect(r.path).toContain(join(home, ".claude", "skills"));
|
|
24
|
-
expect(r.path.endsWith("SKILL.md")).toBe(true);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
it("installs to the cursor target as .mdc files in Cursor's frontmatter shape", async () => {
|
|
28
|
-
const results = await install("cursor", { homeOverride: home });
|
|
29
|
-
expect(results.length).toBe(16);
|
|
30
|
-
const cursorDir = join(home, ".cursor", "rules");
|
|
31
|
-
const files = readdirSync(cursorDir);
|
|
32
|
-
expect(files.every((f) => f.endsWith(".mdc"))).toBe(true);
|
|
33
|
-
expect(files.length).toBe(16);
|
|
34
|
-
// Cursor-shaped frontmatter (the three keys Cursor's rule loader reads).
|
|
35
|
-
const sample = readFileSync(join(cursorDir, files[0] ?? ""), "utf8");
|
|
36
|
-
expect(sample).toMatch(/^description:/m);
|
|
37
|
-
expect(sample).toMatch(/^globs:.*\*\*\/\*\.cls/m);
|
|
38
|
-
expect(sample).toMatch(/^alwaysApply:\s*false$/m);
|
|
39
|
-
// Old frontmatter is rewritten away (would confuse Cursor's parser).
|
|
40
|
-
expect(sample).not.toMatch(/^name:/m);
|
|
41
|
-
expect(sample).not.toMatch(/^triggers:/m);
|
|
42
|
-
expect(sample).not.toMatch(/^tools_used:/m);
|
|
43
|
-
// Body content preserved.
|
|
44
|
-
expect(sample).toMatch(/## Playbook/);
|
|
45
|
-
});
|
|
46
|
-
it("installs to all targets in one call", async () => {
|
|
47
|
-
const results = await install("all", { homeOverride: home });
|
|
48
|
-
const claudeCount = results.filter((r) => r.target === "claude").length;
|
|
49
|
-
const cursorCount = results.filter((r) => r.target === "cursor").length;
|
|
50
|
-
const vscodeCount = results.filter((r) => r.target === "vscode").length;
|
|
51
|
-
expect(claudeCount).toBe(16);
|
|
52
|
-
expect(cursorCount).toBe(16);
|
|
53
|
-
expect(vscodeCount).toBe(16);
|
|
54
|
-
expect(existsSync(join(home, ".claude", "skills"))).toBe(true);
|
|
55
|
-
expect(existsSync(join(home, ".cursor", "rules"))).toBe(true);
|
|
56
|
-
});
|
|
57
|
-
it("dry-run returns would-write actions and writes nothing", async () => {
|
|
58
|
-
const results = await install("all", { homeOverride: home, dryRun: true });
|
|
59
|
-
expect(results.every((r) => r.action === "would-write")).toBe(true);
|
|
60
|
-
expect(existsSync(join(home, ".claude", "skills"))).toBe(false);
|
|
61
|
-
expect(existsSync(join(home, ".cursor", "rules"))).toBe(false);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
//# sourceMappingURL=installer.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"installer.test.js","sourceRoot":"","sources":["../../src/__tests__/installer.test.ts"],"names":[],"mappings":"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"}
|