@sanctuary-framework/mcp-server 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -2037,6 +2037,7 @@ var init_audit_log = __esm({
2037
2037
  maxTotalSizeBytes;
2038
2038
  maxEntries;
2039
2039
  rotationInFlight = false;
2040
+ pendingWrites = /* @__PURE__ */ new Set();
2040
2041
  constructor(storage, masterKey, config) {
2041
2042
  this.storage = storage;
2042
2043
  this.encryptionKey = derivePurposeKey(masterKey, "audit-log");
@@ -2045,6 +2046,15 @@ var init_audit_log = __esm({
2045
2046
  }
2046
2047
  /**
2047
2048
  * Append an audit entry.
2049
+ *
2050
+ * The on-disk persist is async and tracked via `pendingWrites`. Long-lived
2051
+ * callers (the main MCP server) can ignore that tracking and let writes
2052
+ * drain naturally. Short-lived callers — the `sanctuary secrets` CLI which
2053
+ * `process.exit()`s immediately after returning from a broker mutation —
2054
+ * MUST await `flush()` before exiting, or in-flight writes get killed
2055
+ * with the event loop and the entry is silently lost. That was the
2056
+ * v0.10.0-rc.2 soak failure mode where `secrets audit` returned empty
2057
+ * after a clean 7-verb lifecycle.
2048
2058
  */
2049
2059
  append(layer, operation, identityId, details, result = "success") {
2050
2060
  const entry = {
@@ -2056,8 +2066,22 @@ var init_audit_log = __esm({
2056
2066
  details
2057
2067
  };
2058
2068
  this.entries.push(entry);
2059
- this.persistEntry(entry).catch(() => {
2069
+ const writePromise = this.persistEntry(entry).catch(() => {
2060
2070
  });
2071
+ this.pendingWrites.add(writePromise);
2072
+ void writePromise.finally(() => this.pendingWrites.delete(writePromise));
2073
+ }
2074
+ /**
2075
+ * Wait for every in-flight `append()` persist (and its rotation pass) to
2076
+ * settle. Safe to call multiple times — newly-appended entries during a
2077
+ * flush are also awaited. Re-entrant only at the granularity of "drain
2078
+ * everything queued so far". Short-lived CLIs MUST call this before
2079
+ * `process.exit()` to keep audit writes durable.
2080
+ */
2081
+ async flush() {
2082
+ while (this.pendingWrites.size > 0) {
2083
+ await Promise.allSettled([...this.pendingWrites]);
2084
+ }
2061
2085
  }
2062
2086
  async persistEntry(entry) {
2063
2087
  const key = `${Date.now()}-${this.counter++}`;
@@ -2068,7 +2092,7 @@ var init_audit_log = __esm({
2068
2092
  key,
2069
2093
  stringToBytes(JSON.stringify(encrypted))
2070
2094
  );
2071
- this.maybeRotate().catch(() => {
2095
+ await this.maybeRotate().catch(() => {
2072
2096
  });
2073
2097
  }
2074
2098
  /**
@@ -24128,11 +24152,13 @@ var init_runtime = __esm({
24128
24152
  var cli_exports = {};
24129
24153
  __export(cli_exports, {
24130
24154
  COCOON_GOVERNOR_DEFAULTS: () => COCOON_GOVERNOR_DEFAULTS,
24155
+ PORT_FALLBACK_ATTEMPTS: () => PORT_FALLBACK_ATTEMPTS,
24131
24156
  formatWrapSuccess: () => formatWrapSuccess,
24132
24157
  parseCocoonArgs: () => parseCocoonArgs,
24133
24158
  parseWrapArgs: () => parseWrapArgs,
24134
24159
  runCocoon: () => runCocoon,
24135
- runWrap: () => runWrap
24160
+ runWrap: () => runWrap,
24161
+ startDashboardWithFallback: () => startDashboardWithFallback
24136
24162
  });
24137
24163
  async function runWrap(options, deps = {}) {
24138
24164
  if (options.unwrap) {
@@ -24376,7 +24402,8 @@ async function runCocoon(options) {
24376
24402
  }
24377
24403
  async function startDashboardWithFallback(startFn, preferredPort, authToken, serverVersion) {
24378
24404
  let lastErr;
24379
- for (let port = preferredPort; port <= MAX_PORT; port++) {
24405
+ for (let i = 0; i < PORT_FALLBACK_ATTEMPTS; i++) {
24406
+ const port = preferredPort + i;
24380
24407
  try {
24381
24408
  const handle = await startFn({
24382
24409
  port,
@@ -24395,8 +24422,9 @@ async function startDashboardWithFallback(startFn, preferredPort, authToken, ser
24395
24422
  if (!isAddressInUse(err)) throw err;
24396
24423
  }
24397
24424
  }
24425
+ const lastPort = preferredPort + PORT_FALLBACK_ATTEMPTS - 1;
24398
24426
  throw new Error(
24399
- `No free dashboard port in range ${preferredPort}-${MAX_PORT}: ${lastErr?.message ?? "unknown"}`
24427
+ `No free dashboard port in the ${PORT_FALLBACK_ATTEMPTS} ports starting at ${preferredPort} (tried ${preferredPort}-${lastPort}): ${lastErr?.message ?? "unknown"}`
24400
24428
  );
24401
24429
  }
24402
24430
  function isAddressInUse(err) {
@@ -24644,7 +24672,7 @@ function printWrapHelp() {
24644
24672
  5. Every tool call is logged, scanned, and tier-gated
24645
24673
  `);
24646
24674
  }
24647
- var COCOON_GOVERNOR_DEFAULTS, MAX_PORT, parseCocoonArgs;
24675
+ var COCOON_GOVERNOR_DEFAULTS, PORT_FALLBACK_ATTEMPTS, parseCocoonArgs;
24648
24676
  var init_cli = __esm({
24649
24677
  "src/cocoon/cli.ts"() {
24650
24678
  init_config_reader();
@@ -24658,7 +24686,7 @@ var init_cli = __esm({
24658
24686
  rate_limit_per_tool: 20,
24659
24687
  lifetime_limit: 1e3
24660
24688
  };
24661
- MAX_PORT = 3510;
24689
+ PORT_FALLBACK_ATTEMPTS = 20;
24662
24690
  parseCocoonArgs = parseWrapArgs;
24663
24691
  }
24664
24692
  });
@@ -26162,6 +26190,7 @@ async function openBroker(opts = {}) {
26162
26190
  return {
26163
26191
  broker,
26164
26192
  close: async () => {
26193
+ await auditLog.flush();
26165
26194
  }
26166
26195
  };
26167
26196
  }
@@ -27186,12 +27215,12 @@ function optionalNumber(args, key) {
27186
27215
  const v = args[key];
27187
27216
  return typeof v === "number" && Number.isFinite(v) ? v : void 0;
27188
27217
  }
27189
- var require4, PKG_VERSION3;
27218
+ var PKG_VERSION3;
27190
27219
  var init_broker_server = __esm({
27191
27220
  "src/mcp/broker-server.ts"() {
27221
+ init_config();
27192
27222
  init_token_issuer();
27193
- require4 = createRequire(import.meta.url);
27194
- ({ version: PKG_VERSION3 } = require4("../../package.json"));
27223
+ PKG_VERSION3 = SANCTUARY_VERSION;
27195
27224
  }
27196
27225
  });
27197
27226
 
@@ -27610,8 +27639,8 @@ async function checkForUpdate(currentVersion) {
27610
27639
  } catch {
27611
27640
  }
27612
27641
  }
27613
- var require5 = createRequire(import.meta.url);
27614
- var { version: PKG_VERSION4 } = require5("../package.json");
27642
+ var require4 = createRequire(import.meta.url);
27643
+ var { version: PKG_VERSION4 } = require4("../package.json");
27615
27644
  async function main() {
27616
27645
  const args = process.argv.slice(2);
27617
27646
  let passphrase = process.env.SANCTUARY_PASSPHRASE;