@suveren/gateway 0.36.1 → 0.37.0

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 (65) hide show
  1. package/content/integrations/erp.json +1 -1
  2. package/dist/mcp-server/http.mjs +66 -18
  3. package/dist/ui/assets/{index-BQ5Pr6As.js → index-BC2bXeCQ.js} +26 -26
  4. package/dist/ui/index.html +1 -1
  5. package/node_modules/fast-uri/.github/workflows/release.yml +35 -0
  6. package/node_modules/fast-uri/README.md +8 -0
  7. package/node_modules/fast-uri/index.js +98 -18
  8. package/node_modules/fast-uri/lib/utils.js +52 -0
  9. package/node_modules/fast-uri/package.json +1 -1
  10. package/node_modules/fast-uri/test/host-delimiter-security.test.js +94 -0
  11. package/node_modules/fast-uri/test/relative-normalization-security.test.js +156 -0
  12. package/node_modules/fast-uri/test/reserved-path-normalization.test.js +32 -4
  13. package/node_modules/fast-uri/test/scheme-validation.test.js +53 -14
  14. package/node_modules/jose/README.md +2 -2
  15. package/node_modules/jose/dist/types/jwe/compact/decrypt.d.ts +5 -4
  16. package/node_modules/jose/dist/types/jwe/compact/encrypt.d.ts +4 -4
  17. package/node_modules/jose/dist/types/jwe/flattened/decrypt.d.ts +5 -4
  18. package/node_modules/jose/dist/types/jwe/flattened/encrypt.d.ts +5 -5
  19. package/node_modules/jose/dist/types/jwe/general/decrypt.d.ts +5 -4
  20. package/node_modules/jose/dist/types/jwe/general/encrypt.d.ts +5 -5
  21. package/node_modules/jose/dist/types/jws/compact/sign.d.ts +5 -4
  22. package/node_modules/jose/dist/types/jws/compact/verify.d.ts +5 -5
  23. package/node_modules/jose/dist/types/jws/flattened/sign.d.ts +5 -4
  24. package/node_modules/jose/dist/types/jws/flattened/verify.d.ts +6 -5
  25. package/node_modules/jose/dist/types/jws/general/sign.d.ts +9 -6
  26. package/node_modules/jose/dist/types/jws/general/verify.d.ts +7 -5
  27. package/node_modules/jose/dist/types/jwt/decrypt.d.ts +7 -6
  28. package/node_modules/jose/dist/types/jwt/encrypt.d.ts +1 -1
  29. package/node_modules/jose/dist/types/jwt/sign.d.ts +1 -1
  30. package/node_modules/jose/dist/types/jwt/unsecured.d.ts +1 -1
  31. package/node_modules/jose/dist/types/jwt/verify.d.ts +3 -5
  32. package/node_modules/jose/dist/types/key/export.d.ts +1 -1
  33. package/node_modules/jose/dist/types/key/generate_secret.d.ts +1 -1
  34. package/node_modules/jose/dist/types/key/import.d.ts +2 -2
  35. package/node_modules/jose/dist/types/types.d.ts +165 -107
  36. package/node_modules/jose/dist/types/util/decode_jwt.d.ts +2 -2
  37. package/node_modules/jose/dist/types/util/errors.d.ts +1 -1
  38. package/node_modules/jose/dist/webapi/jwe/general/encrypt.js +3 -3
  39. package/node_modules/jose/dist/webapi/jwk/thumbprint.js +8 -8
  40. package/node_modules/jose/dist/webapi/jwks/local.js +2 -1
  41. package/node_modules/jose/dist/webapi/jwks/remote.js +4 -4
  42. package/node_modules/jose/dist/webapi/jws/general/sign.js +3 -3
  43. package/node_modules/jose/dist/webapi/jws/general/verify.js +3 -3
  44. package/node_modules/jose/dist/webapi/jwt/encrypt.js +2 -2
  45. package/node_modules/jose/dist/webapi/jwt/sign.js +2 -2
  46. package/node_modules/jose/dist/webapi/jwt/unsecured.js +3 -3
  47. package/node_modules/jose/dist/webapi/key/generate_secret.js +4 -4
  48. package/node_modules/jose/dist/webapi/lib/asn1.js +2 -2
  49. package/node_modules/jose/dist/webapi/lib/buffer_utils.js +4 -4
  50. package/node_modules/jose/dist/webapi/lib/content_encryption.js +8 -8
  51. package/node_modules/jose/dist/webapi/lib/jwe_decrypt.js +14 -14
  52. package/node_modules/jose/dist/webapi/lib/jwe_encrypt.js +3 -3
  53. package/node_modules/jose/dist/webapi/lib/jws_algorithms.js +2 -2
  54. package/node_modules/jose/dist/webapi/lib/jws_sign.js +11 -11
  55. package/node_modules/jose/dist/webapi/lib/jws_verify.js +19 -16
  56. package/node_modules/jose/dist/webapi/lib/jwt_claims_set.js +44 -43
  57. package/node_modules/jose/dist/webapi/lib/key.js +4 -4
  58. package/node_modules/jose/dist/webapi/lib/key_management.js +17 -17
  59. package/node_modules/jose/dist/webapi/lib/validate.js +10 -10
  60. package/node_modules/jose/dist/webapi/util/decode_jwt.js +12 -12
  61. package/node_modules/jose/dist/webapi/util/decode_protected_header.js +5 -5
  62. package/node_modules/jose/package.json +1 -1
  63. package/package.json +1 -1
  64. package/profiles/delegation/0.6.profile.json +183 -0
  65. package/profiles/index.json +2 -1
@@ -6,7 +6,7 @@
6
6
  "icon": "briefcase",
7
7
  "profile": "sales",
8
8
  "npmPackage": "@humanagencyp/erp-mcp",
9
- "npmVersion": "0.9.4",
9
+ "npmVersion": "0.9.5",
10
10
  "mcp": {
11
11
  "command": "erp-mcp",
12
12
  "args": [],
@@ -4801,6 +4801,15 @@ async function readPreview(integrationManager2, integrationId, previewTool, args
4801
4801
  };
4802
4802
  }
4803
4803
  }
4804
+ function unavailableReadMessage(integrationManager2, read, connector, tool, declaredAt) {
4805
+ if (read.reason === "no_connector") {
4806
+ const running = integrationManager2.getAllTools().some((t) => t.integrationId === connector);
4807
+ if (running) {
4808
+ return `Connector "${connector}" is running but has no tool "${tool}" (declared in ${declaredAt}) \u2014 the installed connector version does not offer it.`;
4809
+ }
4810
+ }
4811
+ return read.message ?? `Connector "${connector}" could not be reached.`;
4812
+ }
4804
4813
  function hashPreviewBody(body) {
4805
4814
  if (body.structured !== void 0) {
4806
4815
  return computeContentHash({ kind: "jcs", version: "1" }, body.structured);
@@ -5461,7 +5470,8 @@ async function resolveDocumentReference(integrationManager2, ref) {
5461
5470
  return { ok: false, error: { code: "NOT_FOUND", message: read.message ?? `No document "${ref.kind}"/"${ref.id}" on "${ref.connector}".` } };
5462
5471
  }
5463
5472
  if (read.status !== "ok") {
5464
- return { ok: false, error: { code: "UNAVAILABLE", message: read.message ?? `Connector "${ref.connector}" could not be reached.` } };
5473
+ const message = unavailableReadMessage(integrationManager2, read, ref.connector, docConfig.tool, `documents.${ref.kind}`);
5474
+ return { ok: false, error: { code: "UNAVAILABLE", message } };
5465
5475
  }
5466
5476
  const body = structuredOrJsonText(read.body);
5467
5477
  if (!body || typeof body !== "object") {
@@ -5542,7 +5552,8 @@ async function resolveInsertValue(integrationManager2, ref) {
5542
5552
  return { ok: false, error: { code: "NOT_FOUND", message: read.message ?? `No value "${ref.kind}"/"${ref.id}" on "${ref.connector}".` } };
5543
5553
  }
5544
5554
  if (read.status !== "ok") {
5545
- return { ok: false, error: { code: "UNAVAILABLE", message: read.message ?? `Connector "${ref.connector}" could not be reached.` } };
5555
+ const message = unavailableReadMessage(integrationManager2, read, ref.connector, valueConfig.tool, `values.${ref.kind}`);
5556
+ return { ok: false, error: { code: "UNAVAILABLE", message } };
5546
5557
  }
5547
5558
  const body = structuredOrJsonText(read.body);
5548
5559
  if (!body || typeof body !== "object") {
@@ -6829,7 +6840,9 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
6829
6840
  content: [{
6830
6841
  type: "text",
6831
6842
  text: `Awaiting commitment from domain${auth.deferredCommitmentDomains.length > 1 ? "s" : ""} "${auth.deferredCommitmentDomains.join('", "')}" for tool ${tool.originalName}.
6832
- Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposal_id: "${proposal.id}").` + await unreadableForNote(unreadableFor ?? [], state2)
6843
+ Proposal ID: ${proposal.id}. Check status with check-pending-commitments(proposal_id: "${proposal.id}").` + await unreadableForNote(unreadableFor ?? [], state2) + // Optional wait (2026-10-19): the AI can stay on the line instead of ending its turn.
6844
+ `
6845
+ Tell the person what you proposed and that it waits for their approval in the gateway; then you may wait for the decision: check-pending-commitments(proposal_id: "${proposal.id}", wait_seconds: 50).`
6833
6846
  }]
6834
6847
  };
6835
6848
  } catch (err) {
@@ -8043,6 +8056,18 @@ Reason: ${detail}` : "";
8043
8056
  isError: false
8044
8057
  };
8045
8058
  }
8059
+ var MAX_WAIT_SECONDS = 50;
8060
+ var WAIT_POLL_MS = 2e3;
8061
+ async function getProposalWaiting(get, id, waitSeconds, sleep2 = (ms) => new Promise((r) => setTimeout(r, ms)), now = Date.now) {
8062
+ const waitMs = Math.min(Math.max(Number(waitSeconds) || 0, 0), MAX_WAIT_SECONDS) * 1e3;
8063
+ const deadline = now() + waitMs;
8064
+ let match = await get(id);
8065
+ while (match && match.status === "pending" && now() < deadline) {
8066
+ await sleep2(Math.min(WAIT_POLL_MS, deadline - now()));
8067
+ match = await get(id);
8068
+ }
8069
+ return match;
8070
+ }
8046
8071
  function checkPendingCommitmentsHandler(state2, integrationManager2) {
8047
8072
  return async (args) => {
8048
8073
  if (!state2.spClient.isUnlocked()) {
@@ -8050,7 +8075,11 @@ function checkPendingCommitmentsHandler(state2, integrationManager2) {
8050
8075
  }
8051
8076
  try {
8052
8077
  if (args.proposal_id) {
8053
- const match = await state2.spClient.getProposalById(args.proposal_id);
8078
+ const match = await getProposalWaiting(
8079
+ (id) => state2.spClient.getProposalById(id),
8080
+ args.proposal_id,
8081
+ args.wait_seconds
8082
+ );
8054
8083
  if (!match) {
8055
8084
  return {
8056
8085
  content: [{
@@ -8304,9 +8333,10 @@ function createMcpServer(state2, integrationManager2) {
8304
8333
  server.registerTool(
8305
8334
  "check-pending-commitments",
8306
8335
  {
8307
- description: "Check status of pending proposals awaiting domain owner commitment. Call with a proposal_id to check a specific proposal, or without to see all.",
8336
+ description: "Check status of pending proposals awaiting domain owner commitment. Call with a proposal_id to check a specific proposal, or without to see all. With a proposal_id you may also pass wait_seconds (max 50): the gateway then waits until the person decides and answers at once \u2014 first tell the person what you proposed and that it waits for their approval in the gateway.",
8308
8337
  inputSchema: {
8309
- proposal_id: z2.string().optional().describe("Specific proposal ID to check. Omit to see all.")
8338
+ proposal_id: z2.string().optional().describe("Specific proposal ID to check. Omit to see all."),
8339
+ wait_seconds: z2.number().int().min(0).max(50).optional().describe("Only with proposal_id: wait up to this many seconds (max 50) while the proposal is still pending; answers as soon as the person decides. Omit or 0 to answer at once.")
8310
8340
  }
8311
8341
  },
8312
8342
  withOutcomeOutbox(checkPendingCommitmentsHandler(state2, integrationManager2))
@@ -10497,7 +10527,7 @@ function unifiedLineDiff(before, after) {
10497
10527
  }
10498
10528
 
10499
10529
  // src/lib/builtins/setup.ts
10500
- import { getProfile as getProfile9 } from "@hap/core";
10530
+ import { getProfile as getProfile9, listProfiles } from "@hap/core";
10501
10531
  var DELEGATION_PROFILE = "delegation";
10502
10532
  var DELEGATION_INTENT_HINT = [
10503
10533
  "Why \u2014 With test data only, I want to find out which routine parts of my work an AI could take over, so people gain time \u2014 before anything touches real systems.",
@@ -10541,10 +10571,28 @@ function shortName(idOrName) {
10541
10571
  function versionOf(id) {
10542
10572
  return id.split("@")[1] ?? "";
10543
10573
  }
10544
- function delegationItselfRefusal(args) {
10545
- const requested = typeof args.profile === "string" ? args.profile : "";
10546
- if (shortName(requested) === DELEGATION_PROFILE) {
10547
- return "Delegation can never be proposed \u2014 the AI cannot widen its own delegation.";
10574
+ var MANDATE_ACTION = "mandate";
10575
+ function knownVersions(short) {
10576
+ const byId = /* @__PURE__ */ new Map();
10577
+ for (const key of listProfiles()) {
10578
+ if (shortName(key) !== short) continue;
10579
+ const p = getProfile9(key);
10580
+ if (p) byId.set(p.id, p);
10581
+ }
10582
+ return [...byId.values()];
10583
+ }
10584
+ function proposalTargetRefusal(args) {
10585
+ const requested = typeof args.profile === "string" ? shortName(args.profile.trim()) : "";
10586
+ const versions = requested ? knownVersions(requested) : [];
10587
+ if (versions.length === 0) {
10588
+ return { code: "UNKNOWN_PROFILE", message: `Unknown profile "${requested}" \u2014 not in this gateway's profile catalog.` };
10589
+ }
10590
+ if (versions.some((p) => p.boundsSchema?.actionTypes?.includes(MANDATE_ACTION))) {
10591
+ const name = versions.map((p) => p.name).find(Boolean) ?? requested;
10592
+ return {
10593
+ code: "DELEGATION_NOT_PROPOSABLE",
10594
+ message: `${name} can never be proposed \u2014 it lets an AI propose mandates, and the AI cannot widen its own delegation.`
10595
+ };
10548
10596
  }
10549
10597
  return void 0;
10550
10598
  }
@@ -10711,7 +10759,7 @@ function setupBuiltin(deps) {
10711
10759
  },
10712
10760
  create_mandate: {
10713
10761
  executionMapping: { profile: "allowed_profiles", mode: "allowed_modes" },
10714
- staticExecution: { action_type: "mandate" },
10762
+ staticExecution: { action_type: MANDATE_ACTION },
10715
10763
  actionLabel: "Mandate proposed",
10716
10764
  hideUnlessAuthorized: true,
10717
10765
  // Shown like the mandate screen: limits and scope by the profile's own names.
@@ -10800,7 +10848,7 @@ ${body}`);
10800
10848
  description: "Propose a new mandate for the person running this gateway \u2014 the authority another tool needs (e.g. sales quotes up to a value). Always goes to the person's current workspace (their team, or Personal if they are not in one) \u2014 there is no way to name a different one. A person approves or rejects the proposal; only after approval is the mandate created, exactly as if they had signed it on the mandate screen. Checked against the profile before the proposal: unknown limits, a mode the profile does not allow, or a team where the person may not give this mandate are refused at once. Outside simulation mode, the profile and mode you may propose are themselves limited by your Delegation mandate's scope \u2014 Delegation itself can never be proposed. Create only.",
10801
10849
  inputSchema: CREATE_MANDATE_INPUT_SCHEMA,
10802
10850
  validate: async (args) => {
10803
- const fixed = delegationItselfRefusal(args);
10851
+ const fixed = proposalTargetRefusal(args);
10804
10852
  if (fixed) {
10805
10853
  deps.state.denialLog?.record({
10806
10854
  ts: Date.now(),
@@ -10808,18 +10856,18 @@ ${body}`);
10808
10856
  integrationId: "setup",
10809
10857
  profile: DELEGATION_PROFILE,
10810
10858
  kind: "bound",
10811
- detail: fixed,
10859
+ detail: fixed.message,
10812
10860
  who: "gateway",
10813
- code: "DELEGATION_NOT_PROPOSABLE"
10861
+ code: fixed.code
10814
10862
  });
10815
- return fixed;
10863
+ return fixed.message;
10816
10864
  }
10817
10865
  const check = await controlPlaneMandate(true, mandateRequest(args));
10818
10866
  return check.ok ? void 0 : check.message;
10819
10867
  },
10820
10868
  handler: async (args) => {
10821
- const fixed = delegationItselfRefusal(args);
10822
- if (fixed) return { ...builtinText(`Refused: ${fixed}`), isError: true };
10869
+ const fixed = proposalTargetRefusal(args);
10870
+ if (fixed) return { ...builtinText(`Refused: ${fixed.message}`), isError: true };
10823
10871
  const r = await controlPlaneMandate(false, mandateRequest(args));
10824
10872
  if (!r.ok) return { ...builtinText(`Refused: ${r.message}`), isError: true };
10825
10873
  return builtinText(