sf-intelligence 0.1.12 → 0.1.13

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.
Files changed (123) hide show
  1. package/LICENSE +20 -13
  2. package/demo-source/main/default/approvalProcesses/Project__c.Discount_Approval.approvalProcess-meta.xml +31 -0
  3. package/demo-source/main/default/classes/IncentiveBatch.cls +54 -0
  4. package/demo-source/main/default/classes/IncentiveBatch.cls-meta.xml +5 -0
  5. package/demo-source/main/default/classes/PaymentService.cls +44 -0
  6. package/demo-source/main/default/classes/PaymentService.cls-meta.xml +5 -0
  7. package/demo-source/main/default/classes/PaymentServiceTest.cls +57 -0
  8. package/demo-source/main/default/classes/PaymentServiceTest.cls-meta.xml +5 -0
  9. package/demo-source/main/default/classes/ProjectTriggerHandler.cls +60 -0
  10. package/demo-source/main/default/classes/ProjectTriggerHandler.cls-meta.xml +5 -0
  11. package/demo-source/main/default/classes/ProjectTriggerHandlerTest.cls +80 -0
  12. package/demo-source/main/default/classes/ProjectTriggerHandlerTest.cls-meta.xml +5 -0
  13. package/demo-source/main/default/flows/Installation_On_Complete.flow-meta.xml +72 -0
  14. package/demo-source/main/default/flows/Project_On_Approve.flow-meta.xml +48 -0
  15. package/demo-source/main/default/groups/Finance_Group.group-meta.xml +7 -0
  16. package/demo-source/main/default/groups/Ops_Group.group-meta.xml +7 -0
  17. package/demo-source/main/default/layouts/Installation__c-Installation Layout.layout-meta.xml +43 -0
  18. package/demo-source/main/default/layouts/Project__c-Residential Layout.layout-meta.xml +78 -0
  19. package/demo-source/main/default/objects/Battery__c/Battery__c.object-meta.xml +12 -0
  20. package/demo-source/main/default/objects/Battery__c/fields/Capacity_kWh__c.field-meta.xml +9 -0
  21. package/demo-source/main/default/objects/Battery__c/fields/Manufacturer__c.field-meta.xml +21 -0
  22. package/demo-source/main/default/objects/Battery__c/fields/Unit_Cost__c.field-meta.xml +9 -0
  23. package/demo-source/main/default/objects/Equipment_Allocation__c/Equipment_Allocation__c.object-meta.xml +13 -0
  24. package/demo-source/main/default/objects/Equipment_Allocation__c/fields/Battery__c.field-meta.xml +10 -0
  25. package/demo-source/main/default/objects/Equipment_Allocation__c/fields/Line_Total__c.field-meta.xml +10 -0
  26. package/demo-source/main/default/objects/Equipment_Allocation__c/fields/Project__c.field-meta.xml +14 -0
  27. package/demo-source/main/default/objects/Equipment_Allocation__c/fields/Quantity__c.field-meta.xml +9 -0
  28. package/demo-source/main/default/objects/Equipment_Allocation__c/fields/Solar_Panel__c.field-meta.xml +10 -0
  29. package/demo-source/main/default/objects/Incentive__c/Incentive__c.object-meta.xml +12 -0
  30. package/demo-source/main/default/objects/Incentive__c/fields/Amount__c.field-meta.xml +9 -0
  31. package/demo-source/main/default/objects/Incentive__c/fields/Approved__c.field-meta.xml +7 -0
  32. package/demo-source/main/default/objects/Incentive__c/fields/Project__c.field-meta.xml +10 -0
  33. package/demo-source/main/default/objects/Incentive__c/fields/Type__c.field-meta.xml +26 -0
  34. package/demo-source/main/default/objects/Installation__c/Installation__c.object-meta.xml +12 -0
  35. package/demo-source/main/default/objects/Installation__c/fields/Crew_Lead__c.field-meta.xml +10 -0
  36. package/demo-source/main/default/objects/Installation__c/fields/Install_Date__c.field-meta.xml +7 -0
  37. package/demo-source/main/default/objects/Installation__c/fields/Panels_Installed__c.field-meta.xml +9 -0
  38. package/demo-source/main/default/objects/Installation__c/fields/Project__c.field-meta.xml +10 -0
  39. package/demo-source/main/default/objects/Installation__c/fields/Status__c.field-meta.xml +31 -0
  40. package/demo-source/main/default/objects/Invoice__c/Invoice__c.object-meta.xml +17 -0
  41. package/demo-source/main/default/objects/Invoice__c/fields/Amount__c.field-meta.xml +12 -0
  42. package/demo-source/main/default/objects/Invoice__c/fields/Balance__c.field-meta.xml +14 -0
  43. package/demo-source/main/default/objects/Invoice__c/fields/Due_Date__c.field-meta.xml +10 -0
  44. package/demo-source/main/default/objects/Invoice__c/fields/Project__c.field-meta.xml +14 -0
  45. package/demo-source/main/default/objects/Invoice__c/fields/Status__c.field-meta.xml +36 -0
  46. package/demo-source/main/default/objects/Invoice__c/fields/Total_Paid__c.field-meta.xml +12 -0
  47. package/demo-source/main/default/objects/Payment__c/Payment__c.object-meta.xml +17 -0
  48. package/demo-source/main/default/objects/Payment__c/fields/Amount__c.field-meta.xml +12 -0
  49. package/demo-source/main/default/objects/Payment__c/fields/Invoice__c.field-meta.xml +14 -0
  50. package/demo-source/main/default/objects/Payment__c/fields/Method__c.field-meta.xml +36 -0
  51. package/demo-source/main/default/objects/Payment__c/fields/Payment_Date__c.field-meta.xml +10 -0
  52. package/demo-source/main/default/objects/Payment__c/validationRules/Amount_Positive.validationRule-meta.xml +9 -0
  53. package/demo-source/main/default/objects/Permit__c/Permit__c.object-meta.xml +12 -0
  54. package/demo-source/main/default/objects/Permit__c/fields/Approved_Date__c.field-meta.xml +7 -0
  55. package/demo-source/main/default/objects/Permit__c/fields/Jurisdiction__c.field-meta.xml +8 -0
  56. package/demo-source/main/default/objects/Permit__c/fields/Project__c.field-meta.xml +10 -0
  57. package/demo-source/main/default/objects/Permit__c/fields/Status__c.field-meta.xml +26 -0
  58. package/demo-source/main/default/objects/Permit__c/fields/Submitted_Date__c.field-meta.xml +7 -0
  59. package/demo-source/main/default/objects/Permit__c/validationRules/Approved_Needs_Date.validationRule-meta.xml +9 -0
  60. package/demo-source/main/default/objects/Project__c/Project__c.object-meta.xml +12 -0
  61. package/demo-source/main/default/objects/Project__c/fields/Account__c.field-meta.xml +10 -0
  62. package/demo-source/main/default/objects/Project__c/fields/Contract_Value__c.field-meta.xml +9 -0
  63. package/demo-source/main/default/objects/Project__c/fields/Expected_Completion__c.field-meta.xml +7 -0
  64. package/demo-source/main/default/objects/Project__c/fields/Is_Complete__c.field-meta.xml +8 -0
  65. package/demo-source/main/default/objects/Project__c/fields/Margin_Percent__c.field-meta.xml +10 -0
  66. package/demo-source/main/default/objects/Project__c/fields/Opportunity__c.field-meta.xml +10 -0
  67. package/demo-source/main/default/objects/Project__c/fields/Permit_Approved__c.field-meta.xml +7 -0
  68. package/demo-source/main/default/objects/Project__c/fields/Risk_Score__c.field-meta.xml +9 -0
  69. package/demo-source/main/default/objects/Project__c/fields/Status__c.field-meta.xml +41 -0
  70. package/demo-source/main/default/objects/Project__c/fields/System_Size_kW__c.field-meta.xml +9 -0
  71. package/demo-source/main/default/objects/Project__c/fields/Total_Invoiced__c.field-meta.xml +9 -0
  72. package/demo-source/main/default/objects/Project__c/recordTypes/Commercial.recordType-meta.xml +6 -0
  73. package/demo-source/main/default/objects/Project__c/recordTypes/Residential.recordType-meta.xml +6 -0
  74. package/demo-source/main/default/objects/Project__c/validationRules/Complete_Requires_Permit.validationRule-meta.xml +9 -0
  75. package/demo-source/main/default/objects/SBQQ__ProductRule__c/SBQQ__ProductRule__c.object-meta.xml +16 -0
  76. package/demo-source/main/default/objects/SBQQ__ProductRule__c/fields/SBQQ__ErrorMessage__c.field-meta.xml +12 -0
  77. package/demo-source/main/default/objects/SBQQ__ProductRule__c/fields/SBQQ__Type__c.field-meta.xml +12 -0
  78. package/demo-source/main/default/objects/Service_Visit__c/Service_Visit__c.object-meta.xml +17 -0
  79. package/demo-source/main/default/objects/Service_Visit__c/fields/Installation__c.field-meta.xml +13 -0
  80. package/demo-source/main/default/objects/Service_Visit__c/fields/Reason__c.field-meta.xml +36 -0
  81. package/demo-source/main/default/objects/Service_Visit__c/fields/Resolved__c.field-meta.xml +10 -0
  82. package/demo-source/main/default/objects/Service_Visit__c/fields/Technician__c.field-meta.xml +13 -0
  83. package/demo-source/main/default/objects/Service_Visit__c/fields/Visit_Date__c.field-meta.xml +10 -0
  84. package/demo-source/main/default/objects/Site_Survey__c/Site_Survey__c.object-meta.xml +12 -0
  85. package/demo-source/main/default/objects/Site_Survey__c/fields/Project__c.field-meta.xml +10 -0
  86. package/demo-source/main/default/objects/Site_Survey__c/fields/Roof_Type__c.field-meta.xml +31 -0
  87. package/demo-source/main/default/objects/Site_Survey__c/fields/Shading_Factor__c.field-meta.xml +9 -0
  88. package/demo-source/main/default/objects/Site_Survey__c/fields/Survey_Date__c.field-meta.xml +7 -0
  89. package/demo-source/main/default/objects/Site_Survey__c/fields/Surveyor__c.field-meta.xml +10 -0
  90. package/demo-source/main/default/objects/Solar_Panel__c/Solar_Panel__c.object-meta.xml +12 -0
  91. package/demo-source/main/default/objects/Solar_Panel__c/fields/Active__c.field-meta.xml +7 -0
  92. package/demo-source/main/default/objects/Solar_Panel__c/fields/Manufacturer__c.field-meta.xml +26 -0
  93. package/demo-source/main/default/objects/Solar_Panel__c/fields/Unit_Cost__c.field-meta.xml +9 -0
  94. package/demo-source/main/default/objects/Solar_Panel__c/fields/Wattage__c.field-meta.xml +9 -0
  95. package/demo-source/main/default/objects/Warranty_Claim__c/Warranty_Claim__c.object-meta.xml +17 -0
  96. package/demo-source/main/default/objects/Warranty_Claim__c/fields/Claim_Date__c.field-meta.xml +10 -0
  97. package/demo-source/main/default/objects/Warranty_Claim__c/fields/Installation__c.field-meta.xml +13 -0
  98. package/demo-source/main/default/objects/Warranty_Claim__c/fields/Issue__c.field-meta.xml +12 -0
  99. package/demo-source/main/default/objects/Warranty_Claim__c/fields/Status__c.field-meta.xml +36 -0
  100. package/demo-source/main/default/omniDataTransforms/Quote_To_Project_Map_1.rpt-meta.xml +83 -0
  101. package/demo-source/main/default/omniIntegrationProcedures/Project_Provision_1.oip-meta.xml +87 -0
  102. package/demo-source/main/default/omniScripts/Customer_Intake_English_1.os-meta.xml +69 -0
  103. package/demo-source/main/default/permissionsets/Finance_Team.permissionset-meta.xml +77 -0
  104. package/demo-source/main/default/permissionsets/Project_Manager.permissionset-meta.xml +88 -0
  105. package/demo-source/main/default/profiles/Verdant_Installer.profile-meta.xml +193 -0
  106. package/demo-source/main/default/profiles/Verdant_Read_Only.profile-meta.xml +263 -0
  107. package/demo-source/main/default/profiles/Verdant_Sales_Rep.profile-meta.xml +194 -0
  108. package/demo-source/main/default/queues/Permit_Review_Queue.queue-meta.xml +9 -0
  109. package/demo-source/main/default/queues/Warranty_Queue.queue-meta.xml +9 -0
  110. package/demo-source/main/default/roles/Installer.role-meta.xml +10 -0
  111. package/demo-source/main/default/roles/Ops_Director.role-meta.xml +9 -0
  112. package/demo-source/main/default/roles/Ops_Manager.role-meta.xml +10 -0
  113. package/demo-source/main/default/roles/Sales_Manager.role-meta.xml +10 -0
  114. package/demo-source/main/default/roles/Sales_Rep.role-meta.xml +10 -0
  115. package/demo-source/main/default/roles/Sales_VP.role-meta.xml +9 -0
  116. package/demo-source/main/default/sharingRules/Invoice__c.sharingRules-meta.xml +17 -0
  117. package/demo-source/main/default/sharingRules/Project__c.sharingRules-meta.xml +17 -0
  118. package/demo-source/main/default/triggers/ProjectTrigger.trigger +8 -0
  119. package/demo-source/main/default/triggers/ProjectTrigger.trigger-meta.xml +5 -0
  120. package/demo-source/main/default/workflows/Opportunity.workflow-meta.xml +24 -0
  121. package/dist/index.js +537 -441
  122. package/package.json +38 -20
  123. package/server.json +32 -0
package/dist/index.js CHANGED
@@ -59767,7 +59767,7 @@ var init_package_version = __esm({
59767
59767
  "use strict";
59768
59768
  readCliPackageVersion = () => {
59769
59769
  if (true)
59770
- return "0.1.12";
59770
+ return "0.1.13";
59771
59771
  for (const rel of ["../package.json", "../../package.json"]) {
59772
59772
  try {
59773
59773
  const raw = readFileSync3(fileURLToPath(new URL(rel, import.meta.url)), "utf8");
@@ -128395,8 +128395,8 @@ ${typesXml}
128395
128395
  });
128396
128396
 
128397
128397
  // dist/src/commands/stale-sweep.js
128398
- import { writeFile as writeFile13 } from "node:fs/promises";
128399
- import { join as join28 } from "node:path";
128398
+ import { writeFile as writeFile14 } from "node:fs/promises";
128399
+ import { join as join30 } from "node:path";
128400
128400
  var SOURCE_MEMBER_TYPE_RE, runStaleSweep, registerStaleSweepCommand;
128401
128401
  var init_stale_sweep = __esm({
128402
128402
  "dist/src/commands/stale-sweep.js"() {
@@ -128405,8 +128405,8 @@ var init_stale_sweep = __esm({
128405
128405
  init_src2();
128406
128406
  SOURCE_MEMBER_TYPE_RE = /^[A-Za-z][A-Za-z0-9_]*$/;
128407
128407
  runStaleSweep = async (options) => {
128408
- const paths = vaultPaths(join28(options.cwd, "org-kb"));
128409
- const manifestResult = await loadManifest(join28(options.cwd, "org-kb"));
128408
+ const paths = vaultPaths(join30(options.cwd, "org-kb"));
128409
+ const manifestResult = await loadManifest(join30(options.cwd, "org-kb"));
128410
128410
  if (!manifestResult.ok) {
128411
128411
  return { ok: false, message: `vault manifest unavailable: ${manifestResult.error.message} \u2014 run sfi init / refresh first` };
128412
128412
  }
@@ -128462,7 +128462,7 @@ var init_stale_sweep = __esm({
128462
128462
  erroredTypes: result.value.erroredTypes
128463
128463
  };
128464
128464
  }
128465
- await writeFile13(join28(paths.meta, "staleness.json"), `${JSON.stringify(snapshot, null, 2)}
128465
+ await writeFile14(join30(paths.meta, "staleness.json"), `${JSON.stringify(snapshot, null, 2)}
128466
128466
  `, "utf8");
128467
128467
  return { ok: true, snapshot };
128468
128468
  };
@@ -128497,8 +128497,8 @@ __export(watch_exports, {
128497
128497
  watchDailyTicks: () => watchDailyTicks
128498
128498
  });
128499
128499
  import { spawn } from "node:child_process";
128500
- import { existsSync as existsSync6, readFileSync as readFileSync4, rmSync, writeFileSync } from "node:fs";
128501
- import { join as join29 } from "node:path";
128500
+ import { existsSync as existsSync7, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
128501
+ import { join as join31 } from "node:path";
128502
128502
  var PIDFILE, DEFAULT_INTERVAL_MS2, MIN_INTERVAL_MS, JITTER_RATIO, watchDailyTicks, pidPath, processAlive, readWatchState, alreadyExists, removeStaleWatchLock, claimWatchLock, releaseWatchLock, jitteredDelay, runWatchLoop, parseInterval, registerWatchCommand;
128503
128503
  var init_watch = __esm({
128504
128504
  "dist/src/commands/watch.js"() {
@@ -128513,7 +128513,7 @@ var init_watch = __esm({
128513
128513
  const n2 = raw ? Number(raw) : NaN;
128514
128514
  return Number.isFinite(n2) && n2 >= 1 ? Math.floor(n2) : 96;
128515
128515
  };
128516
- pidPath = (cwd) => join29(cwd, "org-kb", "meta", PIDFILE);
128516
+ pidPath = (cwd) => join31(cwd, "org-kb", "meta", PIDFILE);
128517
128517
  processAlive = (pid) => {
128518
128518
  try {
128519
128519
  process.kill(pid, 0);
@@ -128524,10 +128524,10 @@ var init_watch = __esm({
128524
128524
  };
128525
128525
  readWatchState = (cwd) => {
128526
128526
  const p2 = pidPath(cwd);
128527
- if (!existsSync6(p2))
128527
+ if (!existsSync7(p2))
128528
128528
  return { state: "absent" };
128529
128529
  try {
128530
- const parsed = JSON.parse(readFileSync4(p2, "utf8"));
128530
+ const parsed = JSON.parse(readFileSync5(p2, "utf8"));
128531
128531
  if (!Number.isInteger(parsed.pid) || parsed.pid < 1)
128532
128532
  return { state: "stale" };
128533
128533
  return processAlive(parsed.pid) ? { state: "running", pidState: parsed } : { state: "stale", pidState: parsed };
@@ -128552,7 +128552,7 @@ var init_watch = __esm({
128552
128552
  `;
128553
128553
  for (let attempt = 0; attempt < 2; attempt += 1) {
128554
128554
  try {
128555
- writeFileSync(pidPath(cwd), contents, { flag: "wx" });
128555
+ writeFileSync2(pidPath(cwd), contents, { flag: "wx" });
128556
128556
  return true;
128557
128557
  } catch (error) {
128558
128558
  if (!alreadyExists(error))
@@ -128667,7 +128667,7 @@ var init_watch = __esm({
128667
128667
  const watch = program.command("watch").description("Org-drift watcher: a small detached daemon running one read-only stale-sweep tick per interval (default 15m, floor 5m, \xB110% jitter, separate daily tick budget) so meta/staleness.json stays current. Single-instance per vault (stale pidfiles recovered). Subcommands: status, stop.").option("--interval <duration>", "Tick interval, e.g. 15m or 1h (floor 5m)", "15m").option("--auto-refresh <mode>", "When a tick detects drift, run `sfi refresh --incremental` automatically \u2014 at most once per hour; lock-safe (epoch side-build); a failure logs and the watcher continues. Mode: 'incremental'.").option("--foreground", "Run the loop in THIS process (used by the detached child)").option("--drain-demand-queue", "After a tick, drain queued automation-critical phantom hits (`meta/demand-queue.jsonl`, recorded by sfi.get_component) via the demand-retrieve gate \u2014 at most once per hour; a failure logs and the watcher continues.").action(async (flags) => {
128668
128668
  const cwd = process.cwd();
128669
128669
  const intervalMs = parseInterval(flags.interval);
128670
- if (!existsSync6(join29(cwd, "org-kb", "meta"))) {
128670
+ if (!existsSync7(join31(cwd, "org-kb", "meta"))) {
128671
128671
  process.stderr.write("watch: no vault here \u2014 run from the vault directory (org-kb/ missing).\n");
128672
128672
  process.exit(1);
128673
128673
  }
@@ -128699,11 +128699,11 @@ var init_watch = __esm({
128699
128699
  drainQueue: {
128700
128700
  peek: async (dir) => {
128701
128701
  const { queuedDrainIds: queuedDrainIds2, readDemandQueue: readDemandQueue2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
128702
- return queuedDrainIds2(await readDemandQueue2(join29(dir, "org-kb"))).length;
128702
+ return queuedDrainIds2(await readDemandQueue2(join31(dir, "org-kb"))).length;
128703
128703
  },
128704
128704
  drain: async (dir) => {
128705
128705
  const { queuedDrainIds: queuedDrainIds2, readDemandQueue: readDemandQueue2 } = await Promise.resolve().then(() => (init_src2(), src_exports));
128706
- const ids = queuedDrainIds2(await readDemandQueue2(join29(dir, "org-kb")));
128706
+ const ids = queuedDrainIds2(await readDemandQueue2(join31(dir, "org-kb")));
128707
128707
  if (ids.length === 0)
128708
128708
  return;
128709
128709
  const { runDemandRetrieve: runDemandRetrieve2 } = await Promise.resolve().then(() => (init_refresh(), refresh_exports));
@@ -128736,8 +128736,8 @@ var init_watch = __esm({
128736
128736
  watch.command("status").description("Report the watcher daemon state and the last sweep stamp.").action(() => {
128737
128737
  const cwd = process.cwd();
128738
128738
  const state = readWatchState(cwd);
128739
- const stalenessPath = join29(cwd, "org-kb", "meta", "staleness.json");
128740
- const lastSweep = existsSync6(stalenessPath) ? JSON.parse(readFileSync4(stalenessPath, "utf8")).generatedAt : void 0;
128739
+ const stalenessPath = join31(cwd, "org-kb", "meta", "staleness.json");
128740
+ const lastSweep = existsSync7(stalenessPath) ? JSON.parse(readFileSync5(stalenessPath, "utf8")).generatedAt : void 0;
128741
128741
  if (state.state === "running") {
128742
128742
  process.stdout.write(`watch: RUNNING (pid ${state.pidState?.pid} since ${state.pidState?.startedAt}, every ~${Math.round((state.pidState?.intervalMs ?? 0) / 6e4)}m). Last sweep: ${lastSweep ?? "(none yet)"}.
128743
128743
  `);
@@ -128769,8 +128769,8 @@ var init_watch = __esm({
128769
128769
  });
128770
128770
 
128771
128771
  // dist/src/program.js
128772
- import { readFileSync as readFileSync5 } from "node:fs";
128773
- import { fileURLToPath as fileURLToPath2 } from "node:url";
128772
+ import { readFileSync as readFileSync6 } from "node:fs";
128773
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
128774
128774
  import { Command } from "commander";
128775
128775
 
128776
128776
  // dist/src/commands/annotate.js
@@ -129099,26 +129099,506 @@ var registerCompareVaultsCommand = (program) => {
129099
129099
  });
129100
129100
  };
129101
129101
 
129102
- // dist/src/commands/doctor.js
129102
+ // dist/src/commands/demo.js
129103
129103
  init_src7();
129104
+ import { cpSync, existsSync as existsSync6, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "node:fs";
129105
+ import { homedir as homedir4 } from "node:os";
129106
+ import { dirname as dirname20, join as join28 } from "node:path";
129107
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
129108
+
129109
+ // dist/src/commands/init.js
129110
+ init_dist();
129104
129111
  init_src2();
129112
+ init_package_version();
129105
129113
  import { exec as exec2 } from "node:child_process";
129106
- import { existsSync as existsSync7 } from "node:fs";
129107
- import { readFile as readFile81, stat as stat12 } from "node:fs/promises";
129108
- import { resolve as resolve8 } from "node:path";
129114
+ import { mkdir as mkdir13, readFile as readFile80, stat as stat11, writeFile as writeFile12 } from "node:fs/promises";
129115
+ import { isAbsolute as isAbsolute5, join as join27, resolve as resolve6 } from "node:path";
129109
129116
  import { promisify as promisify5 } from "node:util";
129117
+ import { confirm, input } from "@inquirer/prompts";
129118
+
129119
+ // dist/src/commands/trust-statement.js
129120
+ var TRUST_GUARANTEES = [
129121
+ {
129122
+ headline: "READ-ONLY to your org",
129123
+ detail: "sf-intelligence never writes, deploys, or modifies anything in Salesforce. It only RETRIEVES metadata (`sf project retrieve`). No create, no update, no delete."
129124
+ },
129125
+ {
129126
+ headline: "OFFLINE by default",
129127
+ detail: "Every answer comes from the local vault built at the last refresh \u2014 not a live call. The org is contacted only when you run `sfi refresh`."
129128
+ },
129129
+ {
129130
+ headline: "LOCAL & private",
129131
+ detail: "The vault lives on THIS machine (org-kb/) and is never uploaded anywhere. No telemetry, no phone-home \u2014 feedback (`sfi feedback`) is captured locally and shared only if you choose to."
129132
+ },
129133
+ {
129134
+ headline: "Live plane is OFF until you turn it on",
129135
+ detail: "The opt-in live read-only plane (capped record counts/samples) stays disabled until you set SFI_LIVE_PLANE_ENABLED=1 (or `sfi.live_consent`). Even enabled it is READ-ONLY and runs only a curated query roster \u2014 never arbitrary SOQL, never a write."
129136
+ },
129137
+ {
129138
+ headline: "The npm package ships NO org data",
129139
+ detail: "The published package contains only code (a `files` whitelist blocks the vault/source/snapshots). Every public version has been downloaded and grepped clean of org identifiers (the leak audit)."
129140
+ }
129141
+ ];
129142
+ var formatTrustStatement = () => {
129143
+ const lines = [];
129144
+ lines.push("");
129145
+ lines.push(" \u250C\u2500 What sf-intelligence does (and does NOT) to your org \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
129146
+ lines.push(" \u2502");
129147
+ for (const g2 of TRUST_GUARANTEES) {
129148
+ lines.push(` \u2502 \u2713 ${g2.headline}`);
129149
+ for (const wrapped of wrap(g2.detail, 64)) {
129150
+ lines.push(` \u2502 ${wrapped}`);
129151
+ }
129152
+ lines.push(" \u2502");
129153
+ }
129154
+ lines.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
129155
+ lines.push("");
129156
+ return lines.join("\n");
129157
+ };
129158
+ var wrap = (text, width) => {
129159
+ const words = text.split(/\s+/);
129160
+ const out = [];
129161
+ let line = "";
129162
+ for (const word of words) {
129163
+ if (line === "") {
129164
+ line = word;
129165
+ } else if (`${line} ${word}`.length <= width) {
129166
+ line = `${line} ${word}`;
129167
+ } else {
129168
+ out.push(line);
129169
+ line = word;
129170
+ }
129171
+ }
129172
+ if (line !== "")
129173
+ out.push(line);
129174
+ return out;
129175
+ };
129176
+
129177
+ // dist/src/commands/init.js
129178
+ var DEFAULT_VAULT_ROOT = "org-kb";
129179
+ var JSON_INDENT6 = 2;
129180
+ var GITIGNORE_ENTRIES = ["org-kb/source/", "org-kb/graph/"];
129181
+ var SF_API_VERSION3 = "62.0";
129182
+ var DEFAULT_PACKAGE_DIR = "force-app";
129183
+ var execAsync2 = promisify5(exec2);
129184
+ var runInit = async (opts) => {
129185
+ const resolvedRoot = isAbsolute5(opts.vaultRoot) ? opts.vaultRoot : resolve6(opts.cwd, opts.vaultRoot);
129186
+ if (!opts.force && await pathExists3(resolvedRoot)) {
129187
+ return err({
129188
+ kind: "already-exists",
129189
+ message: `vault already exists: ${resolvedRoot}`,
129190
+ path: resolvedRoot
129191
+ });
129192
+ }
129193
+ const paths = vaultPaths(resolvedRoot);
129194
+ const mkdirResult = await createVaultDirs(paths);
129195
+ if (!mkdirResult.ok)
129196
+ return mkdirResult;
129197
+ const writeResult = await writeVaultMetadata(paths, opts.targetOrg, resolvedRoot);
129198
+ if (!writeResult.ok)
129199
+ return writeResult;
129200
+ const dxProjectScaffolded = await ensureDxProject(opts.cwd);
129201
+ const gitignoreUpdated = await updateGitignore(opts.cwd);
129202
+ return ok({ vaultRoot: resolvedRoot, targetOrg: opts.targetOrg, gitignoreUpdated, dxProjectScaffolded });
129203
+ };
129204
+ var ensureDxProject = async (cwd) => {
129205
+ const projectPath = join27(cwd, "sfdx-project.json");
129206
+ let wrote = false;
129207
+ if (!await pathExists3(projectPath)) {
129208
+ const project = {
129209
+ packageDirectories: [{ path: DEFAULT_PACKAGE_DIR, default: true }],
129210
+ namespace: "",
129211
+ sourceApiVersion: SF_API_VERSION3
129212
+ };
129213
+ try {
129214
+ await writeFile12(projectPath, `${JSON.stringify(project, null, JSON_INDENT6)}
129215
+ `, "utf8");
129216
+ wrote = true;
129217
+ } catch {
129218
+ }
129219
+ }
129220
+ try {
129221
+ await mkdir13(join27(cwd, DEFAULT_PACKAGE_DIR), { recursive: true });
129222
+ } catch {
129223
+ }
129224
+ return wrote;
129225
+ };
129226
+ var createVaultDirs = async (paths) => {
129227
+ for (const dir of [paths.root, paths.source, paths.components, paths.graph, paths.meta]) {
129228
+ try {
129229
+ await mkdir13(dir, { recursive: true });
129230
+ } catch (cause) {
129231
+ return err({ kind: "mkdir-failed", message: `failed to create directory: ${dir}`, path: dir, cause });
129232
+ }
129233
+ }
129234
+ return ok(void 0);
129235
+ };
129236
+ var writeVaultMetadata = async (paths, targetOrg, resolvedRoot) => {
129237
+ const config = {
129238
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
129239
+ targetOrg,
129240
+ vaultRoot: resolvedRoot,
129241
+ version: readCliPackageVersion(),
129242
+ snapshotOnRefresh: true
129243
+ };
129244
+ try {
129245
+ await writeFile12(paths.config, `${JSON.stringify(config, null, JSON_INDENT6)}
129246
+ `, "utf8");
129247
+ } catch (cause) {
129248
+ return err({ kind: "write-failed", message: `failed to write config: ${paths.config}`, path: paths.config, cause });
129249
+ }
129250
+ const versionTxtPath = join27(paths.meta, "version.txt");
129251
+ try {
129252
+ await writeFile12(versionTxtPath, `${readCliPackageVersion()}
129253
+ `, "utf8");
129254
+ } catch (cause) {
129255
+ return err({ kind: "write-failed", message: `failed to write version.txt: ${versionTxtPath}`, path: versionTxtPath, cause });
129256
+ }
129257
+ return ok(void 0);
129258
+ };
129259
+ var updateGitignore = async (cwd) => {
129260
+ const gitignorePath = join27(cwd, ".gitignore");
129261
+ let existing = "";
129262
+ let exists = true;
129263
+ try {
129264
+ existing = await readFile80(gitignorePath, "utf8");
129265
+ } catch (cause) {
129266
+ if (!isEnoent3(cause))
129267
+ return false;
129268
+ exists = false;
129269
+ }
129270
+ const present = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
129271
+ const missing = GITIGNORE_ENTRIES.filter((entry) => !present.has(entry));
129272
+ if (missing.length === 0)
129273
+ return false;
129274
+ const needsNewline = exists && existing.length > 0 && !existing.endsWith("\n");
129275
+ const next = `${existing}${needsNewline ? "\n" : ""}${missing.join("\n")}
129276
+ `;
129277
+ try {
129278
+ await writeFile12(gitignorePath, next, "utf8");
129279
+ return true;
129280
+ } catch {
129281
+ return false;
129282
+ }
129283
+ };
129284
+ var pathExists3 = async (path) => {
129285
+ try {
129286
+ await stat11(path);
129287
+ return true;
129288
+ } catch (cause) {
129289
+ return !isEnoent3(cause);
129290
+ }
129291
+ };
129292
+ var isEnoent3 = (cause) => typeof cause === "object" && cause !== null && "code" in cause && cause.code === "ENOENT";
129293
+ var ORG_CATEGORIES = ["nonScratchOrgs", "scratchOrgs", "otherOrgs", "devHubs", "sandboxes"];
129294
+ var getDefaultOrgAlias = async () => {
129295
+ try {
129296
+ const { stdout } = await execAsync2("sf org list --json");
129297
+ const parsed = JSON.parse(stdout);
129298
+ const result = parsed.result;
129299
+ if (result === void 0 || result === null)
129300
+ return null;
129301
+ for (const key of ORG_CATEGORIES) {
129302
+ const entries = result[key];
129303
+ if (!Array.isArray(entries))
129304
+ continue;
129305
+ for (const item of entries) {
129306
+ if (typeof item !== "object" || item === null)
129307
+ continue;
129308
+ const entry = item;
129309
+ if (entry["isDefaultUsername"] !== true && entry["isDefaultDevHubUsername"] !== true)
129310
+ continue;
129311
+ const alias = entry["alias"] ?? entry["username"];
129312
+ if (typeof alias === "string" && alias.length > 0)
129313
+ return alias;
129314
+ }
129315
+ }
129316
+ return null;
129317
+ } catch {
129318
+ return null;
129319
+ }
129320
+ };
129321
+ var registerInitCommand = (program) => {
129322
+ program.command("init").description("Initialise a new org-kb vault in the current directory").option("--target-org <alias>", "Salesforce org alias to bind to this vault").option("--vault-root <path>", "Vault root directory (relative to CWD)").option("--force", "Overwrite an existing org-kb/ vault config", false).action(async (flags) => {
129323
+ const cwd = process.cwd();
129324
+ const exitCode = await handleInit(cwd, flags);
129325
+ if (exitCode !== 0)
129326
+ process.exit(exitCode);
129327
+ });
129328
+ };
129329
+ var handleInit = async (cwd, flags) => {
129330
+ const interactive = process.stdin.isTTY === true;
129331
+ const vaultRoot = flags.vaultRoot ?? (interactive ? await input({ message: "Vault root directory:", default: DEFAULT_VAULT_ROOT }) : DEFAULT_VAULT_ROOT);
129332
+ const resolvedRoot = isAbsolute5(vaultRoot) ? vaultRoot : resolve6(cwd, vaultRoot);
129333
+ let force = flags.force ?? false;
129334
+ if (!force && await pathExists3(resolvedRoot)) {
129335
+ if (!interactive) {
129336
+ process.stderr.write(`sfi init: ${vaultRoot}/ already exists. Re-run with --force to overwrite.
129337
+ `);
129338
+ return 1;
129339
+ }
129340
+ const overwrite = await confirm({
129341
+ message: `${vaultRoot}/ already exists. Overwrite config?`,
129342
+ default: false
129343
+ });
129344
+ if (!overwrite) {
129345
+ process.stdout.write("Existing init preserved.\n");
129346
+ return 0;
129347
+ }
129348
+ force = true;
129349
+ }
129350
+ const targetOrg = await resolveTargetOrg(flags, interactive);
129351
+ if (targetOrg === null) {
129352
+ process.stderr.write("sfi init: no --target-org given and no default Salesforce org found. Pass --target-org <alias>.\n");
129353
+ return 1;
129354
+ }
129355
+ return runAndReport({ cwd, targetOrg, vaultRoot, force });
129356
+ };
129357
+ var resolveTargetOrg = async (flags, interactive) => {
129358
+ if (flags.targetOrg !== void 0)
129359
+ return flags.targetOrg;
129360
+ const detected = await getDefaultOrgAlias();
129361
+ if (!interactive)
129362
+ return detected;
129363
+ return input({
129364
+ message: "Target org alias:",
129365
+ ...detected !== null ? { default: detected } : {}
129366
+ });
129367
+ };
129368
+ var runAndReport = async (opts) => {
129369
+ const result = await runInit(opts);
129370
+ if (!result.ok) {
129371
+ process.stderr.write(`sfi init: ${result.error.message}
129372
+ `);
129373
+ return 1;
129374
+ }
129375
+ process.stdout.write([
129376
+ `Initialised vault at ${result.value.vaultRoot}`,
129377
+ `Target org: ${result.value.targetOrg}`,
129378
+ result.value.gitignoreUpdated ? "Updated .gitignore" : ".gitignore already up to date (or could not be written)",
129379
+ result.value.dxProjectScaffolded ? "Scaffolded sfdx-project.json (ready for sf project retrieve)" : "sfdx-project.json already present",
129380
+ ""
129381
+ ].join("\n"));
129382
+ process.stdout.write(formatTrustStatement());
129383
+ process.stdout.write("Next: run sfi refresh\n\n");
129384
+ return 0;
129385
+ };
129386
+
129387
+ // dist/src/commands/mcp.js
129388
+ init_dist();
129389
+ init_src7();
129390
+ init_src2();
129391
+ import { execFile as execFile4 } from "node:child_process";
129392
+ import { readFile as readFile81, stat as stat12 } from "node:fs/promises";
129393
+ import { resolve as resolve7 } from "node:path";
129394
+ import { promisify as promisify6 } from "node:util";
129395
+ var DEFAULT_VAULT_ROOT2 = "org-kb";
129396
+ var SHUTDOWN_SIGNALS = ["SIGINT", "SIGTERM"];
129397
+ var readBoundOrg = async (configPath) => {
129398
+ try {
129399
+ const raw = await readFile81(configPath, "utf8");
129400
+ const parsed = JSON.parse(raw);
129401
+ return typeof parsed.targetOrg === "string" ? parsed.targetOrg : null;
129402
+ } catch {
129403
+ return null;
129404
+ }
129405
+ };
129406
+ var nodeExecFile3 = promisify6(execFile4);
129407
+ var defaultListOrgs = async () => {
129408
+ try {
129409
+ const { stdout } = await nodeExecFile3("sf", ["org", "list", "--json"], {
129410
+ maxBuffer: 10 * 1024 * 1024
129411
+ });
129412
+ const json = JSON.parse(stdout);
129413
+ const groups = json.result ?? {};
129414
+ const seen = /* @__PURE__ */ new Set();
129415
+ const out = [];
129416
+ for (const list of Object.values(groups)) {
129417
+ for (const org of list ?? []) {
129418
+ const label = org.alias ?? org.username;
129419
+ if (label && !seen.has(label)) {
129420
+ seen.add(label);
129421
+ out.push(label);
129422
+ }
129423
+ }
129424
+ }
129425
+ return out;
129426
+ } catch {
129427
+ return [];
129428
+ }
129429
+ };
129430
+ var prepareMcp = async (opts) => {
129431
+ const vaultRoot = opts.vaultRoot !== void 0 ? resolve7(opts.cwd, opts.vaultRoot) : resolve7(opts.cwd, DEFAULT_VAULT_ROOT2);
129432
+ const paths = vaultPaths(vaultRoot);
129433
+ if (!await pathExists4(paths.config)) {
129434
+ const orgs = await (opts.listOrgs ?? defaultListOrgs)();
129435
+ const where = opts.vaultRoot !== void 0 ? ` at ${vaultRoot}` : "";
129436
+ const base = `No vault${where}. Run \`sfi init\` followed by \`sfi refresh\`, or point \`sfi mcp --vault <path>\` at an existing org-kb.`;
129437
+ const hint = orgs.length > 0 ? ` You are authenticated to ${orgs.length} org(s): ${orgs.slice(0, 8).join(", ")}${orgs.length > 8 ? ", \u2026" : ""}. Run \`sfi init\` to pick the one you want and build its knowledge base \u2014 live answers attach to a vault's org, so the product never guesses which of your orgs to query.` : "";
129438
+ return err({ kind: "no-vault", message: base + hint });
129439
+ }
129440
+ const ctxResult = await buildContext(vaultRoot);
129441
+ if (!ctxResult.ok) {
129442
+ return err({ kind: "buildContext-failed", message: ctxResult.error.message });
129443
+ }
129444
+ const targetOrg = await readBoundOrg(paths.config);
129445
+ return ok({
129446
+ ctx: ctxResult.value,
129447
+ server: createServer(ctxResult.value),
129448
+ vaultRoot,
129449
+ targetOrg
129450
+ });
129451
+ };
129452
+ var pathExists4 = async (path) => {
129453
+ try {
129454
+ await stat12(path);
129455
+ return true;
129456
+ } catch (cause) {
129457
+ return !isEnoent4(cause);
129458
+ }
129459
+ };
129460
+ var isEnoent4 = (cause) => typeof cause === "object" && cause !== null && "code" in cause && cause.code === "ENOENT";
129461
+ var registerMcpCommand = (program) => {
129462
+ program.command("mcp").description("Run the MCP server backing the org-kb vault").option("--vault <path>", "Serve a specific org-kb vault instead of ./org-kb (bind a project to the right org)").action(async (cmdOpts) => {
129463
+ const prepared = await prepareMcp({
129464
+ cwd: process.cwd(),
129465
+ ...cmdOpts.vault !== void 0 ? { vaultRoot: cmdOpts.vault } : {}
129466
+ });
129467
+ if (!prepared.ok) {
129468
+ process.stderr.write(`sfi mcp: ${prepared.error.message}
129469
+ `);
129470
+ process.exit(1);
129471
+ }
129472
+ const { ctx, server, vaultRoot, targetOrg } = prepared.value;
129473
+ process.stderr.write(`sfi mcp: serving vault ${vaultRoot}${targetOrg !== null ? ` (org: ${targetOrg})` : " (no targetOrg in config)"}
129474
+ `);
129475
+ const shutdownOnce = makeShutdownOnce(ctx);
129476
+ for (const signal of SHUTDOWN_SIGNALS) {
129477
+ process.on(signal, () => {
129478
+ void shutdownOnce().then(() => process.exit(0));
129479
+ });
129480
+ }
129481
+ await startServer(server);
129482
+ await shutdownOnce();
129483
+ });
129484
+ };
129485
+ var makeShutdownOnce = (ctx) => {
129486
+ let done = null;
129487
+ return () => {
129488
+ if (done === null)
129489
+ done = shutdown(ctx);
129490
+ return done;
129491
+ };
129492
+ };
129493
+
129494
+ // dist/src/commands/demo.js
129495
+ init_refresh();
129496
+ var buildVersion = () => true ? "0.1.13" : "dev";
129497
+ var SHUTDOWN_SIGNALS2 = ["SIGINT", "SIGTERM"];
129498
+ var resolveDemoSource = () => {
129499
+ let dir = dirname20(fileURLToPath2(import.meta.url));
129500
+ for (let i2 = 0; i2 < 7; i2 += 1) {
129501
+ const shipped = join28(dir, "demo-source", "main", "default");
129502
+ if (existsSync6(shipped))
129503
+ return shipped;
129504
+ const repo = join28(dir, "examples", "demo-vault", "source", "main", "default");
129505
+ if (existsSync6(repo))
129506
+ return repo;
129507
+ const parent = dirname20(dir);
129508
+ if (parent === dir)
129509
+ break;
129510
+ dir = parent;
129511
+ }
129512
+ return null;
129513
+ };
129514
+ var registerDemoCommand = (program) => {
129515
+ program.command("demo").description("Try sf-intelligence with no Salesforce org \u2014 serve a built-in synthetic demo org over MCP").option("--rebuild", "Force a rebuild of the cached demo vault", false).action(async (opts) => {
129516
+ const source = resolveDemoSource();
129517
+ if (source === null) {
129518
+ process.stderr.write("sfi demo: bundled demo source not found (expected a shipped demo-source/ or examples/demo-vault/source).\n");
129519
+ process.exit(1);
129520
+ }
129521
+ const cacheCwd = join28(homedir4(), ".sf-intelligence", "demo");
129522
+ const vaultRoot = join28(cacheCwd, "org-kb");
129523
+ const graphDb = join28(vaultRoot, "graph", "graph.duckdb");
129524
+ const stampPath = join28(vaultRoot, "meta", "demo-build.stamp");
129525
+ const stamp = `${buildVersion()}`;
129526
+ const stampOk = (() => {
129527
+ try {
129528
+ return readFileSync4(stampPath, "utf8").trim() === stamp;
129529
+ } catch {
129530
+ return false;
129531
+ }
129532
+ })();
129533
+ const needBuild = opts.rebuild === true || !existsSync6(graphDb) || !stampOk;
129534
+ if (needBuild) {
129535
+ process.stderr.write("sfi demo: building the synthetic demo vault (first run, ~a few seconds)...\n");
129536
+ const init = await runInit({
129537
+ cwd: cacheCwd,
129538
+ targetOrg: "demo-org",
129539
+ vaultRoot: "org-kb",
129540
+ force: true
129541
+ });
129542
+ if (!init.ok) {
129543
+ process.stderr.write(`sfi demo: could not initialise the demo vault: ${init.error.message}
129544
+ `);
129545
+ process.exit(1);
129546
+ }
129547
+ const sourceDest = join28(vaultRoot, "source", "main", "default");
129548
+ mkdirSync(dirname20(sourceDest), { recursive: true });
129549
+ cpSync(source, sourceDest, { recursive: true });
129550
+ await runRefresh({ cwd: cacheCwd, noPull: true });
129551
+ if (!existsSync6(graphDb)) {
129552
+ process.stderr.write("sfi demo: demo build failed \u2014 no graph was produced.\n");
129553
+ process.exit(1);
129554
+ }
129555
+ try {
129556
+ writeFileSync(stampPath, `${stamp}
129557
+ `);
129558
+ } catch {
129559
+ }
129560
+ }
129561
+ const prepared = await prepareMcp({ cwd: cacheCwd, vaultRoot: "org-kb" });
129562
+ if (!prepared.ok) {
129563
+ process.stderr.write(`sfi demo: ${prepared.error.message}
129564
+ `);
129565
+ process.exit(1);
129566
+ }
129567
+ const { ctx, server, vaultRoot: served } = prepared.value;
129568
+ process.stderr.write(`sfi demo: serving the synthetic "Verdant Energy" demo org from ${served} (read-only, offline).
129569
+ `);
129570
+ let shuttingDown = null;
129571
+ const shutdownOnce = () => shuttingDown ??= shutdown(ctx);
129572
+ for (const signal of SHUTDOWN_SIGNALS2) {
129573
+ process.on(signal, () => {
129574
+ void shutdownOnce().then(() => process.exit(0));
129575
+ });
129576
+ }
129577
+ await startServer(server);
129578
+ await shutdownOnce();
129579
+ });
129580
+ };
129581
+
129582
+ // dist/src/commands/doctor.js
129583
+ init_src7();
129584
+ init_src2();
129585
+ import { exec as exec3 } from "node:child_process";
129586
+ import { existsSync as existsSync8 } from "node:fs";
129587
+ import { readFile as readFile83, stat as stat14 } from "node:fs/promises";
129588
+ import { resolve as resolve10 } from "node:path";
129589
+ import { promisify as promisify7 } from "node:util";
129110
129590
 
129111
129591
  // dist/src/commands/feedback.js
129112
129592
  init_src7();
129113
- import { appendFile as appendFile5, mkdir as mkdir13, readFile as readFile80, writeFile as writeFile12 } from "node:fs/promises";
129114
- import { homedir as homedir4 } from "node:os";
129115
- import { dirname as dirname20, join as join27, resolve as resolve6 } from "node:path";
129593
+ import { appendFile as appendFile5, mkdir as mkdir14, readFile as readFile82, writeFile as writeFile13 } from "node:fs/promises";
129594
+ import { homedir as homedir5 } from "node:os";
129595
+ import { dirname as dirname21, join as join29, resolve as resolve8 } from "node:path";
129116
129596
  var FEEDBACK_ISSUES_URL = "https://github.com/PranavNagrecha/Salesforce-Intelligence/issues";
129117
- var feedbackLogPath = () => process.env["SFI_FEEDBACK_LOG_PATH"] ?? join27(homedir4(), ".sf-intelligence", "feedback.jsonl");
129597
+ var feedbackLogPath = () => process.env["SFI_FEEDBACK_LOG_PATH"] ?? join29(homedir5(), ".sf-intelligence", "feedback.jsonl");
129118
129598
  var recordFeedback = async (question, rating, path = feedbackLogPath()) => {
129119
129599
  const entry = { at: (/* @__PURE__ */ new Date()).toISOString(), question, rating };
129120
129600
  try {
129121
- await mkdir13(dirname20(path), { recursive: true });
129601
+ await mkdir14(dirname21(path), { recursive: true });
129122
129602
  await appendFile5(path, `${JSON.stringify(entry)}
129123
129603
  `, "utf8");
129124
129604
  return true;
@@ -129130,7 +129610,7 @@ var scrubText = (s2) => s2.replace(/[\w.+-]+@[\w-]+\.[\w.-]+/g, "[email]").repla
129130
129610
  var readJsonl = async (path) => {
129131
129611
  let raw;
129132
129612
  try {
129133
- raw = await readFile80(path, "utf8");
129613
+ raw = await readFile82(path, "utf8");
129134
129614
  } catch {
129135
129615
  return [];
129136
129616
  }
@@ -129176,7 +129656,7 @@ var registerFeedbackCommand = (program) => {
129176
129656
  ` : "Could not write the local feedback log.\n");
129177
129657
  });
129178
129658
  feedback.command("export").description("Write a scrubbed, shareable feedback file (route gaps + ratings) \u2014 no org PII, nothing uploaded. Gaps are scoped to the CURRENT vault by default; --all exports the whole machine-global log (review before sharing on a multi-org machine).").option("--out <file>", "output path", "sfi-feedback.json").option("--all", "include every vault's gaps + unstamped pre-0.1.10 entries (machine-global)").action(async (flags) => {
129179
- const vaultRoot = resolve6(process.cwd(), "org-kb");
129659
+ const vaultRoot = resolve8(process.cwd(), "org-kb");
129180
129660
  const data = await buildFeedbackExport({
129181
129661
  vaultRoot,
129182
129662
  ...flags.all === true ? { all: true } : {}
@@ -129186,9 +129666,9 @@ var registerFeedbackCommand = (program) => {
129186
129666
  ` : 'Mark a weak answer first: `sfi feedback mark "<question>" --wrong` (or `--weak`).\n'));
129187
129667
  return;
129188
129668
  }
129189
- const out = resolve6(process.cwd(), flags.out);
129669
+ const out = resolve8(process.cwd(), flags.out);
129190
129670
  try {
129191
- await writeFile12(out, `${JSON.stringify(data, null, 2)}
129671
+ await writeFile13(out, `${JSON.stringify(data, null, 2)}
129192
129672
  `, "utf8");
129193
129673
  } catch (cause) {
129194
129674
  process.stderr.write(`Could not write ${out}: ${cause instanceof Error ? cause.message : String(cause)}
@@ -129206,19 +129686,19 @@ Pick a writable path with \`--out <file>\`.
129206
129686
 
129207
129687
  // dist/src/commands/status.js
129208
129688
  init_src2();
129209
- import { stat as stat11 } from "node:fs/promises";
129210
- import { resolve as resolve7 } from "node:path";
129211
- var JSON_INDENT6 = 2;
129212
- var DEFAULT_VAULT_ROOT = "org-kb";
129689
+ import { stat as stat13 } from "node:fs/promises";
129690
+ import { resolve as resolve9 } from "node:path";
129691
+ var JSON_INDENT7 = 2;
129692
+ var DEFAULT_VAULT_ROOT3 = "org-kb";
129213
129693
  var HASH_PREFIX_LENGTH = 12;
129214
129694
  var LABEL_WIDTH = 20;
129215
129695
  var SECONDS_PER_MINUTE = 60;
129216
129696
  var MINUTES_PER_HOUR = 60;
129217
129697
  var HOURS_PER_DAY = 24;
129218
129698
  var runStatus = async (opts) => {
129219
- const vaultRoot = resolve7(opts.cwd, DEFAULT_VAULT_ROOT);
129699
+ const vaultRoot = resolve9(opts.cwd, DEFAULT_VAULT_ROOT3);
129220
129700
  const paths = vaultPaths(vaultRoot);
129221
- if (!await pathExists3(paths.config)) {
129701
+ if (!await pathExists5(paths.config)) {
129222
129702
  return {
129223
129703
  kind: "no-vault",
129224
129704
  message: "No vault. Run `sfi init` followed by `sfi refresh`."
@@ -129256,15 +129736,15 @@ var runStatus = async (opts) => {
129256
129736
  currentSourceHash
129257
129737
  };
129258
129738
  };
129259
- var pathExists3 = async (path) => {
129739
+ var pathExists5 = async (path) => {
129260
129740
  try {
129261
- await stat11(path);
129741
+ await stat13(path);
129262
129742
  return true;
129263
129743
  } catch (cause) {
129264
- return !isEnoent3(cause);
129744
+ return !isEnoent5(cause);
129265
129745
  }
129266
129746
  };
129267
- var isEnoent3 = (cause) => typeof cause === "object" && cause !== null && "code" in cause && cause.code === "ENOENT";
129747
+ var isEnoent5 = (cause) => typeof cause === "object" && cause !== null && "code" in cause && cause.code === "ENOENT";
129268
129748
  var formatAge = (iso, now = /* @__PURE__ */ new Date()) => {
129269
129749
  const then = new Date(iso);
129270
129750
  if (Number.isNaN(then.getTime()))
@@ -129352,7 +129832,7 @@ var registerStatusCommand = (program) => {
129352
129832
  program.command("status").description("Report the freshness of the local vault").option("--json", "Print the raw status as pretty-printed JSON instead of the table", false).option("--skipped", "Print the per-directory skip inventory the refresh walker recorded. Use this when the warning at the end of `sfi refresh` flagged unknown directories.", false).action(async (flags) => {
129353
129833
  const out = await runStatus({ cwd: process.cwd() });
129354
129834
  if (flags.json === true) {
129355
- process.stdout.write(`${JSON.stringify(out, null, JSON_INDENT6)}
129835
+ process.stdout.write(`${JSON.stringify(out, null, JSON_INDENT7)}
129356
129836
  `);
129357
129837
  return;
129358
129838
  }
@@ -129365,8 +129845,8 @@ var registerStatusCommand = (program) => {
129365
129845
  };
129366
129846
 
129367
129847
  // dist/src/commands/doctor.js
129368
- var execAsync2 = promisify5(exec2);
129369
- var DEFAULT_VAULT_ROOT2 = "org-kb";
129848
+ var execAsync3 = promisify7(exec3);
129849
+ var DEFAULT_VAULT_ROOT4 = "org-kb";
129370
129850
  var parseSfCliVersion = (versionLine) => {
129371
129851
  const m2 = /(\d+)\.(\d+)\.(\d+)/.exec(versionLine);
129372
129852
  if (m2 === null)
@@ -129378,7 +129858,7 @@ var formatVersion = (v2) => v2.join(".");
129378
129858
  var summarizeRouteGaps = async (logFile) => {
129379
129859
  let raw;
129380
129860
  try {
129381
- raw = await readFile81(logFile, "utf8");
129861
+ raw = await readFile83(logFile, "utf8");
129382
129862
  } catch {
129383
129863
  return { exists: false, count: 0, topCategory: null, topCount: 0 };
129384
129864
  }
@@ -129405,9 +129885,9 @@ var summarizeRouteGaps = async (logFile) => {
129405
129885
  }
129406
129886
  return { exists: true, count, topCategory, topCount };
129407
129887
  };
129408
- var pathExists4 = async (p2) => {
129888
+ var pathExists6 = async (p2) => {
129409
129889
  try {
129410
- await stat12(p2);
129890
+ await stat14(p2);
129411
129891
  return true;
129412
129892
  } catch {
129413
129893
  return false;
@@ -129415,7 +129895,7 @@ var pathExists4 = async (p2) => {
129415
129895
  };
129416
129896
  var readTargetOrg = async (configPath) => {
129417
129897
  try {
129418
- const raw = await readFile81(configPath, "utf8");
129898
+ const raw = await readFile83(configPath, "utf8");
129419
129899
  const parsed = JSON.parse(raw);
129420
129900
  return typeof parsed.targetOrg === "string" ? parsed.targetOrg : null;
129421
129901
  } catch {
@@ -129423,9 +129903,9 @@ var readTargetOrg = async (configPath) => {
129423
129903
  }
129424
129904
  };
129425
129905
  var runDoctor = async (opts) => {
129426
- const run = opts.exec ?? ((cmd) => execAsync2(cmd, { maxBuffer: 64 * 1024 * 1024 }));
129906
+ const run = opts.exec ?? ((cmd) => execAsync3(cmd, { maxBuffer: 64 * 1024 * 1024 }));
129427
129907
  const checks = [];
129428
- const vaultRoot = resolve8(opts.cwd, DEFAULT_VAULT_ROOT2);
129908
+ const vaultRoot = resolve10(opts.cwd, DEFAULT_VAULT_ROOT4);
129429
129909
  const paths = vaultPaths(vaultRoot);
129430
129910
  const SF_FALLBACK_PATHS = ["/usr/local/bin/sf", "/opt/homebrew/bin/sf"];
129431
129911
  let sfBin = "sf";
@@ -129472,7 +129952,7 @@ var runDoctor = async (opts) => {
129472
129952
  fix: "Install the Salesforce CLI (npm install --global @salesforce/cli). If it IS installed, add its directory (/usr/local/bin or /opt/homebrew/bin) to your PATH; IDE/MCP subprocesses often do not inherit it."
129473
129953
  });
129474
129954
  }
129475
- const vaultInit = await pathExists4(paths.config);
129955
+ const vaultInit = await pathExists6(paths.config);
129476
129956
  if (!vaultInit) {
129477
129957
  checks.push({
129478
129958
  name: "Vault",
@@ -129561,7 +130041,7 @@ var runDoctor = async (opts) => {
129561
130041
  }
129562
130042
  }
129563
130043
  if (vaultInit) {
129564
- const graphOk = await pathExists4(paths.graphDb);
130044
+ const graphOk = await pathExists6(paths.graphDb);
129565
130045
  checks.push(graphOk ? { name: "Graph", status: "pass", detail: "graph.duckdb present" } : { name: "Graph", status: "warn", detail: "graph.duckdb missing", fix: "Run `sfi refresh` to rebuild the graph." });
129566
130046
  }
129567
130047
  const gaps = await summarizeRouteGaps(opts.gapLogFile ?? gapLogPath());
@@ -129628,7 +130108,7 @@ var runDoctor = async (opts) => {
129628
130108
  });
129629
130109
  }
129630
130110
  const registryFile = findRegistryFile(vaultRoot);
129631
- if (existsSync7(registryFile)) {
130111
+ if (existsSync8(registryFile)) {
129632
130112
  const listed = await listRegisteredVaults(findRegistryRoot(vaultRoot));
129633
130113
  if (listed.ok && listed.value.length >= 2) {
129634
130114
  checks.push({
@@ -129674,284 +130154,6 @@ var registerDoctorCommand = (program) => {
129674
130154
  });
129675
130155
  };
129676
130156
 
129677
- // dist/src/commands/init.js
129678
- init_dist();
129679
- init_src2();
129680
- init_package_version();
129681
- import { exec as exec3 } from "node:child_process";
129682
- import { mkdir as mkdir14, readFile as readFile82, stat as stat13, writeFile as writeFile14 } from "node:fs/promises";
129683
- import { isAbsolute as isAbsolute5, join as join30, resolve as resolve9 } from "node:path";
129684
- import { promisify as promisify6 } from "node:util";
129685
- import { confirm, input } from "@inquirer/prompts";
129686
-
129687
- // dist/src/commands/trust-statement.js
129688
- var TRUST_GUARANTEES = [
129689
- {
129690
- headline: "READ-ONLY to your org",
129691
- detail: "sf-intelligence never writes, deploys, or modifies anything in Salesforce. It only RETRIEVES metadata (`sf project retrieve`). No create, no update, no delete."
129692
- },
129693
- {
129694
- headline: "OFFLINE by default",
129695
- detail: "Every answer comes from the local vault built at the last refresh \u2014 not a live call. The org is contacted only when you run `sfi refresh`."
129696
- },
129697
- {
129698
- headline: "LOCAL & private",
129699
- detail: "The vault lives on THIS machine (org-kb/) and is never uploaded anywhere. No telemetry, no phone-home \u2014 feedback (`sfi feedback`) is captured locally and shared only if you choose to."
129700
- },
129701
- {
129702
- headline: "Live plane is OFF until you turn it on",
129703
- detail: "The opt-in live read-only plane (capped record counts/samples) stays disabled until you set SFI_LIVE_PLANE_ENABLED=1 (or `sfi.live_consent`). Even enabled it is READ-ONLY and runs only a curated query roster \u2014 never arbitrary SOQL, never a write."
129704
- },
129705
- {
129706
- headline: "The npm package ships NO org data",
129707
- detail: "The published package contains only code (a `files` whitelist blocks the vault/source/snapshots). Every public version has been downloaded and grepped clean of org identifiers (the leak audit)."
129708
- }
129709
- ];
129710
- var formatTrustStatement = () => {
129711
- const lines = [];
129712
- lines.push("");
129713
- lines.push(" \u250C\u2500 What sf-intelligence does (and does NOT) to your org \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
129714
- lines.push(" \u2502");
129715
- for (const g2 of TRUST_GUARANTEES) {
129716
- lines.push(` \u2502 \u2713 ${g2.headline}`);
129717
- for (const wrapped of wrap(g2.detail, 64)) {
129718
- lines.push(` \u2502 ${wrapped}`);
129719
- }
129720
- lines.push(" \u2502");
129721
- }
129722
- lines.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
129723
- lines.push("");
129724
- return lines.join("\n");
129725
- };
129726
- var wrap = (text, width) => {
129727
- const words = text.split(/\s+/);
129728
- const out = [];
129729
- let line = "";
129730
- for (const word of words) {
129731
- if (line === "") {
129732
- line = word;
129733
- } else if (`${line} ${word}`.length <= width) {
129734
- line = `${line} ${word}`;
129735
- } else {
129736
- out.push(line);
129737
- line = word;
129738
- }
129739
- }
129740
- if (line !== "")
129741
- out.push(line);
129742
- return out;
129743
- };
129744
-
129745
- // dist/src/commands/init.js
129746
- var DEFAULT_VAULT_ROOT3 = "org-kb";
129747
- var JSON_INDENT7 = 2;
129748
- var GITIGNORE_ENTRIES = ["org-kb/source/", "org-kb/graph/"];
129749
- var SF_API_VERSION3 = "62.0";
129750
- var DEFAULT_PACKAGE_DIR = "force-app";
129751
- var execAsync3 = promisify6(exec3);
129752
- var runInit = async (opts) => {
129753
- const resolvedRoot = isAbsolute5(opts.vaultRoot) ? opts.vaultRoot : resolve9(opts.cwd, opts.vaultRoot);
129754
- if (!opts.force && await pathExists5(resolvedRoot)) {
129755
- return err({
129756
- kind: "already-exists",
129757
- message: `vault already exists: ${resolvedRoot}`,
129758
- path: resolvedRoot
129759
- });
129760
- }
129761
- const paths = vaultPaths(resolvedRoot);
129762
- const mkdirResult = await createVaultDirs(paths);
129763
- if (!mkdirResult.ok)
129764
- return mkdirResult;
129765
- const writeResult = await writeVaultMetadata(paths, opts.targetOrg, resolvedRoot);
129766
- if (!writeResult.ok)
129767
- return writeResult;
129768
- const dxProjectScaffolded = await ensureDxProject(opts.cwd);
129769
- const gitignoreUpdated = await updateGitignore(opts.cwd);
129770
- return ok({ vaultRoot: resolvedRoot, targetOrg: opts.targetOrg, gitignoreUpdated, dxProjectScaffolded });
129771
- };
129772
- var ensureDxProject = async (cwd) => {
129773
- const projectPath = join30(cwd, "sfdx-project.json");
129774
- let wrote = false;
129775
- if (!await pathExists5(projectPath)) {
129776
- const project = {
129777
- packageDirectories: [{ path: DEFAULT_PACKAGE_DIR, default: true }],
129778
- namespace: "",
129779
- sourceApiVersion: SF_API_VERSION3
129780
- };
129781
- try {
129782
- await writeFile14(projectPath, `${JSON.stringify(project, null, JSON_INDENT7)}
129783
- `, "utf8");
129784
- wrote = true;
129785
- } catch {
129786
- }
129787
- }
129788
- try {
129789
- await mkdir14(join30(cwd, DEFAULT_PACKAGE_DIR), { recursive: true });
129790
- } catch {
129791
- }
129792
- return wrote;
129793
- };
129794
- var createVaultDirs = async (paths) => {
129795
- for (const dir of [paths.root, paths.source, paths.components, paths.graph, paths.meta]) {
129796
- try {
129797
- await mkdir14(dir, { recursive: true });
129798
- } catch (cause) {
129799
- return err({ kind: "mkdir-failed", message: `failed to create directory: ${dir}`, path: dir, cause });
129800
- }
129801
- }
129802
- return ok(void 0);
129803
- };
129804
- var writeVaultMetadata = async (paths, targetOrg, resolvedRoot) => {
129805
- const config = {
129806
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
129807
- targetOrg,
129808
- vaultRoot: resolvedRoot,
129809
- version: readCliPackageVersion(),
129810
- snapshotOnRefresh: true
129811
- };
129812
- try {
129813
- await writeFile14(paths.config, `${JSON.stringify(config, null, JSON_INDENT7)}
129814
- `, "utf8");
129815
- } catch (cause) {
129816
- return err({ kind: "write-failed", message: `failed to write config: ${paths.config}`, path: paths.config, cause });
129817
- }
129818
- const versionTxtPath = join30(paths.meta, "version.txt");
129819
- try {
129820
- await writeFile14(versionTxtPath, `${readCliPackageVersion()}
129821
- `, "utf8");
129822
- } catch (cause) {
129823
- return err({ kind: "write-failed", message: `failed to write version.txt: ${versionTxtPath}`, path: versionTxtPath, cause });
129824
- }
129825
- return ok(void 0);
129826
- };
129827
- var updateGitignore = async (cwd) => {
129828
- const gitignorePath = join30(cwd, ".gitignore");
129829
- let existing = "";
129830
- let exists = true;
129831
- try {
129832
- existing = await readFile82(gitignorePath, "utf8");
129833
- } catch (cause) {
129834
- if (!isEnoent4(cause))
129835
- return false;
129836
- exists = false;
129837
- }
129838
- const present = new Set(existing.split(/\r?\n/).map((line) => line.trim()));
129839
- const missing = GITIGNORE_ENTRIES.filter((entry) => !present.has(entry));
129840
- if (missing.length === 0)
129841
- return false;
129842
- const needsNewline = exists && existing.length > 0 && !existing.endsWith("\n");
129843
- const next = `${existing}${needsNewline ? "\n" : ""}${missing.join("\n")}
129844
- `;
129845
- try {
129846
- await writeFile14(gitignorePath, next, "utf8");
129847
- return true;
129848
- } catch {
129849
- return false;
129850
- }
129851
- };
129852
- var pathExists5 = async (path) => {
129853
- try {
129854
- await stat13(path);
129855
- return true;
129856
- } catch (cause) {
129857
- return !isEnoent4(cause);
129858
- }
129859
- };
129860
- var isEnoent4 = (cause) => typeof cause === "object" && cause !== null && "code" in cause && cause.code === "ENOENT";
129861
- var ORG_CATEGORIES = ["nonScratchOrgs", "scratchOrgs", "otherOrgs", "devHubs", "sandboxes"];
129862
- var getDefaultOrgAlias = async () => {
129863
- try {
129864
- const { stdout } = await execAsync3("sf org list --json");
129865
- const parsed = JSON.parse(stdout);
129866
- const result = parsed.result;
129867
- if (result === void 0 || result === null)
129868
- return null;
129869
- for (const key of ORG_CATEGORIES) {
129870
- const entries = result[key];
129871
- if (!Array.isArray(entries))
129872
- continue;
129873
- for (const item of entries) {
129874
- if (typeof item !== "object" || item === null)
129875
- continue;
129876
- const entry = item;
129877
- if (entry["isDefaultUsername"] !== true && entry["isDefaultDevHubUsername"] !== true)
129878
- continue;
129879
- const alias = entry["alias"] ?? entry["username"];
129880
- if (typeof alias === "string" && alias.length > 0)
129881
- return alias;
129882
- }
129883
- }
129884
- return null;
129885
- } catch {
129886
- return null;
129887
- }
129888
- };
129889
- var registerInitCommand = (program) => {
129890
- program.command("init").description("Initialise a new org-kb vault in the current directory").option("--target-org <alias>", "Salesforce org alias to bind to this vault").option("--vault-root <path>", "Vault root directory (relative to CWD)").option("--force", "Overwrite an existing org-kb/ vault config", false).action(async (flags) => {
129891
- const cwd = process.cwd();
129892
- const exitCode = await handleInit(cwd, flags);
129893
- if (exitCode !== 0)
129894
- process.exit(exitCode);
129895
- });
129896
- };
129897
- var handleInit = async (cwd, flags) => {
129898
- const interactive = process.stdin.isTTY === true;
129899
- const vaultRoot = flags.vaultRoot ?? (interactive ? await input({ message: "Vault root directory:", default: DEFAULT_VAULT_ROOT3 }) : DEFAULT_VAULT_ROOT3);
129900
- const resolvedRoot = isAbsolute5(vaultRoot) ? vaultRoot : resolve9(cwd, vaultRoot);
129901
- let force = flags.force ?? false;
129902
- if (!force && await pathExists5(resolvedRoot)) {
129903
- if (!interactive) {
129904
- process.stderr.write(`sfi init: ${vaultRoot}/ already exists. Re-run with --force to overwrite.
129905
- `);
129906
- return 1;
129907
- }
129908
- const overwrite = await confirm({
129909
- message: `${vaultRoot}/ already exists. Overwrite config?`,
129910
- default: false
129911
- });
129912
- if (!overwrite) {
129913
- process.stdout.write("Existing init preserved.\n");
129914
- return 0;
129915
- }
129916
- force = true;
129917
- }
129918
- const targetOrg = await resolveTargetOrg(flags, interactive);
129919
- if (targetOrg === null) {
129920
- process.stderr.write("sfi init: no --target-org given and no default Salesforce org found. Pass --target-org <alias>.\n");
129921
- return 1;
129922
- }
129923
- return runAndReport({ cwd, targetOrg, vaultRoot, force });
129924
- };
129925
- var resolveTargetOrg = async (flags, interactive) => {
129926
- if (flags.targetOrg !== void 0)
129927
- return flags.targetOrg;
129928
- const detected = await getDefaultOrgAlias();
129929
- if (!interactive)
129930
- return detected;
129931
- return input({
129932
- message: "Target org alias:",
129933
- ...detected !== null ? { default: detected } : {}
129934
- });
129935
- };
129936
- var runAndReport = async (opts) => {
129937
- const result = await runInit(opts);
129938
- if (!result.ok) {
129939
- process.stderr.write(`sfi init: ${result.error.message}
129940
- `);
129941
- return 1;
129942
- }
129943
- process.stdout.write([
129944
- `Initialised vault at ${result.value.vaultRoot}`,
129945
- `Target org: ${result.value.targetOrg}`,
129946
- result.value.gitignoreUpdated ? "Updated .gitignore" : ".gitignore already up to date (or could not be written)",
129947
- result.value.dxProjectScaffolded ? "Scaffolded sfdx-project.json (ready for sf project retrieve)" : "sfdx-project.json already present",
129948
- ""
129949
- ].join("\n"));
129950
- process.stdout.write(formatTrustStatement());
129951
- process.stdout.write("Next: run sfi refresh\n\n");
129952
- return 0;
129953
- };
129954
-
129955
130157
  // dist/src/commands/list-vaults.js
129956
130158
  init_src2();
129957
130159
  var JSON_INDENT8 = 2;
@@ -129997,113 +130199,6 @@ var registerListVaultsCommand = (program) => {
129997
130199
  });
129998
130200
  };
129999
130201
 
130000
- // dist/src/commands/mcp.js
130001
- init_dist();
130002
- init_src7();
130003
- init_src2();
130004
- import { execFile as execFile4 } from "node:child_process";
130005
- import { readFile as readFile83, stat as stat14 } from "node:fs/promises";
130006
- import { resolve as resolve10 } from "node:path";
130007
- import { promisify as promisify7 } from "node:util";
130008
- var DEFAULT_VAULT_ROOT4 = "org-kb";
130009
- var SHUTDOWN_SIGNALS = ["SIGINT", "SIGTERM"];
130010
- var readBoundOrg = async (configPath) => {
130011
- try {
130012
- const raw = await readFile83(configPath, "utf8");
130013
- const parsed = JSON.parse(raw);
130014
- return typeof parsed.targetOrg === "string" ? parsed.targetOrg : null;
130015
- } catch {
130016
- return null;
130017
- }
130018
- };
130019
- var nodeExecFile3 = promisify7(execFile4);
130020
- var defaultListOrgs = async () => {
130021
- try {
130022
- const { stdout } = await nodeExecFile3("sf", ["org", "list", "--json"], {
130023
- maxBuffer: 10 * 1024 * 1024
130024
- });
130025
- const json = JSON.parse(stdout);
130026
- const groups = json.result ?? {};
130027
- const seen = /* @__PURE__ */ new Set();
130028
- const out = [];
130029
- for (const list of Object.values(groups)) {
130030
- for (const org of list ?? []) {
130031
- const label = org.alias ?? org.username;
130032
- if (label && !seen.has(label)) {
130033
- seen.add(label);
130034
- out.push(label);
130035
- }
130036
- }
130037
- }
130038
- return out;
130039
- } catch {
130040
- return [];
130041
- }
130042
- };
130043
- var prepareMcp = async (opts) => {
130044
- const vaultRoot = opts.vaultRoot !== void 0 ? resolve10(opts.cwd, opts.vaultRoot) : resolve10(opts.cwd, DEFAULT_VAULT_ROOT4);
130045
- const paths = vaultPaths(vaultRoot);
130046
- if (!await pathExists6(paths.config)) {
130047
- const orgs = await (opts.listOrgs ?? defaultListOrgs)();
130048
- const where = opts.vaultRoot !== void 0 ? ` at ${vaultRoot}` : "";
130049
- const base = `No vault${where}. Run \`sfi init\` followed by \`sfi refresh\`, or point \`sfi mcp --vault <path>\` at an existing org-kb.`;
130050
- const hint = orgs.length > 0 ? ` You are authenticated to ${orgs.length} org(s): ${orgs.slice(0, 8).join(", ")}${orgs.length > 8 ? ", \u2026" : ""}. Run \`sfi init\` to pick the one you want and build its knowledge base \u2014 live answers attach to a vault's org, so the product never guesses which of your orgs to query.` : "";
130051
- return err({ kind: "no-vault", message: base + hint });
130052
- }
130053
- const ctxResult = await buildContext(vaultRoot);
130054
- if (!ctxResult.ok) {
130055
- return err({ kind: "buildContext-failed", message: ctxResult.error.message });
130056
- }
130057
- const targetOrg = await readBoundOrg(paths.config);
130058
- return ok({
130059
- ctx: ctxResult.value,
130060
- server: createServer(ctxResult.value),
130061
- vaultRoot,
130062
- targetOrg
130063
- });
130064
- };
130065
- var pathExists6 = async (path) => {
130066
- try {
130067
- await stat14(path);
130068
- return true;
130069
- } catch (cause) {
130070
- return !isEnoent5(cause);
130071
- }
130072
- };
130073
- var isEnoent5 = (cause) => typeof cause === "object" && cause !== null && "code" in cause && cause.code === "ENOENT";
130074
- var registerMcpCommand = (program) => {
130075
- program.command("mcp").description("Run the MCP server backing the org-kb vault").option("--vault <path>", "Serve a specific org-kb vault instead of ./org-kb (bind a project to the right org)").action(async (cmdOpts) => {
130076
- const prepared = await prepareMcp({
130077
- cwd: process.cwd(),
130078
- ...cmdOpts.vault !== void 0 ? { vaultRoot: cmdOpts.vault } : {}
130079
- });
130080
- if (!prepared.ok) {
130081
- process.stderr.write(`sfi mcp: ${prepared.error.message}
130082
- `);
130083
- process.exit(1);
130084
- }
130085
- const { ctx, server, vaultRoot, targetOrg } = prepared.value;
130086
- process.stderr.write(`sfi mcp: serving vault ${vaultRoot}${targetOrg !== null ? ` (org: ${targetOrg})` : " (no targetOrg in config)"}
130087
- `);
130088
- const shutdownOnce = makeShutdownOnce(ctx);
130089
- for (const signal of SHUTDOWN_SIGNALS) {
130090
- process.on(signal, () => {
130091
- void shutdownOnce().then(() => process.exit(0));
130092
- });
130093
- }
130094
- await startServer(server);
130095
- await shutdownOnce();
130096
- });
130097
- };
130098
- var makeShutdownOnce = (ctx) => {
130099
- let done = null;
130100
- return () => {
130101
- if (done === null)
130102
- done = shutdown(ctx);
130103
- return done;
130104
- };
130105
- };
130106
-
130107
130202
  // dist/src/commands/quickstart.js
130108
130203
  init_src();
130109
130204
  init_src2();
@@ -130361,9 +130456,9 @@ init_vault_git();
130361
130456
  init_watch();
130362
130457
  var readVersion = () => {
130363
130458
  if (true)
130364
- return "0.1.12";
130459
+ return "0.1.13";
130365
130460
  const pkgUrl = new URL("../../package.json", import.meta.url);
130366
- const raw = readFileSync5(fileURLToPath2(pkgUrl), "utf8");
130461
+ const raw = readFileSync6(fileURLToPath3(pkgUrl), "utf8");
130367
130462
  const parsed = JSON.parse(raw);
130368
130463
  return parsed.version ?? "0.0.0";
130369
130464
  };
@@ -130380,6 +130475,7 @@ var createProgram = () => {
130380
130475
  registerVaultCommand(program);
130381
130476
  registerDoctorCommand(program);
130382
130477
  registerMcpCommand(program);
130478
+ registerDemoCommand(program);
130383
130479
  registerServeCommand(program);
130384
130480
  registerSelftestCommand(program);
130385
130481
  registerFeedbackCommand(program);