sf-intelligence 0.1.22 → 0.1.23
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 +801 -57
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/index.js
CHANGED
|
@@ -24806,6 +24806,73 @@ var init_intent_router = __esm({
|
|
|
24806
24806
|
/\bwhat_if_remove_picklist_value\b/
|
|
24807
24807
|
]
|
|
24808
24808
|
},
|
|
24809
|
+
// === R3 §5b — what-if CHANGE-TYPE WHITELIST honest routes ================
|
|
24810
|
+
// The what_if_* simulators cover a fixed change-type list (field type /
|
|
24811
|
+
// required / picklist value, flow deactivation, trigger disable, method
|
|
24812
|
+
// signature, profile merge/split). A what-if ask about a change type with
|
|
24813
|
+
// NO simulator (remove a record type, change a layout assignment, change a
|
|
24814
|
+
// flow variable's type) must not be absorbed by the nearest-neighbor
|
|
24815
|
+
// what_if_* — these rules catch those shapes FIRST and route the honest
|
|
24816
|
+
// dependency read (get_impact & friends) with an explicit no-simulator
|
|
24817
|
+
// disclosure, mirroring `permission-set-deactivation-impact`.
|
|
24818
|
+
{
|
|
24819
|
+
intent: "record-type-removal-impact",
|
|
24820
|
+
plane: "vault",
|
|
24821
|
+
tools: ["sfi.resolve", "sfi.get_impact", "sfi.recordtype_availability"],
|
|
24822
|
+
liveRequired: false,
|
|
24823
|
+
needsResolve: true,
|
|
24824
|
+
reason: "No what_if simulator exists for removing a record type, so this routes honestly to the dependency read: get_impact surfaces the flows, layouts, validation rules, and profiles referencing the record type, and recordtype_availability shows who can see it today \u2014 the truthful stand-in for a removal blast radius, not a fabricated simulation.",
|
|
24825
|
+
patterns: [
|
|
24826
|
+
/\b(?:remov\w+|delet\w+|dropp?\w*|consolidat\w+|retir\w+)\b[^.?!]{0,50}\brecord\s+types?\b/,
|
|
24827
|
+
/\brecord\s+types?\b[^.?!]{0,50}\b(?:is|are|was|were|gets?|being)\s+(?:removed|deleted|dropped|consolidated|retired)\b/
|
|
24828
|
+
]
|
|
24829
|
+
},
|
|
24830
|
+
{
|
|
24831
|
+
intent: "layout-assignment-change-impact",
|
|
24832
|
+
plane: "vault",
|
|
24833
|
+
tools: ["sfi.resolve", "sfi.layout_assignments", "sfi.get_impact"],
|
|
24834
|
+
liveRequired: false,
|
|
24835
|
+
needsResolve: true,
|
|
24836
|
+
reason: "No what_if simulator exists for changing a page-layout assignment, so this routes honestly to the current state: layout_assignments shows the Profile \xD7 RecordType assignments the change would rewire, plus get_impact for the dependency surface \u2014 a lookup plus impact read, not a fabricated simulation.",
|
|
24837
|
+
patterns: [
|
|
24838
|
+
/\b(?:chang\w+|swapp?\w*|reassign\w*|switch\w*)\b[^.?!]{0,60}\blayout\s+assignments?\b/,
|
|
24839
|
+
/\bwhat\s+(?:if|happens|breaks)\b[^.?!]{0,80}\blayout\s+assignments?\b/
|
|
24840
|
+
]
|
|
24841
|
+
},
|
|
24842
|
+
{
|
|
24843
|
+
intent: "flow-variable-type-change-impact",
|
|
24844
|
+
plane: "vault",
|
|
24845
|
+
tools: ["sfi.resolve", "sfi.get_impact", "sfi.explain_flow"],
|
|
24846
|
+
liveRequired: false,
|
|
24847
|
+
needsResolve: true,
|
|
24848
|
+
reason: "No what_if simulator models changing a flow variable's type (e.g. single record to collection), so this routes honestly to the callers: get_impact surfaces the flows/processes invoking it (whose passed values a type change breaks), and explain_flow the variable's uses inside \u2014 an interface-impact read, not a fabricated simulation.",
|
|
24849
|
+
patterns: [
|
|
24850
|
+
/\b(?:input|output)\s+variable\b[^.?!]{0,60}\btype\b/,
|
|
24851
|
+
/\bvariable\s+type\b[^.?!]{0,60}\bflow\b/,
|
|
24852
|
+
/\bflow\b[^.?!]{0,60}\bvariable\s+type\b/
|
|
24853
|
+
]
|
|
24854
|
+
},
|
|
24855
|
+
{
|
|
24856
|
+
// R3 §5b — ENUMERATION-vs-ID gate: `cpq_rule_chain` and
|
|
24857
|
+
// `cpq_quote_template_breakdown` REQUIRE a specific canonical id, so an
|
|
24858
|
+
// org-wide ask ("map the whole CPQ rule chain", "what quote template does
|
|
24859
|
+
// the org use?") must route the ENUMERATION path — the id-free dependency
|
|
24860
|
+
// map plus list_components — never commit an id-required tool without an
|
|
24861
|
+
// id. Hoisted ABOVE the call-graph/"map the chain" family and the generic
|
|
24862
|
+
// `cpq` rule (first-match): only org-wide CPQ phrasings land here; a
|
|
24863
|
+
// named rule/template still gets the per-id chain tools.
|
|
24864
|
+
intent: "cpq-enumeration",
|
|
24865
|
+
plane: "vault",
|
|
24866
|
+
tools: ["sfi.cpq_dependency_map", "sfi.list_components"],
|
|
24867
|
+
liveRequired: false,
|
|
24868
|
+
needsResolve: false,
|
|
24869
|
+
reason: "Org-wide CPQ enumeration: cpq_dependency_map maps the whole rule/template surface with no id needed, and list_components enumerates the CPQ rules/templates themselves. The per-id tools (cpq_rule_chain, cpq_quote_template_breakdown) need a specific named rule or template \u2014 pick one from the enumeration first.",
|
|
24870
|
+
patterns: [
|
|
24871
|
+
/\bmap\s+the\b[^.?!]{0,40}\bcpq\b|\bcpq\b[^.?!]{0,40}\brule\s+chain\b[^.?!]{0,60}\b(?:evaluation\s+order|all|every|org-?wide|whole)\b/,
|
|
24872
|
+
/\b(?:what|which)\s+(?:cpq\s+)?quote\s+templates?\b[^.?!]{0,50}\b(?:do(?:es)?\s+(?:we|the\s+org)|org)\s*use\b/,
|
|
24873
|
+
/\b(?:all|every|list)\b[^.?!]{0,30}\b(?:price|product|discount)\s+rules?\b[^.?!]{0,50}\b(?:evaluation\s+order|and\s+their)\b/
|
|
24874
|
+
]
|
|
24875
|
+
},
|
|
24809
24876
|
{
|
|
24810
24877
|
intent: "async-chain-depth",
|
|
24811
24878
|
plane: "vault",
|
|
@@ -26111,6 +26178,35 @@ var init_intent_router = __esm({
|
|
|
26111
26178
|
/\bhighlights?\b.*\b(vs|versus|full)\b.*\blayout\b/
|
|
26112
26179
|
]
|
|
26113
26180
|
},
|
|
26181
|
+
{
|
|
26182
|
+
// COMPONENT-TYPE CONFUSION (router-v2 R2, type-confusion trap family):
|
|
26183
|
+
// "is <Name> a flow or a trigger?", "is that an Apex class or a flow?",
|
|
26184
|
+
// "the name has 'Trigger' in it but is it actually a test class?", "what
|
|
26185
|
+
// type is that?". The user is unsure WHAT KIND of component a name is —
|
|
26186
|
+
// resolve answers the type question, and the two explainers cover
|
|
26187
|
+
// whichever family it lands on (the stage-5 type guard swaps the
|
|
26188
|
+
// incompatible one once the entity resolves). MUST precede
|
|
26189
|
+
// automation-on-object, whose "triggers … on <object>" pattern otherwise
|
|
26190
|
+
// steals "…an actual trigger on Contact?".
|
|
26191
|
+
intent: "component-type",
|
|
26192
|
+
plane: "vault",
|
|
26193
|
+
tools: ["sfi.resolve", "sfi.explain_flow", "sfi.explain_apex_method"],
|
|
26194
|
+
liveRequired: false,
|
|
26195
|
+
needsResolve: true,
|
|
26196
|
+
reason: "The question asks WHICH KIND of component a name is (flow vs trigger vs Apex class vs test class). Resolve the name to its actual type first; then explain it with the family-appropriate tool \u2014 the resolver output, not the name, decides which.",
|
|
26197
|
+
patterns: [
|
|
26198
|
+
// Two component-family nouns joined by "or" inside one clause:
|
|
26199
|
+
// "is <name>/that/it (actually) a flow … or (an actual) trigger".
|
|
26200
|
+
/\bis\s+(?:that|this|it|[a-z0-9_]+)\s+(?:actually\s+)?(?:an?\s+)?(?:apex(?:\s+(?:class|test\s+class|logging))?|flow|trigger|test\s+class)\b[^.?!]{0,40}\bor\s+(?:an?\s+)?(?:actual(?:ly)?\s+a?\s*)?(?:apex(?:\s+class)?|flow|trigger|test\s+class|something\s+else)/,
|
|
26201
|
+
// Name-vs-nature: "…but is it actually a test class?"
|
|
26202
|
+
/\bbut\s+is\s+(?:it|that)\s+(?:actually\s+)?an?\s+(?:test\s+class|trigger|flow|apex\s+class)\b/,
|
|
26203
|
+
// "what type is that / what type of component is <name>" — `that/this`
|
|
26204
|
+
// only (not `it`), and never when the question names a __c FIELD:
|
|
26205
|
+
// "what type is it?" about CON_...__c asks the field's DATA type, not
|
|
26206
|
+
// the component family (the cov3-029 negative).
|
|
26207
|
+
/^(?!.*__c\b)(?=[\s\S]*\bwhat\s+type\s+(?:is\s+(?:that|this)|of\s+component\s+is)\b)/
|
|
26208
|
+
]
|
|
26209
|
+
},
|
|
26114
26210
|
{
|
|
26115
26211
|
intent: "field-access",
|
|
26116
26212
|
plane: "vault",
|
|
@@ -26361,6 +26457,35 @@ var init_intent_router = __esm({
|
|
|
26361
26457
|
/\busers?\b[^.?!]{0,30}\bassigned\b[^.?!]{0,30}\bpermission\s+sets?\b/
|
|
26362
26458
|
]
|
|
26363
26459
|
},
|
|
26460
|
+
{
|
|
26461
|
+
// HONEST GAP (round-2, q1948/q1559): "which PSG grants the X custom
|
|
26462
|
+
// permission / the Y role" is a PermissionSetGroup COMPOSITION lookup —
|
|
26463
|
+
// PSG membership/composition is not modeled (same boundary as the two PSG
|
|
26464
|
+
// gaps above), and roles are not granted by PSGs at all, so substituting
|
|
26465
|
+
// object_access_audit / effective_permissions would be confidently wrong.
|
|
26466
|
+
// Requires the GROUP noun: "which permission SETS grant edit on X" (no
|
|
26467
|
+
// `group`) stays on the real field/effective-permissions routes.
|
|
26468
|
+
intent: "permset-group-grants",
|
|
26469
|
+
plane: "vault",
|
|
26470
|
+
tools: [],
|
|
26471
|
+
liveRequired: false,
|
|
26472
|
+
needsResolve: false,
|
|
26473
|
+
reason: "Which permission set group grants a permission (PermissionSetGroup composition) is not modeled \u2014 capability gap.",
|
|
26474
|
+
gap: {
|
|
26475
|
+
category: "permset-group-grants",
|
|
26476
|
+
note: 'PermissionSetGroup composition/membership modeling is not built yet, so "which PSG grants X" cannot be answered. Do not substitute effective_permissions or object_access_audit \u2014 they cover permission sets and profiles, not PSG composition. (If X is a custom permission, sfi.resolve + the permission-set reverse lookup covers PERMISSION SETS granting it.)'
|
|
26477
|
+
},
|
|
26478
|
+
patterns: [
|
|
26479
|
+
// Tempered verb→grants gap: "which permission set groups REFERENCE a
|
|
26480
|
+
// permission set that grants X" is a graph-edge read (answerable) — a
|
|
26481
|
+
// reference/contain/include verb between the PSG noun and `grants`
|
|
26482
|
+
// breaks the match, so only the PSG-as-grantor ask gaps. `not` breaks it
|
|
26483
|
+
// too: "why would a PSG NOT grant expected access" is a troubleshooting
|
|
26484
|
+
// ask that stays on its pre-round-2 route (sweep-parity pin).
|
|
26485
|
+
/\b(?:which|what)\s+(?:permission\s+set\s+groups?|psgs?)\b(?:(?!\b(?:references?|referencing|contains?|containing|includes?|including|not)\b)[^.?!]){0,60}\bgrants?\b/,
|
|
26486
|
+
/\b(?:permission\s+set\s+groups?|psgs?)\b(?:(?!\b(?:references?|referencing|contains?|containing|includes?|including|not)\b)[^.?!]){0,40}\bgrants?\b[^.?!]{0,60}\b(?:custom\s+permission|permission|role|access)\b/
|
|
26487
|
+
]
|
|
26488
|
+
},
|
|
26364
26489
|
{
|
|
26365
26490
|
intent: "empty-queues-groups",
|
|
26366
26491
|
plane: "vault",
|
|
@@ -55261,7 +55386,7 @@ var init_retrieve_blindspot_report = __esm({
|
|
|
55261
55386
|
});
|
|
55262
55387
|
|
|
55263
55388
|
// ../mcp/dist/src/context-resolution.js
|
|
55264
|
-
var PRONOUN_ANCHORS, REPARAM_ANCHORS, detectPronounAnchor, detectReparamAnchor, ANAPHOR_ONLY, isAnaphorOnly, ORDINAL_INDEX, SELECTION_SHAPE, NON_DESCRIPTOR_TOKENS, detectClarificationSelection, COMPONENT_ID_SHAPE, validatePreviousContext, CONTINUATION_TOOL_TYPES, continuationToolCompatible, REPARAM_FILLER, extractReparamTarget;
|
|
55389
|
+
var PRONOUN_ANCHORS, REPARAM_ANCHORS, detectPronounAnchor, detectReparamAnchor, ANAPHOR_ONLY, isAnaphorOnly, ORDINAL_INDEX, SELECTION_SHAPE, NON_DESCRIPTOR_TOKENS, detectClarificationSelection, GAP_FOLLOW_UP_SHAPES, detectGapShapedFollowUp, COMPONENT_ID_SHAPE, validatePreviousContext, CONTINUATION_TOOL_TYPES, continuationToolCompatible, REPARAM_FILLER, extractReparamTarget;
|
|
55265
55390
|
var init_context_resolution = __esm({
|
|
55266
55391
|
"../mcp/dist/src/context-resolution.js"() {
|
|
55267
55392
|
"use strict";
|
|
@@ -55352,6 +55477,37 @@ var init_context_resolution = __esm({
|
|
|
55352
55477
|
const containing = options.filter((option) => option.toLowerCase().includes(token));
|
|
55353
55478
|
return containing.length === 1 ? { kind: "selected", anaphor, selection: containing[0] } : { kind: "re-ask", anaphor };
|
|
55354
55479
|
};
|
|
55480
|
+
GAP_FOLLOW_UP_SHAPES = [
|
|
55481
|
+
// Normative/judgment asks — the product reads metadata, it has no opinion
|
|
55482
|
+
// (q891/q30 "should they be able to?", q95 "is it normal?", q1075 "was any
|
|
55483
|
+
// of it risky?", q1054 "are those considered sensitive?", q1065 "how hard
|
|
55484
|
+
// is it to close?", q1060 "does that mean something's broken?", q1012 "is
|
|
55485
|
+
// it doing its job?").
|
|
55486
|
+
[/\bshould\s+(?:they|he|she|it)\s+(?:be\s+able|have|see)\b/i, "judgment"],
|
|
55487
|
+
[/\bis\s+(?:it|that|this)\s+normal\b|\bseems?\s+like\s+a\s+lot\b/i, "judgment"],
|
|
55488
|
+
[/\bwas\s+(?:any\s+of\s+)?(?:it|that|this)\s+risky\b/i, "judgment"],
|
|
55489
|
+
[/\bare\s+(?:those|these|they)\s+considered\s+\w+/i, "judgment"],
|
|
55490
|
+
[/\bhow\s+hard\s+(?:is|would)\s+it\b/i, "judgment"],
|
|
55491
|
+
[/\bdoes\s+that\s+mean\s+something(?:'s|\s+is)\s+broken\b/i, "judgment"],
|
|
55492
|
+
[/\bis\s+it\s+doing\s+its\s+job\b/i, "judgment"],
|
|
55493
|
+
// Delivery/export asks (q914 "as a file rather than on screen", q882 "can
|
|
55494
|
+
// it be exported…", q1939 "flag those as an audit finding").
|
|
55495
|
+
[/\bas\s+a\s+file\b|\bcan\s+(?:it|this|that)\s+be\s+exported\b/i, "delivery"],
|
|
55496
|
+
[/^\s*flag\s+(?:those|these|them|it)\b/i, "delivery"],
|
|
55497
|
+
// Self-capability probes about the TOOL, not the org (q849 "does the tool
|
|
55498
|
+
// trace transitive access like that, or is that beyond it?").
|
|
55499
|
+
[/\b(?:does|can)\s+(?:the|this)\s+tool\b/i, "tool-self-capability"],
|
|
55500
|
+
// Deployment-status telemetry (q1402 "was the change deployed or is it
|
|
55501
|
+
// still pending?").
|
|
55502
|
+
[/\bstill\s+pending\b|\bwas\s+(?:it|that|the\s+change)\s+deployed\b/i, "deployment-status"]
|
|
55503
|
+
];
|
|
55504
|
+
detectGapShapedFollowUp = (question) => {
|
|
55505
|
+
for (const [shape, family] of GAP_FOLLOW_UP_SHAPES) {
|
|
55506
|
+
if (shape.test(question))
|
|
55507
|
+
return family;
|
|
55508
|
+
}
|
|
55509
|
+
return null;
|
|
55510
|
+
};
|
|
55355
55511
|
COMPONENT_ID_SHAPE = /^[A-Za-z]+:.+$/;
|
|
55356
55512
|
validatePreviousContext = (previous, isRegisteredTool) => {
|
|
55357
55513
|
const ignored = [];
|
|
@@ -55437,7 +55593,7 @@ var init_context_resolution = __esm({
|
|
|
55437
55593
|
});
|
|
55438
55594
|
|
|
55439
55595
|
// ../mcp/dist/src/refusal-gates.js
|
|
55440
|
-
var INJECTION_PATTERNS, EXFIL_VERB, EXFIL_QUANTIFIER, EXFIL_SENSITIVE, EXFIL_VALUES, EXFIL_SINGLE_VALUE, INJECTION_DISCLOSURE, WRITE_VERB, WRITE_VERB_FILLER, WRITE_EXCLUDER, WRITE_SENTENCE_INITIAL, WRITE_LEAD_IN, WRITE_TRAILING_FRAME, WRITE_MAKE_SCHEMA, WRITE_GIVE_GRANT, WRITE_GIVE_INITIAL, WRITE_CHAINED_DUPE_DELETE, readOnlyAlternativeFor, RUNTIME_TRIGGERS, RUNTIME_WINDOW, RUNTIME_INCIDENT, runtimeDisclosure, EXTERNAL_SYSTEM, POLICY_ASK, RETENTION_POLICY_ASK, CONSENT_PROCESS_ASK, OPINION_ASK, SHOULD_WE, METADATA_NOUN, DELIVERY_ASK, WRITE_CODE_ASK, outOfScopeDisclosure, detectRefusalShape;
|
|
55596
|
+
var INJECTION_PATTERNS, EXFIL_VERB, EXFIL_QUANTIFIER, EXFIL_SENSITIVE, EXFIL_VALUES, EXFIL_SINGLE_VALUE, INJECTION_DISCLOSURE, WRITE_VERB, WRITE_VERB_FILLER, WRITE_EXCLUDER, SIMULATION_TAIL, WRITE_SENTENCE_INITIAL, WRITE_LEAD_IN, WRITE_TRAILING_FRAME, WRITE_MAKE_SCHEMA, WRITE_GIVE_GRANT, WRITE_GIVE_INITIAL, WRITE_CHAINED_DUPE_DELETE, RUN_VERB, RUN_TARGET, RUN_GAP, RUN_IMPERATIVE_INITIAL, RUN_IMPERATIVE_LEAD_IN, RUN_ANAPHOR, runReadOnlyAlternativeFor, readOnlyAlternativeFor, IDENTITY_IDIOM, IDENTITY_ALLOWED_MUTATE, IDENTITY_LOOK_EXCLUDER, IDENTITY_DISCLOSURE, RUNTIME_TRIGGERS, RUNTIME_WINDOW, RUNTIME_INCIDENT, runtimeDisclosure, EXTERNAL_SYSTEM, POLICY_ASK, RETENTION_POLICY_ASK, CONSENT_PROCESS_ASK, OPINION_ASK, SHOULD_WE, METADATA_NOUN, DELIVERY_ASK, WRITE_CODE_ASK, DRAFT_DOCUMENT_ASK, CAREER_ASK, outOfScopeDisclosure, detectRefusalShape;
|
|
55441
55597
|
var init_refusal_gates = __esm({
|
|
55442
55598
|
"../mcp/dist/src/refusal-gates.js"() {
|
|
55443
55599
|
"use strict";
|
|
@@ -55446,7 +55602,14 @@ var init_refusal_gates = __esm({
|
|
|
55446
55602
|
/\bpretend\s+the\s+(?:previous|prior)\s+rules\b/i,
|
|
55447
55603
|
/\byou\s+are\s+now\s+(?:in\s+)?(?:admin|deploy|god)\s*[- ]?mode\b/i,
|
|
55448
55604
|
/\byou'?re\s+actually\s+an?\b[^.?!]*\bbot\b/i,
|
|
55449
|
-
/\b(?:print|reveal|show)\s+(?:me\s+)?your\s+(?:system\s+)?prompt\b/i
|
|
55605
|
+
/\b(?:print|reveal|show)\s+(?:me\s+)?your\s+(?:system\s+)?prompt\b/i,
|
|
55606
|
+
// Privilege-escalation asks (q1548 "sudo give me full access"): `sudo` as a
|
|
55607
|
+
// command prefix, or a grant-to-SELF ("give me full/admin access"). The
|
|
55608
|
+
// READ delivery ask "give me the FLS grant list" carries no privilege noun
|
|
55609
|
+
// and stays routed — the escalation arm requires full/admin/elevated +
|
|
55610
|
+
// access/permission.
|
|
55611
|
+
/(?:^|[.!?;]\s+)sudo\b/i,
|
|
55612
|
+
/\bgive\s+me\s+(?:full|admin|superuser|elevated|god[-\s]?mode)\s+(?:access|permissions?|rights?|privileges?)\b/i
|
|
55450
55613
|
];
|
|
55451
55614
|
EXFIL_VERB = /\b(?:dump|export|give\s+me|tell\s+me|list|retrieve)\b/i;
|
|
55452
55615
|
EXFIL_QUANTIFIER = /\b(?:every|all|actual|the\s+real|random)\b/i;
|
|
@@ -55456,14 +55619,33 @@ var init_refusal_gates = __esm({
|
|
|
55456
55619
|
INJECTION_DISCLOSURE = "REFUSED: this request asks me to override instructions or exfiltrate record values. sf-intelligence reads metadata only; it never returns stored record values and its instructions are not overridable.";
|
|
55457
55620
|
WRITE_VERB = "(?:create|add|delete|remove|update|change|(?<!permission\\s)set|deploy|assign|reassign|revoke|deactivate|activate|disable|enable|merge|reset|rename|fix|grant|provision|turn\\s+(?:on|off)|clean\\s+up|migrate|convert|insert|upsert|push|publish|install|uninstall|schedule|upgrade|downgrade|throttle|purge)";
|
|
55458
55621
|
WRITE_VERB_FILLER = "(?:(?:bulk|mass|batch|just|please|go\\s+ahead\\s+and)\\s+)*";
|
|
55459
|
-
WRITE_EXCLUDER = /\b(?:am\s+i|can\s+i|could\s+i|do\s+i|who\s+can|who\s+is\s+able|allowed\s+to|able\s+to|what\s+if|what\s+would|would\s+happen|is\s+it\s+safe|safe\s+to|before\s+i|if\s+i|should\s+i|how\s+do\s+i|how\s+would\s+i|what\s+happens\s+when)\b/i;
|
|
55622
|
+
WRITE_EXCLUDER = /\b(?:am\s+i|can\s+i|could\s+i|do\s+i|who\s+can|who\s+is\s+able|allowed\s+to|able\s+to|what\s+if|what\s+would|would\s+happen|is\s+it\s+safe|safe\s+to|before\s+i|if\s+(?:i|we)|when\s+(?:i|we)|suppose|should\s+i|how\s+do\s+i|how\s+would\s+i|what\s+happens\s+when)\b|\bsafely\s*\?|\bwhat\s+(?:depends\s+on|breaks|would\s+break|will\s+break|stops\s+working)\b/i;
|
|
55623
|
+
SIMULATION_TAIL = /\b(?:and\s+)?(?:tell|show|give)\s+me\s+(?:the\s+)?(?:impact|blast\s+radius|consequences?|every\s+conflict|conflicts|what\s+(?:breaks|happens|stops|changes))\b|[—–-]\s*(?:impact|consequences?|blast\s+radius)\s*\??\s*$|\b(?:impact|consequences)\s*\?\s*$|\bwhat(?:'s|\s+is)\s+the\s+(?:impact|blast\s+radius|fallout)\b|\bwhat\s+(?:happens|stops|breaks)\s+(?:to|if|when|after|downstream)\b/i;
|
|
55460
55624
|
WRITE_SENTENCE_INITIAL = new RegExp(`(?:^|[.!?;]\\s+)(?:please\\s+|just\\s+)?${WRITE_VERB_FILLER}(${WRITE_VERB}\\b[^.?!;]{0,80})`, "i");
|
|
55461
|
-
WRITE_LEAD_IN = new RegExp(`\\b(?:please|just|go\\s+ahead\\s+and|can\\s+(?:you|u)|could\\s+(?:you|u)|would\\s+(?:you|u)|you\\s+should|i\\s+need\\s+you\\s+to)\\s+(?:please\\s+|just\\s+)?${WRITE_VERB_FILLER}(${WRITE_VERB}\\b[^.?!;]{0,80})`, "i");
|
|
55625
|
+
WRITE_LEAD_IN = new RegExp(`\\b(?:please|(?<!\\b(?:or|vs|than)\\s)just|go\\s+ahead\\s+and|can\\s+(?:you|u)|could\\s+(?:you|u)|would\\s+(?:you|u)|you\\s+should|i\\s+(?:need|want)\\s+you\\s+to)\\s+(?:please\\s+|just\\s+)?${WRITE_VERB_FILLER}(${WRITE_VERB}\\b[^.?!;]{0,80})`, "i");
|
|
55462
55626
|
WRITE_TRAILING_FRAME = new RegExp(`\\b(${WRITE_VERB}\\b[^.?!;]{0,80}?\\b(?:for\\s+me|right\\s+now|and\\s+confirm)\\b[^.?!;]{0,20})`, "i");
|
|
55463
55627
|
WRITE_MAKE_SCHEMA = new RegExp(`\\b(?:can|could|would)\\s+(?:you|u)\\b[^.?!;]{0,10}\\s(make\\b[^.?!;]{0,60}\\b(?:required|mandatory|optional|unique|read[-\\s]?only|editable|visible)\\b)`, "i");
|
|
55464
55628
|
WRITE_GIVE_GRANT = new RegExp(`\\b(?:can|could|would)\\s+(?:you|u)\\b[^.?!;]{0,30}\\b(give\\s+(?!me\\b)[^.?!;]{0,60}\\b(?:profile|permission|perm\\s+set|access|user)\\b[^.?!;]{0,40})`, "i");
|
|
55465
55629
|
WRITE_GIVE_INITIAL = /(?:^|[.!?;]\s+)(give\s+(?!me\b)[^.?!;]{0,60}\b(?:admin|access|permission|profile)\b[^.?!;]{0,30})/i;
|
|
55466
55630
|
WRITE_CHAINED_DUPE_DELETE = /\b(?:and|then)\s+(?:just\s+)?((?:delete|remove|purge|merge)\s+(?:the\s+)?dup(?:e|licate)s?\b[^.?!;]{0,30})/i;
|
|
55631
|
+
RUN_VERB = "(?:run|re-?run|execute|invoke|kick\\s+off|trigger|launch|fire\\s+off)";
|
|
55632
|
+
RUN_TARGET = "(?:flows?|triggers?|batch(?:\\s+(?:jobs?|class(?:es)?|apex))?|jobs?|apex\\s+class(?:es)?|automations?|scripts?)";
|
|
55633
|
+
RUN_GAP = "(?:(?!\\b(?:on|of|for|across|against|in|over|about)\\b)[^.?!;]){0,60}?";
|
|
55634
|
+
RUN_IMPERATIVE_INITIAL = new RegExp(`(?:^|[.!?;]\\s+)(?:please\\s+|just\\s+)?(${RUN_VERB}\\b${RUN_GAP}\\b${RUN_TARGET}\\b[^.?!;]{0,60})`, "i");
|
|
55635
|
+
RUN_IMPERATIVE_LEAD_IN = new RegExp(`\\b(?:please|just|go\\s+ahead\\s+and|can\\s+(?:you|u)|could\\s+(?:you|u)|would\\s+(?:you|u)|you\\s+should|i\\s+need\\s+you\\s+to)\\s+(?:please\\s+|just\\s+)?(${RUN_VERB}\\b${RUN_GAP}\\b${RUN_TARGET}\\b[^.?!;]{0,60})`, "i");
|
|
55636
|
+
RUN_ANAPHOR = new RegExp(`(?:(?:^|[.!?;]\\s+)(?:please\\s+|just\\s+)?|\\b(?:please|just|go\\s+ahead\\s+and|can\\s+(?:you|u)|could\\s+(?:you|u)|would\\s+(?:you|u)|you\\s+should|i\\s+need\\s+you\\s+to)\\s+(?:please\\s+|just\\s+)?)(${RUN_VERB}\\s+(?:it|that|this)\\b(?!\\s+(?:by|past)\\b)[^.?!;]{0,40}|(?:kick|fire|set)\\s+(?:it|that|this)\\s+off\\b[^.?!;]{0,30})`, "i");
|
|
55637
|
+
runReadOnlyAlternativeFor = (verbPhrase) => {
|
|
55638
|
+
const v2 = verbPhrase.toLowerCase();
|
|
55639
|
+
if (/\bflows?\b/.test(v2))
|
|
55640
|
+
return "sfi.explain_flow";
|
|
55641
|
+
if (/\b(?:batch|jobs?)\b/.test(v2))
|
|
55642
|
+
return "sfi.scheduled_job_catalog";
|
|
55643
|
+
if (/\btriggers?\b/.test(v2))
|
|
55644
|
+
return "sfi.what_happens_on_save";
|
|
55645
|
+
if (/\bapex|class(?:es)?\b/.test(v2))
|
|
55646
|
+
return "sfi.explain_apex_method";
|
|
55647
|
+
return "sfi.get_impact";
|
|
55648
|
+
};
|
|
55467
55649
|
readOnlyAlternativeFor = (verbPhrase, question) => {
|
|
55468
55650
|
const v2 = verbPhrase.toLowerCase();
|
|
55469
55651
|
const q2 = question.toLowerCase();
|
|
@@ -55499,14 +55681,134 @@ var init_refusal_gates = __esm({
|
|
|
55499
55681
|
}
|
|
55500
55682
|
return "sfi.get_impact";
|
|
55501
55683
|
};
|
|
55684
|
+
IDENTITY_IDIOM = /\bcan\s+i\s+be\s+trusted\s+to\b|\bwithin\s+my\s+power\b|\babove\s+my\s+(?:permission\s+level|pay\s+grade)\b|\bwhat\s+(?:am\s+i|i'?m)\s+capable\s+of\b|\bwondering\s+what\s+i'?m\s+capable\s+of\b/i;
|
|
55685
|
+
IDENTITY_ALLOWED_MUTATE = /\bam\s+i\s+(?:allowed|permitted|able)\s+to\s+(?:change|delete|remove|merge|deactivate|disable|create|rename|reset|convert|reassign|modify|update)\b|\bis\s+it\s+(?:okay?|ok)\s+for\s+me\s+to\s+(?:change|delete|remove|merge|deactivate|disable|create|rename|reset|convert|reassign|modify|update)\b/i;
|
|
55686
|
+
IDENTITY_LOOK_EXCLUDER = /\bam\s+i\s+(?:allowed|permitted|able)\s+to\s+(?:look|see|view|read|ask|know|check|understand|open)\b|\bis\s+it\s+(?:okay?|ok)\s+for\s+me\s+to\s+(?:look|see|view|read|ask|know|check)\b/i;
|
|
55687
|
+
IDENTITY_DISCLOSURE = "HONEST GAP (identity): sf-intelligence has no session-user identity \u2014 it cannot know what YOU specifically are allowed to do. Name the user, profile, or permission set to check and I can answer from the permission metadata (sfi.effective_permissions / sfi.user_ability). Which user or profile should I check?";
|
|
55502
55688
|
RUNTIME_TRIGGERS = [
|
|
55503
55689
|
[/\blogin\s+history\b|\baudit\s+trail\s+of\s+logins?\b/i, "login history"],
|
|
55690
|
+
// Per-user LOGIN EVENTS (hon-031/hon-036/hon-060): who logged in when,
|
|
55691
|
+
// exact login timestamps, who is logged in right now, or a full per-user
|
|
55692
|
+
// last-login roster. All are LoginHistory/session event data no tool reads.
|
|
55693
|
+
// Precision guards, each a live_inactive_users question that must NOT gate:
|
|
55694
|
+
// "which users are inactive", "who HASN'T logged in for 90 days" (the
|
|
55695
|
+
// negation breaks the strict token sequence), "login IP ranges on a
|
|
55696
|
+
// profile" (profile_security metadata — no logged-in/timestamp token).
|
|
55697
|
+
[
|
|
55698
|
+
/\b(?:which|what)\s+(?:specific\s+)?users?\s+(?:have\s+|are\s+)?logged\s+in(?:to)?\b|\bwho\s+logged\s+in(?:to)?\b/i,
|
|
55699
|
+
"per-user login events (who logged in when)"
|
|
55700
|
+
],
|
|
55701
|
+
[
|
|
55702
|
+
/\blogin\s+timestamps?\b|\bcurrently\s+logged\s+in(?:to)?\b|\blogged\s+in(?:to)?\b[^.?!]{0,30}\bright\s+now\b/i,
|
|
55703
|
+
"login sessions/timestamps"
|
|
55704
|
+
],
|
|
55705
|
+
[
|
|
55706
|
+
/\b(?:every|each|all)\s+(?:salesforce\s+)?users?'?s?\b[^.?!]{0,30}\blast\s+login\b/i,
|
|
55707
|
+
"a full per-user last-login roster (sfi.live_inactive_users covers dormancy thresholds, not a full roster)"
|
|
55708
|
+
],
|
|
55504
55709
|
[/\badoption\b|\bhow\s+often\s+do\s+users\s+actually\s+use\b/i, "adoption/usage telemetry"],
|
|
55505
55710
|
[
|
|
55506
55711
|
/\bping\s+(?:the\s+)?\S+|\bendpoints?\b[^.?!]*\bup\b|\b(?:returned|returning|throwing|threw)\s+errors?\b/i,
|
|
55507
55712
|
"endpoint health"
|
|
55508
55713
|
],
|
|
55509
|
-
[/\brunning[-\s]user\s+context\b/i, "the runtime running-user context"]
|
|
55714
|
+
[/\brunning[-\s]user\s+context\b/i, "the runtime running-user context"],
|
|
55715
|
+
// Automation EXECUTION forensics (hon-032/hon-039/hon-037): traces of what
|
|
55716
|
+
// a run touched, aggregate run counts, the error message from the last
|
|
55717
|
+
// failure. Static reads stay routed: "how many times is this field
|
|
55718
|
+
// REFERENCED" (no run verb), "what runs when an Application is submitted"
|
|
55719
|
+
// (no how-many-times/trace), "when was it last MODIFIED" (no failed/ran).
|
|
55720
|
+
[
|
|
55721
|
+
/\bexecution\s+trace\b|\bwhat\s+records\s+did\s+(?:it|the\s+\S+(?:\s+\S+)?)\s+touch\b/i,
|
|
55722
|
+
"flow/automation execution traces"
|
|
55723
|
+
],
|
|
55724
|
+
[
|
|
55725
|
+
/\bhow\s+many\s+times\s+(?:has|have|did|was|were)\b[^.?!]{0,80}\b(?:executed|run|ran|fired|triggered)\b/i,
|
|
55726
|
+
"aggregate automation run counts (sfi.live_automation_fired infers per-record only)"
|
|
55727
|
+
],
|
|
55728
|
+
[
|
|
55729
|
+
/\b(?:the\s+)?last\s+time\b[^.?!]{0,60}\b(?:failed|errored|crashed|ran)\b/i,
|
|
55730
|
+
"run/failure forensics from past executions"
|
|
55731
|
+
],
|
|
55732
|
+
// Apex/query RUNTIME PROFILING + debug logs (hon-040/hon-044/hon-053):
|
|
55733
|
+
// CPU/heap profiles of a past run, debug logs, SOQL execution plans.
|
|
55734
|
+
// Static reads stay routed: "which classes RISK hitting governor limits"
|
|
55735
|
+
// (governor_limit_risks — no profile/log/plan noun), "which class contains
|
|
55736
|
+
// System.debug" (code-literal search — no `debug log` bigram).
|
|
55737
|
+
[
|
|
55738
|
+
/\b(?:cpu\s+time|heap\s+(?:usage|size)|memory\s+(?:usage|utilization|consumption))\b[^.?!]{0,50}\bprofile\b|\bprofile\b[^.?!]{0,50}\b(?:cpu\s+time|heap\s+usage)\b/i,
|
|
55739
|
+
"runtime CPU/heap profiling"
|
|
55740
|
+
],
|
|
55741
|
+
[/\bmemory\s+(?:utilization|consumption)\b|\bapplication\s+servers?\b/i, "infrastructure telemetry"],
|
|
55742
|
+
// Debug-LOG retrieval needs the retrieval-verb frame: "SHOW ME the debug
|
|
55743
|
+
// log from yesterday's batch run" is runtime; "leftover debug logs in apex"
|
|
55744
|
+
// (q522 — System.debug code artifacts, search_apex_source) and "is it in a
|
|
55745
|
+
// debug log anywhere" carry no retrieval verb and stay routed. Shield
|
|
55746
|
+
// EVENT-MONITORING logs (router-v2 R2, hon-057) are the same retrieval
|
|
55747
|
+
// shape — runtime telemetry no vault holds; "which flows subscribe to
|
|
55748
|
+
// platform events" carries no log noun and stays routed.
|
|
55749
|
+
[
|
|
55750
|
+
/\b(?:show|see|view|pull|get|give|retrieve|read|check|download|fetch)\b[^.?!]{0,45}\b(?:debug|event[\s-]monitoring)\s+logs?\b/i,
|
|
55751
|
+
"debug / event-monitoring logs"
|
|
55752
|
+
],
|
|
55753
|
+
[
|
|
55754
|
+
/\b(?:query|execution|soql)\s+plans?\b|\bindexes?\s+(?:are\s+)?being\s+used\b/i,
|
|
55755
|
+
"SOQL execution plans / index usage"
|
|
55756
|
+
],
|
|
55757
|
+
// Message DELIVERY telemetry (hon-056/hon-041): delivered/bounce counts and
|
|
55758
|
+
// the ACTUAL content of sent messages. Metadata reads stay routed: "which
|
|
55759
|
+
// email templates are unused" (live_email_template_usage), "what emails go
|
|
55760
|
+
// out for this approval" (sendsEmail edges — no delivered/sent-count ask).
|
|
55761
|
+
[
|
|
55762
|
+
/\b(?:emails?|sms|messages?|texts?)\b[^.?!]{0,50}\b(?:delivered|deliverability|bounced?|bounce\s+rate)\b/i,
|
|
55763
|
+
"message delivery telemetry"
|
|
55764
|
+
],
|
|
55765
|
+
[
|
|
55766
|
+
/\bhow\s+many\s+(?:emails?|sms|messages?|texts?)\b[^.?!]{0,60}\b(?:sent|delivered|went\s+out)\b/i,
|
|
55767
|
+
"sent-message counts"
|
|
55768
|
+
],
|
|
55769
|
+
[
|
|
55770
|
+
/\bactual\s+content\s+of\s+the\s+(?:emails?|messages?|texts?)\b/i,
|
|
55771
|
+
"the content of individually sent messages (the TEMPLATE body is metadata \u2014 sfi.get_component reads it)"
|
|
55772
|
+
],
|
|
55773
|
+
// Site/community WEB ANALYTICS (hon-050): click paths, page views.
|
|
55774
|
+
[
|
|
55775
|
+
/\b(?:click|page|site|web)\s*[- ]?(?:analytics|traffic)\b|\bpage\s+views?\b|\bwhich\s+pages\b[^.?!]{0,60}\bvisit/i,
|
|
55776
|
+
"site/community click analytics"
|
|
55777
|
+
],
|
|
55778
|
+
// RECORD-LEVEL field history (hon-054): before/after values of changed
|
|
55779
|
+
// records. "Which fields HAVE history tracking enabled" is object metadata
|
|
55780
|
+
// and stays routed (no before/after-values bigram).
|
|
55781
|
+
[
|
|
55782
|
+
/\bbefore(?:\s*\/\s*|\s*-\s*|\s+and\s+)after\b[^.?!]{0,40}\b(?:values?|data)\b/i,
|
|
55783
|
+
"record-level field history (before/after values)"
|
|
55784
|
+
],
|
|
55785
|
+
// RECORD-ACCESS audit (q960/q1117): who ACCESSED/viewed a record or field.
|
|
55786
|
+
// "Who CAN see/access X" is a permissions read (who_can_access_object /
|
|
55787
|
+
// field_access_audit) and never matches — the arm requires the past-tense
|
|
55788
|
+
// accessed/viewed/opened event verb.
|
|
55789
|
+
[
|
|
55790
|
+
/\bwho\b[^.?!]{0,30}\b(?:accessed|viewed|opened|looked\s+at)\b[^.?!]{0,60}\b(?:records?|fields?|data)\b/i,
|
|
55791
|
+
"record-access audit events (who accessed what)"
|
|
55792
|
+
],
|
|
55793
|
+
// R3 §5b AUDIT-TRAIL-PLANE arms (8-question over-route cluster): Setup
|
|
55794
|
+
// Audit Trail asks — who changed a SETTING (FLS, sharing, OWD, session/
|
|
55795
|
+
// password policy) and when. Component lastModifiedBy IS metadata
|
|
55796
|
+
// (sfi.last_modified stays routed — those asks say "who changed <component>",
|
|
55797
|
+
// no settings noun); FLS/OWD/policy flips are only in the Setup Audit
|
|
55798
|
+
// Trail, which neither the vault nor the live plane reads.
|
|
55799
|
+
[/\bsetup\s+audit\s+trail\b/i, "Setup Audit Trail entries"],
|
|
55800
|
+
[
|
|
55801
|
+
/\bwho\s+(?:modified|changed|flipped|updated|edited)\b[^.?!]{0,50}\b(?:field-?level\s+security|fls|sharing\s+settings?|org-?wide\s+defaults?|owd|session\s+settings?|password\s+polic\w*|mfa)\b/i,
|
|
55802
|
+
"who changed org security settings and when (Setup Audit Trail data)"
|
|
55803
|
+
],
|
|
55804
|
+
// R3 §5b: report/dashboard DEFINITIONS (source object, columns, broken
|
|
55805
|
+
// references) are not retrieved into the vault — "which reports are
|
|
55806
|
+
// stale/unused" (live_report_usage) and "who can see the dashboard"
|
|
55807
|
+
// (folder access) carry none of these definition verbs and stay routed.
|
|
55808
|
+
[
|
|
55809
|
+
/\b(?:reports?|dashboards?)\b[^.?!]{0,50}\b(?:built|based)\s+on\b|\breports?\b[^.?!]{0,50}\breference\b[^.?!]{0,50}\b(?:deleted|renamed|broken|missing)\b|\bdashboards?\b[^.?!]{0,40}\b(?:broken|point\s+at)\b/i,
|
|
55810
|
+
"report/dashboard definitions (source object, columns, referenced fields) \u2014 not retrieved into the vault"
|
|
55811
|
+
]
|
|
55510
55812
|
];
|
|
55511
55813
|
RUNTIME_WINDOW = /\b(?:this\s+week|yesterday|last\s+night|in\s+the\s+\w+\s+incident)\b/i;
|
|
55512
55814
|
RUNTIME_INCIDENT = /\b(?:errors?|failed|failures?|incident|outage|gated)\b/i;
|
|
@@ -55520,6 +55822,8 @@ var init_refusal_gates = __esm({
|
|
|
55520
55822
|
METADATA_NOUN = /\b(?:field|object|flow|trigger|class|profile|permission|layout|validation|record\s+type|apex|report|dashboard|picklist|component|rule)\b|__(?:c|mdt|e|x|b|kav)\b/i;
|
|
55521
55823
|
DELIVERY_ASK = /\bemail\s+me\b|\bsend\s+(?:this|it)\s+to\b|\bpost\s+(?:this\s+|it\s+)?to\s+slack\b/i;
|
|
55522
55824
|
WRITE_CODE_ASK = /\bwrite\s+(?:me\s+)?(?:an?\s+)?(?:apex|lwc|trigger|class|component)\b[^.?!]*\b(?:that|to)\b/i;
|
|
55825
|
+
DRAFT_DOCUMENT_ASK = /\bdraft\s+(?:me\s+)?(?:a|an)\b[^.?!]{0,60}\b(?:agreement|contract|clause|policy|memo|press\s+release)\b/i;
|
|
55826
|
+
CAREER_ASK = /\bhow\s+do\s+i\s+become\b/i;
|
|
55523
55827
|
outOfScopeDisclosure = (topic) => `OUT OF SCOPE: sf-intelligence answers questions about this org's Salesforce metadata. ${topic} is outside that boundary (no external systems, no policy authorship, no code generation, no message delivery).`;
|
|
55524
55828
|
detectRefusalShape = (question) => {
|
|
55525
55829
|
const q2 = question.replace(/[‘’ʼ]/g, "'").replace(/\s+/g, " ").trim();
|
|
@@ -55530,7 +55834,8 @@ var init_refusal_gates = __esm({
|
|
|
55530
55834
|
return { kind: "injection-exfiltration", disclosure: INJECTION_DISCLOSURE };
|
|
55531
55835
|
}
|
|
55532
55836
|
if (!WRITE_EXCLUDER.test(q2)) {
|
|
55533
|
-
const
|
|
55837
|
+
const simulationFrame = SIMULATION_TAIL.test(q2);
|
|
55838
|
+
const verbPhrase = simulationFrame ? void 0 : (WRITE_SENTENCE_INITIAL.exec(q2) ?? WRITE_LEAD_IN.exec(q2) ?? WRITE_TRAILING_FRAME.exec(q2) ?? WRITE_MAKE_SCHEMA.exec(q2) ?? WRITE_GIVE_GRANT.exec(q2) ?? WRITE_GIVE_INITIAL.exec(q2) ?? WRITE_CHAINED_DUPE_DELETE.exec(q2))?.[1]?.trim().replace(/[,;:]$/, "");
|
|
55534
55839
|
if (verbPhrase !== void 0 && verbPhrase.length > 0) {
|
|
55535
55840
|
const alternative = readOnlyAlternativeFor(verbPhrase, q2);
|
|
55536
55841
|
return {
|
|
@@ -55539,13 +55844,25 @@ var init_refusal_gates = __esm({
|
|
|
55539
55844
|
readOnlyAlternative: alternative
|
|
55540
55845
|
};
|
|
55541
55846
|
}
|
|
55847
|
+
const runPhrase = (RUN_IMPERATIVE_INITIAL.exec(q2) ?? RUN_IMPERATIVE_LEAD_IN.exec(q2) ?? RUN_ANAPHOR.exec(q2))?.[1]?.trim().replace(/[,;:]$/, "");
|
|
55848
|
+
if (runPhrase !== void 0 && runPhrase.length > 0) {
|
|
55849
|
+
const alternative = runReadOnlyAlternativeFor(runPhrase);
|
|
55850
|
+
return {
|
|
55851
|
+
kind: "write-imperative",
|
|
55852
|
+
disclosure: `REFUSED (read-only boundary): sf-intelligence never executes org automation \u2014 it cannot ${runPhrase}. I can show you what it WOULD do instead: ${alternative}.`,
|
|
55853
|
+
readOnlyAlternative: alternative
|
|
55854
|
+
};
|
|
55855
|
+
}
|
|
55856
|
+
}
|
|
55857
|
+
if ((IDENTITY_IDIOM.test(q2) || IDENTITY_ALLOWED_MUTATE.test(q2)) && !IDENTITY_LOOK_EXCLUDER.test(q2)) {
|
|
55858
|
+
return { kind: "identity-gap", disclosure: IDENTITY_DISCLOSURE };
|
|
55542
55859
|
}
|
|
55543
55860
|
const runtimeTopic = RUNTIME_TRIGGERS.find(([pattern]) => pattern.test(q2))?.[1] ?? (RUNTIME_WINDOW.test(q2) && RUNTIME_INCIDENT.test(q2) ? "runtime incident forensics" : void 0);
|
|
55544
55861
|
if (runtimeTopic !== void 0) {
|
|
55545
55862
|
return { kind: "runtime-analytics", disclosure: runtimeDisclosure(runtimeTopic) };
|
|
55546
55863
|
}
|
|
55547
55864
|
const externalSystem = EXTERNAL_SYSTEM.exec(q2)?.[1];
|
|
55548
|
-
const outOfScopeTopic = externalSystem !== void 0 ? `"${externalSystem}"` : RETENTION_POLICY_ASK.test(q2) ? "A data-retention policy (organizational governance, not org metadata)" : CONSENT_PROCESS_ASK.test(q2) ? "A consent process (organizational governance, not org metadata)" : POLICY_ASK.test(q2) ? "Org policy authorship" : OPINION_ASK.test(q2) ? "An opinion" : DELIVERY_ASK.test(q2) ? "Message delivery" : WRITE_CODE_ASK.test(q2) ? "Code generation" : SHOULD_WE.test(q2) && !METADATA_NOUN.test(q2) ? "An org-decision recommendation" : void 0;
|
|
55865
|
+
const outOfScopeTopic = externalSystem !== void 0 ? `"${externalSystem}"` : RETENTION_POLICY_ASK.test(q2) ? "A data-retention policy (organizational governance, not org metadata)" : CONSENT_PROCESS_ASK.test(q2) ? "A consent process (organizational governance, not org metadata)" : POLICY_ASK.test(q2) ? "Org policy authorship" : OPINION_ASK.test(q2) ? "An opinion" : DELIVERY_ASK.test(q2) ? "Message delivery" : WRITE_CODE_ASK.test(q2) ? "Code generation" : DRAFT_DOCUMENT_ASK.test(q2) ? "Document authorship (agreements, policies, memos)" : CAREER_ASK.test(q2) ? "Career/self-improvement guidance" : SHOULD_WE.test(q2) && !METADATA_NOUN.test(q2) ? "An org-decision recommendation" : void 0;
|
|
55549
55866
|
if (outOfScopeTopic !== void 0) {
|
|
55550
55867
|
return { kind: "out-of-scope", disclosure: outOfScopeDisclosure(outOfScopeTopic) };
|
|
55551
55868
|
}
|
|
@@ -55576,7 +55893,22 @@ var init_funnel_utterances = __esm({
|
|
|
55576
55893
|
"what validation rules exist on the Order object?",
|
|
55577
55894
|
"show me every component that references the <PermSet> permission set",
|
|
55578
55895
|
"is there an approval process on Opportunity?",
|
|
55579
|
-
"find me anything that blocks record creation when a required field is empty"
|
|
55896
|
+
"find me anything that blocks record creation when a required field is empty",
|
|
55897
|
+
// biz-user register (router-v2 R2): existence-check with a look-inside.
|
|
55898
|
+
"does a <Object> object exist in this org? I want to see its fields",
|
|
55899
|
+
// R3 custom-permission band (DIAGNOSIS-R3 §2 rank 2 — the #1 corpus
|
|
55900
|
+
// family): describe-what-it-gates and bypass/guard phrasings. The tools
|
|
55901
|
+
// work (0.1.19 CustomPermission exposure); the vocabulary was missing.
|
|
55902
|
+
"what does the <CustomPermission> custom permission bypass exactly?",
|
|
55903
|
+
"whos allowed to bypass the validation and what is that custom permission guarding?",
|
|
55904
|
+
"which custom permission gates the <FlowName> screen flow?",
|
|
55905
|
+
"is there a custom permission that could let someone bypass a control?",
|
|
55906
|
+
"which custom permissions have descriptions that mention bypassing something?",
|
|
55907
|
+
"tell me every custom permission checked by a validation rule",
|
|
55908
|
+
// R3 cross-object field-existence band (same §2 row).
|
|
55909
|
+
"does Amount__c exist on any object, and which ones?",
|
|
55910
|
+
"do we track a completion date anywhere I could report on?",
|
|
55911
|
+
"is the <RecordType> record type only on Case or is it on other objects too?"
|
|
55580
55912
|
],
|
|
55581
55913
|
"sfi.resolve": [
|
|
55582
55914
|
"pull the <vague-field-name> field \u2014 <PermSet> implies we have one",
|
|
@@ -55591,7 +55923,20 @@ var init_funnel_utterances = __esm({
|
|
|
55591
55923
|
"I keep hearing about a <fuzzy-name> flow \u2014 can you find it?",
|
|
55592
55924
|
"what's the canonical name for the field that stores the SLA deadline?",
|
|
55593
55925
|
"look up Status__c \u2014 which object is it on?",
|
|
55594
|
-
"do we have anything for tracking escalation dates on Case?"
|
|
55926
|
+
"do we have anything for tracking escalation dates on Case?",
|
|
55927
|
+
// biz-user register (router-v2 R2): nickname-existence and
|
|
55928
|
+
// component-type-confusion phrasings ("is that a flow or a trigger").
|
|
55929
|
+
"I keep calling it the '<nickname>' object \u2014 does this org have something like that?",
|
|
55930
|
+
"is <ComponentName> a flow or a trigger? I can't tell from the name",
|
|
55931
|
+
"what type of component is <ComponentName> \u2014 an Apex class or a flow?",
|
|
55932
|
+
// R3 existence/verification/typo band (DIAGNOSIS-R3 §2 rank 1 +
|
|
55933
|
+
// trap-122-a): explicit "does X exist" asks, prove-it challenges, and
|
|
55934
|
+
// is-that-the-right-name verification.
|
|
55935
|
+
"does <Field__c> exist on Contact or only on Lead?",
|
|
55936
|
+
"is <ComponentName> even the right name? prove it actually exists",
|
|
55937
|
+
"wait, is <Name__c> a field or an object?",
|
|
55938
|
+
"pull up <ComponentName> \u2014 I might have the name spelled wrong",
|
|
55939
|
+
"does the <ComponentName> component actually exist in this org, yes or no?"
|
|
55595
55940
|
],
|
|
55596
55941
|
"sfi.capabilities": [
|
|
55597
55942
|
"what can you actually do?",
|
|
@@ -55648,7 +55993,12 @@ var init_funnel_utterances = __esm({
|
|
|
55648
55993
|
"pulse check \u2014 is this org healthy?",
|
|
55649
55994
|
"quick status: how is the org doing right now?",
|
|
55650
55995
|
"is there anything alarming about this org at a glance?",
|
|
55651
|
-
"one-liner on org health"
|
|
55996
|
+
"one-liner on org health",
|
|
55997
|
+
// biz-user register (router-v2 R2): "who is changing things" asked as a
|
|
55998
|
+
// people question, not a metadata question.
|
|
55999
|
+
"who has been modifying things in this org the most?",
|
|
56000
|
+
"who are the top contributors to changes in this org lately?",
|
|
56001
|
+
"who's been making the most changes to this org lately?"
|
|
55652
56002
|
],
|
|
55653
56003
|
"sfi.org_card": [
|
|
55654
56004
|
"show me the org's basic info \u2014 edition, limits, creation date",
|
|
@@ -55680,7 +56030,13 @@ var init_funnel_utterances = __esm({
|
|
|
55680
56030
|
"get me the raw component data for the Contact validation rule",
|
|
55681
56031
|
"fetch the permission set definition for <PermSet>",
|
|
55682
56032
|
"show me the layout metadata for Case",
|
|
55683
|
-
"pull the full metadata for <FlowName>"
|
|
56033
|
+
"pull the full metadata for <FlowName>",
|
|
56034
|
+
// R3 show-me-the-thing band (DIAGNOSIS-R3 §2 rank 4).
|
|
56035
|
+
"whats in the <PermSet> permission set?",
|
|
56036
|
+
"what is the <PermSet> permission set for? the name confuses me",
|
|
56037
|
+
"is the <FlowName> flow active or dormant?",
|
|
56038
|
+
"can you give me the raw metadata XML for the <CustomPermission> custom permission?",
|
|
56039
|
+
"pull up <ComponentName> so I can look at it"
|
|
55684
56040
|
],
|
|
55685
56041
|
"sfi.list_components": [
|
|
55686
56042
|
"whats on the Account object \u2014 give me the whole field list",
|
|
@@ -55695,7 +56051,15 @@ var init_funnel_utterances = __esm({
|
|
|
55695
56051
|
"show me all the triggers on Account",
|
|
55696
56052
|
"what approval processes are deployed?",
|
|
55697
56053
|
"list all custom labels",
|
|
55698
|
-
"give me every email template in the org"
|
|
56054
|
+
"give me every email template in the org",
|
|
56055
|
+
// R3 custom-permission enumeration band (DIAGNOSIS-R3 §2 rank 6) + the
|
|
56056
|
+
// "can i see the validation rules" type-noun phrasings.
|
|
56057
|
+
"which custom permissions exist and what do they gate?",
|
|
56058
|
+
"what custom permissions are defined in this org?",
|
|
56059
|
+
"pull the full custom permission inventory for the audit workpaper",
|
|
56060
|
+
"can i see the validation rules on the <Object> object",
|
|
56061
|
+
"is there validation on the <Object> object?",
|
|
56062
|
+
"show me all the invocable apex methods"
|
|
55699
56063
|
],
|
|
55700
56064
|
"sfi.get_edges": [
|
|
55701
56065
|
"what are the edges between <ApexClass> and the objects it touches?",
|
|
@@ -55730,7 +56094,13 @@ var init_funnel_utterances = __esm({
|
|
|
55730
56094
|
"find flows that call the <ApexClass> Apex class",
|
|
55731
56095
|
"which flows have a Get Records step on the Account object?",
|
|
55732
56096
|
"search for flows that send emails",
|
|
55733
|
-
"find every flow that creates an Opportunity"
|
|
56097
|
+
"find every flow that creates an Opportunity",
|
|
56098
|
+
// R3 q738-class boundary recovery: custom-permission checks inside flow
|
|
56099
|
+
// XML, subflow-by-name, and field-stamping searches.
|
|
56100
|
+
"does any flow reference the <CustomPermission> custom permission to skip a validation rule?",
|
|
56101
|
+
"which custom permissions are checked inside flows?",
|
|
56102
|
+
"find the flow that fires the <SubflowName> subflow",
|
|
56103
|
+
"is there a flow that stamps <Field__c> when the record closes?"
|
|
55734
56104
|
],
|
|
55735
56105
|
"sfi.get_naming_convention_report": [
|
|
55736
56106
|
"do our field names follow any consistent pattern?",
|
|
@@ -55819,7 +56189,11 @@ var init_funnel_utterances = __esm({
|
|
|
55819
56189
|
"pull a random sample of Opportunity records",
|
|
55820
56190
|
"show me what Account data actually looks like",
|
|
55821
56191
|
"grab a handful of Order records for me to inspect",
|
|
55822
|
-
"give me a sample of 10 Opportunities with Stage = Prospecting"
|
|
56192
|
+
"give me a sample of 10 Opportunities with Stage = Prospecting",
|
|
56193
|
+
// biz-user register (router-v2 R2): single-record lookup by an id the
|
|
56194
|
+
// user has in hand, asking for every field value.
|
|
56195
|
+
"can you pull up the specific record for id <RecordId>? I need to see all their field values",
|
|
56196
|
+
"show me one actual record with every field value filled in"
|
|
55823
56197
|
],
|
|
55824
56198
|
"sfi.live_field_population": [
|
|
55825
56199
|
"what percentage of Contacts have the Email field filled in?",
|
|
@@ -55835,7 +56209,10 @@ var init_funnel_utterances = __esm({
|
|
|
55835
56209
|
"how many people are in the queue right now?",
|
|
55836
56210
|
"show me group sizes across all public groups",
|
|
55837
56211
|
"how many members does the Sales territory group have?",
|
|
55838
|
-
"how are Cases distributed by Status right now?"
|
|
56212
|
+
"how are Cases distributed by Status right now?",
|
|
56213
|
+
// biz-user register (router-v2 R2): distribution-by-field phrasing.
|
|
56214
|
+
"how are <Object> records distributed by their Type field?",
|
|
56215
|
+
"breakdown of records by picklist value \u2014 how many land in each bucket?"
|
|
55839
56216
|
],
|
|
55840
56217
|
"sfi.live_stale_records": [
|
|
55841
56218
|
"which Cases haven't been updated in over 90 days?",
|
|
@@ -55931,7 +56308,9 @@ var init_funnel_utterances = __esm({
|
|
|
55931
56308
|
"which users can see the Executive dashboards folder?",
|
|
55932
56309
|
"who can access the shared document library?",
|
|
55933
56310
|
"folder-level access for the Finance reports",
|
|
55934
|
-
"are any report or dashboard folders publicly accessible?"
|
|
56311
|
+
"are any report or dashboard folders publicly accessible?",
|
|
56312
|
+
// biz-user register (router-v2 R2): single-report ownership question.
|
|
56313
|
+
"the <ReportName> report \u2014 who owns it and who can run it?"
|
|
55935
56314
|
],
|
|
55936
56315
|
"sfi.live_email_template_usage": [
|
|
55937
56316
|
"which email templates are actually being used?",
|
|
@@ -55983,7 +56362,10 @@ var init_funnel_utterances = __esm({
|
|
|
55983
56362
|
"executive summary of org risk",
|
|
55984
56363
|
"what should I be worried about before we go live?",
|
|
55985
56364
|
"pull together the top risks I need to present to leadership",
|
|
55986
|
-
"is there anything that would block a production release right now?"
|
|
56365
|
+
"is there anything that would block a production release right now?",
|
|
56366
|
+
// biz-user register (router-v2 R2): quality asked as a grade.
|
|
56367
|
+
"is our Salesforce org well-architected? would you give it a passing grade?",
|
|
56368
|
+
"if an outside expert graded this org's setup, what would they flag?"
|
|
55987
56369
|
],
|
|
55988
56370
|
"sfi.field_cleanup_candidates": [
|
|
55989
56371
|
"which fields can we safely delete?",
|
|
@@ -56061,7 +56443,18 @@ var init_funnel_utterances = __esm({
|
|
|
56061
56443
|
"what's the net permission for a user with <Profile> and <PermSet>?",
|
|
56062
56444
|
"does this user actually have delete access on Account?",
|
|
56063
56445
|
"what objects can the <Profile> profile read?",
|
|
56064
|
-
"effective read/write/delete access for <Profile> on Order"
|
|
56446
|
+
"effective read/write/delete access for <Profile> on Order",
|
|
56447
|
+
// R3 PSG-expansion band (DIAGNOSIS-R3 permissions family): what a member
|
|
56448
|
+
// of a permission set GROUP ends up with — effective_permissions expands
|
|
56449
|
+
// PSGs (verified). The genuinely-unanswerable directions stay gapped:
|
|
56450
|
+
// "which USERS are in the group" (permset-user-roster) and "which PSG
|
|
56451
|
+
// grants X" (permset-group-grants) are capability-gap intents, untouched.
|
|
56452
|
+
"what does a user get through the <PermSetGroup> permission set group?",
|
|
56453
|
+
"expand the <PermSetGroup> permission set group \u2014 every permission a member ends up with",
|
|
56454
|
+
"if someone is assigned the <PermSetGroup> permission set group, do they automatically get <CustomPermission>?",
|
|
56455
|
+
"what custom permissions does a new hire end up with after all their permission set group assignments?",
|
|
56456
|
+
"can a user in the <PermSetGroup> permission set group edit these records?",
|
|
56457
|
+
"walk me through how permission set group inheritance works here, with a real group as the example"
|
|
56065
56458
|
],
|
|
56066
56459
|
"sfi.who_can_run": [
|
|
56067
56460
|
"who can run the <Report> report?",
|
|
@@ -56085,7 +56478,12 @@ var init_funnel_utterances = __esm({
|
|
|
56085
56478
|
"a user is getting access denied on Opportunity \u2014 what's wrong?",
|
|
56086
56479
|
"why is this record invisible to a specific user?",
|
|
56087
56480
|
"I need to figure out why a user can't open this record",
|
|
56088
|
-
"user says they get a 'No access' error on a Contact record \u2014 what gives?"
|
|
56481
|
+
"user says they get a 'No access' error on a Contact record \u2014 what gives?",
|
|
56482
|
+
// R3 access-diagnostics band (DIAGNOSIS-R3 permissions family): symptom
|
|
56483
|
+
// phrasings — greyed-out fields, blocked edits, blocked reassignment.
|
|
56484
|
+
"a user cant edit the <Field__c> field on a record, they say its greyed out \u2014 why?",
|
|
56485
|
+
"why cant a user with the <Profile> profile reassign the Case owner?",
|
|
56486
|
+
"a user reports the record is read-only for them \u2014 which layer blocks the edit?"
|
|
56089
56487
|
],
|
|
56090
56488
|
"sfi.layout_for_user": [
|
|
56091
56489
|
"what page layout does <Profile> see on Case?",
|
|
@@ -56101,7 +56499,11 @@ var init_funnel_utterances = __esm({
|
|
|
56101
56499
|
"what can a specific user actually do in the org?",
|
|
56102
56500
|
"check if <Username> can create Opportunities",
|
|
56103
56501
|
"what record types can this user access on Case?",
|
|
56104
|
-
"what flows can users with the <Profile> profile actually run?"
|
|
56502
|
+
"what flows can users with the <Profile> profile actually run?",
|
|
56503
|
+
// R3 access-diagnostics band: missing-button / failing-action symptoms.
|
|
56504
|
+
"a user says the Convert button is missing on a Lead \u2014 why?",
|
|
56505
|
+
"why does the send action fail for one user \u2014 do they need the <PermSet> permission set?",
|
|
56506
|
+
"which permission is this user missing to perform the action?"
|
|
56105
56507
|
],
|
|
56106
56508
|
"sfi.profile_security": [
|
|
56107
56509
|
"how locked down is the <Profile> profile?",
|
|
@@ -56141,7 +56543,9 @@ var init_funnel_utterances = __esm({
|
|
|
56141
56543
|
"which objects have tabs hidden from the support profile?",
|
|
56142
56544
|
"show me tab settings for the <Profile> profile",
|
|
56143
56545
|
"which tabs are set to 'Default Off' for a specific profile?",
|
|
56144
|
-
"which tabs are visible to users with the <Profile> profile?"
|
|
56546
|
+
"which tabs are visible to users with the <Profile> profile?",
|
|
56547
|
+
// biz-user register (router-v2 R2): imperative "list its tabs" shape.
|
|
56548
|
+
"the <Profile> profile \u2014 what does it have access to? list its tabs"
|
|
56145
56549
|
],
|
|
56146
56550
|
"sfi.lifecycle_process": [
|
|
56147
56551
|
"what's the Case lifecycle \u2014 statuses and transitions?",
|
|
@@ -56149,7 +56553,11 @@ var init_funnel_utterances = __esm({
|
|
|
56149
56553
|
"what are the valid Lead status transitions?",
|
|
56150
56554
|
"describe the record lifecycle for Order",
|
|
56151
56555
|
"what's the path an Account goes through from creation to active?",
|
|
56152
|
-
"what happens when an Opportunity moves to Closed Won?"
|
|
56556
|
+
"what happens when an Opportunity moves to Closed Won?",
|
|
56557
|
+
// biz-user register (router-v2 R2): status-transition asked as "what
|
|
56558
|
+
// kicks in when the value flips".
|
|
56559
|
+
"when the Status field flips to Resolved, what processes kick in for that value transition?",
|
|
56560
|
+
"what happens behind the scenes when a record moves to a new stage?"
|
|
56153
56561
|
],
|
|
56154
56562
|
"sfi.layout_assignments": [
|
|
56155
56563
|
"which layouts are assigned to which profiles on Case?",
|
|
@@ -56337,7 +56745,9 @@ var init_funnel_utterances = __esm({
|
|
|
56337
56745
|
"compare the Case validation rules in two orgs",
|
|
56338
56746
|
"what's different between the <Profile> profile in sandbox vs prod?",
|
|
56339
56747
|
"compare the <ApexClass> class across environments",
|
|
56340
|
-
"are these two record types actually different or just named differently?"
|
|
56748
|
+
"are these two record types actually different or just named differently?",
|
|
56749
|
+
// biz-user register (router-v2 R2): duplicate-automation confusion.
|
|
56750
|
+
"why do we have two triggers on the same object \u2014 what does each one do differently?"
|
|
56341
56751
|
],
|
|
56342
56752
|
"sfi.export_manifest": [
|
|
56343
56753
|
"export the full org manifest",
|
|
@@ -56369,7 +56779,9 @@ var init_funnel_utterances = __esm({
|
|
|
56369
56779
|
"who has delete access to Account?",
|
|
56370
56780
|
"object-level permission audit for Contact",
|
|
56371
56781
|
"show me which profiles have full CRUD on custom object <ObjectName>",
|
|
56372
|
-
"which profiles have Create access on the Case object?"
|
|
56782
|
+
"which profiles have Create access on the Case object?",
|
|
56783
|
+
// biz-user register (router-v2 R2): group-membership create-access ask.
|
|
56784
|
+
"can members of <GroupName> create <Object> records, and where does that access come from?"
|
|
56373
56785
|
],
|
|
56374
56786
|
"sfi.recordtype_availability": [
|
|
56375
56787
|
"which record types on Case are available to the Support profile?",
|
|
@@ -56391,7 +56803,10 @@ var init_funnel_utterances = __esm({
|
|
|
56391
56803
|
"describe this org to me like I just joined the team",
|
|
56392
56804
|
"how big is this org \u2014 fields, flows, classes, the works?",
|
|
56393
56805
|
"what's the overall complexity of this org?",
|
|
56394
|
-
"give me a lay of the land for this Salesforce environment"
|
|
56806
|
+
"give me a lay of the land for this Salesforce environment",
|
|
56807
|
+
// biz-user register (router-v2 R2): the new-joiner altitude idioms.
|
|
56808
|
+
"I just joined this team \u2014 what's the 10,000-foot view of what's in this Salesforce org?",
|
|
56809
|
+
"give me the bird's-eye view of this org for a newcomer"
|
|
56395
56810
|
],
|
|
56396
56811
|
"sfi.domain_clusters": [
|
|
56397
56812
|
"what functional areas does this org cover?",
|
|
@@ -56430,7 +56845,19 @@ var init_funnel_utterances = __esm({
|
|
|
56430
56845
|
"before I add a new flow to Contact, what else is already running on save?",
|
|
56431
56846
|
"which flows fire synchronously on Lead save?",
|
|
56432
56847
|
"complete save-event automation inventory for the Account object",
|
|
56433
|
-
"what happens behind the scenes when I create a new Contact?"
|
|
56848
|
+
"what happens behind the scenes when I create a new Contact?",
|
|
56849
|
+
// biz-user register (router-v2 R2): terse "show me its automation" shape.
|
|
56850
|
+
"the <Object> object \u2014 can you show me its automation?",
|
|
56851
|
+
// R3 save-cascade band (DIAGNOSIS-R3 §2 rank 7): terse "whats on save",
|
|
56852
|
+
// event-split phrasings, apex-on-insert, and the automation footprint.
|
|
56853
|
+
"whats on save for the <Object> object?",
|
|
56854
|
+
"how many automations fire when a record gets saved?",
|
|
56855
|
+
"what apex runs on Contact insert?",
|
|
56856
|
+
"list the flows that run on Contact insert",
|
|
56857
|
+
"which flows are triggered by Case creation vs Case update?",
|
|
56858
|
+
"whats the automation footprint on the <Object> object \u2014 flows, triggers, everything together?",
|
|
56859
|
+
"why did the flow not fire on my lead update \u2014 what is even wired to Lead saves?",
|
|
56860
|
+
"does anything on <Object> save update a date field automatically?"
|
|
56434
56861
|
],
|
|
56435
56862
|
"sfi.why_field_changed": [
|
|
56436
56863
|
"which flows write to Contact.Status__c?",
|
|
@@ -56467,7 +56894,28 @@ var init_funnel_utterances = __esm({
|
|
|
56467
56894
|
"what's the happy path through <FlowName>?",
|
|
56468
56895
|
"does <FlowName> have any error handling?",
|
|
56469
56896
|
"what variables does <FlowName> use?",
|
|
56470
|
-
"which object does <FlowName> primarily operate on?"
|
|
56897
|
+
"which object does <FlowName> primarily operate on?",
|
|
56898
|
+
// biz-user register (router-v2 R2): non-technical phrasings from the
|
|
56899
|
+
// business-user persona misses — purpose-of-flow asked as a business
|
|
56900
|
+
// question, and the "is that a flow or a trigger" type-confusion shape.
|
|
56901
|
+
"there's a flow called <FlowName> \u2014 what is it for? what business process does it support?",
|
|
56902
|
+
"what does the <FlowName> flow do for the business?",
|
|
56903
|
+
"<FlowName> \u2014 is that a flow or a trigger? what does it invoke?",
|
|
56904
|
+
"is <ComponentName> an Apex class or a flow? I want to see what it does",
|
|
56905
|
+
// R3 flow-explain band (DIAGNOSIS-R3 §2 rank 3): indirect explanation
|
|
56906
|
+
// phrasings — orchestrate/breakdown/what-triggers-it/fires-on-update.
|
|
56907
|
+
"before i touch the <FlowName> flow, what does it even do?",
|
|
56908
|
+
"what does the <FlowName> flow orchestrate?",
|
|
56909
|
+
"give me a breakdown of the <FlowName> flow",
|
|
56910
|
+
"what triggers the <FlowName> flow \u2014 a record change, a schedule, or a button?",
|
|
56911
|
+
"does <FlowName> fire on update too or just on insert?",
|
|
56912
|
+
"which record type does the <FlowName> flow assign to the Case?",
|
|
56913
|
+
"the <FlowName> screen flow \u2014 walk me through its screens and decisions",
|
|
56914
|
+
// R3 flow-diagnostics band ("why did it NOT fire / not stamp"):
|
|
56915
|
+
"why did the <FlowName> flow NOT fire when the record was updated?",
|
|
56916
|
+
"why is the <FlowName> flow not sending the confirmation email \u2014 walk the decision branches",
|
|
56917
|
+
"the flow didnt stamp the date when the stage moved \u2014 why not?",
|
|
56918
|
+
"a reviewer says the <FlowName> flow is skipping records \u2014 what does it actually gate?"
|
|
56471
56919
|
],
|
|
56472
56920
|
"sfi.explain_apex_method": [
|
|
56473
56921
|
"what does the <MethodName> method in <ApexClass> do?",
|
|
@@ -56475,7 +56923,12 @@ var init_funnel_utterances = __esm({
|
|
|
56475
56923
|
"walk me through the logic of <ApexClass>.<MethodName>",
|
|
56476
56924
|
"what does this method return and what does it modify?",
|
|
56477
56925
|
"explain the business logic in the <MethodName> method",
|
|
56478
|
-
"what does the AccountController class do?"
|
|
56926
|
+
"what does the AccountController class do?",
|
|
56927
|
+
// biz-user register (router-v2 R2): whole-class purpose questions and the
|
|
56928
|
+
// "Trigger in the name but is it a test class" type-confusion shape.
|
|
56929
|
+
"we have an Apex class called <ClassName> \u2014 what does it do and what objects does it touch?",
|
|
56930
|
+
"is <ClassName> an Apex test class or an actual trigger?",
|
|
56931
|
+
"that class has Trigger in its name \u2014 is it actually a test class?"
|
|
56479
56932
|
],
|
|
56480
56933
|
"sfi.explain_formula": [
|
|
56481
56934
|
"what does this formula field actually calculate?",
|
|
@@ -56499,7 +56952,10 @@ var init_funnel_utterances = __esm({
|
|
|
56499
56952
|
"which processes are candidates for Flow migration?",
|
|
56500
56953
|
"what Process Builder is left that we need to retire?",
|
|
56501
56954
|
"identify Process Builder processes that would be straightforward to convert",
|
|
56502
|
-
"which Process Builders should we migrate to Flow first?"
|
|
56955
|
+
"which Process Builders should we migrate to Flow first?",
|
|
56956
|
+
// biz-user register (router-v2 R2): "sunset/retire" business phrasing.
|
|
56957
|
+
"which automation is Salesforce going to sunset that we need to replace?",
|
|
56958
|
+
"what legacy automation is being retired that we still depend on?"
|
|
56503
56959
|
],
|
|
56504
56960
|
"sfi.unassigned_permission_sets": [
|
|
56505
56961
|
"are there permission sets that aren't assigned to anyone?",
|
|
@@ -56507,7 +56963,12 @@ var init_funnel_utterances = __esm({
|
|
|
56507
56963
|
"find permission sets that are effectively dead \u2014 no assignments",
|
|
56508
56964
|
"show me unassigned permission sets we could clean up",
|
|
56509
56965
|
"permission sets nobody has \u2014 are there any?",
|
|
56510
|
-
"which permission sets aren't assigned to any user?"
|
|
56966
|
+
"which permission sets aren't assigned to any user?",
|
|
56967
|
+
// biz-user register (router-v2 R2): single-perm-set assignment questions
|
|
56968
|
+
// ("is X assigned to anyone") — the premise-trap family phrasing.
|
|
56969
|
+
"is the <PermSet> permission set assigned to anyone?",
|
|
56970
|
+
"is <PermSet> assigned to any active users right now?",
|
|
56971
|
+
"who has the <PermSet> permission set assigned and what does it let them do?"
|
|
56511
56972
|
],
|
|
56512
56973
|
"sfi.empty_queues_and_groups": [
|
|
56513
56974
|
"are there any queues with no members?",
|
|
@@ -56523,7 +56984,9 @@ var init_funnel_utterances = __esm({
|
|
|
56523
56984
|
"give me a technical debt rating for this Salesforce org",
|
|
56524
56985
|
"debt score breakdown \u2014 what's contributing most?",
|
|
56525
56986
|
"quantify the technical debt in this org",
|
|
56526
|
-
"what's the overall technical debt score for this org?"
|
|
56987
|
+
"what's the overall technical debt score for this org?",
|
|
56988
|
+
// biz-user register (router-v2 R2): quality asked as a grade.
|
|
56989
|
+
"overall, is this org in good shape or carrying a lot of debt \u2014 passing grade or not?"
|
|
56527
56990
|
],
|
|
56528
56991
|
"sfi.code_quality_audit": [
|
|
56529
56992
|
"how good is our Apex code quality?",
|
|
@@ -56591,7 +57054,9 @@ var init_funnel_utterances = __esm({
|
|
|
56591
57054
|
"impact of making Contact.External_Id__c required",
|
|
56592
57055
|
"can I safely make this field required without breaking flows?",
|
|
56593
57056
|
"what automation would break if I make this field mandatory?",
|
|
56594
|
-
"what would break if I made Account.Website required?"
|
|
57057
|
+
"what would break if I made Account.Website required?",
|
|
57058
|
+
// biz-user register (router-v2 R2): "I want to set X to required" ask.
|
|
57059
|
+
"I want to set <Field__c> to required \u2014 can you check what flows and Apex would break?"
|
|
56595
57060
|
],
|
|
56596
57061
|
"sfi.what_if_deactivate_flow": [
|
|
56597
57062
|
"what breaks if I deactivate <FlowName>?",
|
|
@@ -56599,7 +57064,22 @@ var init_funnel_utterances = __esm({
|
|
|
56599
57064
|
"impact of deactivating the Case assignment flow",
|
|
56600
57065
|
"can I safely deactivate <FlowName> without breaking anything?",
|
|
56601
57066
|
"what would stop working if I switch off <FlowName>?",
|
|
56602
|
-
"what happens if I deactivate the <FlowName> flow?"
|
|
57067
|
+
"what happens if I deactivate the <FlowName> flow?",
|
|
57068
|
+
// biz-user register (router-v2 R2): "can you deactivate it safely" and
|
|
57069
|
+
// "impact if we turn it off" phrasings (premise-trap family).
|
|
57070
|
+
"can you deactivate <FlowName> safely? I need to know what depends on it",
|
|
57071
|
+
"we have a <ProcessName> process that runs on these records \u2014 what's the impact if we turn it off?",
|
|
57072
|
+
// R3 what-if band (DIAGNOSIS-R3 flows family + §5c simulation frames):
|
|
57073
|
+
// imperative-plus-impact phrasings the write gate now carves out.
|
|
57074
|
+
"deactivate <FlowName> and tell me the impact",
|
|
57075
|
+
"deactivating <FlowName> \u2014 consequences?",
|
|
57076
|
+
"what happens if the <FlowName> flow is turned off during a busy period?",
|
|
57077
|
+
"deactivate the <FlowName> flow \u2014 what happens to new records?",
|
|
57078
|
+
"deactivate <FlowName> and tell me what stops recalculating",
|
|
57079
|
+
"does deactivating <FlowName> stop the confirmation emails?",
|
|
57080
|
+
"when I deactivate <FlowName>, does the review process just stall?",
|
|
57081
|
+
"consequences of deactivating the <FlowName> flow?",
|
|
57082
|
+
"what would happen if the <FlowName> flow were deactivated?"
|
|
56603
57083
|
],
|
|
56604
57084
|
"sfi.what_if_disable_trigger": [
|
|
56605
57085
|
"what breaks if I disable the Contact trigger?",
|
|
@@ -56641,7 +57121,10 @@ var init_funnel_utterances = __esm({
|
|
|
56641
57121
|
"build a data dictionary I can share with the data team",
|
|
56642
57122
|
"export field descriptions and types for all custom objects",
|
|
56643
57123
|
"generate a schema reference document",
|
|
56644
|
-
"generate a data dictionary for the Contact object"
|
|
57124
|
+
"generate a data dictionary for the Contact object",
|
|
57125
|
+
// biz-user register (router-v2 R2): "reference sheet" business phrasing.
|
|
57126
|
+
"our business team needs a reference sheet for the <Object> object \u2014 field names, types, required vs optional",
|
|
57127
|
+
"make a field reference sheet the business team can read"
|
|
56645
57128
|
],
|
|
56646
57129
|
"sfi.generate_admin_handbook": [
|
|
56647
57130
|
"write an admin handbook for this org",
|
|
@@ -56657,7 +57140,9 @@ var init_funnel_utterances = __esm({
|
|
|
56657
57140
|
"create a high-level architecture summary for stakeholders",
|
|
56658
57141
|
"document the overall structure of this Salesforce implementation",
|
|
56659
57142
|
"generate an architecture diagram description for this org",
|
|
56660
|
-
"write an architecture overview document for this Salesforce org"
|
|
57143
|
+
"write an architecture overview document for this Salesforce org",
|
|
57144
|
+
// biz-user register (router-v2 R2): altitude idiom for leadership.
|
|
57145
|
+
"the leadership team wants the 10,000-foot architecture picture of our Salesforce org"
|
|
56661
57146
|
],
|
|
56662
57147
|
"sfi.generate_sharing_summary": [
|
|
56663
57148
|
"generate a sharing model summary for this org",
|
|
@@ -56698,12 +57183,18 @@ var init_funnel_utterances = __esm({
|
|
|
56698
57183
|
"subflow map \u2014 which flows call other flows?"
|
|
56699
57184
|
],
|
|
56700
57185
|
"sfi.downstream_effects": [
|
|
56701
|
-
"what does changing <Field__c> ripple out to?",
|
|
57186
|
+
"what does changing <Field__c> ripple out to downstream?",
|
|
56702
57187
|
"show me the downstream effects of modifying <ApexClass>",
|
|
56703
|
-
"if I change <FlowName>, what else is affected?",
|
|
57188
|
+
"if I change <FlowName>, what else is affected downstream?",
|
|
56704
57189
|
"downstream impact of updating the Case status picklist",
|
|
56705
57190
|
"what does it affect if <ComponentName> changes?",
|
|
56706
|
-
"what side effects does the AccountTrigger handler produce downstream?"
|
|
57191
|
+
"what side effects does the AccountTrigger handler produce downstream?",
|
|
57192
|
+
// self-recall reinforcement (router-v2 R2): the two paraphrase-only
|
|
57193
|
+
// utterances above ("what else is affected", "what does it affect")
|
|
57194
|
+
// shared no vocabulary with the tool's own name and lost the tie to
|
|
57195
|
+
// get_impact — anchor the downstream/effects terms.
|
|
57196
|
+
"what are the downstream effects if I change <FlowName>?",
|
|
57197
|
+
"show downstream effects of a change to <ComponentName>"
|
|
56707
57198
|
],
|
|
56708
57199
|
"sfi.test_coverage_for_method": [
|
|
56709
57200
|
"what tests cover the <MethodName> method?",
|
|
@@ -56783,7 +57274,12 @@ var init_funnel_utterances = __esm({
|
|
|
56783
57274
|
"what's the semantic meaning of Status__c on Order?",
|
|
56784
57275
|
"what does Amount__c represent \u2014 is it revenue, cost, or something else?",
|
|
56785
57276
|
"in plain English, what does this field track?",
|
|
56786
|
-
"what does the External_Id__c field on Account actually mean in this org?"
|
|
57277
|
+
"what does the External_Id__c field on Account actually mean in this org?",
|
|
57278
|
+
// biz-user register (router-v2 R2): label-first "what is it really for /
|
|
57279
|
+
// who sets it" phrasings from the business-user misses.
|
|
57280
|
+
"what is the <Field__c> field really for in this org?",
|
|
57281
|
+
"the bad email field \u2014 what does it represent and who sets it?",
|
|
57282
|
+
"what does that field mean in context \u2014 is it set by automation or by users, and what object is it on?"
|
|
56787
57283
|
],
|
|
56788
57284
|
"sfi.disambiguate_concepts": [
|
|
56789
57285
|
"we have both Priority__c and Case.Priority \u2014 which one should I use?",
|
|
@@ -56801,7 +57297,9 @@ var init_funnel_utterances = __esm({
|
|
|
56801
57297
|
"is Amount__c auto-populated or user-entered?",
|
|
56802
57298
|
"where does the data in this field come from?",
|
|
56803
57299
|
"is this field set by a trigger, a flow, or does a user type it in?",
|
|
56804
|
-
"trace the origin of values in <Field__c>"
|
|
57300
|
+
"trace the origin of values in <Field__c>",
|
|
57301
|
+
// biz-user register (router-v2 R2): "how does it get its value" shape.
|
|
57302
|
+
"how does the <Field__c> field get its value \u2014 is it a formula or is something writing to it?"
|
|
56805
57303
|
],
|
|
56806
57304
|
"sfi.find_field_anywhere": [
|
|
56807
57305
|
"find all objects that have a field called External_Id__c",
|
|
@@ -56985,7 +57483,18 @@ var init_funnel_utterances = __esm({
|
|
|
56985
57483
|
"which layouts include the <ComponentName> component?",
|
|
56986
57484
|
"which flows invoke <ComponentName>?",
|
|
56987
57485
|
"where is this custom label used?",
|
|
56988
|
-
"what uses the <PermSet> permission set \u2014 show me all assignments and references"
|
|
57486
|
+
"what uses the <PermSet> permission set \u2014 show me all assignments and references",
|
|
57487
|
+
// R3 reverse custom-permission grant band (DIAGNOSIS-R3 §2 rank 5): who
|
|
57488
|
+
// holds / which perm sets turn on / which profiles enable a custom
|
|
57489
|
+
// permission — the reverse lookup shipped in 0.1.19; the vocabulary here.
|
|
57490
|
+
"who holds the <CustomPermission> custom permission and which perm sets grant it?",
|
|
57491
|
+
"which permission sets or permission set groups turn on <CustomPermission>?",
|
|
57492
|
+
"which profiles enable the <CustomPermission> custom permission directly \u2014 not perm sets?",
|
|
57493
|
+
"is <CustomPermission> granted anywhere besides the <PermSet> permission set?",
|
|
57494
|
+
"i need the granting perm set for the <CustomPermission> custom permission",
|
|
57495
|
+
"how could a user have gotten the <CustomPermission> custom permission?",
|
|
57496
|
+
"what perm set gives access to the <ComponentName> component?",
|
|
57497
|
+
"who is allowed to bypass the validation \u2014 which custom permission guards it and who holds it?"
|
|
56989
57498
|
],
|
|
56990
57499
|
"sfi.installed_package_catalog": [
|
|
56991
57500
|
"what managed packages are installed in this org?",
|
|
@@ -57275,7 +57784,57 @@ var init_semantic_funnel = __esm({
|
|
|
57275
57784
|
untested: ["coverage", "gaps", "test", "tests"],
|
|
57276
57785
|
// queue / assignment routing family
|
|
57277
57786
|
queue: ["assignment", "routing", "owner", "group"],
|
|
57278
|
-
routed: ["assignment", "queue", "rule", "routing"]
|
|
57787
|
+
routed: ["assignment", "queue", "rule", "routing"],
|
|
57788
|
+
// ---- router-v2 R2 biz-user vocabulary bridges. Grown from the
|
|
57789
|
+
// business-user persona misses on the additions-tuning set; every entry is
|
|
57790
|
+
// GENERIC business English mapped to Salesforce vocabulary — no org terms.
|
|
57791
|
+
// "which automation gets sunset / retired" → legacy-migration vocabulary
|
|
57792
|
+
sunset: ["retire", "retired", "deprecated", "migrate", "legacy", "replace"],
|
|
57793
|
+
retiring: ["sunset", "deprecated", "migrate", "legacy"],
|
|
57794
|
+
// "when the status flips to X" → transition vocabulary
|
|
57795
|
+
flips: ["changes", "transition", "moves", "value", "status"],
|
|
57796
|
+
// "who are the top contributors" → change-activity vocabulary
|
|
57797
|
+
contributors: ["changes", "modified", "activity", "churn"],
|
|
57798
|
+
// "how are records distributed by X" → grouped-count vocabulary
|
|
57799
|
+
distributed: ["count", "group", "grouped", "breakdown"],
|
|
57800
|
+
// "would you give it a passing grade" → health/risk vocabulary
|
|
57801
|
+
grade: ["risk", "health", "score", "debt"],
|
|
57802
|
+
graded: ["risk", "health", "score", "debt"],
|
|
57803
|
+
architected: ["architecture", "risk", "health", "design"],
|
|
57804
|
+
// "the report my boss uses / the thing she made" → ownership vocabulary
|
|
57805
|
+
boss: ["owner", "user"],
|
|
57806
|
+
made: ["created", "built"],
|
|
57807
|
+
// ---- router-v2 R3 vocabulary bridges. Grown from the v0.1.22 labeled-miss
|
|
57808
|
+
// permissions/flows families (DIAGNOSIS-R3 §2); every entry is GENERIC
|
|
57809
|
+
// Salesforce/business vocabulary — no org terms — and safe at
|
|
57810
|
+
// EXPANSION_WEIGHT (originals always win).
|
|
57811
|
+
// custom-permission family: bypass / gate / guard / unlock verbs → the
|
|
57812
|
+
// permission vocabulary the tool docs actually use.
|
|
57813
|
+
bypass: ["permission", "custom", "validation", "skip"],
|
|
57814
|
+
bypasses: ["bypass", "permission", "custom", "validation"],
|
|
57815
|
+
bypassing: ["bypass", "permission", "custom", "validation"],
|
|
57816
|
+
gate: ["permission", "custom", "guard", "control"],
|
|
57817
|
+
gates: ["gate", "permission", "custom", "guard"],
|
|
57818
|
+
gated: ["gate", "permission", "custom"],
|
|
57819
|
+
guarding: ["gate", "permission", "custom", "validation"],
|
|
57820
|
+
unlock: ["grant", "permission", "access", "enable"],
|
|
57821
|
+
unlocks: ["grant", "permission", "access", "enable"],
|
|
57822
|
+
// PSG-expansion family: expand/inheritance → effective-permission union.
|
|
57823
|
+
expand: ["effective", "permission", "group", "union"],
|
|
57824
|
+
inheritance: ["group", "permission", "effective", "union"],
|
|
57825
|
+
inherits: ["group", "permission", "effective", "union"],
|
|
57826
|
+
// access-diagnostics family: greyed-out / read-only symptom words.
|
|
57827
|
+
greyed: ["edit", "editable", "access", "security", "field"],
|
|
57828
|
+
grayed: ["edit", "editable", "access", "security", "field"],
|
|
57829
|
+
// flow-diagnostics family: "didn't stamp the date", "what does it
|
|
57830
|
+
// orchestrate", "the flow is skipping records".
|
|
57831
|
+
stamp: ["writes", "sets", "populates", "updates", "flow"],
|
|
57832
|
+
stamps: ["writes", "sets", "populates", "updates", "flow"],
|
|
57833
|
+
orchestrate: ["flow", "subflow", "invoke", "explain"],
|
|
57834
|
+
orchestrates: ["flow", "subflow", "invoke", "explain"],
|
|
57835
|
+
skipping: ["skip", "bypass", "decision", "flow"],
|
|
57836
|
+
// automation-footprint family (what_happens_on_save / risk report).
|
|
57837
|
+
footprint: ["automation", "inventory", "overview", "save"]
|
|
57279
57838
|
};
|
|
57280
57839
|
PHRASE_SYNONYMS3 = [
|
|
57281
57840
|
["social security number", "ssn"],
|
|
@@ -57287,7 +57846,18 @@ var init_semantic_funnel = __esm({
|
|
|
57287
57846
|
// becomes 'break' (→ impact/dependency synonyms) + 'down' — the impact
|
|
57288
57847
|
// expansion hijacks the ranking. Collapse the phrase to the single token
|
|
57289
57848
|
// 'breakdown' (whose SYNONYMS entry bridges to explain/overview/walk).
|
|
57290
|
-
["break down", "breakdown"]
|
|
57849
|
+
["break down", "breakdown"],
|
|
57850
|
+
// router-v2 R2 biz-user idioms: altitude metaphors are OVERVIEW asks
|
|
57851
|
+
// ("10,000-foot view" survives tokenization as "...-foot view"), and
|
|
57852
|
+
// "kicks in" is the business phrasing of "fires".
|
|
57853
|
+
["foot view", "overview"],
|
|
57854
|
+
["birds eye view", "overview"],
|
|
57855
|
+
["bird's eye view", "overview"],
|
|
57856
|
+
["big picture", "overview"],
|
|
57857
|
+
["lay of the land", "overview"],
|
|
57858
|
+
["kicks in", "fires"],
|
|
57859
|
+
["kick in", "fire"],
|
|
57860
|
+
["reference sheet", "dictionary"]
|
|
57291
57861
|
].sort((a2, b2) => b2[0].length - a2[0].length);
|
|
57292
57862
|
applyPhraseSynonyms3 = (lower) => {
|
|
57293
57863
|
let out = lower;
|
|
@@ -57311,7 +57881,7 @@ var init_semantic_funnel = __esm({
|
|
|
57311
57881
|
return out;
|
|
57312
57882
|
};
|
|
57313
57883
|
TOOL_KEYWORDS = {
|
|
57314
|
-
"sfi.list_components": "list inventory enumerate catalog all what do we have how many exist objects fields custom fields how many fields on object contact account lead opportunity case metadata count layouts list views triggers validation rules record types web links flows classes triggers profiles permission sets layouts record types validation rules approval processes reports dashboards omniscripts custom standard relationship child parent inactive active picklist values which flows are inactive active draft obsolete flows triggers rules by status enumerate components",
|
|
57884
|
+
"sfi.list_components": "list inventory enumerate catalog all what do we have how many exist objects fields custom fields how many fields on object contact account lead opportunity case metadata count layouts list views triggers validation rules record types web links flows classes triggers profiles permission sets layouts record types validation rules approval processes reports dashboards omniscripts custom standard relationship child parent inactive active picklist values which flows are inactive active draft obsolete flows triggers rules by status enumerate components custom permissions defined exist inventory what do they gate",
|
|
57315
57885
|
"sfi.capabilities": "what can you do help capabilities what can i ask how do i use",
|
|
57316
57886
|
"sfi.automation_risk_report": "objects more than one multiple triggers per object trigger quality automation risk",
|
|
57317
57887
|
"sfi.live_group_count": "how many users assigned to profile membership group count",
|
|
@@ -57563,7 +58133,7 @@ import { createHash as createHash7 } from "node:crypto";
|
|
|
57563
58133
|
import { readFile as readFile82 } from "node:fs/promises";
|
|
57564
58134
|
import { join as join23, resolve as resolve3 } from "node:path";
|
|
57565
58135
|
import { z as z115 } from "zod";
|
|
57566
|
-
var RESOLVE_FALLBACK_MAX_TOKENS, SAVE_ORDER_INTENTS, SINGLE_ENTITY_INTENTS, COMPARISON_ASIDE, stripComparisonAside, tryResolveFallback, routeQuestionInputSchema, routeTrust, clarificationIdFor, selectedEntityArgsForRoute, extractEntityQuery, inferEntityTypes, normLiteral, refineEntityResolution, resolveParentQualifier, applyGlossaryAliases, entityAmbiguityRequiresClarification, hygienicClarificationOptions, splitCompoundQuestion, mixedInventoryAndStoragePlan, PLAN_FAMILY, ASSESSMENT_FAMILY, ROUTE_PREAMBLE_TOOLS, TOOL_COMPATIBLE_TYPES, ACCESS_FLAVORED_TOOLS, resolvedTypeForGuard, applyComponentTypeGuard, REGEX_BONUS, resolveActiveVaultAlias, buildRouteToolArgsMap, mergeRouteHintsIntoCandidates, invokeFromArgsMap, rerankForMode, MARGIN, FUNNEL_PRIMARY_MIN_SCORE, DESTRUCTIVE_TOOL, INFORMATIONAL_IMPACT_TOOL, planesDiverge, LIVE_DATA_SIGNAL, resolvePlaneTie, risksDiverge, marginClarification, LIVE_DISCLOSURE_LOOKAHEAD, liveConsentDisclosure, guidanceForMode, buildFunnelCandidates, routerMode, REFUSAL_INTENT, REFUSAL_GAP, refusalResponse, CONTEXT_SAVE_ORDER_TOOLS, CONTEXT_TOOL_ARG_KEYS, GENERIC_SCHEMA_INTENTS, contextArgsFor, buildContextContinuation, routeQuestionHandler;
|
|
58136
|
+
var RESOLVE_FALLBACK_MAX_TOKENS, SAVE_ORDER_INTENTS, SINGLE_ENTITY_INTENTS, COMPARISON_ASIDE, stripComparisonAside, tryResolveFallback, routeQuestionInputSchema, routeTrust, clarificationIdFor, selectedEntityArgsForRoute, isToolNameMention, extractEntityQuery, NAME_IGNORABLE_WORD, looksLikeComponentName, extractExistenceProbeToken, inferEntityTypes, normLiteral, refineEntityResolution, resolveParentQualifier, applyGlossaryAliases, questionAssertsNameMultiplicity, entityAmbiguityRequiresClarification, hygienicClarificationOptions, splitCompoundQuestion, mixedInventoryAndStoragePlan, PLAN_FAMILY, ASSESSMENT_FAMILY, ROUTE_PREAMBLE_TOOLS, TOOL_COMPATIBLE_TYPES, ACCESS_FLAVORED_TOOLS, resolvedTypeForGuard, applyComponentTypeGuard, REGEX_BONUS, resolveActiveVaultAlias, buildRouteToolArgsMap, mergeRouteHintsIntoCandidates, invokeFromArgsMap, rerankForMode, MARGIN, FUNNEL_PRIMARY_MIN_SCORE, DESTRUCTIVE_TOOL, INFORMATIONAL_IMPACT_TOOL, planesDiverge, LIVE_DATA_SIGNAL, resolvePlaneTie, isCompoundPlaneAsk, risksDiverge, marginClarification, LIVE_DISCLOSURE_LOOKAHEAD, liveConsentDisclosure, guidanceForMode, buildFunnelCandidates, routerMode, REFUSAL_INTENT, REFUSAL_GAP, refusalResponse, CONTEXT_SAVE_ORDER_TOOLS, CONTEXT_TOOL_ARG_KEYS, GENERIC_SCHEMA_INTENTS, contextArgsFor, buildContextContinuation, routeQuestionHandler;
|
|
57567
58137
|
var init_route_question = __esm({
|
|
57568
58138
|
"../mcp/dist/src/tools/route-question.js"() {
|
|
57569
58139
|
"use strict";
|
|
@@ -57737,8 +58307,12 @@ var init_route_question = __esm({
|
|
|
57737
58307
|
}
|
|
57738
58308
|
return null;
|
|
57739
58309
|
};
|
|
58310
|
+
isToolNameMention = (token) => {
|
|
58311
|
+
const bare = token.toLowerCase().replace(/^sfi[._]/, "");
|
|
58312
|
+
return getPlaneByTool().has(`sfi.${bare}`);
|
|
58313
|
+
};
|
|
57740
58314
|
extractEntityQuery = (question, intent) => {
|
|
57741
|
-
const apiReference = question.
|
|
58315
|
+
const apiReference = [...question.matchAll(/\b[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)\b|\b[A-Za-z][A-Za-z0-9_]*__(?:c|mdt|e|x|b|kav)\b|\b[A-Za-z][A-Za-z0-9]*(?:_+[A-Za-z0-9]+)+\b/g)].map((match) => match[0]).find((token) => !isToolNameMention(token));
|
|
57742
58316
|
if (apiReference !== void 0) {
|
|
57743
58317
|
if (intent === "what-if-method-signature" && apiReference.includes(".")) {
|
|
57744
58318
|
return `${apiReference.slice(0, apiReference.indexOf("."))} class`;
|
|
@@ -57750,6 +58324,9 @@ var init_route_question = __esm({
|
|
|
57750
58324
|
}
|
|
57751
58325
|
return apiReference;
|
|
57752
58326
|
}
|
|
58327
|
+
const quotedTyped = question.match(/['"‘“]([A-Za-z][A-Za-z0-9_ ]{1,40}?)['"’”]\s+(?:field|object|profile|permission\s+set|flow|record\s+type)\b/i)?.[1];
|
|
58328
|
+
if (quotedTyped !== void 0)
|
|
58329
|
+
return quotedTyped.trim();
|
|
57753
58330
|
const prefixedTypePhrase = question.match(/\b((?:validation\s+rule|permission\s+set|record\s+type|page\s+layout|object|field|flow|class|trigger|layout|profile|report|dashboard)\s+(?:named\s+)?[A-Z][A-Za-z0-9_]*(?:\s+[A-Z][A-Za-z0-9_]*){0,5})\b/)?.[1];
|
|
57754
58331
|
if (prefixedTypePhrase !== void 0)
|
|
57755
58332
|
return prefixedTypePhrase.trim();
|
|
@@ -57767,6 +58344,15 @@ var init_route_question = __esm({
|
|
|
57767
58344
|
const parent = typedMatch?.[2];
|
|
57768
58345
|
return parent === void 0 ? phrase : `${phrase} on ${parent}`;
|
|
57769
58346
|
};
|
|
58347
|
+
NAME_IGNORABLE_WORD = /^(?:object|field|flow|class|trigger|page|layout|profile|permission|set|record|type|validation|rule|report|dashboard|logic|named|of|and|or|the|a|an|for)$/i;
|
|
58348
|
+
looksLikeComponentName = (query) => {
|
|
58349
|
+
const words = query.trim().split(/\s+/);
|
|
58350
|
+
if (words.length <= 1)
|
|
58351
|
+
return true;
|
|
58352
|
+
const nameWords = words.filter((word) => !NAME_IGNORABLE_WORD.test(word));
|
|
58353
|
+
return nameWords.length > 0 && nameWords.every((word) => /^["'‘“(]?[A-Z0-9]/.test(word));
|
|
58354
|
+
};
|
|
58355
|
+
extractExistenceProbeToken = (question) => [...question.matchAll(/\b[A-Za-z][A-Za-z0-9_]*__(?:c|mdt|e|x|b|kav)\b|\b[A-Za-z][A-Za-z0-9]*(?:_+[A-Za-z0-9]+)+\b/g)].map((match) => match[0]).find((token) => !isToolNameMention(token) && !/^\d/.test(token)) ?? null;
|
|
57770
58356
|
inferEntityTypes = (query, intent, question) => {
|
|
57771
58357
|
if (intent === "what-if-method-signature")
|
|
57772
58358
|
return ["ApexClass"];
|
|
@@ -57891,9 +58477,24 @@ var init_route_question = __esm({
|
|
|
57891
58477
|
]
|
|
57892
58478
|
};
|
|
57893
58479
|
};
|
|
57894
|
-
|
|
58480
|
+
questionAssertsNameMultiplicity = (question) => /\b(?:a\s+few|several|a\s+couple)\s+of\s+(?:these|those|them)\b|\b(?:two|three|four|five|\d+)\s+different\s+(?:things?|ones?|fields?|objects?|components?|versions?)\b|\bmore\s+than\s+one\s+(?:of\s+(?:these|those|them)|with\s+(?:that|this)\s+name)\b|\bwhich\s+one\s+(?:do|should|did)\s+i\b/i.test(question);
|
|
58481
|
+
entityAmbiguityRequiresClarification = (query, resolution, question) => {
|
|
58482
|
+
if (resolution.disposition === "exact" && resolution.candidates.length >= 2 && !/__|\./.test(query)) {
|
|
58483
|
+
const [top2, second2] = resolution.candidates;
|
|
58484
|
+
const sameName = top2 !== void 0 && second2 !== void 0 && top2.matchKind === "exact" && second2.matchKind === "exact" && top2.base === second2.base && top2.apiName.toLowerCase() === second2.apiName.toLowerCase() && top2.parentApiName !== second2.parentApiName;
|
|
58485
|
+
if (sameName) {
|
|
58486
|
+
const promoted = resolveParentQualifier(question ?? "", {
|
|
58487
|
+
...resolution,
|
|
58488
|
+
disposition: "ambiguous"
|
|
58489
|
+
});
|
|
58490
|
+
if (promoted.disposition === "ambiguous")
|
|
58491
|
+
return true;
|
|
58492
|
+
}
|
|
58493
|
+
}
|
|
57895
58494
|
if (resolution.disposition !== "ambiguous" || resolution.candidates.length < 2)
|
|
57896
58495
|
return false;
|
|
58496
|
+
if (question !== void 0 && questionAssertsNameMultiplicity(question))
|
|
58497
|
+
return true;
|
|
57897
58498
|
const normalized = query.toLowerCase();
|
|
57898
58499
|
const literalMatches = resolution.candidates.filter((candidate) => candidate.apiName.toLowerCase() === normalized || candidate.id.toLowerCase().endsWith(`:${normalized}`));
|
|
57899
58500
|
if (literalMatches.length > 1)
|
|
@@ -58136,6 +58737,12 @@ var init_route_question = __esm({
|
|
|
58136
58737
|
return [...cands];
|
|
58137
58738
|
return [second, top, ...cands.slice(2)];
|
|
58138
58739
|
};
|
|
58740
|
+
isCompoundPlaneAsk = (question) => {
|
|
58741
|
+
const liveHalf = /\b(?:actually|really)\s+(?:running|firing|executing|live)\b|\bright\s+now\b|\bin\s+production\b/i;
|
|
58742
|
+
const vaultHalf = /\bwhat\s+(?:breaks?|depends|would\s+break|will\s+break)\b|\bwhat\s+does\b[^.?!]{0,60}\bdo\b|\bschema\b|\bmetadata\b|\bsafe\s+to\s+(?:disable|deactivate|delete|remove)\b|\btell\s+me\s+about\b/i;
|
|
58743
|
+
const conjoined = /\b(?:and|also|plus)\b/i;
|
|
58744
|
+
return liveHalf.test(question) && vaultHalf.test(question) && conjoined.test(question);
|
|
58745
|
+
};
|
|
58139
58746
|
risksDiverge = (a2, b2) => DESTRUCTIVE_TOOL.test(a2.tool) && INFORMATIONAL_IMPACT_TOOL.test(b2.tool) || DESTRUCTIVE_TOOL.test(b2.tool) && INFORMATIONAL_IMPACT_TOOL.test(a2.tool);
|
|
58140
58747
|
marginClarification = (cands, existingClarification) => {
|
|
58141
58748
|
if (existingClarification !== null)
|
|
@@ -58185,6 +58792,7 @@ var init_route_question = __esm({
|
|
|
58185
58792
|
REFUSAL_INTENT = {
|
|
58186
58793
|
"write-imperative": "refused-write",
|
|
58187
58794
|
"injection-exfiltration": "refused-injection",
|
|
58795
|
+
"identity-gap": "honest-gap-identity",
|
|
58188
58796
|
"runtime-analytics": "honest-gap-runtime",
|
|
58189
58797
|
"out-of-scope": "out-of-scope"
|
|
58190
58798
|
};
|
|
@@ -58197,6 +58805,10 @@ var init_route_question = __esm({
|
|
|
58197
58805
|
category: "injection",
|
|
58198
58806
|
note: "prompt-injection/exfiltration shape refused"
|
|
58199
58807
|
},
|
|
58808
|
+
"identity-gap": {
|
|
58809
|
+
category: "identity-gap",
|
|
58810
|
+
note: "first-person capability ask; no session-user identity \u2014 declined with a which-user clarify pointer"
|
|
58811
|
+
},
|
|
58200
58812
|
"runtime-analytics": {
|
|
58201
58813
|
category: "runtime-analytics",
|
|
58202
58814
|
note: "runtime/ops telemetry the product does not model; honest gap disclosed"
|
|
@@ -58470,8 +59082,11 @@ ${renderContextApplied(contextApplied2)}`
|
|
|
58470
59082
|
...entityTypes.length > 0 ? { types: entityTypes } : {}
|
|
58471
59083
|
}) : null;
|
|
58472
59084
|
const glossaryAwareEntityResolution = entityQuery !== null && entityResolution?.ok === true ? await applyGlossaryAliases(ctx, entityQuery, entityTypes, entityResolution.value) : null;
|
|
58473
|
-
|
|
58474
|
-
const entityClarificationRequired = entityQuery !== null && refinedEntityResolution !== null &&
|
|
59085
|
+
let refinedEntityResolution = contextExactResolution ?? (entityQuery !== null && glossaryAwareEntityResolution !== null ? resolveParentQualifier(input2.question, refineEntityResolution(entityQuery, glossaryAwareEntityResolution)) : null);
|
|
59086
|
+
const entityClarificationRequired = entityQuery !== null && refinedEntityResolution !== null && // component-type asks ("is X a flow or a trigger?") are EXEMPT: a
|
|
59087
|
+
// same-name cross-type collision is the ANSWER to that question, not an
|
|
59088
|
+
// obstacle — sfi.resolve enumerates the types and the host explains.
|
|
59089
|
+
route.intent !== "component-type" && entityAmbiguityRequiresClarification(entityQuery, refinedEntityResolution, input2.question);
|
|
58475
59090
|
let entityEvidence = refinedEntityResolution !== null && refinedEntityResolution.disposition !== "none" ? {
|
|
58476
59091
|
query: entityQuery,
|
|
58477
59092
|
typeHints: entityTypes,
|
|
@@ -58536,6 +59151,22 @@ ${renderContextApplied(contextApplied2)}`
|
|
|
58536
59151
|
route = { ...route, confidence: "low", clarification: marginClar };
|
|
58537
59152
|
}
|
|
58538
59153
|
}
|
|
59154
|
+
if (routerMode() === "hybrid" && route.clarification === null && isCompoundPlaneAsk(input2.question)) {
|
|
59155
|
+
const compoundCands = buildFunnelCandidates(route, input2.question, marginRouteToolArgs, input2.mode);
|
|
59156
|
+
const vaultTop = compoundCands.find((candidate) => candidate.plane === "vault");
|
|
59157
|
+
const liveTop = compoundCands.find((candidate) => candidate.plane === "live" || candidate.plane === "hybrid") ?? (/\b(?:running|firing|executing|fired?|ran)\b/i.test(input2.question) ? { tool: "sfi.live_automation_fired" } : void 0);
|
|
59158
|
+
if (vaultTop !== void 0 && liveTop !== void 0) {
|
|
59159
|
+
route = {
|
|
59160
|
+
...route,
|
|
59161
|
+
confidence: "low",
|
|
59162
|
+
clarification: {
|
|
59163
|
+
required: true,
|
|
59164
|
+
question: `This asks for BOTH a vault-metadata answer AND a live-org verification \u2014 \`${vaultTop.tool}\` answers from the offline vault; \`${liveTop.tool}\` queries the org right now and needs the opt-in live plane. Which should lead? (Pick one; the other can run as a follow-up.)`,
|
|
59165
|
+
options: [vaultTop.tool, liveTop.tool]
|
|
59166
|
+
}
|
|
59167
|
+
};
|
|
59168
|
+
}
|
|
59169
|
+
}
|
|
58539
59170
|
let premiseFlagged = false;
|
|
58540
59171
|
if (entityQuery !== null && refinedEntityResolution !== null && refinedEntityResolution.disposition === "none") {
|
|
58541
59172
|
const bareQuery = entityQuery.replace(/^(?:the|a|an)\s+/i, "").replace(/\s+(?:class(?:es)?|trigger(?:s)?|field(?:s)?|object(?:s)?|flow(?:s)?|component(?:s)?|layout(?:s)?|profile(?:s)?|report(?:s)?|dashboard(?:s)?|rule(?:s)?)$/i, "");
|
|
@@ -58544,7 +59175,43 @@ ${renderContextApplied(contextApplied2)}`
|
|
|
58544
59175
|
...entityTypes.length > 0 ? { types: entityTypes } : {}
|
|
58545
59176
|
}) : null;
|
|
58546
59177
|
const bareResolution = bareRetry?.ok === true && bareRetry.value.disposition !== "none" ? bareRetry.value : null;
|
|
58547
|
-
|
|
59178
|
+
let crossTypeResolution = null;
|
|
59179
|
+
if (bareResolution === null && entityTypes.length > 0) {
|
|
59180
|
+
const unscopedQuery = bareQuery.length > 0 ? bareQuery : entityQuery;
|
|
59181
|
+
const unscopedRetry = await resolveComponents(ctx.graph, unscopedQuery, { limit: 5 });
|
|
59182
|
+
if (unscopedRetry.ok && unscopedRetry.value.disposition !== "none" && (unscopedRetry.value.candidates[0]?.base ?? 0) >= 0.9) {
|
|
59183
|
+
crossTypeResolution = unscopedRetry.value;
|
|
59184
|
+
}
|
|
59185
|
+
}
|
|
59186
|
+
if (crossTypeResolution !== null) {
|
|
59187
|
+
const real = crossTypeResolution.candidates[0];
|
|
59188
|
+
const statedTypes = entityTypes.join("/");
|
|
59189
|
+
const typeWarning = `TYPE CHECK: no ${statedTypes} named '${entityQuery}' exists in the vault, but the name matches ${real.id} (a ${real.type}). The question's stated component type appears to be wrong \u2014 answer about the component that actually exists, and say so.`;
|
|
59190
|
+
route = {
|
|
59191
|
+
...route,
|
|
59192
|
+
confidence: "low",
|
|
59193
|
+
reason: `${route.reason} ${typeWarning}`
|
|
59194
|
+
};
|
|
59195
|
+
refinedEntityResolution = crossTypeResolution;
|
|
59196
|
+
entityEvidence = {
|
|
59197
|
+
query: entityQuery,
|
|
59198
|
+
typeHints: entityTypes,
|
|
59199
|
+
disposition: crossTypeResolution.disposition,
|
|
59200
|
+
clarificationRequired: false,
|
|
59201
|
+
warning: typeWarning,
|
|
59202
|
+
candidates: crossTypeResolution.candidates.slice(0, 5).map((candidate) => ({
|
|
59203
|
+
componentId: candidate.id,
|
|
59204
|
+
type: candidate.type,
|
|
59205
|
+
apiName: candidate.apiName,
|
|
59206
|
+
label: candidate.label,
|
|
59207
|
+
parentApiName: candidate.parentApiName,
|
|
59208
|
+
score: candidate.score,
|
|
59209
|
+
base: candidate.base,
|
|
59210
|
+
matchKind: candidate.matchKind,
|
|
59211
|
+
evidence: candidate.evidence
|
|
59212
|
+
}))
|
|
59213
|
+
};
|
|
59214
|
+
} else if (bareResolution !== null) {
|
|
58548
59215
|
entityEvidence = {
|
|
58549
59216
|
query: bareQuery,
|
|
58550
59217
|
typeHints: entityTypes,
|
|
@@ -58563,7 +59230,7 @@ ${renderContextApplied(contextApplied2)}`
|
|
|
58563
59230
|
evidence: candidate.evidence
|
|
58564
59231
|
}))
|
|
58565
59232
|
};
|
|
58566
|
-
} else {
|
|
59233
|
+
} else if (looksLikeComponentName(entityQuery)) {
|
|
58567
59234
|
premiseFlagged = true;
|
|
58568
59235
|
const premiseWarning = `PREMISE CHECK: no component matching '${entityQuery}' exists in the vault \u2014 verify the name (a typo, or metadata newer than the last refresh; /sfi-refresh may help). The routed tool fails closed on an unknown component; do not present its error as an answer about a real component.`;
|
|
58569
59236
|
route = {
|
|
@@ -58579,6 +59246,15 @@ ${renderContextApplied(contextApplied2)}`
|
|
|
58579
59246
|
warning: premiseWarning,
|
|
58580
59247
|
candidates: []
|
|
58581
59248
|
};
|
|
59249
|
+
} else {
|
|
59250
|
+
entityEvidence = {
|
|
59251
|
+
query: entityQuery,
|
|
59252
|
+
typeHints: entityTypes,
|
|
59253
|
+
disposition: "none",
|
|
59254
|
+
clarificationRequired: false,
|
|
59255
|
+
warning: null,
|
|
59256
|
+
candidates: []
|
|
59257
|
+
};
|
|
58582
59258
|
}
|
|
58583
59259
|
} else if (entityQuery !== null && refinedEntityResolution !== null && refinedEntityResolution.disposition === "ambiguous" && (/__(?:c|mdt|e|x|b|kav)\b/i.test(entityQuery) || entityQuery.includes(".")) && !refinedEntityResolution.candidates.some((candidate) => candidate.apiName.toLowerCase() === entityQuery.toLowerCase() || candidate.id.toLowerCase().endsWith(`:${entityQuery.toLowerCase()}`))) {
|
|
58584
59260
|
premiseFlagged = true;
|
|
@@ -58609,11 +59285,77 @@ ${renderContextApplied(contextApplied2)}`
|
|
|
58609
59285
|
candidates: []
|
|
58610
59286
|
};
|
|
58611
59287
|
}
|
|
59288
|
+
if (!premiseFlagged && entityQuery === null && route.clarification === null && route.intent !== "empty" && route.intent !== "component-lookup") {
|
|
59289
|
+
const probeToken = extractExistenceProbeToken(input2.question);
|
|
59290
|
+
if (probeToken !== null) {
|
|
59291
|
+
const probe = await resolveComponents(ctx.graph, probeToken, { limit: 5 });
|
|
59292
|
+
if (probe.ok) {
|
|
59293
|
+
const lowered = probeToken.toLowerCase();
|
|
59294
|
+
const loose = normLiteral(probeToken);
|
|
59295
|
+
const literalHit = probe.value.candidates.some((candidate) => candidate.apiName.toLowerCase() === lowered || candidate.id.toLowerCase().endsWith(`:${lowered}`) || normLiteral(candidate.apiName) === loose);
|
|
59296
|
+
if (probe.value.disposition === "none" || !literalHit) {
|
|
59297
|
+
premiseFlagged = true;
|
|
59298
|
+
const premiseWarning = `PREMISE CHECK: no component named '${probeToken}' exists in the vault \u2014 any listed candidates are fuzzy lookalikes, not the component you named. Verify the name (a typo, or metadata newer than the last refresh; /sfi-refresh may help). The routed tool fails closed on an unknown component; do not present its error as an answer about a real component.`;
|
|
59299
|
+
route = {
|
|
59300
|
+
...route,
|
|
59301
|
+
confidence: "low",
|
|
59302
|
+
reason: `${route.reason} ${premiseWarning}`
|
|
59303
|
+
};
|
|
59304
|
+
entityEvidence = {
|
|
59305
|
+
query: probeToken,
|
|
59306
|
+
typeHints: [],
|
|
59307
|
+
disposition: "none",
|
|
59308
|
+
clarificationRequired: false,
|
|
59309
|
+
warning: premiseWarning,
|
|
59310
|
+
candidates: probe.value.candidates.slice(0, 5).map((candidate) => ({
|
|
59311
|
+
componentId: candidate.id,
|
|
59312
|
+
type: candidate.type,
|
|
59313
|
+
apiName: candidate.apiName,
|
|
59314
|
+
label: candidate.label,
|
|
59315
|
+
parentApiName: candidate.parentApiName,
|
|
59316
|
+
score: candidate.score,
|
|
59317
|
+
base: candidate.base,
|
|
59318
|
+
matchKind: candidate.matchKind,
|
|
59319
|
+
evidence: candidate.evidence
|
|
59320
|
+
}))
|
|
59321
|
+
};
|
|
59322
|
+
}
|
|
59323
|
+
}
|
|
59324
|
+
}
|
|
59325
|
+
}
|
|
58612
59326
|
let contextRouteApplied = null;
|
|
58613
59327
|
if (validatedContext !== null && route.clarification === null && !premiseFlagged) {
|
|
58614
59328
|
const previous = validatedContext.previous;
|
|
58615
59329
|
const stillUnrouted = route.intent === "unrouted" && route.plane === "unknown";
|
|
58616
|
-
const
|
|
59330
|
+
const gapFollowUpFamily = stillUnrouted ? detectGapShapedFollowUp(input2.question) : null;
|
|
59331
|
+
if (gapFollowUpFamily !== null) {
|
|
59332
|
+
const gapDescription = {
|
|
59333
|
+
judgment: "a normative judgment (should/normal/risky) \u2014 sf-intelligence reads org metadata and has no opinion to offer",
|
|
59334
|
+
delivery: "file export or message delivery, which the product does not perform",
|
|
59335
|
+
"tool-self-capability": "the product's own capability boundary \u2014 sfi.capabilities answers what is and is not built",
|
|
59336
|
+
"deployment-status": "deployment/pending-change status, runtime telemetry the vault does not model"
|
|
59337
|
+
};
|
|
59338
|
+
const carried = previous.componentId !== void 0 ? ` The component carried from the previous turn (${previous.componentId}) was noted but the previous tool was NOT inherited \u2014 inheriting it would execute a read that cannot answer this ask.` : "";
|
|
59339
|
+
route = {
|
|
59340
|
+
question: input2.question,
|
|
59341
|
+
plane: "unknown",
|
|
59342
|
+
intent: "context-gap-followup",
|
|
59343
|
+
tools: [],
|
|
59344
|
+
liveRequired: false,
|
|
59345
|
+
needsResolve: false,
|
|
59346
|
+
reason: `HONEST GAP (context follow-up): this follow-up asks for ${gapDescription[gapFollowUpFamily] ?? gapFollowUpFamily}.${carried}`,
|
|
59347
|
+
gap: {
|
|
59348
|
+
category: "context-gap-followup",
|
|
59349
|
+
note: `gap-shaped follow-up (${gapFollowUpFamily}); context continuation suppressed rather than inheriting the previous tool`
|
|
59350
|
+
},
|
|
59351
|
+
confidence: "high",
|
|
59352
|
+
risk: "informational",
|
|
59353
|
+
alternatives: [],
|
|
59354
|
+
clarification: null,
|
|
59355
|
+
plan: []
|
|
59356
|
+
};
|
|
59357
|
+
}
|
|
59358
|
+
const reparamAnchor = gapFollowUpFamily !== null ? null : detectReparamAnchor(input2.question);
|
|
58617
59359
|
const ownRouteWeak = stillUnrouted || GENERIC_SCHEMA_INTENTS.has(route.intent) && route.confidence !== "high";
|
|
58618
59360
|
if (reparamAnchor !== null && ownRouteWeak && previous.tool !== void 0) {
|
|
58619
59361
|
let target = contextSubstitution === null && refinedEntityResolution?.disposition === "exact" ? refinedEntityResolution.candidates[0] : null;
|
|
@@ -58677,7 +59419,9 @@ ${renderContextApplied(contextApplied2)}`
|
|
|
58677
59419
|
}
|
|
58678
59420
|
}
|
|
58679
59421
|
let advisoryCandidates = null;
|
|
58680
|
-
|
|
59422
|
+
const questionHead = input2.question.trim().split(/\s+/).slice(0, 5).join(" ");
|
|
59423
|
+
const anaphorOnlyFragment = validatedContext === null && detectPronounAnchor(questionHead) !== null && (entityQuery === null || isAnaphorOnly(entityQuery));
|
|
59424
|
+
if (route.intent === "unrouted" && route.plane === "unknown" && route.clarification === null && !premiseFlagged && !anaphorOnlyFragment) {
|
|
58681
59425
|
const cands = buildFunnelCandidates(route, input2.question, marginRouteToolArgs, input2.mode);
|
|
58682
59426
|
advisoryCandidates = cands;
|
|
58683
59427
|
const resolvedExact = refinedEntityResolution?.disposition === "exact" ? refinedEntityResolution.candidates[0] : void 0;
|
|
@@ -72446,7 +73190,7 @@ var init_package_version = __esm({
|
|
|
72446
73190
|
"use strict";
|
|
72447
73191
|
readCliPackageVersion = () => {
|
|
72448
73192
|
if (true)
|
|
72449
|
-
return "0.1.
|
|
73193
|
+
return "0.1.23";
|
|
72450
73194
|
for (const rel of ["../package.json", "../../package.json"]) {
|
|
72451
73195
|
try {
|
|
72452
73196
|
const raw = readFileSync3(fileURLToPath(new URL(rel, import.meta.url)), "utf8");
|
|
@@ -142370,7 +143114,7 @@ var makeShutdownOnce = (ctx) => {
|
|
|
142370
143114
|
|
|
142371
143115
|
// dist/src/commands/demo.js
|
|
142372
143116
|
init_refresh();
|
|
142373
|
-
var buildVersion = () => true ? "0.1.
|
|
143117
|
+
var buildVersion = () => true ? "0.1.23" : "dev";
|
|
142374
143118
|
var SHUTDOWN_SIGNALS2 = ["SIGINT", "SIGTERM"];
|
|
142375
143119
|
var resolveDemoSource = () => {
|
|
142376
143120
|
let dir = dirname21(fileURLToPath2(import.meta.url));
|
|
@@ -143355,7 +144099,7 @@ init_vault_git();
|
|
|
143355
144099
|
init_watch();
|
|
143356
144100
|
var readVersion = () => {
|
|
143357
144101
|
if (true)
|
|
143358
|
-
return "0.1.
|
|
144102
|
+
return "0.1.23";
|
|
143359
144103
|
const pkgUrl = new URL("../../package.json", import.meta.url);
|
|
143360
144104
|
const raw = readFileSync6(fileURLToPath3(pkgUrl), "utf8");
|
|
143361
144105
|
const parsed = JSON.parse(raw);
|