sf-intelligence 0.1.16 → 0.1.18

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 CHANGED
@@ -25194,7 +25194,7 @@ var init_intent_router = __esm({
25194
25194
  reason: "What happens when {Object}.{field} becomes {value} \u2014 the automation coupled to a value/stage transition, from the vault (lifecycle_process).",
25195
25195
  patterns: [
25196
25196
  /\bwhat\s+happens\s+when\b.*\b(becomes?|turns?|changes?\s+to|is\s+set\s+to|reaches?)\b/,
25197
- /\bwhat\s+happens\s+when\b.*\b(closed\s+won|closed\s+lost|converted|approved|activated)\b/,
25197
+ /\bwhat\s+(?:happens|runs|fires)\s+when\b.*\b(closed\s+won|closed\s+lost|converted|approved|activated)\b/,
25198
25198
  /\b(value.?coupl\w*|coupled)\b.*\b(StageName|Closed Won|stage|transition)\b/,
25199
25199
  /\bStageName\b.*\b(Closed Won|closed won|transition)\b/,
25200
25200
  /\bClosed Won\b.*\b(automation|flow|trigger|coupl)\b/
@@ -49412,7 +49412,8 @@ var init_lifecycle_process = __esm({
49412
49412
  const disclosures = [
49413
49413
  `Composed from the documented order of execution for the ${event} event \u2014 conditions are LISTED but NOT EVALUATED; whether a given record actually matches ${field !== null && value !== null ? `${field} = "${value}"` : "the transition"} needs record data.`,
49414
49414
  "Value coupling is a literal match of the value over the parsed condition expression \u2014 it can miss a value encoded in a formula and can over-match a substring. Field coupling uses the condition\u2019s extracted field references.",
49415
- "This is the metadata automation chain. It does not include manual user actions, the runtime field-history / audit trail, roll-up / cross-object parent recalculation, or external callouts."
49415
+ "This is the metadata automation chain. It does not include manual user actions, the runtime field-history / audit trail, roll-up / cross-object parent recalculation, or external callouts.",
49416
+ "Distinct record ACTIONS \u2014 Lead Convert (IsConverted), Approval submission, and Activation \u2014 are not plain field edits and are not modeled as save-order steps: their action-specific automation (for Lead Convert, the Convert field mapping, matching / duplicate rules, and any managed-package auto-convert; for approval / activation, the approval or activation process itself) is outside this insert/update view. Treat a conversion / approval / activation answer as the save-time slice only, not the whole operation."
49416
49417
  ];
49417
49418
  if (field === null || value === null) {
49418
49419
  disclosures.push('No specific value transition supplied \u2014 showing the full automation chain. Pass `field` + `value` (e.g. field="StageName", value="Closed Won") to highlight the automation coupled to that transition.');
@@ -57375,6 +57376,7 @@ var init_synthesize_answer = __esm({
57375
57376
  let ungroundedAnnotationClaims;
57376
57377
  let grounded;
57377
57378
  let ungroundedAbsenceClaims;
57379
+ const evidenceEmpty = source === void 0 || source === null || typeof source === "string" && source.trim().length === 0 || Array.isArray(source) && source.length === 0 || typeof source === "object" && !Array.isArray(source) && Object.keys(source).length === 0;
57378
57380
  if (input2.draft !== void 0) {
57379
57381
  const draftIds = [...new Set(input2.draft.match(CANONICAL_ID_INLINE) ?? [])];
57380
57382
  groundedIds = draftIds.filter((id) => out.ids.has(id)).sort();
@@ -57384,6 +57386,10 @@ var init_synthesize_answer = __esm({
57384
57386
  const absenceClaims = findAbsenceClaims(input2.draft);
57385
57387
  ungroundedAbsenceClaims = out.coverageIncomplete ? absenceClaims : [];
57386
57388
  grounded = ungroundedAbsenceClaims.length === 0;
57389
+ if (evidenceEmpty) {
57390
+ grounded = false;
57391
+ out.caveats.unshift("GROUNDING NOT VERIFIED: no evidence was supplied in `input`, so the draft was not checked against any tool output. Do NOT present it as grounded \u2014 pass the prior sfi.* tool result(s) as `input` and retry.");
57392
+ }
57387
57393
  }
57388
57394
  const qPrefix = input2.question !== void 0 && input2.question.trim().length > 0 ? `Q: ${input2.question.trim()} \u2014 ` : "";
57389
57395
  const summary = `${qPrefix}Grounded in the supplied tool output: ${citations.length} component(s) cited, ${out.bullets.length} key fact(s), ${out.caveats.length} caveat(s)` + (hallucinatedIds !== void 0 ? `, ${hallucinatedIds.length} ungrounded id(s) in the draft` : "") + // I3c: only appended when a draft is present AND the guard fired, so the
@@ -65081,7 +65087,7 @@ var init_tools = __esm({
65081
65087
  },
65082
65088
  {
65083
65089
  name: "sfi.synthesize_answer",
65084
- description: "Answer-layer grounding pass: turns the JSON returned by prior sfi.* tool call(s) into a structured, citation-grounded answer skeleton \u2014 `summary`, `bullets` (headline facts extracted from the input), `citations` (ONLY canonical ids present in the input, parsed to type + apiName), and `caveats` (honesty/limitation strings carried verbatim; an input reduced by the global response byte budget \u2014 a `responseBudget` truncation block \u2014 becomes an explicit caveat with the dropped/trimmed counts, so a synthesis over truncated data never reads absence as evidence). It also returns a grounded `evidence` skeleton \u2014 `finding` \u2192 `evidence` (the cited ids) \u2192 `likelyCause` \u2192 `recommendedFix` \u2192 `risk` \u2192 `nextAction` \u2014 where every field is lifted VERBATIM from the source tool output (a `reason`/`recommendation`/`nextStep`/caveat field) and is `null` when the source carried nothing for it, so the recommended action is never fabricated; `nextAction` falls back to the recommended fix, and `orphanComponentIds` flags any id mentioned inside a cause/fix/next string that is not independently cited (an ungrounded reference). Pass the source tool output as `input` (any JSON), optionally the user `question` (echoed into the summary), and optionally a `draft` narrative \u2014 when given, `hallucinatedIds` lists canonical ids in the draft that do NOT appear in the source so they can be removed before answering. `provenance` rolls the source output(s) trust provenance up into `{ stamp, sources }` (`offline_snapshot` / `live_org` / `hybrid` when the input fuses both / `mixed` / `null`) so the host can stamp where the answer came from and never let a vault claim read as a live one. Pure transform: reads ONLY `input`, never the graph or live org, so it can never add a fact it was not handed. Prose wording stays with the caller; this guarantees grounding, not sentences.",
65090
+ description: "Answer-layer grounding pass: turns the JSON returned by prior sfi.* tool call(s) into a structured, citation-grounded answer skeleton \u2014 `summary`, `bullets` (headline facts extracted from the input), `citations` (ONLY canonical ids present in the input, parsed to type + apiName), and `caveats` (honesty/limitation strings carried verbatim; an input reduced by the global response byte budget \u2014 a `responseBudget` truncation block \u2014 becomes an explicit caveat with the dropped/trimmed counts, so a synthesis over truncated data never reads absence as evidence). It also returns a grounded `evidence` skeleton \u2014 `finding` \u2192 `evidence` (the cited ids) \u2192 `likelyCause` \u2192 `recommendedFix` \u2192 `risk` \u2192 `nextAction` \u2014 where every field is lifted VERBATIM from the source tool output (a `reason`/`recommendation`/`nextStep`/caveat field) and is `null` when the source carried nothing for it, so the recommended action is never fabricated; `nextAction` falls back to the recommended fix, and `orphanComponentIds` flags any id mentioned inside a cause/fix/next string that is not independently cited (an ungrounded reference). Pass the source tool output as `input` (any JSON), optionally the user `question` (echoed into the summary), and optionally a `draft` narrative \u2014 when given, `hallucinatedIds` lists canonical ids in the draft that do NOT appear in the source so they can be removed before answering. A `draft` supplied with an empty or missing `input` FAILS CLOSED to `grounded: false` with a caveat \u2014 grounding is never rubber-stamped when there is no evidence to check the draft against. `provenance` rolls the source output(s) trust provenance up into `{ stamp, sources }` (`offline_snapshot` / `live_org` / `hybrid` when the input fuses both / `mixed` / `null`) so the host can stamp where the answer came from and never let a vault claim read as a live one. Pure transform: reads ONLY `input`, never the graph or live org, so it can never add a fact it was not handed. Prose wording stays with the caller; this guarantees grounding, not sentences.",
65085
65091
  inputSchema: SYNTHESIZE_ANSWER_INPUT_SCHEMA
65086
65092
  },
65087
65093
  {
@@ -68015,7 +68021,7 @@ var init_package_version = __esm({
68015
68021
  "use strict";
68016
68022
  readCliPackageVersion = () => {
68017
68023
  if (true)
68018
- return "0.1.16";
68024
+ return "0.1.18";
68019
68025
  for (const rel of ["../package.json", "../../package.json"]) {
68020
68026
  try {
68021
68027
  const raw = readFileSync3(fileURLToPath(new URL(rel, import.meta.url)), "utf8");
@@ -137915,7 +137921,7 @@ var makeShutdownOnce = (ctx) => {
137915
137921
 
137916
137922
  // dist/src/commands/demo.js
137917
137923
  init_refresh();
137918
- var buildVersion = () => true ? "0.1.16" : "dev";
137924
+ var buildVersion = () => true ? "0.1.18" : "dev";
137919
137925
  var SHUTDOWN_SIGNALS2 = ["SIGINT", "SIGTERM"];
137920
137926
  var resolveDemoSource = () => {
137921
137927
  let dir = dirname21(fileURLToPath2(import.meta.url));
@@ -138889,7 +138895,7 @@ init_vault_git();
138889
138895
  init_watch();
138890
138896
  var readVersion = () => {
138891
138897
  if (true)
138892
- return "0.1.16";
138898
+ return "0.1.18";
138893
138899
  const pkgUrl = new URL("../../package.json", import.meta.url);
138894
138900
  const raw = readFileSync6(fileURLToPath3(pkgUrl), "utf8");
138895
138901
  const parsed = JSON.parse(raw);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sf-intelligence",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Offline-first, MCP-first knowledge base for a Salesforce org. Ask about your org's metadata, dependencies, permissions, and automation — grounded in real retrieved metadata. Ships the sfi CLI and an MCP server.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://salesforce-intelligence.pages.dev",
@@ -66,16 +66,16 @@
66
66
  "devDependencies": {
67
67
  "esbuild": "^0.28.0",
68
68
  "vitest": "^1.6.0",
69
+ "@sf-intelligence/contracts": "0.1.0",
69
70
  "@sf-intelligence/extractors": "0.1.0",
70
- "@sf-intelligence/graph": "0.1.0",
71
- "@sf-intelligence/parsers": "0.1.0",
72
- "@sf-intelligence/core": "0.1.0",
71
+ "@sf-intelligence/mcp": "0.1.0",
73
72
  "@sf-intelligence/patterns": "0.1.0",
74
73
  "@sf-intelligence/renderers": "0.1.0",
74
+ "@sf-intelligence/core": "0.1.0",
75
75
  "@sf-intelligence/tooling-api": "0.1.0",
76
76
  "@sf-intelligence/vault": "0.1.0",
77
- "@sf-intelligence/mcp": "0.1.0",
78
- "@sf-intelligence/contracts": "0.1.0"
77
+ "@sf-intelligence/graph": "0.1.0",
78
+ "@sf-intelligence/parsers": "0.1.0"
79
79
  },
80
80
  "scripts": {
81
81
  "build": "tsc --build && node build.mjs",
package/server.json CHANGED
@@ -7,13 +7,13 @@
7
7
  "url": "https://github.com/PranavNagrecha/Salesforce-Intelligence",
8
8
  "source": "github"
9
9
  },
10
- "version": "0.1.16",
10
+ "version": "0.1.18",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "registryBaseUrl": "https://registry.npmjs.org",
15
15
  "identifier": "sf-intelligence",
16
- "version": "0.1.16",
16
+ "version": "0.1.18",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  },