@ryanstark24/sfgraph-server 1.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/dist/__tests__/context-cache.test.d.ts +2 -0
- package/dist/__tests__/context-cache.test.d.ts.map +1 -0
- package/dist/__tests__/context-cache.test.js +77 -0
- package/dist/__tests__/context-cache.test.js.map +1 -0
- package/dist/__tests__/context-default-factory.test.d.ts +2 -0
- package/dist/__tests__/context-default-factory.test.d.ts.map +1 -0
- package/dist/__tests__/context-default-factory.test.js +89 -0
- package/dist/__tests__/context-default-factory.test.js.map +1 -0
- package/dist/__tests__/network-egress.test.d.ts +2 -0
- package/dist/__tests__/network-egress.test.d.ts.map +1 -0
- package/dist/__tests__/network-egress.test.js +33 -0
- package/dist/__tests__/network-egress.test.js.map +1 -0
- package/dist/__tests__/shutdown.test.d.ts +2 -0
- package/dist/__tests__/shutdown.test.d.ts.map +1 -0
- package/dist/__tests__/shutdown.test.js +78 -0
- package/dist/__tests__/shutdown.test.js.map +1 -0
- package/dist/__tests__/tool-registry.test.d.ts +2 -0
- package/dist/__tests__/tool-registry.test.d.ts.map +1 -0
- package/dist/__tests__/tool-registry.test.js +21 -0
- package/dist/__tests__/tool-registry.test.js.map +1 -0
- package/dist/__tests__/zod-schema.test.d.ts +2 -0
- package/dist/__tests__/zod-schema.test.d.ts.map +1 -0
- package/dist/__tests__/zod-schema.test.js +15 -0
- package/dist/__tests__/zod-schema.test.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +14 -0
- package/dist/bin.js.map +1 -0
- package/dist/context.d.ts +29 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +202 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +31 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +91 -0
- package/dist/server.js.map +1 -0
- package/dist/shutdown.d.ts +10 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +43 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/tool-registry.d.ts +31 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +29 -0
- package/dist/tool-registry.js.map +1 -0
- package/dist/tools/__tests__/_fixture.d.ts +29 -0
- package/dist/tools/__tests__/_fixture.d.ts.map +1 -0
- package/dist/tools/__tests__/_fixture.js +59 -0
- package/dist/tools/__tests__/_fixture.js.map +1 -0
- package/dist/tools/__tests__/_runner.d.ts +10 -0
- package/dist/tools/__tests__/_runner.d.ts.map +1 -0
- package/dist/tools/__tests__/_runner.js +12 -0
- package/dist/tools/__tests__/_runner.js.map +1 -0
- package/dist/tools/__tests__/analyze_field.test.d.ts +2 -0
- package/dist/tools/__tests__/analyze_field.test.d.ts.map +1 -0
- package/dist/tools/__tests__/analyze_field.test.js +92 -0
- package/dist/tools/__tests__/analyze_field.test.js.map +1 -0
- package/dist/tools/__tests__/cross_layer_flow_map.test.d.ts +2 -0
- package/dist/tools/__tests__/cross_layer_flow_map.test.d.ts.map +1 -0
- package/dist/tools/__tests__/cross_layer_flow_map.test.js +111 -0
- package/dist/tools/__tests__/cross_layer_flow_map.test.js.map +1 -0
- package/dist/tools/__tests__/cross_org_diff.test.d.ts +2 -0
- package/dist/tools/__tests__/cross_org_diff.test.d.ts.map +1 -0
- package/dist/tools/__tests__/cross_org_diff.test.js +112 -0
- package/dist/tools/__tests__/cross_org_diff.test.js.map +1 -0
- package/dist/tools/__tests__/dead_code_audit.test.d.ts +2 -0
- package/dist/tools/__tests__/dead_code_audit.test.d.ts.map +1 -0
- package/dist/tools/__tests__/dead_code_audit.test.js +71 -0
- package/dist/tools/__tests__/dead_code_audit.test.js.map +1 -0
- package/dist/tools/__tests__/deployment_manifest_gen.test.d.ts +2 -0
- package/dist/tools/__tests__/deployment_manifest_gen.test.d.ts.map +1 -0
- package/dist/tools/__tests__/deployment_manifest_gen.test.js +143 -0
- package/dist/tools/__tests__/deployment_manifest_gen.test.js.map +1 -0
- package/dist/tools/__tests__/dispatcher.test.d.ts +2 -0
- package/dist/tools/__tests__/dispatcher.test.d.ts.map +1 -0
- package/dist/tools/__tests__/dispatcher.test.js +39 -0
- package/dist/tools/__tests__/dispatcher.test.js.map +1 -0
- package/dist/tools/__tests__/explain_code.test.d.ts +2 -0
- package/dist/tools/__tests__/explain_code.test.d.ts.map +1 -0
- package/dist/tools/__tests__/explain_code.test.js +88 -0
- package/dist/tools/__tests__/explain_code.test.js.map +1 -0
- package/dist/tools/__tests__/freshness_report.test.d.ts +2 -0
- package/dist/tools/__tests__/freshness_report.test.d.ts.map +1 -0
- package/dist/tools/__tests__/freshness_report.test.js +103 -0
- package/dist/tools/__tests__/freshness_report.test.js.map +1 -0
- package/dist/tools/__tests__/get_ingest_job.test.d.ts +2 -0
- package/dist/tools/__tests__/get_ingest_job.test.d.ts.map +1 -0
- package/dist/tools/__tests__/get_ingest_job.test.js +42 -0
- package/dist/tools/__tests__/get_ingest_job.test.js.map +1 -0
- package/dist/tools/__tests__/governor_risk_check.test.d.ts +2 -0
- package/dist/tools/__tests__/governor_risk_check.test.d.ts.map +1 -0
- package/dist/tools/__tests__/governor_risk_check.test.js +66 -0
- package/dist/tools/__tests__/governor_risk_check.test.js.map +1 -0
- package/dist/tools/__tests__/impact_from_git_diff.test.d.ts +2 -0
- package/dist/tools/__tests__/impact_from_git_diff.test.d.ts.map +1 -0
- package/dist/tools/__tests__/impact_from_git_diff.test.js +115 -0
- package/dist/tools/__tests__/impact_from_git_diff.test.js.map +1 -0
- package/dist/tools/__tests__/list_orgs.test.d.ts +2 -0
- package/dist/tools/__tests__/list_orgs.test.d.ts.map +1 -0
- package/dist/tools/__tests__/list_orgs.test.js +137 -0
- package/dist/tools/__tests__/list_orgs.test.js.map +1 -0
- package/dist/tools/__tests__/ping.test.d.ts +2 -0
- package/dist/tools/__tests__/ping.test.d.ts.map +1 -0
- package/dist/tools/__tests__/ping.test.js +10 -0
- package/dist/tools/__tests__/ping.test.js.map +1 -0
- package/dist/tools/__tests__/point_in_time_diff.test.d.ts +2 -0
- package/dist/tools/__tests__/point_in_time_diff.test.d.ts.map +1 -0
- package/dist/tools/__tests__/point_in_time_diff.test.js +64 -0
- package/dist/tools/__tests__/point_in_time_diff.test.js.map +1 -0
- package/dist/tools/__tests__/security_audit.test.d.ts +2 -0
- package/dist/tools/__tests__/security_audit.test.d.ts.map +1 -0
- package/dist/tools/__tests__/security_audit.test.js +99 -0
- package/dist/tools/__tests__/security_audit.test.js.map +1 -0
- package/dist/tools/__tests__/snapshot.test.d.ts +2 -0
- package/dist/tools/__tests__/snapshot.test.d.ts.map +1 -0
- package/dist/tools/__tests__/snapshot.test.js +54 -0
- package/dist/tools/__tests__/snapshot.test.js.map +1 -0
- package/dist/tools/__tests__/staleness_check.test.d.ts +2 -0
- package/dist/tools/__tests__/staleness_check.test.d.ts.map +1 -0
- package/dist/tools/__tests__/staleness_check.test.js +51 -0
- package/dist/tools/__tests__/staleness_check.test.js.map +1 -0
- package/dist/tools/__tests__/start_ingest_job.test.d.ts +2 -0
- package/dist/tools/__tests__/start_ingest_job.test.d.ts.map +1 -0
- package/dist/tools/__tests__/start_ingest_job.test.js +55 -0
- package/dist/tools/__tests__/start_ingest_job.test.js.map +1 -0
- package/dist/tools/__tests__/test_gap_intelligence.test.d.ts +2 -0
- package/dist/tools/__tests__/test_gap_intelligence.test.d.ts.map +1 -0
- package/dist/tools/__tests__/test_gap_intelligence.test.js +77 -0
- package/dist/tools/__tests__/test_gap_intelligence.test.js.map +1 -0
- package/dist/tools/__tests__/trace.test.d.ts +2 -0
- package/dist/tools/__tests__/trace.test.d.ts.map +1 -0
- package/dist/tools/__tests__/trace.test.js +130 -0
- package/dist/tools/__tests__/trace.test.js.map +1 -0
- package/dist/tools/__tests__/what_broke.test.d.ts +2 -0
- package/dist/tools/__tests__/what_broke.test.d.ts.map +1 -0
- package/dist/tools/__tests__/what_broke.test.js +60 -0
- package/dist/tools/__tests__/what_broke.test.js.map +1 -0
- package/dist/tools/__tests__/wip.test.d.ts +2 -0
- package/dist/tools/__tests__/wip.test.d.ts.map +1 -0
- package/dist/tools/__tests__/wip.test.js +173 -0
- package/dist/tools/__tests__/wip.test.js.map +1 -0
- package/dist/tools/_define.d.ts +11 -0
- package/dist/tools/_define.d.ts.map +1 -0
- package/dist/tools/_define.js +29 -0
- package/dist/tools/_define.js.map +1 -0
- package/dist/tools/_job-store.d.ts +19 -0
- package/dist/tools/_job-store.d.ts.map +1 -0
- package/dist/tools/_job-store.js +26 -0
- package/dist/tools/_job-store.js.map +1 -0
- package/dist/tools/_project-root.d.ts +20 -0
- package/dist/tools/_project-root.d.ts.map +1 -0
- package/dist/tools/_project-root.js +44 -0
- package/dist/tools/_project-root.js.map +1 -0
- package/dist/tools/analyze_field.d.ts +2 -0
- package/dist/tools/analyze_field.d.ts.map +1 -0
- package/dist/tools/analyze_field.js +77 -0
- package/dist/tools/analyze_field.js.map +1 -0
- package/dist/tools/cross_layer_flow_map.d.ts +2 -0
- package/dist/tools/cross_layer_flow_map.d.ts.map +1 -0
- package/dist/tools/cross_layer_flow_map.js +104 -0
- package/dist/tools/cross_layer_flow_map.js.map +1 -0
- package/dist/tools/cross_org_diff.d.ts +2 -0
- package/dist/tools/cross_org_diff.d.ts.map +1 -0
- package/dist/tools/cross_org_diff.js +59 -0
- package/dist/tools/cross_org_diff.js.map +1 -0
- package/dist/tools/dead_code_audit.d.ts +2 -0
- package/dist/tools/dead_code_audit.d.ts.map +1 -0
- package/dist/tools/dead_code_audit.js +67 -0
- package/dist/tools/dead_code_audit.js.map +1 -0
- package/dist/tools/deployment_manifest_gen.d.ts +2 -0
- package/dist/tools/deployment_manifest_gen.d.ts.map +1 -0
- package/dist/tools/deployment_manifest_gen.js +43 -0
- package/dist/tools/deployment_manifest_gen.js.map +1 -0
- package/dist/tools/explain_code.d.ts +2 -0
- package/dist/tools/explain_code.d.ts.map +1 -0
- package/dist/tools/explain_code.js +109 -0
- package/dist/tools/explain_code.js.map +1 -0
- package/dist/tools/freshness_report.d.ts +2 -0
- package/dist/tools/freshness_report.d.ts.map +1 -0
- package/dist/tools/freshness_report.js +66 -0
- package/dist/tools/freshness_report.js.map +1 -0
- package/dist/tools/get_ingest_job.d.ts +2 -0
- package/dist/tools/get_ingest_job.d.ts.map +1 -0
- package/dist/tools/get_ingest_job.js +24 -0
- package/dist/tools/get_ingest_job.js.map +1 -0
- package/dist/tools/governor_risk_check.d.ts +2 -0
- package/dist/tools/governor_risk_check.d.ts.map +1 -0
- package/dist/tools/governor_risk_check.js +50 -0
- package/dist/tools/governor_risk_check.js.map +1 -0
- package/dist/tools/impact_from_git_diff.d.ts +2 -0
- package/dist/tools/impact_from_git_diff.d.ts.map +1 -0
- package/dist/tools/impact_from_git_diff.js +67 -0
- package/dist/tools/impact_from_git_diff.js.map +1 -0
- package/dist/tools/index.d.ts +27 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +28 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list_orgs.d.ts +30 -0
- package/dist/tools/list_orgs.d.ts.map +1 -0
- package/dist/tools/list_orgs.js +302 -0
- package/dist/tools/list_orgs.js.map +1 -0
- package/dist/tools/ping.d.ts +3 -0
- package/dist/tools/ping.d.ts.map +1 -0
- package/dist/tools/ping.js +23 -0
- package/dist/tools/ping.js.map +1 -0
- package/dist/tools/point_in_time_diff.d.ts +2 -0
- package/dist/tools/point_in_time_diff.d.ts.map +1 -0
- package/dist/tools/point_in_time_diff.js +37 -0
- package/dist/tools/point_in_time_diff.js.map +1 -0
- package/dist/tools/security_audit.d.ts +2 -0
- package/dist/tools/security_audit.d.ts.map +1 -0
- package/dist/tools/security_audit.js +56 -0
- package/dist/tools/security_audit.js.map +1 -0
- package/dist/tools/snapshot_create.d.ts +2 -0
- package/dist/tools/snapshot_create.d.ts.map +1 -0
- package/dist/tools/snapshot_create.js +24 -0
- package/dist/tools/snapshot_create.js.map +1 -0
- package/dist/tools/snapshot_list.d.ts +2 -0
- package/dist/tools/snapshot_list.d.ts.map +1 -0
- package/dist/tools/snapshot_list.js +22 -0
- package/dist/tools/snapshot_list.js.map +1 -0
- package/dist/tools/staleness_check.d.ts +2 -0
- package/dist/tools/staleness_check.d.ts.map +1 -0
- package/dist/tools/staleness_check.js +50 -0
- package/dist/tools/staleness_check.js.map +1 -0
- package/dist/tools/start_ingest_job.d.ts +2 -0
- package/dist/tools/start_ingest_job.d.ts.map +1 -0
- package/dist/tools/start_ingest_job.js +83 -0
- package/dist/tools/start_ingest_job.js.map +1 -0
- package/dist/tools/test_gap_intelligence_from_git_diff.d.ts +2 -0
- package/dist/tools/test_gap_intelligence_from_git_diff.d.ts.map +1 -0
- package/dist/tools/test_gap_intelligence_from_git_diff.js +50 -0
- package/dist/tools/test_gap_intelligence_from_git_diff.js.map +1 -0
- package/dist/tools/trace_downstream.d.ts +2 -0
- package/dist/tools/trace_downstream.d.ts.map +1 -0
- package/dist/tools/trace_downstream.js +43 -0
- package/dist/tools/trace_downstream.js.map +1 -0
- package/dist/tools/trace_upstream.d.ts +2 -0
- package/dist/tools/trace_upstream.d.ts.map +1 -0
- package/dist/tools/trace_upstream.js +43 -0
- package/dist/tools/trace_upstream.js.map +1 -0
- package/dist/tools/what_broke.d.ts +2 -0
- package/dist/tools/what_broke.d.ts.map +1 -0
- package/dist/tools/what_broke.js +86 -0
- package/dist/tools/what_broke.js.map +1 -0
- package/dist/tools/wip_diff.d.ts +2 -0
- package/dist/tools/wip_diff.d.ts.map +1 -0
- package/dist/tools/wip_diff.js +55 -0
- package/dist/tools/wip_diff.js.map +1 -0
- package/dist/tools/wip_impact.d.ts +2 -0
- package/dist/tools/wip_impact.d.ts.map +1 -0
- package/dist/tools/wip_impact.js +55 -0
- package/dist/tools/wip_impact.js.map +1 -0
- package/dist/tools/wip_test_gap.d.ts +2 -0
- package/dist/tools/wip_test_gap.d.ts.map +1 -0
- package/dist/tools/wip_test_gap.js +50 -0
- package/dist/tools/wip_test_gap.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ConfigError } from "@ryanstark24/sfgraph-shared";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve and sanity-check a user-supplied `project_root` for the WIP tools.
|
|
6
|
+
*
|
|
7
|
+
* The WIP tools walk the local filesystem under `project_root`. Without a
|
|
8
|
+
* containment check, a malicious or careless caller can point them at `/`,
|
|
9
|
+
* `/etc`, or anywhere the user can read — turning local read-access into
|
|
10
|
+
* an MCP-mediated arbitrary-file read.
|
|
11
|
+
*
|
|
12
|
+
* This helper:
|
|
13
|
+
* 1. Resolves `project_root` to an absolute path via `path.resolve`.
|
|
14
|
+
* 2. Verifies the path exists and is a directory.
|
|
15
|
+
* 3. Requires an `sfdx-project.json` at the root (proof this is a real
|
|
16
|
+
* Salesforce DX project, not `/home/victim`).
|
|
17
|
+
* 4. Returns the `realpath`-resolved root so downstream walkers operate
|
|
18
|
+
* on a stable, symlink-resolved path.
|
|
19
|
+
*
|
|
20
|
+
* Throws `ConfigError` on any failure.
|
|
21
|
+
*/
|
|
22
|
+
export function resolveWipProjectRoot(rawProjectRoot) {
|
|
23
|
+
const abs = path.resolve(rawProjectRoot);
|
|
24
|
+
if (!existsSync(abs)) {
|
|
25
|
+
throw new ConfigError(`project_root does not exist: ${rawProjectRoot}`);
|
|
26
|
+
}
|
|
27
|
+
let stats;
|
|
28
|
+
try {
|
|
29
|
+
stats = statSync(abs);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
throw new ConfigError(`project_root not readable: ${e.message}`);
|
|
33
|
+
}
|
|
34
|
+
if (!stats.isDirectory()) {
|
|
35
|
+
throw new ConfigError(`project_root is not a directory: ${rawProjectRoot}`);
|
|
36
|
+
}
|
|
37
|
+
const real = realpathSync(abs);
|
|
38
|
+
const sfdxProject = path.join(real, "sfdx-project.json");
|
|
39
|
+
if (!existsSync(sfdxProject)) {
|
|
40
|
+
throw new ConfigError(`project_root is not a Salesforce DX project (no sfdx-project.json at ${real}). WIP tools refuse to walk arbitrary filesystem locations.`);
|
|
41
|
+
}
|
|
42
|
+
return real;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=_project-root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_project-root.js","sourceRoot":"","sources":["../../src/tools/_project-root.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE1D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,qBAAqB,CAAC,cAAsB;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,WAAW,CAAC,gCAAgC,cAAc,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,KAAkC,CAAC;IACvC,IAAI,CAAC;QACH,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,WAAW,CAAC,8BAA+B,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QACzB,MAAM,IAAI,WAAW,CAAC,oCAAoC,cAAc,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;IACzD,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,WAAW,CACnB,wEAAwE,IAAI,6DAA6D,CAC1I,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze_field.d.ts","sourceRoot":"","sources":["../../src/tools/analyze_field.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { render } from "@ryanstark24/sfgraph-core";
|
|
2
|
+
import { REL_TYPES } from "@ryanstark24/sfgraph-core";
|
|
3
|
+
import { asQualifiedName } from "@ryanstark24/sfgraph-shared";
|
|
4
|
+
import { getToolContext } from "../context.js";
|
|
5
|
+
import { defineTool, z } from "./_define.js";
|
|
6
|
+
// Salesforce SObject and Field API names are letters/digits/underscore only
|
|
7
|
+
// (custom suffix `__c` / `__r` / etc. is allowed). Reject anything else
|
|
8
|
+
// up-front rather than silently returning "field not found" — agents that
|
|
9
|
+
// pass `object: "Account.Tier__c"` should see the validation error.
|
|
10
|
+
const SF_API_NAME_RE = /^[A-Za-z][A-Za-z0-9_]*(?:__[a-zA-Z])?$/;
|
|
11
|
+
const inputSchema = z.object({
|
|
12
|
+
org: z.string().min(1),
|
|
13
|
+
object: z
|
|
14
|
+
.string()
|
|
15
|
+
.min(1)
|
|
16
|
+
.regex(SF_API_NAME_RE, "object must be a Salesforce SObject API name (no dots or spaces)"),
|
|
17
|
+
field: z
|
|
18
|
+
.string()
|
|
19
|
+
.min(1)
|
|
20
|
+
.regex(SF_API_NAME_RE, "field must be a Salesforce field API name (no dots or spaces)"),
|
|
21
|
+
});
|
|
22
|
+
defineTool({
|
|
23
|
+
name: "analyze_field",
|
|
24
|
+
description: "USE THIS for any 'where is X.Y field used' / 'who reads or writes Account.Status__c' / 'who has access to this field' question about a Salesforce CustomField. Returns every Apex method, Flow, LWC, validation rule, and formula that reads/writes the field, plus FLS grants (which Profile/PermSet can see or edit it). Prefer this over grep / file search for any field-impact question.",
|
|
25
|
+
inputSchema,
|
|
26
|
+
async execute(input) {
|
|
27
|
+
const ctx = await getToolContext({ orgId: input.org });
|
|
28
|
+
const qname = asQualifiedName(`CustomField:${input.object}.${input.field}`);
|
|
29
|
+
const node = ctx.graphStore.getNode(ctx.orgId, qname);
|
|
30
|
+
if (!node) {
|
|
31
|
+
return {
|
|
32
|
+
summary: "field not found",
|
|
33
|
+
markdown: `> no node \`${qname}\``,
|
|
34
|
+
data: { found: false },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const readers = ctx.graphStore.listEdgesTo(ctx.orgId, qname, REL_TYPES.READS_FIELD);
|
|
38
|
+
const writers = ctx.graphStore.listEdgesTo(ctx.orgId, qname, REL_TYPES.WRITES_FIELD);
|
|
39
|
+
const grants = ctx.graphStore.listEdgesTo(ctx.orgId, qname, REL_TYPES.GRANTS_FIELD_ACCESS);
|
|
40
|
+
const allEdges = [...readers, ...writers, ...grants];
|
|
41
|
+
const nodeSet = new Map();
|
|
42
|
+
nodeSet.set(qname, { qualifiedName: qname, label: "CustomField" });
|
|
43
|
+
for (const e of allEdges) {
|
|
44
|
+
const src = ctx.graphStore.getNode(ctx.orgId, e.srcQualifiedName);
|
|
45
|
+
nodeSet.set(e.srcQualifiedName, {
|
|
46
|
+
qualifiedName: e.srcQualifiedName,
|
|
47
|
+
label: src?.label ?? "Unknown",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const mermaid = render.renderDependencyGraph({
|
|
51
|
+
nodes: Array.from(nodeSet.values()),
|
|
52
|
+
edges: allEdges.map((e) => ({
|
|
53
|
+
srcQualifiedName: e.srcQualifiedName,
|
|
54
|
+
dstQualifiedName: e.dstQualifiedName,
|
|
55
|
+
relType: e.relType,
|
|
56
|
+
})),
|
|
57
|
+
title: `field ${qname}`,
|
|
58
|
+
});
|
|
59
|
+
const md = [
|
|
60
|
+
`**${qname}** — readers ${readers.length} · writers ${writers.length} · grants ${grants.length}`,
|
|
61
|
+
"",
|
|
62
|
+
"```mermaid",
|
|
63
|
+
mermaid,
|
|
64
|
+
"```",
|
|
65
|
+
].join("\n");
|
|
66
|
+
return {
|
|
67
|
+
summary: `${readers.length} readers / ${writers.length} writers`,
|
|
68
|
+
markdown: md,
|
|
69
|
+
data: {
|
|
70
|
+
readers: readers.map((e) => e.srcQualifiedName),
|
|
71
|
+
writers: writers.map((e) => e.srcQualifiedName),
|
|
72
|
+
grants: grants.map((e) => e.srcQualifiedName),
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=analyze_field.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze_field.js","sourceRoot":"","sources":["../../src/tools/analyze_field.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross_layer_flow_map.d.ts","sourceRoot":"","sources":["../../src/tools/cross_layer_flow_map.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { render } from "@ryanstark24/sfgraph-core";
|
|
2
|
+
import { REL_TYPES } from "@ryanstark24/sfgraph-core";
|
|
3
|
+
import { asQualifiedName } from "@ryanstark24/sfgraph-shared";
|
|
4
|
+
import { getToolContext } from "../context.js";
|
|
5
|
+
import { defineTool, z } from "./_define.js";
|
|
6
|
+
const inputSchema = z.object({
|
|
7
|
+
org: z.string().min(1),
|
|
8
|
+
entry: z.string().min(1),
|
|
9
|
+
});
|
|
10
|
+
const REL_PRIORITY = [
|
|
11
|
+
REL_TYPES.CALLS_APEX_FROM_LWC,
|
|
12
|
+
REL_TYPES.CALLS,
|
|
13
|
+
REL_TYPES.EXECUTES_SOQL,
|
|
14
|
+
REL_TYPES.READS_FIELD,
|
|
15
|
+
];
|
|
16
|
+
function layerFor(label) {
|
|
17
|
+
if (label === "LWC" || label === "LightningComponentBundle")
|
|
18
|
+
return "LWC";
|
|
19
|
+
if (label.startsWith("Apex"))
|
|
20
|
+
return "Apex";
|
|
21
|
+
if (label === "CustomField")
|
|
22
|
+
return "Field";
|
|
23
|
+
if (label === "CustomObject")
|
|
24
|
+
return "SOQL";
|
|
25
|
+
return label;
|
|
26
|
+
}
|
|
27
|
+
defineTool({
|
|
28
|
+
name: "cross_layer_flow_map",
|
|
29
|
+
description: "USE THIS for any 'how does X flow from UI to DB' / 'trace this LWC end-to-end' / 'show the full path from accountTile to the database' question about a Salesforce entry point (LWC bundle, ApexPage, Flow). Returns the layered LWC -> Apex -> SOQL -> CustomField sequence + Mermaid sequenceDiagram.",
|
|
30
|
+
inputSchema,
|
|
31
|
+
async execute(input) {
|
|
32
|
+
const ctx = await getToolContext({ orgId: input.org });
|
|
33
|
+
const entry = asQualifiedName(input.entry);
|
|
34
|
+
const participants = new Map();
|
|
35
|
+
const messages = [];
|
|
36
|
+
const visited = new Set();
|
|
37
|
+
const queue = [entry];
|
|
38
|
+
visited.add(entry);
|
|
39
|
+
const entryNode = ctx.graphStore.getNode(ctx.orgId, entry);
|
|
40
|
+
if (entryNode) {
|
|
41
|
+
participants.set(entry, {
|
|
42
|
+
id: entry,
|
|
43
|
+
label: entry,
|
|
44
|
+
layer: layerFor(entryNode.label),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
participants.set(entry, { id: entry, label: entry, layer: "Entry" });
|
|
49
|
+
}
|
|
50
|
+
// Per-node visit cap, not per-edge step cap. Previously `steps < 50`
|
|
51
|
+
// counted every edge traversed across the BFS, so any moderately-fanned
|
|
52
|
+
// LWC -> Apex chain (30 fields + 25 SOQL reads) would silently truncate
|
|
53
|
+
// mid-tree. Capping visited *nodes* gives predictable depth and lets us
|
|
54
|
+
// emit an explicit "_truncated_" marker the user can act on.
|
|
55
|
+
const NODE_CAP = 100;
|
|
56
|
+
let truncated = false;
|
|
57
|
+
bfs: while (queue.length > 0) {
|
|
58
|
+
if (visited.size >= NODE_CAP) {
|
|
59
|
+
truncated = true;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
const cur = queue.shift();
|
|
63
|
+
if (!cur)
|
|
64
|
+
break;
|
|
65
|
+
for (const rt of REL_PRIORITY) {
|
|
66
|
+
const out = ctx.graphStore.listEdgesFrom(ctx.orgId, cur, rt);
|
|
67
|
+
for (const e of out) {
|
|
68
|
+
const dstNode = ctx.graphStore.getNode(ctx.orgId, e.dstQualifiedName);
|
|
69
|
+
if (!participants.has(e.dstQualifiedName)) {
|
|
70
|
+
participants.set(e.dstQualifiedName, {
|
|
71
|
+
id: e.dstQualifiedName,
|
|
72
|
+
label: e.dstQualifiedName,
|
|
73
|
+
layer: layerFor(dstNode?.label ?? "Unknown"),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
messages.push({ fromId: cur, toId: e.dstQualifiedName, label: rt });
|
|
77
|
+
if (!visited.has(e.dstQualifiedName)) {
|
|
78
|
+
visited.add(e.dstQualifiedName);
|
|
79
|
+
queue.push(e.dstQualifiedName);
|
|
80
|
+
if (visited.size >= NODE_CAP) {
|
|
81
|
+
truncated = true;
|
|
82
|
+
break bfs;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const mermaid = render.renderSequence({
|
|
89
|
+
participants: Array.from(participants.values()),
|
|
90
|
+
messages,
|
|
91
|
+
});
|
|
92
|
+
const mdLines = ["```mermaid", mermaid, "```"];
|
|
93
|
+
if (truncated) {
|
|
94
|
+
mdLines.push("", `_truncated_ — BFS hit the ${NODE_CAP}-node ceiling; deeper paths from this entry were not explored.`);
|
|
95
|
+
}
|
|
96
|
+
const md = mdLines.join("\n");
|
|
97
|
+
return {
|
|
98
|
+
summary: `${participants.size} participants across layers${truncated ? " (truncated)" : ""}`,
|
|
99
|
+
markdown: md,
|
|
100
|
+
data: { participants: Array.from(participants.values()), messages, truncated },
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
//# sourceMappingURL=cross_layer_flow_map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross_layer_flow_map.js","sourceRoot":"","sources":["../../src/tools/cross_layer_flow_map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACzB,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG;IACnB,SAAS,CAAC,mBAAmB;IAC7B,SAAS,CAAC,KAAK;IACf,SAAS,CAAC,aAAa;IACvB,SAAS,CAAC,WAAW;CACtB,CAAC;AAEF,SAAS,QAAQ,CAAC,KAAa;IAC7B,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,0BAA0B;QAAE,OAAO,KAAK,CAAC;IAC1E,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5C,IAAI,KAAK,KAAK,aAAa;QAAE,OAAO,OAAO,CAAC;IAC5C,IAAI,KAAK,KAAK,cAAc;QAAE,OAAO,MAAM,CAAC;IAC5C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,UAAU,CAAC;IACT,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACT,ySAAyS;IAC3S,WAAW;IACX,KAAK,CAAC,OAAO,CAAC,KAAK;QACjB,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAwD,CAAC;QACrF,MAAM,QAAQ,GAA2D,EAAE,CAAC;QAC5E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,MAAM,KAAK,GAAoB,CAAC,KAAK,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC3D,IAAI,SAAS,EAAE,CAAC;YACd,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE;gBACtB,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC;aACjC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,qEAAqE;QACrE,wEAAwE;QACxE,wEAAwE;QACxE,wEAAwE;QACxE,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,GAAG,CAAC;QACrB,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,GAAG,EAAE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,IAAI,OAAO,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC7B,SAAS,GAAG,IAAI,CAAC;gBACjB,MAAM;YACR,CAAC;YACD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG;gBAAE,MAAM;YAChB,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC7D,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;oBACpB,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,gBAAgB,CAAC,CAAC;oBACtE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC;wBAC1C,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,EAAE;4BACnC,EAAE,EAAE,CAAC,CAAC,gBAAgB;4BACtB,KAAK,EAAE,CAAC,CAAC,gBAAgB;4BACzB,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,IAAI,SAAS,CAAC;yBAC7C,CAAC,CAAC;oBACL,CAAC;oBACD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,gBAAgB,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;oBACpE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC;wBACrC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;wBAChC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;wBAC/B,IAAI,OAAO,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;4BAC7B,SAAS,GAAG,IAAI,CAAC;4BACjB,MAAM,GAAG,CAAC;wBACZ,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC;YACpC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAU;YACxD,QAAQ;SACT,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QAC/C,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CACV,EAAE,EACF,6BAA6B,QAAQ,gEAAgE,CACtG,CAAC;QACJ,CAAC;QACD,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO;YACL,OAAO,EAAE,GAAG,YAAY,CAAC,IAAI,8BAA8B,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE;YAC5F,QAAQ,EAAE,EAAE;YACZ,IAAI,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE;SAC/E,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross_org_diff.d.ts","sourceRoot":"","sources":["../../src/tools/cross_org_diff.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { analyze, render } from "@ryanstark24/sfgraph-core";
|
|
2
|
+
import { getToolContext } from "../context.js";
|
|
3
|
+
import { defineTool, z } from "./_define.js";
|
|
4
|
+
const inputSchema = z.object({
|
|
5
|
+
org_a: z.string().min(1),
|
|
6
|
+
org_b: z.string().min(1),
|
|
7
|
+
category: z.string().default("all"),
|
|
8
|
+
});
|
|
9
|
+
defineTool({
|
|
10
|
+
name: "cross_org_diff",
|
|
11
|
+
description: "USE THIS for any 'what is different between prod and sandbox' / 'compare two orgs' / 'org drift' question. Set difference of metadata between two ingested Salesforce orgs by category. Returns onlyInA / onlyInB / changed lists.",
|
|
12
|
+
inputSchema,
|
|
13
|
+
async execute(input) {
|
|
14
|
+
// Each org has its own SQLite file. Open BOTH contexts so onlyInA/onlyInB
|
|
15
|
+
// are computed against the right rows. getToolContext resolves aliases
|
|
16
|
+
// for both org_a and org_b.
|
|
17
|
+
const ctxA = await getToolContext({ orgId: input.org_a });
|
|
18
|
+
const ctxB = await getToolContext({ orgId: input.org_b });
|
|
19
|
+
const diff = analyze.diffOrgs({
|
|
20
|
+
storeA: ctxA.graphStore,
|
|
21
|
+
orgA: ctxA.orgId,
|
|
22
|
+
storeB: ctxB.graphStore,
|
|
23
|
+
orgB: ctxB.orgId,
|
|
24
|
+
category: input.category,
|
|
25
|
+
});
|
|
26
|
+
const mermaid = render.renderDiff({
|
|
27
|
+
added: diff.onlyInB.slice(0, 30).map((n) => ({ qualifiedName: n.qualifiedName })),
|
|
28
|
+
removed: diff.onlyInA.slice(0, 30).map((n) => ({ qualifiedName: n.qualifiedName })),
|
|
29
|
+
changed: diff.changed.slice(0, 30).map((c) => ({ qualifiedName: c.a.qualifiedName })),
|
|
30
|
+
});
|
|
31
|
+
const md = [
|
|
32
|
+
"| metric | count |",
|
|
33
|
+
"|---|---|",
|
|
34
|
+
`| only in A | ${diff.onlyInA.length} |`,
|
|
35
|
+
`| only in B | ${diff.onlyInB.length} |`,
|
|
36
|
+
`| changed | ${diff.changed.length} |`,
|
|
37
|
+
"",
|
|
38
|
+
"```mermaid",
|
|
39
|
+
mermaid,
|
|
40
|
+
"```",
|
|
41
|
+
].join("\n");
|
|
42
|
+
const truncationNote = diff.truncated
|
|
43
|
+
? ` — results capped at ${analyze.CROSS_ORG_PER_LABEL_CAP}/label; narrow with category filter`
|
|
44
|
+
: "";
|
|
45
|
+
return {
|
|
46
|
+
summary: `A-only:${diff.onlyInA.length} B-only:${diff.onlyInB.length} changed:${diff.changed.length}${truncationNote}`,
|
|
47
|
+
markdown: diff.truncated
|
|
48
|
+
? `${md}\n\n> _Note: at least one label hit the ${analyze.CROSS_ORG_PER_LABEL_CAP}-row cap. Diff is incomplete — pass a narrower \`category\` to investigate._`
|
|
49
|
+
: md,
|
|
50
|
+
data: {
|
|
51
|
+
onlyInA: diff.onlyInA.map((n) => n.qualifiedName),
|
|
52
|
+
onlyInB: diff.onlyInB.map((n) => n.qualifiedName),
|
|
53
|
+
changed: diff.changed.map((c) => c.a.qualifiedName),
|
|
54
|
+
truncated: diff.truncated ?? false,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=cross_org_diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross_org_diff.js","sourceRoot":"","sources":["../../src/tools/cross_org_diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dead_code_audit.d.ts","sourceRoot":"","sources":["../../src/tools/dead_code_audit.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { analyze } from "@ryanstark24/sfgraph-core";
|
|
2
|
+
import { getToolContext } from "../context.js";
|
|
3
|
+
import { defineTool, z } from "./_define.js";
|
|
4
|
+
const inputSchema = z.object({ org: z.string().min(1) });
|
|
5
|
+
function readCachedDeadCode(db, orgId) {
|
|
6
|
+
try {
|
|
7
|
+
const d = db;
|
|
8
|
+
const rows = d
|
|
9
|
+
.prepare("SELECT qualified_name, score, confidence, reasons FROM _sfgraph_dead_code_scores WHERE org_id = ? ORDER BY score ASC")
|
|
10
|
+
.all(orgId);
|
|
11
|
+
if (!rows || rows.length === 0)
|
|
12
|
+
return null;
|
|
13
|
+
return rows.map((r) => ({
|
|
14
|
+
qualifiedName: r.qualified_name,
|
|
15
|
+
score: r.score,
|
|
16
|
+
confidence: r.confidence,
|
|
17
|
+
reasons: (() => {
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(r.reasons);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
})(),
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
defineTool({
|
|
32
|
+
name: "dead_code_audit",
|
|
33
|
+
description: "USE THIS for any 'what can I delete' / 'find unused Apex / LWC / Flow' / 'dead code' / 'orphan metadata' question about a Salesforce org. Returns nodes with low freshness AND zero incoming edges, bucketed by confidence with reasons.",
|
|
34
|
+
inputSchema,
|
|
35
|
+
async execute(input) {
|
|
36
|
+
const ctx = await getToolContext({ orgId: input.org });
|
|
37
|
+
const cached = ctx.db ? readCachedDeadCode(ctx.db, ctx.orgId) : null;
|
|
38
|
+
if (cached) {
|
|
39
|
+
const md = cached.length
|
|
40
|
+
? [
|
|
41
|
+
"| qname | confidence | score | reasons |",
|
|
42
|
+
"|---|---|---|---|",
|
|
43
|
+
...cached.map((d) => `| \`${d.qualifiedName}\` | ${d.confidence} | ${d.score.toFixed(2)} | ${d.reasons.join(", ")} |`),
|
|
44
|
+
].join("\n")
|
|
45
|
+
: "_no dead code detected_";
|
|
46
|
+
return {
|
|
47
|
+
summary: `${cached.length} dead-code candidates (cached)`,
|
|
48
|
+
markdown: md,
|
|
49
|
+
data: { dead: cached, cached: true },
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const dead = analyze.findDeadCode(ctx.graphStore, ctx.orgId);
|
|
53
|
+
const md = dead.length
|
|
54
|
+
? [
|
|
55
|
+
"| qname | label |",
|
|
56
|
+
"|---|---|",
|
|
57
|
+
...dead.map((d) => `| \`${d.qualifiedName}\` | ${d.label} |`),
|
|
58
|
+
].join("\n")
|
|
59
|
+
: "_no dead code detected_";
|
|
60
|
+
return {
|
|
61
|
+
summary: `${dead.length} dead-code candidates`,
|
|
62
|
+
markdown: md,
|
|
63
|
+
data: { dead: dead.map((d) => d.qualifiedName), cached: false },
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=dead_code_audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dead_code_audit.js","sourceRoot":"","sources":["../../src/tools/dead_code_audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment_manifest_gen.d.ts","sourceRoot":"","sources":["../../src/tools/deployment_manifest_gen.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { analyze } from "@ryanstark24/sfgraph-core";
|
|
2
|
+
import { getToolContext } from "../context.js";
|
|
3
|
+
import { defineTool, z } from "./_define.js";
|
|
4
|
+
const inputSchema = z.object({
|
|
5
|
+
from_org: z.string().min(1),
|
|
6
|
+
to_org: z.string().min(1),
|
|
7
|
+
category: z.string().optional(),
|
|
8
|
+
});
|
|
9
|
+
defineTool({
|
|
10
|
+
name: "deployment_manifest_gen",
|
|
11
|
+
description: "Generate package.xml + destructiveChanges.xml from cross-org diff.",
|
|
12
|
+
inputSchema,
|
|
13
|
+
async execute(input) {
|
|
14
|
+
// Open BOTH org contexts so the manifest sees the target org's actual
|
|
15
|
+
// node set (each org has its own SQLite file). Aliases for both inputs
|
|
16
|
+
// are resolved by getToolContext.
|
|
17
|
+
const ctxA = await getToolContext({ orgId: input.from_org });
|
|
18
|
+
const ctxB = await getToolContext({ orgId: input.to_org });
|
|
19
|
+
const manifest = analyze.generateManifest({
|
|
20
|
+
storeA: ctxA.graphStore,
|
|
21
|
+
orgA: ctxA.orgId,
|
|
22
|
+
storeB: ctxB.graphStore,
|
|
23
|
+
orgB: ctxB.orgId,
|
|
24
|
+
category: input.category ?? "all",
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
summary: `${manifest.summary.addedOrChanged} added/changed, ${manifest.summary.removed} removed`,
|
|
28
|
+
markdown: [
|
|
29
|
+
"### package.xml",
|
|
30
|
+
"```xml",
|
|
31
|
+
manifest.packageXml.trimEnd(),
|
|
32
|
+
"```",
|
|
33
|
+
"",
|
|
34
|
+
"### destructiveChanges.xml",
|
|
35
|
+
"```xml",
|
|
36
|
+
manifest.destructiveXml.trimEnd(),
|
|
37
|
+
"```",
|
|
38
|
+
].join("\n"),
|
|
39
|
+
data: manifest,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=deployment_manifest_gen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment_manifest_gen.js","sourceRoot":"","sources":["../../src/tools/deployment_manifest_gen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAEH,UAAU,CAAC;IACT,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EAAE,oEAAoE;IACjF,WAAW;IACX,KAAK,CAAC,OAAO,CAAC,KAAK;QACjB,sEAAsE;QACtE,uEAAuE;QACvE,kCAAkC;QAClC,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC;YACxC,MAAM,EAAE,IAAI,CAAC,UAAU;YACvB,IAAI,EAAE,IAAI,CAAC,KAAK;YAChB,MAAM,EAAE,IAAI,CAAC,UAAU;YACvB,IAAI,EAAE,IAAI,CAAC,KAAK;YAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK;SAClC,CAAC,CAAC;QACH,OAAO;YACL,OAAO,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,mBAAmB,QAAQ,CAAC,OAAO,CAAC,OAAO,UAAU;YAChG,QAAQ,EAAE;gBACR,iBAAiB;gBACjB,QAAQ;gBACR,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE;gBAC7B,KAAK;gBACL,EAAE;gBACF,4BAA4B;gBAC5B,QAAQ;gBACR,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE;gBACjC,KAAK;aACN,CAAC,IAAI,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,QAAQ;SACf,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain_code.d.ts","sourceRoot":"","sources":["../../src/tools/explain_code.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { asQualifiedName } from "@ryanstark24/sfgraph-shared";
|
|
2
|
+
import { getToolContext } from "../context.js";
|
|
3
|
+
import { defineTool, z } from "./_define.js";
|
|
4
|
+
// Cap annotation size at 16 KiB. Cached explanations are echoed back inside
|
|
5
|
+
// markdown blockquotes; unbounded input bloats the SQLite row and would let
|
|
6
|
+
// a poisoned graph break the host's markdown renderer.
|
|
7
|
+
const ANNOTATION_MAX_BYTES = 16 * 1024;
|
|
8
|
+
const inputSchema = z.object({
|
|
9
|
+
org: z.string().min(1),
|
|
10
|
+
qname: z.string().min(1),
|
|
11
|
+
refresh: z.boolean().default(false),
|
|
12
|
+
annotation: z.string().max(ANNOTATION_MAX_BYTES, "annotation exceeds 16 KiB cap").optional(),
|
|
13
|
+
});
|
|
14
|
+
defineTool({
|
|
15
|
+
name: "explain_code",
|
|
16
|
+
description: "USE THIS for any 'explain this method' / 'walk me through X' / 'what does Apex method Y do' question about a stored Salesforce code snippet. Returns the source text + cached LLM explanation (if any). Pass annotation to cache the LLM's explanation back to the graph for future use.",
|
|
17
|
+
inputSchema,
|
|
18
|
+
async execute(input) {
|
|
19
|
+
const ctx = await getToolContext({ orgId: input.org });
|
|
20
|
+
const qname = asQualifiedName(input.qname);
|
|
21
|
+
// Annotation write path
|
|
22
|
+
if (typeof input.annotation === "string" && input.annotation.length > 0) {
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
const ok = ctx.graphStore.updateSnippetExplanation(ctx.orgId, qname, input.annotation, now);
|
|
25
|
+
if (!ok) {
|
|
26
|
+
return {
|
|
27
|
+
summary: `no snippet stored for ${input.qname} — annotation not persisted`,
|
|
28
|
+
markdown: `> No snippet exists for \`${input.qname}\`. Likely a non-code metadata type, or the org has not been ingested yet.`,
|
|
29
|
+
data: {
|
|
30
|
+
qname: input.qname,
|
|
31
|
+
sourceFormat: null,
|
|
32
|
+
sourceText: null,
|
|
33
|
+
startLine: null,
|
|
34
|
+
endLine: null,
|
|
35
|
+
cachedExplanation: null,
|
|
36
|
+
cachedAt: null,
|
|
37
|
+
stored: false,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const snippet = ctx.graphStore.getSnippet(ctx.orgId, qname);
|
|
42
|
+
return {
|
|
43
|
+
summary: `cached explanation for ${input.qname}`,
|
|
44
|
+
markdown: `> Explanation cached for \`${input.qname}\` at ${new Date(now).toISOString()}.`,
|
|
45
|
+
data: {
|
|
46
|
+
qname: input.qname,
|
|
47
|
+
sourceFormat: snippet?.sourceFormat ?? null,
|
|
48
|
+
sourceText: snippet?.sourceText ?? null,
|
|
49
|
+
startLine: snippet?.startLine ?? null,
|
|
50
|
+
endLine: snippet?.endLine ?? null,
|
|
51
|
+
cachedExplanation: snippet?.llmExplanation ?? input.annotation,
|
|
52
|
+
cachedAt: snippet?.explainedAt ?? now,
|
|
53
|
+
stored: true,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Read path
|
|
58
|
+
const snippet = ctx.graphStore.getSnippet(ctx.orgId, qname);
|
|
59
|
+
if (!snippet) {
|
|
60
|
+
return {
|
|
61
|
+
summary: `no snippet stored for ${input.qname} — likely a non-code metadata type`,
|
|
62
|
+
markdown: `> No snippet stored for \`${input.qname}\`. Snippets are emitted only for code parsers (currently Apex methods). For declarative metadata, use \`analyze_field\` or \`trace_upstream\` instead.`,
|
|
63
|
+
data: {
|
|
64
|
+
qname: input.qname,
|
|
65
|
+
sourceFormat: null,
|
|
66
|
+
sourceText: null,
|
|
67
|
+
startLine: null,
|
|
68
|
+
endLine: null,
|
|
69
|
+
cachedExplanation: null,
|
|
70
|
+
cachedAt: null,
|
|
71
|
+
stored: false,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const showCached = !input.refresh && snippet.llmExplanation;
|
|
76
|
+
const md = [
|
|
77
|
+
`**${input.qname}** — \`${snippet.sourceFormat}\`${snippet.startLine != null ? ` (lines ${snippet.startLine}–${snippet.endLine ?? "?"})` : ""}`,
|
|
78
|
+
"",
|
|
79
|
+
`\`\`\`${snippet.sourceFormat}`,
|
|
80
|
+
snippet.sourceText,
|
|
81
|
+
"```",
|
|
82
|
+
"",
|
|
83
|
+
];
|
|
84
|
+
if (showCached) {
|
|
85
|
+
md.push("**Cached explanation:**", "", `> ${snippet.llmExplanation}`);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
md.push("> No explanation cached yet — generate one and call `explain_code` again with `annotation` to persist it.");
|
|
89
|
+
}
|
|
90
|
+
md.push("", "_follow_up_tools: `analyze_field`, `trace_upstream`, `trace_downstream`_");
|
|
91
|
+
return {
|
|
92
|
+
summary: showCached
|
|
93
|
+
? `snippet + cached explanation for ${input.qname}`
|
|
94
|
+
: `snippet for ${input.qname} (no cached explanation)`,
|
|
95
|
+
markdown: md.join("\n"),
|
|
96
|
+
data: {
|
|
97
|
+
qname: input.qname,
|
|
98
|
+
sourceFormat: snippet.sourceFormat,
|
|
99
|
+
sourceText: snippet.sourceText,
|
|
100
|
+
startLine: snippet.startLine ?? null,
|
|
101
|
+
endLine: snippet.endLine ?? null,
|
|
102
|
+
cachedExplanation: showCached ? (snippet.llmExplanation ?? null) : null,
|
|
103
|
+
cachedAt: showCached ? (snippet.explainedAt ?? null) : null,
|
|
104
|
+
stored: false,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=explain_code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain_code.js","sourceRoot":"","sources":["../../src/tools/explain_code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freshness_report.d.ts","sourceRoot":"","sources":["../../src/tools/freshness_report.ts"],"names":[],"mappings":""}
|