@trops/dash-core 0.1.511 → 0.1.513

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.
@@ -2426,7 +2426,7 @@ function isFsWriteAction(action) {
2426
2426
  return WRITE_ACTIONS.has(action);
2427
2427
  }
2428
2428
 
2429
- function _isNoGrantDenial$2(reason) {
2429
+ function _isNoGrantDenial$1(reason) {
2430
2430
  return (
2431
2431
  typeof reason === "string" && /no fs permissions granted/i.test(reason)
2432
2432
  );
@@ -2572,7 +2572,7 @@ async function gateFsCallWithJit$1(req, opts = {}) {
2572
2572
  const initial = gateFsCall$1(req);
2573
2573
  if (initial.allow) return initial;
2574
2574
  if (!opts.enableJit) return initial;
2575
- if (!_isNoGrantDenial$2(initial.reason)) return initial;
2575
+ if (!_isNoGrantDenial$1(initial.reason)) return initial;
2576
2576
 
2577
2577
  // Resolve verified identity once (token wins over claimed widgetId).
2578
2578
  // Re-using the same resolution as gateFsCall keeps the JIT prompt
@@ -2714,7 +2714,7 @@ function _resolveIdentity$1({ token, widgetId }) {
2714
2714
  return { widgetId: widgetId || null, source: "legacy" };
2715
2715
  }
2716
2716
 
2717
- function _isNoGrantDenial$1(reason) {
2717
+ function _isNoGrantDenial(reason) {
2718
2718
  return (
2719
2719
  typeof reason === "string" && /no network permissions granted/i.test(reason)
2720
2720
  );
@@ -2853,7 +2853,7 @@ async function gateNetworkCallWithJit$2(req, opts = {}) {
2853
2853
  const initial = gateNetworkCall$2(req);
2854
2854
  if (initial.allow) return initial;
2855
2855
  if (!opts.enableJit) return initial;
2856
- if (!_isNoGrantDenial$1(initial.reason)) return initial;
2856
+ if (!_isNoGrantDenial(initial.reason)) return initial;
2857
2857
 
2858
2858
  // Same identity-resolution as the sync gate — the JIT prompt and
2859
2859
  // grant write must use the verified widgetId, not whatever the
@@ -22582,18 +22582,6 @@ function gateToolCall$1({ widgetId, token, serverName, toolName, args }) {
22582
22582
  return { allow: true };
22583
22583
  }
22584
22584
 
22585
- /**
22586
- * Heuristic — "no grant" is the only denial reason JIT can recover.
22587
- * Other denials (missing widgetId, malformed args, server-not-declared
22588
- * post-grant, path-traversal-rejected) are bugs or attempted abuse,
22589
- * not consent gaps; the user shouldn't be prompted about those.
22590
- */
22591
- function _isNoGrantDenial(reason) {
22592
- return (
22593
- typeof reason === "string" && /no MCP permissions granted/i.test(reason)
22594
- );
22595
- }
22596
-
22597
22585
  /**
22598
22586
  * Merge `addition` (a grant blob) into the widget's existing grant. Used
22599
22587
  * by the JIT path to extend an existing grant with a new tool/path
@@ -22627,29 +22615,55 @@ function _mergeGrant(current, addition) {
22627
22615
  }
22628
22616
 
22629
22617
  /**
22630
- * Async wrapper around gateToolCall that escalates "no grant" denials
22631
- * to a just-in-time consent prompt when `opts.enableJit` is true.
22618
+ * Async wrapper around gateToolCall that escalates "missing in grant"
22619
+ * denials to a just-in-time consent prompt when `opts.enableJit` is true.
22632
22620
  * On approval, the user's chosen grant shape (carried on
22633
22621
  * `decision.granted`) is merged into the persisted grant and the gate
22634
22622
  * re-evaluates. On denial / timeout / disabled-flag, returns the
22635
22623
  * synchronous decision unchanged.
22636
22624
  *
22625
+ * Escalation signal is STRUCTURAL, not message-based: if the requested
22626
+ * tool isn't listed in the widget's grant for the requested server, JIT
22627
+ * fires. This uniformly covers no-grant, server-not-in-grant, and
22628
+ * tool-not-in-server's-allowlist — all three are recoverable by adding
22629
+ * to the grant via the modal. If the tool IS in the grant, the sync
22630
+ * gate's verdict stands: any denial it returns is a structural-integrity
22631
+ * issue (path-arg traversal, path-arg without paths declared) that isn't
22632
+ * a consent gap and shouldn't prompt. Identity-resolution failures
22633
+ * (unknown token, missing widgetId) likewise short-circuit to the sync
22634
+ * verdict — those are abuse or caller bugs, not consent gaps.
22635
+ *
22637
22636
  * @returns {Promise<{ allow: true } | { allow: false, reason: string }>}
22638
22637
  */
22639
22638
  async function gateToolCallWithJit$1(req, opts = {}) {
22640
- const initial = gateToolCall$1(req);
22641
- if (initial.allow) return initial;
22642
- if (!opts.enableJit) return initial;
22643
- if (!_isNoGrantDenial(initial.reason)) return initial;
22639
+ if (!opts.enableJit) return gateToolCall$1(req);
22644
22640
 
22645
- // Same identity-resolution as the sync gate JIT prompt and grant
22646
- // write must use the verified widgetId.
22641
+ // Identity must resolve to a concrete widgetId. Unknown tokens and
22642
+ // missing widgetId are returned by the sync gate — those denials are
22643
+ // not recoverable via consent.
22647
22644
  const resolved = _resolveIdentity({
22648
22645
  token: req.token,
22649
22646
  widgetId: req.widgetId,
22650
22647
  });
22648
+ if (resolved.source === "token-unknown" || !resolved.widgetId) {
22649
+ return gateToolCall$1(req);
22650
+ }
22651
22651
  const verifiedWidgetId = resolved.widgetId;
22652
- if (!verifiedWidgetId) return initial;
22652
+
22653
+ // Structural escalation: when the tool already exists in the grant,
22654
+ // the sync gate's verdict is authoritative — any denial is structural
22655
+ // (containment / scope) and not recoverable by re-prompting. When the
22656
+ // tool is missing from the grant, escalate regardless of which of the
22657
+ // three "missing" shapes caused it.
22658
+ const grant = getGrant$1(verifiedWidgetId);
22659
+ const hasToolInGrant = !!(
22660
+ grant &&
22661
+ grant.servers &&
22662
+ grant.servers[req.serverName] &&
22663
+ Array.isArray(grant.servers[req.serverName].tools) &&
22664
+ grant.servers[req.serverName].tools.includes(req.toolName)
22665
+ );
22666
+ if (hasToolInGrant) return gateToolCall$1(req);
22653
22667
 
22654
22668
  let decision;
22655
22669
  try {
@@ -22669,11 +22683,7 @@ async function gateToolCallWithJit$1(req, opts = {}) {
22669
22683
  } catch (e) {
22670
22684
  return {
22671
22685
  allow: false,
22672
- reason:
22673
- "JIT consent " +
22674
- (e && e.message ? e.message : "failed") +
22675
- "; original denial: " +
22676
- initial.reason,
22686
+ reason: "JIT consent " + (e && e.message ? e.message : "failed"),
22677
22687
  };
22678
22688
  }
22679
22689