sf-intelligence 0.1.0 → 0.1.1
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/index.js +300 -55
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -944,7 +944,7 @@ var init_resolve_index = __esm({
|
|
|
944
944
|
});
|
|
945
945
|
|
|
946
946
|
// ../graph/dist/src/resolve.js
|
|
947
|
-
var DEFAULT_LIMIT, MAX_LIMIT, MIN_BASE, MATCHED_FLOOR, NONE_THRESHOLD, EXACT_THRESHOLD, EXACT_COVERAGE, CONTENDER_RATIO, LENGTH_RATIO_FLOOR, SYNONYM_SCORE, POP_K, COVERAGE_EXP, STRONG_ANCHOR, TYPE_WEIGHT, typeWeight, scoreToken, rollupKind, buildEvidence, resolveComponents;
|
|
947
|
+
var DEFAULT_LIMIT, MAX_LIMIT, MIN_BASE, MATCHED_FLOOR, NONE_THRESHOLD, EXACT_THRESHOLD, EXACT_COVERAGE, CONTENDER_RATIO, LENGTH_RATIO_FLOOR, SYNONYM_SCORE, POP_K, COVERAGE_EXP, STRONG_ANCHOR, PARENT_MATCH_BONUS, TYPE_WEIGHT, typeWeight, scoreToken, rollupKind, buildEvidence, resolveComponents;
|
|
948
948
|
var init_resolve = __esm({
|
|
949
949
|
"../graph/dist/src/resolve.js"() {
|
|
950
950
|
"use strict";
|
|
@@ -964,6 +964,7 @@ var init_resolve = __esm({
|
|
|
964
964
|
POP_K = 0.08;
|
|
965
965
|
COVERAGE_EXP = 0.5;
|
|
966
966
|
STRONG_ANCHOR = 0.9;
|
|
967
|
+
PARENT_MATCH_BONUS = 1.1;
|
|
967
968
|
TYPE_WEIGHT = {
|
|
968
969
|
CustomObject: 1,
|
|
969
970
|
CustomField: 0.95,
|
|
@@ -1053,12 +1054,34 @@ var init_resolve = __esm({
|
|
|
1053
1054
|
qt,
|
|
1054
1055
|
...scoreToken(qt, node.tokens)
|
|
1055
1056
|
}));
|
|
1057
|
+
const nameMatchedSomething = perToken.some((t) => t.score >= MATCHED_FLOOR);
|
|
1058
|
+
let parentMatched = false;
|
|
1059
|
+
if (nameMatchedSomething && node.parentApiName) {
|
|
1060
|
+
const parentTokens = tokenizeText(node.parentApiName);
|
|
1061
|
+
if (parentTokens.length > 0) {
|
|
1062
|
+
for (let i = 0; i < perToken.length; i += 1) {
|
|
1063
|
+
if (perToken[i].score >= MATCHED_FLOOR)
|
|
1064
|
+
continue;
|
|
1065
|
+
const pm = scoreToken(queryTokens[i], parentTokens);
|
|
1066
|
+
if (pm.score > perToken[i].score) {
|
|
1067
|
+
perToken[i] = {
|
|
1068
|
+
qt: queryTokens[i],
|
|
1069
|
+
score: pm.score,
|
|
1070
|
+
kind: "substring",
|
|
1071
|
+
matchedToken: pm.matchedToken
|
|
1072
|
+
};
|
|
1073
|
+
if (pm.score >= MATCHED_FLOOR)
|
|
1074
|
+
parentMatched = true;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1056
1079
|
for (let i = 0; i < perToken.length; i += 1) {
|
|
1057
1080
|
if (perToken[i].score > globalBest[i])
|
|
1058
1081
|
globalBest[i] = perToken[i].score;
|
|
1059
1082
|
}
|
|
1060
|
-
const wholeExact = normQuery.length >= 2 && node.normName === normQuery;
|
|
1061
|
-
pass1.push({ node, perToken, wholeExact });
|
|
1083
|
+
const wholeExact = normQuery.length >= 2 && node.normName === normQuery && query.includes(".") === node.apiName.includes(".");
|
|
1084
|
+
pass1.push({ node, perToken, wholeExact, parentMatched });
|
|
1062
1085
|
}
|
|
1063
1086
|
const anchorIdx = [];
|
|
1064
1087
|
for (let i = 0; i < queryTokens.length; i += 1) {
|
|
@@ -1083,9 +1106,10 @@ var init_resolve = __esm({
|
|
|
1083
1106
|
continue;
|
|
1084
1107
|
const type = c.node.type;
|
|
1085
1108
|
const refs = c.node.inbound;
|
|
1086
|
-
const score = base * typeWeight(type) * (1 + POP_K * Math.log10(1 + refs));
|
|
1109
|
+
const score = base * typeWeight(type) * (1 + POP_K * Math.log10(1 + refs)) * (c.parentMatched ? PARENT_MATCH_BONUS : 1);
|
|
1087
1110
|
const kind = c.wholeExact ? "exact" : rollupKind(matched);
|
|
1088
|
-
const
|
|
1111
|
+
const nodeTokenSet = new Set(c.node.tokens);
|
|
1112
|
+
const matchedNodeTokens = new Set(matched.map((m) => m.matchedToken).filter((t) => nodeTokenSet.has(t)));
|
|
1089
1113
|
coverageById.set(c.node.id, c.wholeExact ? 1 : matchedNodeTokens.size / c.node.tokens.length);
|
|
1090
1114
|
if (c.wholeExact)
|
|
1091
1115
|
wholeExactIds.add(c.node.id);
|
|
@@ -1549,6 +1573,7 @@ var init_manifest = __esm({
|
|
|
1549
1573
|
const coveredTypes = filtered.filter((entry) => entry.requested && !entry.errored && !entry.neverModeled).map((entry) => entry.type);
|
|
1550
1574
|
const partialTypes = filtered.filter((entry) => entry.errored && !entry.neverModeled).map((entry) => entry.type);
|
|
1551
1575
|
const notModeledTypes = filtered.filter((entry) => entry.neverModeled).map((entry) => entry.type);
|
|
1576
|
+
const notRequestedTypes = filtered.filter((entry) => !entry.requested && !entry.neverModeled).map((entry) => entry.type);
|
|
1552
1577
|
if (wanted !== null) {
|
|
1553
1578
|
const knownTypes = new Set(filtered.map((entry) => entry.type));
|
|
1554
1579
|
for (const type of wanted) {
|
|
@@ -1557,7 +1582,9 @@ var init_manifest = __esm({
|
|
|
1557
1582
|
}
|
|
1558
1583
|
}
|
|
1559
1584
|
}
|
|
1560
|
-
const missingCoverage = [
|
|
1585
|
+
const missingCoverage = [
|
|
1586
|
+
.../* @__PURE__ */ new Set([...partialTypes, ...notModeledTypes, ...notRequestedTypes])
|
|
1587
|
+
].sort();
|
|
1561
1588
|
const coverageKnown = readCoverageEntries(manifest).length > 0;
|
|
1562
1589
|
const status = missingCoverage.length > 0 ? "partial" : coverageKnown ? "complete" : "unknown";
|
|
1563
1590
|
return {
|
|
@@ -7615,7 +7642,7 @@ var init_explain_field = __esm({
|
|
|
7615
7642
|
|
|
7616
7643
|
// ../mcp/dist/src/tools/explain-flow.js
|
|
7617
7644
|
import { z as z32 } from "zod";
|
|
7618
|
-
var FLOW_PREFIX, DISCLOSURE2, explainFlowInputSchema, readFlowLabel, readFlowStatus, readFlowProcessType, readFlowTriggerType, findTriggerObject, collectTriggerConditions, stripObjectPrefix, collectActionCalls, prefixOf, collectRecordLookups, classifyWriteOperation, collectRecordWrites, decisionNameOf, collectDecisions, explainFlowHandler;
|
|
7645
|
+
var FLOW_PREFIX, DISCLOSURE2, explainFlowInputSchema, readFlowLabel, readFlowStatus, readFlowProcessType, readFlowTriggerType, findTriggerObject, collectTriggerConditions, stripObjectPrefix, collectActionCalls, prefixOf, collectRecordLookups, classifyWriteOperation, collectRecordWrites, decisionNameOf, collectDecisions, ALTERNATE_TYPE_PREFIXES, findAlternateTypeId, explainFlowHandler;
|
|
7619
7646
|
var init_explain_flow = __esm({
|
|
7620
7647
|
"../mcp/dist/src/tools/explain-flow.js"() {
|
|
7621
7648
|
"use strict";
|
|
@@ -7788,6 +7815,21 @@ var init_explain_flow = __esm({
|
|
|
7788
7815
|
}
|
|
7789
7816
|
return out;
|
|
7790
7817
|
};
|
|
7818
|
+
ALTERNATE_TYPE_PREFIXES = [
|
|
7819
|
+
"ApexTrigger",
|
|
7820
|
+
"ApexClass",
|
|
7821
|
+
"WorkflowRule",
|
|
7822
|
+
"ValidationRule"
|
|
7823
|
+
];
|
|
7824
|
+
findAlternateTypeId = async (ctx, bareName) => {
|
|
7825
|
+
for (const prefix of ALTERNATE_TYPE_PREFIXES) {
|
|
7826
|
+
const candidate = `${prefix}:${bareName}`;
|
|
7827
|
+
const r = await getNodeById(ctx.graph, candidate);
|
|
7828
|
+
if (r.ok && r.value !== null)
|
|
7829
|
+
return candidate;
|
|
7830
|
+
}
|
|
7831
|
+
return null;
|
|
7832
|
+
};
|
|
7791
7833
|
explainFlowHandler = async (ctx, input2) => {
|
|
7792
7834
|
const coercedFlowId = coercePrefix(input2.flowId, [FLOW_PREFIX]);
|
|
7793
7835
|
if (!coercedFlowId.startsWith(FLOW_PREFIX)) {
|
|
@@ -7806,9 +7848,11 @@ var init_explain_flow = __esm({
|
|
|
7806
7848
|
});
|
|
7807
7849
|
}
|
|
7808
7850
|
if (nodeResult.value === null) {
|
|
7851
|
+
const bareName = flowId.slice(FLOW_PREFIX.length);
|
|
7852
|
+
const alt = await findAlternateTypeId(ctx, bareName);
|
|
7809
7853
|
return err({
|
|
7810
7854
|
kind: "component-not-found",
|
|
7811
|
-
message: `no Flow with id ${flowId}`,
|
|
7855
|
+
message: alt ? `no Flow named '${bareName}', but '${alt}' exists \u2014 it is a ${alt.slice(0, alt.indexOf(":"))}, not a Flow. explain_flow only handles Flows; use get_component (or the matching trigger/apex tool) for '${alt}'.` : `no Flow with id ${flowId}`,
|
|
7812
7856
|
path: flowId
|
|
7813
7857
|
});
|
|
7814
7858
|
}
|
|
@@ -9345,11 +9389,11 @@ var init_naming_convention = __esm({
|
|
|
9345
9389
|
parseScope = (scope) => {
|
|
9346
9390
|
if (scope === void 0 || scope === "all")
|
|
9347
9391
|
return ok(null);
|
|
9348
|
-
const match = /^CustomField:([^.]+)
|
|
9392
|
+
const match = /^CustomField:([^.]+)(?:\.\*)?$/.exec(scope);
|
|
9349
9393
|
if (match === null) {
|
|
9350
9394
|
return err({
|
|
9351
9395
|
kind: "invalid-scope",
|
|
9352
|
-
message: `unrecognized scope "${scope}"; expected 'all' or 'CustomField:{ObjectApiName}.*'`
|
|
9396
|
+
message: `unrecognized scope "${scope}"; expected 'all', 'CustomField:{ObjectApiName}', or 'CustomField:{ObjectApiName}.*'`
|
|
9353
9397
|
});
|
|
9354
9398
|
}
|
|
9355
9399
|
return ok(match[1]);
|
|
@@ -17053,7 +17097,7 @@ var init_get_edges = __esm({
|
|
|
17053
17097
|
];
|
|
17054
17098
|
getEdgesInputSchema = z65.object({
|
|
17055
17099
|
nodeId: z65.string().min(1),
|
|
17056
|
-
direction: z65.enum(["in", "out", "both"]).optional(),
|
|
17100
|
+
direction: z65.preprocess((v) => v === "incoming" ? "in" : v === "outgoing" ? "out" : v, z65.enum(["in", "out", "both"])).optional(),
|
|
17057
17101
|
edgeType: z65.enum(EDGE_TYPES).optional(),
|
|
17058
17102
|
confidence: z65.enum(CONFIDENCE_LEVELS).optional()
|
|
17059
17103
|
});
|
|
@@ -18920,7 +18964,7 @@ var init_live_consent = __esm({
|
|
|
18920
18964
|
import { execFile as execFile2 } from "node:child_process";
|
|
18921
18965
|
import { promisify as promisify2 } from "node:util";
|
|
18922
18966
|
import { z as z73 } from "zod";
|
|
18923
|
-
var nodeExecFile2, redactSecrets, LIVE_PLANE_DISCLOSURE, MAX_SAMPLE_ROWS, liveEnabledSchema, isLivePlaneEnabled, liveTrust, resolveOrg, resolveLiveAccess, liveConsentRequiredError, gateLive, getLiveAuth, runSfJson, apiPath, restGet, liveDescribeInputSchema, liveDescribeHandler, liveCountInputSchema, assertCountSoql, liveCountHandler, liveSampleInputSchema, capSampleSoql, liveSampleHandler, liveFieldPopulationInputSchema, liveFieldPopulationHandler, liveOrgLimitsInputSchema, liveOrgLimitsHandler, MAX_INACTIVE_USER_ROWS, DEFAULT_INACTIVE_DAYS, MS_PER_DAY, liveInactiveUsersInputSchema, soqlDateTime, liveInactiveUsersHandler, DEFAULT_LICENSE_INACTIVE_DAYS, MAX_RECLAIM_ROWS, LICENSE_USAGE_DISCLOSURE, liveLicenseUsageInputSchema, toUtilization, renderLicenseUsageMarkdown, liveLicenseUsageHandler, liveConsentInputSchema, consentTrust, liveConsentHandler, liveQuery, MAX_DETAIL_ROWS, daysAgoSoql, daysSince, livePlaneVaultState, UNAVAILABLE_ERROR, assertSoqlIdentifier, soqlLiteral, MAX_GROUP_BUCKETS, DEFAULT_STALE_DAYS, DEFAULT_RECENT_DAYS, liveGroupCountInputSchema, liveGroupCountHandler, liveStaleRecordsInputSchema, liveStaleRecordsHandler, liveRecentActivityInputSchema, liveRecentActivityHandler, buildEqualityWhere, aggregateCountFromRow, liveAggregateInputSchema, liveAggregateHandler, MAX_DUPLICATE_GROUPS, liveDuplicateCheckInputSchema, liveDuplicateCheckHandler, MAX_OWNER_BUCKETS, liveOwnerBreakdownInputSchema, liveOwnerBreakdownHandler, DEFAULT_REPORT_STALE_DAYS, liveReportUsageInputSchema, liveReportUsageHandler, liveFolderAccessInputSchema, liveFolderAccessHandler, DEFAULT_TEMPLATE_STALE_DAYS, CLASSIC_TEMPLATE_TYPES, liveEmailTemplateUsageInputSchema, liveEmailTemplateUsageHandler, DEFAULT_HEALTH_DAYS, LIMIT_RISK_THRESHOLD, liveOrgHealthInputSchema, liveOrgHealthHandler, liveStorageByObjectInputSchema, liveStorageByObjectHandler, liveDataSkewInputSchema, liveSetupAuditTrailInputSchema, liveSecurityExposureInputSchema;
|
|
18967
|
+
var nodeExecFile2, redactSecrets, LIVE_PLANE_DISCLOSURE, MAX_SAMPLE_ROWS, liveEnabledSchema, isLivePlaneEnabled, liveTrust, resolveOrg, resolveLiveAccess, liveConsentRequiredError, gateLive, getLiveAuth, runSfJson, apiPath, restGet, liveDescribeInputSchema, liveDescribeHandler, liveCountInputSchema, OBJECT_API_NAME_RE, resolveCountSoql, assertCountSoql, liveCountHandler, liveSampleInputSchema, capSampleSoql, liveSampleHandler, liveFieldPopulationInputSchema, liveFieldPopulationHandler, liveOrgLimitsInputSchema, liveOrgLimitsHandler, MAX_INACTIVE_USER_ROWS, DEFAULT_INACTIVE_DAYS, MS_PER_DAY, liveInactiveUsersInputSchema, soqlDateTime, liveInactiveUsersHandler, DEFAULT_LICENSE_INACTIVE_DAYS, MAX_RECLAIM_ROWS, LICENSE_USAGE_DISCLOSURE, liveLicenseUsageInputSchema, toUtilization, renderLicenseUsageMarkdown, liveLicenseUsageHandler, liveConsentInputSchema, consentTrust, liveConsentHandler, liveQuery, MAX_DETAIL_ROWS, daysAgoSoql, daysSince, livePlaneVaultState, UNAVAILABLE_ERROR, assertSoqlIdentifier, soqlLiteral, MAX_GROUP_BUCKETS, DEFAULT_STALE_DAYS, DEFAULT_RECENT_DAYS, liveGroupCountInputSchema, liveGroupCountHandler, liveStaleRecordsInputSchema, liveStaleRecordsHandler, liveRecentActivityInputSchema, liveRecentActivityHandler, buildEqualityWhere, aggregateCountFromRow, liveAggregateInputSchema, liveAggregateHandler, MAX_DUPLICATE_GROUPS, liveDuplicateCheckInputSchema, liveDuplicateCheckHandler, MAX_OWNER_BUCKETS, liveOwnerBreakdownInputSchema, liveOwnerBreakdownHandler, DEFAULT_REPORT_STALE_DAYS, liveReportUsageInputSchema, liveReportUsageHandler, liveFolderAccessInputSchema, liveFolderAccessHandler, DEFAULT_TEMPLATE_STALE_DAYS, CLASSIC_TEMPLATE_TYPES, liveEmailTemplateUsageInputSchema, liveEmailTemplateUsageHandler, DEFAULT_HEALTH_DAYS, LIMIT_RISK_THRESHOLD, liveOrgHealthInputSchema, liveOrgHealthHandler, liveStorageByObjectInputSchema, liveStorageByObjectHandler, liveDataSkewInputSchema, liveSetupAuditTrailInputSchema, liveSecurityExposureInputSchema;
|
|
18924
18968
|
var init_live_plane = __esm({
|
|
18925
18969
|
"../mcp/dist/src/tools/live-plane.js"() {
|
|
18926
18970
|
"use strict";
|
|
@@ -19037,9 +19081,33 @@ var init_live_plane = __esm({
|
|
|
19037
19081
|
});
|
|
19038
19082
|
};
|
|
19039
19083
|
liveCountInputSchema = liveEnabledSchema.extend({
|
|
19040
|
-
soql
|
|
19084
|
+
// Either `soql` (a SELECT COUNT() query) OR `objectApiName` (count every row
|
|
19085
|
+
// of that object). Both optional at the schema level; the handler requires
|
|
19086
|
+
// exactly one and turns objectApiName into `SELECT COUNT() FROM <object>`.
|
|
19087
|
+
soql: z73.string().min(1).optional(),
|
|
19088
|
+
objectApiName: z73.string().min(1).optional(),
|
|
19041
19089
|
orgAlias: z73.string().min(1).optional()
|
|
19042
19090
|
});
|
|
19091
|
+
OBJECT_API_NAME_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
19092
|
+
resolveCountSoql = (input2) => {
|
|
19093
|
+
if (input2.soql !== void 0)
|
|
19094
|
+
return ok(input2.soql);
|
|
19095
|
+
if (input2.objectApiName !== void 0) {
|
|
19096
|
+
if (!OBJECT_API_NAME_RE.test(input2.objectApiName)) {
|
|
19097
|
+
return err({
|
|
19098
|
+
kind: "invalid-query",
|
|
19099
|
+
message: `objectApiName "${input2.objectApiName}" is not a valid Salesforce object API name.`,
|
|
19100
|
+
path: "objectApiName"
|
|
19101
|
+
});
|
|
19102
|
+
}
|
|
19103
|
+
return ok(`SELECT COUNT() FROM ${input2.objectApiName}`);
|
|
19104
|
+
}
|
|
19105
|
+
return err({
|
|
19106
|
+
kind: "invalid-query",
|
|
19107
|
+
message: "live_count needs either `soql` (a SELECT COUNT() query) or `objectApiName`.",
|
|
19108
|
+
path: "soql"
|
|
19109
|
+
});
|
|
19110
|
+
};
|
|
19043
19111
|
assertCountSoql = (soql) => {
|
|
19044
19112
|
const normalized = soql.trim().replace(/\s+/g, " ");
|
|
19045
19113
|
if (!/^select\s+count\s*\(/i.test(normalized)) {
|
|
@@ -19055,7 +19123,10 @@ var init_live_plane = __esm({
|
|
|
19055
19123
|
const gate = await gateLive(ctx, input2);
|
|
19056
19124
|
if (!gate.ok)
|
|
19057
19125
|
return gate;
|
|
19058
|
-
const
|
|
19126
|
+
const soqlResult = resolveCountSoql(input2);
|
|
19127
|
+
if (!soqlResult.ok)
|
|
19128
|
+
return soqlResult;
|
|
19129
|
+
const soqlCheck = assertCountSoql(soqlResult.value);
|
|
19059
19130
|
if (!soqlCheck.ok)
|
|
19060
19131
|
return soqlCheck;
|
|
19061
19132
|
const org = resolveOrg(ctx, input2.orgAlias);
|
|
@@ -21223,7 +21294,7 @@ var init_omniuicard_widget_breakdown = __esm({
|
|
|
21223
21294
|
});
|
|
21224
21295
|
|
|
21225
21296
|
// ../mcp/dist/src/tools/soe-admission.js
|
|
21226
|
-
var OBJECT_NOT_MODELED_BOUNDARY, evaluateSoeAdmission, composeSoeDisclosure;
|
|
21297
|
+
var OBJECT_NOT_MODELED_BOUNDARY, evaluateSoeAdmission, composeSoeDisclosure, soeNotAdmittedMessage;
|
|
21227
21298
|
var init_soe_admission = __esm({
|
|
21228
21299
|
"../mcp/dist/src/tools/soe-admission.js"() {
|
|
21229
21300
|
"use strict";
|
|
@@ -21259,9 +21330,74 @@ var init_soe_admission = __esm({
|
|
|
21259
21330
|
if (parentOf.value.length > 0) {
|
|
21260
21331
|
return ok({ admitted: true, objectModeled: false });
|
|
21261
21332
|
}
|
|
21262
|
-
|
|
21333
|
+
const inbound = await listEdges(ctx.graph, objectId, { direction: "in" });
|
|
21334
|
+
if (!inbound.ok) {
|
|
21335
|
+
return err(inbound.error.message);
|
|
21336
|
+
}
|
|
21337
|
+
return ok({
|
|
21338
|
+
admitted: false,
|
|
21339
|
+
objectModeled: false,
|
|
21340
|
+
referencedButNotModeled: inbound.value.length > 0
|
|
21341
|
+
});
|
|
21263
21342
|
};
|
|
21264
21343
|
composeSoeDisclosure = (baseDisclosure, objectModeled) => objectModeled ? baseDisclosure : `${baseDisclosure} ${OBJECT_NOT_MODELED_BOUNDARY}`;
|
|
21344
|
+
soeNotAdmittedMessage = (objectId, referencedButNotModeled) => referencedButNotModeled ? `\`${objectId}\` is referenced by this org (e.g. permission-set grants) but its definition was never retrieved into this vault \u2014 typically a managed-package or filtered object. Save-order can't be composed without the object's own metadata and automation. Run \`sfi refresh\` if it is retrievable, otherwise treat it as external.` : `no automation or object definition for \`${objectId}\` in this vault`;
|
|
21345
|
+
}
|
|
21346
|
+
});
|
|
21347
|
+
|
|
21348
|
+
// ../mcp/dist/src/tools/soe-payload-bounds.js
|
|
21349
|
+
var SOE_MAX_PAYLOAD_BYTES, KEEP_ALL_AT_OR_BELOW, sizeOf, enforceSoeByteBudget, soeTruncationNote;
|
|
21350
|
+
var init_soe_payload_bounds = __esm({
|
|
21351
|
+
"../mcp/dist/src/tools/soe-payload-bounds.js"() {
|
|
21352
|
+
"use strict";
|
|
21353
|
+
SOE_MAX_PAYLOAD_BYTES = 4e4;
|
|
21354
|
+
KEEP_ALL_AT_OR_BELOW = 4;
|
|
21355
|
+
sizeOf = (payload) => Buffer.byteLength(JSON.stringify(payload), "utf8");
|
|
21356
|
+
enforceSoeByteBudget = (payload, steps) => {
|
|
21357
|
+
if (sizeOf(payload) <= SOE_MAX_PAYLOAD_BYTES) {
|
|
21358
|
+
return { truncated: false, actionsOmitted: 0 };
|
|
21359
|
+
}
|
|
21360
|
+
let totalOmitted = 0;
|
|
21361
|
+
const trimTo = (step3, keep) => {
|
|
21362
|
+
if (keep >= step3.actions.length)
|
|
21363
|
+
return;
|
|
21364
|
+
const removed = step3.actions.length - keep;
|
|
21365
|
+
step3.actions = step3.actions.slice(0, keep);
|
|
21366
|
+
step3.actionsOmitted = (step3.actionsOmitted ?? 0) + removed;
|
|
21367
|
+
totalOmitted += removed;
|
|
21368
|
+
};
|
|
21369
|
+
const actionBytes = steps.reduce((n, s) => n + Buffer.byteLength(JSON.stringify(s.actions), "utf8"), 0);
|
|
21370
|
+
const nonActionBytes = Math.max(0, sizeOf(payload) - actionBytes);
|
|
21371
|
+
const budgetForActions = SOE_MAX_PAYLOAD_BYTES - nonActionBytes;
|
|
21372
|
+
if (budgetForActions <= 0) {
|
|
21373
|
+
for (const s of steps)
|
|
21374
|
+
trimTo(s, 0);
|
|
21375
|
+
} else if (actionBytes > budgetForActions) {
|
|
21376
|
+
const ratio = budgetForActions / actionBytes;
|
|
21377
|
+
for (const s of steps) {
|
|
21378
|
+
if (s.actions.length <= KEEP_ALL_AT_OR_BELOW)
|
|
21379
|
+
continue;
|
|
21380
|
+
trimTo(s, Math.max(0, Math.floor(s.actions.length * ratio)));
|
|
21381
|
+
}
|
|
21382
|
+
}
|
|
21383
|
+
for (let guard = 0; guard < 1e5; guard += 1) {
|
|
21384
|
+
if (sizeOf(payload) <= SOE_MAX_PAYLOAD_BYTES)
|
|
21385
|
+
break;
|
|
21386
|
+
let target;
|
|
21387
|
+
for (const s of steps) {
|
|
21388
|
+
if (s.actions.length <= KEEP_ALL_AT_OR_BELOW)
|
|
21389
|
+
continue;
|
|
21390
|
+
if (target === void 0 || s.actions.length > target.actions.length) {
|
|
21391
|
+
target = s;
|
|
21392
|
+
}
|
|
21393
|
+
}
|
|
21394
|
+
if (target === void 0)
|
|
21395
|
+
break;
|
|
21396
|
+
trimTo(target, Math.floor(target.actions.length / 2));
|
|
21397
|
+
}
|
|
21398
|
+
return { truncated: totalOmitted > 0, actionsOmitted: totalOmitted };
|
|
21399
|
+
};
|
|
21400
|
+
soeTruncationNote = (n) => `Response trimmed to fit the ~${Math.round(SOE_MAX_PAYLOAD_BYTES / 1e3)} KB MCP response budget: every save-order STEP is present and in order, but ${n} per-step action edge(s) across the heaviest steps were omitted (see each step's \`actionsOmitted\`). Query a single object/event or use \`get_edges\` on a specific step's component for its full action list.`;
|
|
21265
21401
|
}
|
|
21266
21402
|
});
|
|
21267
21403
|
|
|
@@ -21274,6 +21410,7 @@ var init_order_of_execution = __esm({
|
|
|
21274
21410
|
init_dist();
|
|
21275
21411
|
init_src();
|
|
21276
21412
|
init_soe_admission();
|
|
21413
|
+
init_soe_payload_bounds();
|
|
21277
21414
|
DISCLOSURE6 = "v2.0e composes the documented Salesforce order-of-execution instantiated against THIS org's extracted automation. Conditions ARE listed but NOT EVALUATED \u2014 the tool does not know whether this particular record satisfies them at runtime. Manual sharing, sharing sets, account teams, and Apex callouts after save are out of scope.";
|
|
21278
21415
|
SOE_EVENTS = ["insert", "update", "delete", "undelete"];
|
|
21279
21416
|
orderOfExecutionInputSchema = z82.object({
|
|
@@ -21603,7 +21740,7 @@ var init_order_of_execution = __esm({
|
|
|
21603
21740
|
if (!admission.value.admitted) {
|
|
21604
21741
|
return err({
|
|
21605
21742
|
kind: "component-not-found",
|
|
21606
|
-
message:
|
|
21743
|
+
message: soeNotAdmittedMessage(objectId, admission.value.referencedButNotModeled ?? false),
|
|
21607
21744
|
path: objectId
|
|
21608
21745
|
});
|
|
21609
21746
|
}
|
|
@@ -21621,13 +21758,20 @@ var init_order_of_execution = __esm({
|
|
|
21621
21758
|
}
|
|
21622
21759
|
byEvent[event] = perEventResult.value;
|
|
21623
21760
|
}
|
|
21761
|
+
const data = {
|
|
21762
|
+
objectApiName: input2.objectApiName,
|
|
21763
|
+
objectModeled,
|
|
21764
|
+
byEvent,
|
|
21765
|
+
disclosure: composeSoeDisclosure(DISCLOSURE6, objectModeled)
|
|
21766
|
+
};
|
|
21767
|
+
const allSteps = SOE_EVENTS.flatMap((event) => byEvent[event].soe);
|
|
21768
|
+
const budget = enforceSoeByteBudget(data, allSteps);
|
|
21769
|
+
if (budget.truncated) {
|
|
21770
|
+
data.truncated = true;
|
|
21771
|
+
data.disclosure = `${data.disclosure} ${soeTruncationNote(budget.actionsOmitted)}`;
|
|
21772
|
+
}
|
|
21624
21773
|
return ok({
|
|
21625
|
-
data
|
|
21626
|
-
objectApiName: input2.objectApiName,
|
|
21627
|
-
objectModeled,
|
|
21628
|
-
byEvent,
|
|
21629
|
-
disclosure: composeSoeDisclosure(DISCLOSURE6, objectModeled)
|
|
21630
|
-
},
|
|
21774
|
+
data,
|
|
21631
21775
|
vaultState: {
|
|
21632
21776
|
sourceTreeHash: ctx.manifest.sourceTreeHash,
|
|
21633
21777
|
refreshedAt: ctx.manifest.refreshedAt
|
|
@@ -22755,7 +22899,9 @@ var init_intent_router = __esm({
|
|
|
22755
22899
|
/\bwho\s+can\s+(see|read|view|edit|access)\b\s+[\w\s.]+[?.!]?$/,
|
|
22756
22900
|
/\b(access|permission|fls|field[-\s]level\s+security)\b.*\b(field|object)\b/,
|
|
22757
22901
|
/\bwho\s+has\s+access\s+to\b/,
|
|
22758
|
-
|
|
22902
|
+
// "allow|read|view" added: "which permission sets allow read on X" was a
|
|
22903
|
+
// router gap (the verbs grant/access/see/edit didn't cover it).
|
|
22904
|
+
/\bwhich\s+(profiles?|permission\s+sets?)\b.*\b(grant|allow|access|see|read|view|edit)\b/
|
|
22759
22905
|
]
|
|
22760
22906
|
},
|
|
22761
22907
|
{
|
|
@@ -22880,11 +23026,15 @@ var init_intent_router = __esm({
|
|
|
22880
23026
|
tools: ["sfi.resolve", "sfi.what_happens_on_save", "sfi.order_of_execution"],
|
|
22881
23027
|
liveRequired: false,
|
|
22882
23028
|
needsResolve: true,
|
|
22883
|
-
reason: "Order of execution / what runs on save is reconstructed from the vault graph.",
|
|
23029
|
+
reason: "Order of execution / what runs on save is reconstructed from the vault graph. what_happens_on_save needs an explicit DML event \u2014 default to 'update' (or insert/delete to match the question) when none is stated.",
|
|
22884
23030
|
patterns: [
|
|
22885
23031
|
/\b(trigger\s+order|order\s+of\s+execution)\b/,
|
|
22886
23032
|
/\bwhat\s+(happens|runs|fires)\b.*\b(on\s+save|when\b.*\b(created|saved|updated|inserted|deleted))\b/,
|
|
22887
|
-
|
|
23033
|
+
// "which/what flows|triggers|VRs|workflows run|fire when ..." — the
|
|
23034
|
+
// "which" phrasing was a router gap (e.g. "which flows run when a Case is
|
|
23035
|
+
// created"), so the question fell through to unrouted.
|
|
23036
|
+
/\b(what|which)\s+(triggers?|automation|flows?|validation\s+rules?|workflows?)\b.*\b(fire|run|execute|happen)\b/,
|
|
23037
|
+
/\b(flows?|triggers?|automation)\b.*\bwhen\b.*\b\w+\s+is\b.*\b(created|updated|inserted|deleted|saved)\b/
|
|
22888
23038
|
]
|
|
22889
23039
|
},
|
|
22890
23040
|
{
|
|
@@ -26078,6 +26228,7 @@ var init_what_happens_on_save = __esm({
|
|
|
26078
26228
|
init_dist();
|
|
26079
26229
|
init_src();
|
|
26080
26230
|
init_soe_admission();
|
|
26231
|
+
init_soe_payload_bounds();
|
|
26081
26232
|
DISCLOSURE7 = "v2.0e composes the documented Salesforce order-of-execution instantiated against THIS org's extracted automation. Conditions ARE listed but NOT EVALUATED \u2014 the tool does not know whether this particular record satisfies them at runtime. Manual sharing, sharing sets, account teams, and Apex callouts after save are out of scope.";
|
|
26082
26233
|
ALLOWED_EVENTS = [
|
|
26083
26234
|
"insert",
|
|
@@ -26088,7 +26239,10 @@ var init_what_happens_on_save = __esm({
|
|
|
26088
26239
|
];
|
|
26089
26240
|
whatHappensOnSaveInputSchema = z103.object({
|
|
26090
26241
|
objectApiName: z103.string().min(1),
|
|
26091
|
-
|
|
26242
|
+
// Accept "after update" / "Before Insert" etc.: lower-case and drop the
|
|
26243
|
+
// before/after timing prefix so the bare DML event matches the enum. The
|
|
26244
|
+
// SOE walker models both timings internally; the event arg selects the row.
|
|
26245
|
+
event: z103.preprocess((v) => typeof v === "string" ? v.trim().toLowerCase().replace(/^(?:before|after)\s+/, "") : v, z103.enum(ALLOWED_EVENTS)),
|
|
26092
26246
|
recordTypeId: z103.string().min(1).optional()
|
|
26093
26247
|
});
|
|
26094
26248
|
workflowMatchesEvent2 = (triggerType, event) => {
|
|
@@ -26307,7 +26461,7 @@ var init_what_happens_on_save = __esm({
|
|
|
26307
26461
|
if (!admission.value.admitted) {
|
|
26308
26462
|
return err({
|
|
26309
26463
|
kind: "component-not-found",
|
|
26310
|
-
message:
|
|
26464
|
+
message: soeNotAdmittedMessage(objectId, admission.value.referencedButNotModeled ?? false),
|
|
26311
26465
|
path: objectId
|
|
26312
26466
|
});
|
|
26313
26467
|
}
|
|
@@ -26444,20 +26598,26 @@ var init_what_happens_on_save = __esm({
|
|
|
26444
26598
|
const asyncFanOut = asyncStepsResult.value.length;
|
|
26445
26599
|
stepIndex += asyncFanOut;
|
|
26446
26600
|
const conditionalCount = soe.filter((s) => s.conditional !== void 0).length;
|
|
26447
|
-
|
|
26448
|
-
|
|
26449
|
-
|
|
26450
|
-
|
|
26451
|
-
|
|
26452
|
-
|
|
26453
|
-
|
|
26454
|
-
|
|
26455
|
-
|
|
26456
|
-
|
|
26457
|
-
asyncFanOut
|
|
26458
|
-
},
|
|
26459
|
-
disclosure: composeSoeDisclosure(DISCLOSURE7, objectModeled)
|
|
26601
|
+
const data = {
|
|
26602
|
+
objectApiName: input2.objectApiName,
|
|
26603
|
+
event: input2.event,
|
|
26604
|
+
recordTypeId: input2.recordTypeId ?? null,
|
|
26605
|
+
objectModeled,
|
|
26606
|
+
soe,
|
|
26607
|
+
summary: {
|
|
26608
|
+
totalSteps: soe.length,
|
|
26609
|
+
conditionalSteps: conditionalCount,
|
|
26610
|
+
asyncFanOut
|
|
26460
26611
|
},
|
|
26612
|
+
disclosure: composeSoeDisclosure(DISCLOSURE7, objectModeled)
|
|
26613
|
+
};
|
|
26614
|
+
const budget = enforceSoeByteBudget(data, soe);
|
|
26615
|
+
if (budget.truncated) {
|
|
26616
|
+
data.truncated = true;
|
|
26617
|
+
data.disclosure = `${data.disclosure} ${soeTruncationNote(budget.actionsOmitted)}`;
|
|
26618
|
+
}
|
|
26619
|
+
return ok({
|
|
26620
|
+
data,
|
|
26461
26621
|
vaultState: {
|
|
26462
26622
|
sourceTreeHash: ctx.manifest.sourceTreeHash,
|
|
26463
26623
|
refreshedAt: ctx.manifest.refreshedAt
|
|
@@ -28731,7 +28891,8 @@ var init_tools = __esm({
|
|
|
28731
28891
|
type: "object",
|
|
28732
28892
|
properties: {
|
|
28733
28893
|
nodeId: { type: "string", minLength: 1 },
|
|
28734
|
-
|
|
28894
|
+
// 'incoming'/'outgoing' are accepted aliases (normalized to in/out).
|
|
28895
|
+
direction: { type: "string", enum: ["in", "out", "both", "incoming", "outgoing"] },
|
|
28735
28896
|
edgeType: {
|
|
28736
28897
|
type: "string",
|
|
28737
28898
|
// Single-sourced from the contracts EDGE_TYPES tuple so the advertised
|
|
@@ -28914,9 +29075,12 @@ var init_tools = __esm({
|
|
|
28914
29075
|
});
|
|
28915
29076
|
LIVE_COUNT_INPUT_SCHEMA = Object.freeze({
|
|
28916
29077
|
type: "object",
|
|
28917
|
-
|
|
29078
|
+
// Either `soql` (a SELECT COUNT() query) or `objectApiName` (count all rows).
|
|
29079
|
+
// The one-of requirement is enforced in the handler, not the JSON schema, so
|
|
29080
|
+
// the advertised shape stays simple for clients.
|
|
28918
29081
|
properties: {
|
|
28919
29082
|
soql: { type: "string", minLength: 1 },
|
|
29083
|
+
objectApiName: { type: "string", minLength: 1 },
|
|
28920
29084
|
...LIVE_ENABLED_PROPERTY
|
|
28921
29085
|
}
|
|
28922
29086
|
});
|
|
@@ -30195,7 +30359,7 @@ var init_tools = __esm({
|
|
|
30195
30359
|
},
|
|
30196
30360
|
{
|
|
30197
30361
|
name: "sfi.live_count",
|
|
30198
|
-
description: "Opt-in live org:
|
|
30362
|
+
description: "Opt-in live org: count records. Pass `objectApiName` to count every row of an object, or `soql` for a custom SELECT COUNT() query (strict shape validation). Read-only; never falls back to vault data.",
|
|
30199
30363
|
inputSchema: LIVE_COUNT_INPUT_SCHEMA
|
|
30200
30364
|
},
|
|
30201
30365
|
{
|
|
@@ -31521,15 +31685,40 @@ var runDoctor = async (opts) => {
|
|
|
31521
31685
|
const checks = [];
|
|
31522
31686
|
const vaultRoot = resolve4(opts.cwd, DEFAULT_VAULT_ROOT);
|
|
31523
31687
|
const paths = vaultPaths(vaultRoot);
|
|
31688
|
+
const SF_FALLBACK_PATHS = ["/usr/local/bin/sf", "/opt/homebrew/bin/sf"];
|
|
31689
|
+
let sfBin = "sf";
|
|
31690
|
+
let sfDetail = null;
|
|
31691
|
+
let sfOnPath = false;
|
|
31524
31692
|
try {
|
|
31525
31693
|
const { stdout } = await run("sf --version");
|
|
31526
|
-
|
|
31694
|
+
sfDetail = stdout.trim().split("\n")[0] ?? "installed";
|
|
31695
|
+
sfOnPath = true;
|
|
31527
31696
|
} catch {
|
|
31697
|
+
for (const abs of SF_FALLBACK_PATHS) {
|
|
31698
|
+
try {
|
|
31699
|
+
const { stdout } = await run(`"${abs}" --version`);
|
|
31700
|
+
sfDetail = stdout.trim().split("\n")[0] ?? "installed";
|
|
31701
|
+
sfBin = `"${abs}"`;
|
|
31702
|
+
break;
|
|
31703
|
+
} catch {
|
|
31704
|
+
}
|
|
31705
|
+
}
|
|
31706
|
+
}
|
|
31707
|
+
if (sfOnPath) {
|
|
31708
|
+
checks.push({ name: "Salesforce CLI", status: "pass", detail: sfDetail ?? "installed" });
|
|
31709
|
+
} else if (sfDetail !== null) {
|
|
31710
|
+
checks.push({
|
|
31711
|
+
name: "Salesforce CLI",
|
|
31712
|
+
status: "warn",
|
|
31713
|
+
detail: `${sfDetail} \u2014 found via absolute path, not on PATH`,
|
|
31714
|
+
fix: "Add the Salesforce CLI directory (e.g. /usr/local/bin or /opt/homebrew/bin) to the PATH of whatever launches sfi; IDE/MCP subprocesses often do not inherit it."
|
|
31715
|
+
});
|
|
31716
|
+
} else {
|
|
31528
31717
|
checks.push({
|
|
31529
31718
|
name: "Salesforce CLI",
|
|
31530
31719
|
status: "fail",
|
|
31531
|
-
detail: "`sf` not found on PATH",
|
|
31532
|
-
fix: "Install the Salesforce CLI
|
|
31720
|
+
detail: "`sf` not found on PATH or common install locations",
|
|
31721
|
+
fix: "Install the Salesforce CLI (npm install --global @salesforce/cli). If it IS installed, add its directory (/usr/local/bin or /opt/homebrew/bin) to your PATH; IDE/MCP subprocesses often do not inherit it."
|
|
31533
31722
|
});
|
|
31534
31723
|
}
|
|
31535
31724
|
const vaultInit = await pathExists2(paths.config);
|
|
@@ -31553,7 +31742,7 @@ var runDoctor = async (opts) => {
|
|
|
31553
31742
|
});
|
|
31554
31743
|
} else {
|
|
31555
31744
|
try {
|
|
31556
|
-
const { stdout } = await run(
|
|
31745
|
+
const { stdout } = await run(`${sfBin} org display --target-org "${targetOrg}" --json`);
|
|
31557
31746
|
const parsed = JSON.parse(stdout);
|
|
31558
31747
|
const status = parsed.result?.connectedStatus;
|
|
31559
31748
|
if (status === "Connected") {
|
|
@@ -35729,8 +35918,8 @@ import { XMLParser as XMLParser19, XMLValidator as XMLValidator18 } from "fast-x
|
|
|
35729
35918
|
var APPLICATION_FILE_SUFFIX = ".app-meta.xml";
|
|
35730
35919
|
var ROOT_ELEMENT18 = "CustomApplication";
|
|
35731
35920
|
var EXTRACTOR_SOURCE8 = "custom-application-extractor";
|
|
35732
|
-
var REQUIRED_ELEMENTS4 = ["label"
|
|
35733
|
-
var ALLOWED_NAV_TYPE = ["Standard", "Console"];
|
|
35921
|
+
var REQUIRED_ELEMENTS4 = ["label"];
|
|
35922
|
+
var ALLOWED_NAV_TYPE = ["Standard", "Console", "Classic"];
|
|
35734
35923
|
var unwrapSingle19 = (value) => Array.isArray(value) ? value[0] : value;
|
|
35735
35924
|
var toArray12 = (value) => {
|
|
35736
35925
|
if (value === void 0 || value === null)
|
|
@@ -35779,6 +35968,8 @@ var validateRoot10 = (parsed, path) => {
|
|
|
35779
35968
|
if (rootObj["navType"] === void 0)
|
|
35780
35969
|
rootObj["navType"] = "Standard";
|
|
35781
35970
|
}
|
|
35971
|
+
if (rootObj["navType"] === void 0)
|
|
35972
|
+
rootObj["navType"] = "Classic";
|
|
35782
35973
|
for (const required of REQUIRED_ELEMENTS4) {
|
|
35783
35974
|
if (rootObj[required] === void 0) {
|
|
35784
35975
|
return err({
|
|
@@ -35903,6 +36094,24 @@ var ROOT_ELEMENT19 = "CustomField";
|
|
|
35903
36094
|
var FIELDS_DIR_NAME = "fields";
|
|
35904
36095
|
var PICKLIST_TYPES3 = ["Picklist", "MultiselectPicklist"];
|
|
35905
36096
|
var FORMULA_ELEMENT_NAME = "formula";
|
|
36097
|
+
var STANDARD_FIELD_TYPES = {
|
|
36098
|
+
Email: "Email",
|
|
36099
|
+
Phone: "Phone",
|
|
36100
|
+
Fax: "Phone",
|
|
36101
|
+
MobilePhone: "Phone",
|
|
36102
|
+
HomePhone: "Phone",
|
|
36103
|
+
OtherPhone: "Phone",
|
|
36104
|
+
AssistantPhone: "Phone",
|
|
36105
|
+
Website: "Url",
|
|
36106
|
+
CreatedDate: "DateTime",
|
|
36107
|
+
LastModifiedDate: "DateTime",
|
|
36108
|
+
SystemModstamp: "DateTime",
|
|
36109
|
+
LastViewedDate: "DateTime",
|
|
36110
|
+
LastReferencedDate: "DateTime",
|
|
36111
|
+
LastActivityDate: "Date",
|
|
36112
|
+
Birthdate: "Date",
|
|
36113
|
+
IsDeleted: "Checkbox"
|
|
36114
|
+
};
|
|
35906
36115
|
var unwrapSingle20 = (value) => Array.isArray(value) ? value[0] : value;
|
|
35907
36116
|
var coerceBoolean12 = (value) => {
|
|
35908
36117
|
if (typeof value === "boolean")
|
|
@@ -35976,7 +36185,8 @@ var validateRoot11 = (parsed, path) => {
|
|
|
35976
36185
|
message: "missing required element: <type>"
|
|
35977
36186
|
});
|
|
35978
36187
|
}
|
|
35979
|
-
|
|
36188
|
+
const bareName = fullName.includes(".") ? fullName.split(".").pop() : fullName;
|
|
36189
|
+
rootObj["type"] = STANDARD_FIELD_TYPES[bareName] ?? "Unknown";
|
|
35980
36190
|
}
|
|
35981
36191
|
return ok(rootObj);
|
|
35982
36192
|
};
|
|
@@ -42326,6 +42536,7 @@ var QUICK_ACTIONS_DIR_NAME = "quickActions";
|
|
|
42326
42536
|
var REQUIRED_ELEMENTS20 = ["type"];
|
|
42327
42537
|
var ALLOWED_ACTION_TYPES = [
|
|
42328
42538
|
"Create",
|
|
42539
|
+
"Flow",
|
|
42329
42540
|
"LogACall",
|
|
42330
42541
|
"LightningComponent",
|
|
42331
42542
|
"LightningWebComponent",
|
|
@@ -42465,6 +42676,19 @@ var buildReferencesEdge = (fromId, actionType, rootObj) => {
|
|
|
42465
42676
|
properties: { targetKind: "page" }
|
|
42466
42677
|
};
|
|
42467
42678
|
}
|
|
42679
|
+
if (actionType === "Flow") {
|
|
42680
|
+
const name = optionalString23(rootObj, "flowDefinition");
|
|
42681
|
+
if (name === null || name.length === 0)
|
|
42682
|
+
return null;
|
|
42683
|
+
return {
|
|
42684
|
+
fromId,
|
|
42685
|
+
toId: `Flow:${name}`,
|
|
42686
|
+
edgeType: "references",
|
|
42687
|
+
confidence: "declared",
|
|
42688
|
+
source: EXTRACTOR_SOURCE25,
|
|
42689
|
+
properties: { targetKind: "flow" }
|
|
42690
|
+
};
|
|
42691
|
+
}
|
|
42468
42692
|
return null;
|
|
42469
42693
|
};
|
|
42470
42694
|
var extractQuickAction = async (path) => {
|
|
@@ -42529,6 +42753,7 @@ var extractQuickAction = async (path) => {
|
|
|
42529
42753
|
lightningComponent: optionalString23(rootObj, "lightningComponent"),
|
|
42530
42754
|
lightningWebComponent: optionalString23(rootObj, "lightningWebComponent"),
|
|
42531
42755
|
page: optionalString23(rootObj, "page"),
|
|
42756
|
+
flowDefinition: optionalString23(rootObj, "flowDefinition"),
|
|
42532
42757
|
icon: optionalString23(rootObj, "icon"),
|
|
42533
42758
|
height: optionalInteger2(rootObj, "height"),
|
|
42534
42759
|
width: optionalString23(rootObj, "width")
|
|
@@ -45879,12 +46104,17 @@ var runRefresh = async (opts) => {
|
|
|
45879
46104
|
const paths = vaultPaths(configResult.value.vaultRoot);
|
|
45880
46105
|
const targetOrg = opts.targetOrg ?? configResult.value.targetOrg;
|
|
45881
46106
|
const requestedTypes = parseTypeFilter(opts.types);
|
|
46107
|
+
const progress = opts.onProgress ?? (() => {
|
|
46108
|
+
});
|
|
45882
46109
|
if (!opts.noPull) {
|
|
46110
|
+
progress(`Retrieving metadata from ${targetOrg} (this can take several minutes)...`);
|
|
45883
46111
|
const pulled = await runSfRetrieve(targetOrg, paths.source, requestedTypes);
|
|
45884
46112
|
if (!pulled.ok)
|
|
45885
46113
|
return failed(started, pulled.error, []);
|
|
45886
46114
|
}
|
|
46115
|
+
progress("Extracting components from retrieved source...");
|
|
45887
46116
|
const walked = await walkAndExtract(paths.source, requestedTypes);
|
|
46117
|
+
progress(`Extracted ${walked.results.length} component file(s); building graph...`);
|
|
45888
46118
|
await mkdir9(paths.graph, { recursive: true });
|
|
45889
46119
|
const storeResult = await openGraph(paths.graphDb);
|
|
45890
46120
|
if (!storeResult.ok) {
|
|
@@ -45953,10 +46183,13 @@ var buildCoverageEntries2 = (counts, skippedDirectories, requestedTypes, sourceR
|
|
|
45953
46183
|
};
|
|
45954
46184
|
var runWithOpenGraph = async (args) => {
|
|
45955
46185
|
const { store, paths, started, targetOrg, walked, opts, requestedTypes } = args;
|
|
46186
|
+
const progress = opts.onProgress ?? (() => {
|
|
46187
|
+
});
|
|
45956
46188
|
const importResult = await importExtractionResults(store, walked.results);
|
|
45957
46189
|
if (!importResult.ok) {
|
|
45958
46190
|
return failed(started, `importExtractionResults: ${importResult.error.message}`, walked.failures, EMPTY_COUNTS, walked.skippedDirectories);
|
|
45959
46191
|
}
|
|
46192
|
+
progress("Rendering Markdown vault...");
|
|
45960
46193
|
let counts;
|
|
45961
46194
|
try {
|
|
45962
46195
|
counts = await renderVault(store, paths.root);
|
|
@@ -46173,7 +46406,14 @@ var loadVaultConfig = async (cwd) => {
|
|
|
46173
46406
|
};
|
|
46174
46407
|
var METADATA_API_NAME = {
|
|
46175
46408
|
VisualforcePage: "ApexPage",
|
|
46176
|
-
VisualforceComponent: "ApexComponent"
|
|
46409
|
+
VisualforceComponent: "ApexComponent",
|
|
46410
|
+
// Sharing rules are exposed by the org as the aggregate type `SharingRules`
|
|
46411
|
+
// (one file per object, e.g. `Account.sharingRules-meta.xml`).
|
|
46412
|
+
SharingRule: "SharingRules",
|
|
46413
|
+
// Custom-metadata *records* (the rows of a `__mdt` type) are retrieved under
|
|
46414
|
+
// the `CustomMetadata` type as `{Type}.{Record}.md-meta.xml` files. The
|
|
46415
|
+
// `__mdt` type definitions themselves come down separately as CustomObject.
|
|
46416
|
+
CustomMetadataRecord: "CustomMetadata"
|
|
46177
46417
|
};
|
|
46178
46418
|
var toApiName = (type) => METADATA_API_NAME[type] ?? type;
|
|
46179
46419
|
var SF_MAX_BUFFER = 256 * 1024 * 1024;
|
|
@@ -46242,7 +46482,8 @@ var runSfRetrieve = async (targetOrg, sourceDir, requestedTypes) => {
|
|
|
46242
46482
|
}
|
|
46243
46483
|
const { included: manifestTypes, dropped } = selectManifestTypes(requestedTypes, orgTypes);
|
|
46244
46484
|
if (dropped.length > 0) {
|
|
46245
|
-
|
|
46485
|
+
const labelled = dropped.map((type) => toApiName(type) === type ? type : `${type} (${toApiName(type)})`).join(", ");
|
|
46486
|
+
process.stdout.write(`Skipping ${dropped.length} metadata type(s) the ${targetOrg} describe does not expose: ${labelled}
|
|
46246
46487
|
`);
|
|
46247
46488
|
}
|
|
46248
46489
|
if (manifestTypes.length === 0) {
|
|
@@ -46344,7 +46585,11 @@ var registerRefreshCommand = (program) => {
|
|
|
46344
46585
|
noPull: flags.pull === false,
|
|
46345
46586
|
...flags.targetOrg !== void 0 ? { targetOrg: flags.targetOrg } : {},
|
|
46346
46587
|
...flags.types !== void 0 ? { types: flags.types } : {},
|
|
46347
|
-
...flags.withToolingApi === true ? { withToolingApi: true } : {}
|
|
46588
|
+
...flags.withToolingApi === true ? { withToolingApi: true } : {},
|
|
46589
|
+
// Progress goes to stderr so a multi-minute refresh isn't a silent
|
|
46590
|
+
// wait; stdout stays reserved for the final summary.
|
|
46591
|
+
onProgress: (message) => process.stderr.write(`${message}
|
|
46592
|
+
`)
|
|
46348
46593
|
});
|
|
46349
46594
|
process.stdout.write(formatRefreshSummary(result));
|
|
46350
46595
|
if (result.status !== "success")
|
|
@@ -46503,7 +46748,7 @@ var registerStatusCommand = (program) => {
|
|
|
46503
46748
|
// dist/src/program.js
|
|
46504
46749
|
var readVersion = () => {
|
|
46505
46750
|
if (true)
|
|
46506
|
-
return "0.1.
|
|
46751
|
+
return "0.1.1";
|
|
46507
46752
|
const pkgUrl = new URL("../../package.json", import.meta.url);
|
|
46508
46753
|
const raw = readFileSync2(fileURLToPath(pkgUrl), "utf8");
|
|
46509
46754
|
const parsed = JSON.parse(raw);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sf-intelligence",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Offline-first, MCP-first knowledge base for a Salesforce org. Ask about your org's metadata, dependencies, permissions, and automation — grounded in real retrieved metadata. Ships the sfi CLI and an MCP server.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/PranavNagrecha/Salesforce-Intelligence",
|
|
@@ -52,15 +52,15 @@
|
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"esbuild": "^0.28.0",
|
|
54
54
|
"vitest": "^1.6.0",
|
|
55
|
-
"@sf-intelligence/contracts": "0.1.0",
|
|
56
|
-
"@sf-intelligence/core": "0.1.0",
|
|
57
|
-
"@sf-intelligence/extractors": "0.1.0",
|
|
58
|
-
"@sf-intelligence/graph": "0.1.0",
|
|
59
55
|
"@sf-intelligence/mcp": "0.1.0",
|
|
56
|
+
"@sf-intelligence/core": "0.1.0",
|
|
57
|
+
"@sf-intelligence/contracts": "0.1.0",
|
|
60
58
|
"@sf-intelligence/patterns": "0.1.0",
|
|
59
|
+
"@sf-intelligence/extractors": "0.1.0",
|
|
61
60
|
"@sf-intelligence/renderers": "0.1.0",
|
|
62
|
-
"@sf-intelligence/
|
|
63
|
-
"@sf-intelligence/vault": "0.1.0"
|
|
61
|
+
"@sf-intelligence/graph": "0.1.0",
|
|
62
|
+
"@sf-intelligence/vault": "0.1.0",
|
|
63
|
+
"@sf-intelligence/tooling-api": "0.1.0"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"build": "tsc --build && node build.mjs",
|