@topolo/mcp 0.11.12 → 0.12.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 (3) hide show
  1. package/dist/http.js +893 -695
  2. package/dist/index.js +806 -36
  3. package/package.json +10 -5
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/index.ts
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
 
6
- // node_modules/@topolo/sdk/dist/index.js
6
+ // node_modules/.pnpm/@topolo+sdk@0.17.1/node_modules/@topolo/sdk/dist/index.js
7
7
  function applyAuthHeaders(headers, credential) {
8
8
  if (credential.kind === "api_key") {
9
9
  headers.set("X-Api-Key", credential.apiKey);
@@ -167,10 +167,10 @@ var TopoloPermissionError = class extends TopoloSdkError {
167
167
  };
168
168
  function extractTopoloServiceErrorCode(body) {
169
169
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
170
- const record = body;
171
- const topLevel = canonicalTopoloErrorCode(record.code);
170
+ const record2 = body;
171
+ const topLevel = canonicalTopoloErrorCode(record2.code);
172
172
  if (topLevel) return topLevel;
173
- const nested = record.error;
173
+ const nested = record2.error;
174
174
  const nestedString = canonicalTopoloErrorCode(nested);
175
175
  if (nestedString) return nestedString;
176
176
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
@@ -185,14 +185,14 @@ function serviceErrorCode(body, fallback) {
185
185
  }
186
186
  function extractTopoloServiceErrorDetails(body) {
187
187
  if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
188
- const record = body;
189
- let candidate = record.details;
190
- const nested = record.error;
188
+ const record2 = body;
189
+ let candidate = record2.details;
190
+ const nested = record2.error;
191
191
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
192
192
  const nestedRecord = nested;
193
193
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
194
194
  }
195
- if (candidate === void 0) candidate = record;
195
+ if (candidate === void 0) candidate = record2;
196
196
  if (Array.isArray(candidate)) {
197
197
  const paths = canonicalTopoloValidationPaths(candidate);
198
198
  return paths.length ? { paths } : void 0;
@@ -244,8 +244,8 @@ function canonicalTopoloValidationPaths(issues) {
244
244
  const paths = [];
245
245
  for (const issue of issues) {
246
246
  if (!issue || typeof issue !== "object" || Array.isArray(issue)) continue;
247
- const record = issue;
248
- const path = canonicalTopoloValidationPath(record.field) ?? canonicalTopoloValidationPath(record.path);
247
+ const record2 = issue;
248
+ const path = canonicalTopoloValidationPath(record2.field) ?? canonicalTopoloValidationPath(record2.path);
249
249
  if (path && !paths.includes(path)) paths.push(path);
250
250
  if (paths.length === 32) break;
251
251
  }
@@ -712,6 +712,222 @@ function isMultipleOf(value, divisor) {
712
712
  const quotient = value / divisor;
713
713
  return Math.abs(quotient - Math.round(quotient)) < Number.EPSILON * Math.max(1, Math.abs(quotient)) * 4;
714
714
  }
715
+ var ACTOR_ENVELOPE_VERSION = 1;
716
+ var TOPOLO_ACTOR_ENVELOPE_HEADER = "X-Topolo-Actor-Envelope";
717
+ var PRINCIPAL_TYPES = /* @__PURE__ */ new Set([
718
+ "human",
719
+ "managed_agent",
720
+ "external_agent",
721
+ "service",
722
+ "browser_automation"
723
+ ]);
724
+ var ACCOUNTABLE_SUBJECT_TYPES = /* @__PURE__ */ new Set(["human", "organization"]);
725
+ var CHANNELS = /* @__PURE__ */ new Set(["web", "mobile", "cli", "mcp", "api", "workflow", "browser_automation"]);
726
+ var ASSURANCE_LEVELS = /* @__PURE__ */ new Set(["authenticated", "workload_identity", "user_verified"]);
727
+ var HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;
728
+ var ActorEnvelopeValidationError = class extends Error {
729
+ path;
730
+ constructor(path, message) {
731
+ super(`${path}: ${message}`);
732
+ this.name = "ActorEnvelopeValidationError";
733
+ this.path = path;
734
+ }
735
+ };
736
+ function parseActorEnvelope(value) {
737
+ const envelope = record(value, "actorEnvelope");
738
+ exactKeys(envelope, [
739
+ "schemaVersion",
740
+ "organizationId",
741
+ "accountableSubject",
742
+ "performer",
743
+ "delegation",
744
+ "channel",
745
+ "assurance",
746
+ "action",
747
+ "issuedAt",
748
+ "expiresAt"
749
+ ], "actorEnvelope");
750
+ if (envelope.schemaVersion !== ACTOR_ENVELOPE_VERSION) {
751
+ fail("actorEnvelope.schemaVersion", `must equal ${ACTOR_ENVELOPE_VERSION}`);
752
+ }
753
+ const accountableSubject = parseAccountableSubject(envelope.accountableSubject);
754
+ const performer = parseIdentity(envelope.performer, "actorEnvelope.performer");
755
+ const organizationId = text(envelope.organizationId, "actorEnvelope.organizationId");
756
+ const channel = member(envelope.channel, CHANNELS, "actorEnvelope.channel");
757
+ const issuedAt = timestamp(envelope.issuedAt, "actorEnvelope.issuedAt");
758
+ const expiresAt = envelope.expiresAt === void 0 ? void 0 : timestamp(envelope.expiresAt, "actorEnvelope.expiresAt");
759
+ if (expiresAt && Date.parse(expiresAt) <= Date.parse(issuedAt)) {
760
+ fail("actorEnvelope.expiresAt", "must be later than issuedAt");
761
+ }
762
+ const assuranceValue = record(envelope.assurance, "actorEnvelope.assurance");
763
+ exactKeys(assuranceValue, ["level", "methods"], "actorEnvelope.assurance");
764
+ const assurance = {
765
+ level: member(assuranceValue.level, ASSURANCE_LEVELS, "actorEnvelope.assurance.level"),
766
+ methods: textArray(assuranceValue.methods, "actorEnvelope.assurance.methods")
767
+ };
768
+ const actionValue = record(envelope.action, "actorEnvelope.action");
769
+ exactKeys(actionValue, ["requestId", "actionId", "resourceType", "resourceId", "inputHash"], "actorEnvelope.action");
770
+ const inputHash = text(actionValue.inputHash, "actorEnvelope.action.inputHash");
771
+ if (!HASH_PATTERN.test(inputHash)) fail("actorEnvelope.action.inputHash", "must be a lowercase sha256 digest");
772
+ const action = {
773
+ requestId: text(actionValue.requestId, "actorEnvelope.action.requestId"),
774
+ actionId: text(actionValue.actionId, "actorEnvelope.action.actionId"),
775
+ ...actionValue.resourceType === void 0 ? {} : { resourceType: text(actionValue.resourceType, "actorEnvelope.action.resourceType") },
776
+ ...actionValue.resourceId === void 0 ? {} : { resourceId: text(actionValue.resourceId, "actorEnvelope.action.resourceId") },
777
+ inputHash
778
+ };
779
+ if (action.resourceType === void 0 !== (action.resourceId === void 0)) {
780
+ fail("actorEnvelope.action", "resourceType and resourceId must be provided together");
781
+ }
782
+ const delegation = parseDelegation(envelope.delegation);
783
+ const directHuman = performer.principalType === "human" && performer.principalId === accountableSubject.principalId;
784
+ if (directHuman && delegation !== null) fail("actorEnvelope.delegation", "must be null for direct human action");
785
+ if (!directHuman && delegation === null) fail("actorEnvelope.delegation", "is required when performer differs from accountable subject");
786
+ if (delegation) {
787
+ const finalHop = delegation.lineage.at(-1);
788
+ if (!finalHop || finalHop.principalId !== performer.principalId || finalHop.principalType !== performer.principalType) {
789
+ fail("actorEnvelope.delegation.lineage", "must end with the performer");
790
+ }
791
+ }
792
+ if (performer.principalType === "external_agent" && (!performer.installationId || !performer.provider)) {
793
+ fail("actorEnvelope.performer", "external_agent requires installationId and provider");
794
+ }
795
+ if (performer.principalType === "managed_agent" && !performer.agentInstanceId) {
796
+ fail("actorEnvelope.performer.agentInstanceId", "is required for managed_agent");
797
+ }
798
+ if (performer.principalType === "browser_automation" && (!performer.installationId || !performer.browserSessionId)) {
799
+ fail("actorEnvelope.performer", "browser_automation requires installationId and browserSessionId");
800
+ }
801
+ return {
802
+ schemaVersion: ACTOR_ENVELOPE_VERSION,
803
+ organizationId,
804
+ accountableSubject,
805
+ performer,
806
+ delegation,
807
+ channel,
808
+ assurance,
809
+ action,
810
+ issuedAt,
811
+ ...expiresAt ? { expiresAt } : {}
812
+ };
813
+ }
814
+ function canonicalizeActorEnvelope(value) {
815
+ return canonicalJson(parseActorEnvelope(value));
816
+ }
817
+ function encodeActorEnvelopeHeader(value) {
818
+ const bytes = new TextEncoder().encode(canonicalizeActorEnvelope(value));
819
+ const binary = Array.from(bytes, (byte) => String.fromCharCode(byte)).join("");
820
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
821
+ }
822
+ function canonicalJson(value) {
823
+ if (value === null) return "null";
824
+ if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
825
+ if (typeof value === "number") {
826
+ if (!Number.isFinite(value)) throw new TypeError("Canonical JSON accepts finite numbers only.");
827
+ return JSON.stringify(value);
828
+ }
829
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
830
+ if (typeof value !== "object" || !value || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) {
831
+ throw new TypeError("Canonical JSON accepts JSON objects, arrays, and primitives only.");
832
+ }
833
+ const entries = Object.entries(value).filter(([, item]) => item !== void 0).sort(([left], [right]) => left.localeCompare(right));
834
+ return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${canonicalJson(item)}`).join(",")}}`;
835
+ }
836
+ function parseAccountableSubject(value) {
837
+ const path = "actorEnvelope.accountableSubject";
838
+ const subject = record(value, path);
839
+ exactKeys(subject, ["principalType", "principalId", "displayName"], path);
840
+ return {
841
+ principalType: member(subject.principalType, ACCOUNTABLE_SUBJECT_TYPES, `${path}.principalType`),
842
+ principalId: text(subject.principalId, `${path}.principalId`),
843
+ ...subject.displayName === void 0 ? {} : { displayName: text(subject.displayName, `${path}.displayName`) }
844
+ };
845
+ }
846
+ async function sha256CanonicalValue(value) {
847
+ const bytes = new TextEncoder().encode(canonicalJson(value));
848
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
849
+ return `sha256:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
850
+ }
851
+ function parseIdentity(value, path) {
852
+ const identity = record(value, path);
853
+ exactKeys(identity, [
854
+ "principalType",
855
+ "principalId",
856
+ "displayName",
857
+ "installationId",
858
+ "agentInstanceId",
859
+ "browserSessionId",
860
+ "provider",
861
+ "model"
862
+ ], path);
863
+ return {
864
+ principalType: member(identity.principalType, PRINCIPAL_TYPES, `${path}.principalType`),
865
+ principalId: text(identity.principalId, `${path}.principalId`),
866
+ ...optionalTextFields(identity, path, [
867
+ "displayName",
868
+ "installationId",
869
+ "agentInstanceId",
870
+ "browserSessionId",
871
+ "provider",
872
+ "model"
873
+ ])
874
+ };
875
+ }
876
+ function parseDelegation(value) {
877
+ if (value === null) return null;
878
+ const delegation = record(value, "actorEnvelope.delegation");
879
+ exactKeys(delegation, ["taskId", "runId", "lineage"], "actorEnvelope.delegation");
880
+ if (!Array.isArray(delegation.lineage) || delegation.lineage.length === 0 || delegation.lineage.length > 16) {
881
+ fail("actorEnvelope.delegation.lineage", "must contain between 1 and 16 hops");
882
+ }
883
+ return {
884
+ taskId: text(delegation.taskId, "actorEnvelope.delegation.taskId"),
885
+ runId: text(delegation.runId, "actorEnvelope.delegation.runId"),
886
+ lineage: delegation.lineage.map((value2, index) => {
887
+ const hop = record(value2, `actorEnvelope.delegation.lineage[${index}]`);
888
+ exactKeys(hop, ["principalType", "principalId"], `actorEnvelope.delegation.lineage[${index}]`);
889
+ return {
890
+ principalType: member(hop.principalType, PRINCIPAL_TYPES, `actorEnvelope.delegation.lineage[${index}].principalType`),
891
+ principalId: text(hop.principalId, `actorEnvelope.delegation.lineage[${index}].principalId`)
892
+ };
893
+ })
894
+ };
895
+ }
896
+ function record(value, path) {
897
+ if (!value || typeof value !== "object" || Array.isArray(value)) fail(path, "must be an object");
898
+ return value;
899
+ }
900
+ function exactKeys(value, allowed, path) {
901
+ const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
902
+ if (unknown.length) fail(path, `contains unknown field ${unknown[0]}`);
903
+ }
904
+ function text(value, path) {
905
+ if (typeof value !== "string" || value.trim() !== value || value.length === 0 || value.length > 256) {
906
+ fail(path, "must be a non-empty trimmed string of at most 256 characters");
907
+ }
908
+ return value;
909
+ }
910
+ function timestamp(value, path) {
911
+ const result = text(value, path);
912
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(result) || Number.isNaN(Date.parse(result))) {
913
+ fail(path, "must be an RFC 3339 UTC timestamp");
914
+ }
915
+ return result;
916
+ }
917
+ function member(value, values, path) {
918
+ if (typeof value !== "string" || !values.has(value)) fail(path, "contains an unsupported value");
919
+ return value;
920
+ }
921
+ function textArray(value, path) {
922
+ if (!Array.isArray(value) || value.length === 0 || value.length > 16) fail(path, "must contain between 1 and 16 values");
923
+ return value.map((item, index) => text(item, `${path}[${index}]`));
924
+ }
925
+ function optionalTextFields(value, path, keys) {
926
+ return Object.fromEntries(keys.flatMap((key) => value[key] === void 0 ? [] : [[key, text(value[key], `${path}.${key}`)]]));
927
+ }
928
+ function fail(path, message) {
929
+ throw new ActorEnvelopeValidationError(path, message);
930
+ }
715
931
  function parseTopoloActionUploadContract(value) {
716
932
  if (!isRecord2(value) || value.profile !== "inline-base64" && value.profile !== "url-session") {
717
933
  throw new TopoloSdkError("upload_contract_unavailable", "This action does not publish a supported upload contract.");
@@ -916,6 +1132,7 @@ var NEGATIVE_CACHE_TTL_MS = 60 * 1e3;
916
1132
  var TopoloClient = class _TopoloClient {
917
1133
  credential;
918
1134
  agent;
1135
+ actorContext;
919
1136
  serviceUrls;
920
1137
  environment;
921
1138
  appIds;
@@ -946,6 +1163,11 @@ var TopoloClient = class _TopoloClient {
946
1163
  if (!options.agent?.clientName) throw new TopoloAuthError("agent.clientName is required");
947
1164
  this.credential = options.credential;
948
1165
  this.agent = options.agent;
1166
+ this.actorContext = options.actorContext ? {
1167
+ channel: options.actorContext.channel,
1168
+ taskId: options.actorContext.taskId ?? `task_${generateRequestId()}`,
1169
+ runId: options.actorContext.runId ?? `run_${generateRequestId()}`
1170
+ } : void 0;
949
1171
  this.environment = options.environment;
950
1172
  this.serviceUrls = options.environment ? topoloServiceOrigins(options.serviceUrls, options.environment) : options.serviceUrls;
951
1173
  this.appIds = options.appIds;
@@ -999,11 +1221,15 @@ var TopoloClient = class _TopoloClient {
999
1221
  const platformAppId = resolveConfiguredAppId(resolvedService.serviceKey, this.appIds);
1000
1222
  if (platformAppId) headers.set("X-App-ID", platformAppId);
1001
1223
  applyAuthHeaders(headers, this.credential);
1002
- const requestId = generateRequestId();
1224
+ const actorEnvelope = opts.actorEnvelope === void 0 ? void 0 : parseActorEnvelope(opts.actorEnvelope);
1225
+ const requestId = actorEnvelope?.action.requestId ?? generateRequestId();
1003
1226
  applyAuditHeaders(headers, this.agent, requestId);
1004
1227
  if (opts.headers) {
1005
1228
  for (const [k, v] of Object.entries(opts.headers)) headers.set(k, v);
1006
1229
  }
1230
+ if (actorEnvelope) {
1231
+ headers.set(TOPOLO_ACTOR_ENVELOPE_HEADER, encodeActorEnvelopeHeader(actorEnvelope));
1232
+ }
1007
1233
  if (opts.resource) {
1008
1234
  const resourceType = opts.resource.resourceType.trim();
1009
1235
  const resourceId = opts.resource.resourceId.trim();
@@ -1450,14 +1676,14 @@ var TopoloClient = class _TopoloClient {
1450
1676
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
1451
1677
  throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is unavailable.");
1452
1678
  }
1453
- const record = raw;
1454
- if (record.algorithm !== "sha256-v1" || typeof record.digest !== "string" || !/^[a-f0-9]{64}$/.test(record.digest) || !Number.isSafeInteger(record.actionCount) || Number(record.actionCount) < 0) {
1679
+ const record2 = raw;
1680
+ if (record2.algorithm !== "sha256-v1" || typeof record2.digest !== "string" || !/^[a-f0-9]{64}$/.test(record2.digest) || !Number.isSafeInteger(record2.actionCount) || Number(record2.actionCount) < 0) {
1455
1681
  throw new TopoloSdkError("action_catalog_summary_unavailable", "Action catalog summary is invalid.");
1456
1682
  }
1457
1683
  return {
1458
1684
  algorithm: "sha256-v1",
1459
- digest: record.digest,
1460
- actionCount: Number(record.actionCount)
1685
+ digest: record2.digest,
1686
+ actionCount: Number(record2.actionCount)
1461
1687
  };
1462
1688
  }
1463
1689
  /** @deprecated Prefer searchActions() so callers retain the continuation cursor. */
@@ -1657,6 +1883,20 @@ var TopoloClient = class _TopoloClient {
1657
1883
  );
1658
1884
  }
1659
1885
  const mapped = mapActionInput(entry, input);
1886
+ const resolvedActorEnvelope = options.actorEnvelope ?? await this.buildVerifiedAgentActorEnvelope(entry.actionId, input, options.resource);
1887
+ if (resolvedActorEnvelope) {
1888
+ const actorEnvelope = parseActorEnvelope(resolvedActorEnvelope);
1889
+ if (actorEnvelope.action.actionId !== entry.actionId) {
1890
+ throw new TopoloSdkError("actor_envelope_action_mismatch", "Actor envelope actionId does not match the executed action.");
1891
+ }
1892
+ if (actorEnvelope.action.inputHash !== await sha256CanonicalValue(input)) {
1893
+ throw new TopoloSdkError("actor_envelope_input_mismatch", "Actor envelope inputHash does not match the executed action input.");
1894
+ }
1895
+ const envelopeResource = actorEnvelope.action.resourceType && actorEnvelope.action.resourceId ? { resourceType: actorEnvelope.action.resourceType, resourceId: actorEnvelope.action.resourceId } : void 0;
1896
+ if (envelopeResource?.resourceType !== options.resource?.resourceType || envelopeResource?.resourceId !== options.resource?.resourceId) {
1897
+ throw new TopoloSdkError("actor_envelope_resource_mismatch", "Actor envelope resource does not match the executed action resource.");
1898
+ }
1899
+ }
1660
1900
  const service = entry.appSlug || entry.appId;
1661
1901
  const result = await this.request({
1662
1902
  service,
@@ -1666,6 +1906,7 @@ var TopoloClient = class _TopoloClient {
1666
1906
  ...mapped.query ? { query: mapped.query } : {},
1667
1907
  ...mapped.body !== void 0 ? { body: mapped.body } : {},
1668
1908
  ...options.resource ? { resource: options.resource } : {},
1909
+ ...resolvedActorEnvelope ? { actorEnvelope: resolvedActorEnvelope } : {},
1669
1910
  headers: {
1670
1911
  [TOPOLO_ACTION_ID_HEADER]: entry.actionId,
1671
1912
  [TOPOLO_ACTION_NAME_HEADER]: entry.name
@@ -1674,6 +1915,56 @@ var TopoloClient = class _TopoloClient {
1674
1915
  });
1675
1916
  return redactActionResult(result);
1676
1917
  }
1918
+ async buildVerifiedAgentActorEnvelope(actionId, input, resource) {
1919
+ if (!this.actorContext) return void 0;
1920
+ const identity = await this.introspect();
1921
+ const principalType = identity.user.principalType;
1922
+ if (principalType !== "agent_employee" && principalType !== "external_agent") return void 0;
1923
+ if (!identity.organization || !identity.user.accountableUserId || !identity.user.principalId) {
1924
+ throw new TopoloSdkError(
1925
+ "incomplete_agent_identity",
1926
+ "Verified agent credentials must resolve an organization, accountable user, and principal id."
1927
+ );
1928
+ }
1929
+ const performer = principalType === "external_agent" ? {
1930
+ principalType: "external_agent",
1931
+ principalId: identity.user.principalId,
1932
+ installationId: identity.user.installationId ?? void 0,
1933
+ provider: identity.user.provider ?? void 0,
1934
+ model: identity.user.model ?? void 0
1935
+ } : {
1936
+ principalType: "managed_agent",
1937
+ principalId: identity.user.principalId,
1938
+ agentInstanceId: identity.user.agentInstanceId ?? void 0,
1939
+ model: identity.user.model ?? void 0
1940
+ };
1941
+ if (performer.principalType === "external_agent" && (!performer.installationId || !performer.provider) || performer.principalType === "managed_agent" && !performer.agentInstanceId) {
1942
+ throw new TopoloSdkError(
1943
+ "incomplete_agent_identity",
1944
+ "Verified agent credentials are missing the performer identity required for provenance."
1945
+ );
1946
+ }
1947
+ return parseActorEnvelope({
1948
+ schemaVersion: 1,
1949
+ organizationId: identity.organization.id,
1950
+ accountableSubject: { principalType: "human", principalId: identity.user.accountableUserId },
1951
+ performer,
1952
+ delegation: {
1953
+ taskId: this.actorContext.taskId,
1954
+ runId: this.actorContext.runId,
1955
+ lineage: [{ principalType: performer.principalType, principalId: performer.principalId }]
1956
+ },
1957
+ channel: this.actorContext.channel,
1958
+ assurance: { level: "workload_identity", methods: ["client_credentials"] },
1959
+ action: {
1960
+ requestId: generateRequestId(),
1961
+ actionId,
1962
+ ...resource ? resource : {},
1963
+ inputHash: await sha256CanonicalValue(input)
1964
+ },
1965
+ issuedAt: (/* @__PURE__ */ new Date()).toISOString()
1966
+ });
1967
+ }
1677
1968
  /**
1678
1969
  * Introspect the current credential. Returns the caller's resolved identity,
1679
1970
  * organization, and permission set. Used by CLI `whoami` and by MCP to gate
@@ -1701,7 +1992,18 @@ var TopoloClient = class _TopoloClient {
1701
1992
  email: user.email,
1702
1993
  name: user.name ?? null,
1703
1994
  role: user.role ?? (kind === "api_key" ? "service" : "member"),
1704
- permissions: payload.permissions ?? user.permissions ?? []
1995
+ permissions: payload.permissions ?? user.permissions ?? [],
1996
+ ...normalizeAgentPrincipalType(user.principalType) ? {
1997
+ principalId: readOptionalString(user.principalId),
1998
+ principalType: normalizeAgentPrincipalType(user.principalType),
1999
+ accountableUserId: readOptionalString(user.accountableUserId),
2000
+ agentInstanceId: readOptionalString(user.agentInstanceId),
2001
+ installationId: readOptionalString(user.installationId),
2002
+ provider: readOptionalString(user.provider),
2003
+ model: readOptionalString(user.model),
2004
+ serviceScopes: stringArray(user.serviceScopes),
2005
+ policyRef: readOptionalString(user.policyRef)
2006
+ } : {}
1705
2007
  },
1706
2008
  organization: organization ? {
1707
2009
  id: organization.id,
@@ -1830,12 +2132,21 @@ function redactActionResult(value) {
1830
2132
  if (!isRecord3(value)) return value;
1831
2133
  return Object.fromEntries(Object.entries(value).map(([key, item]) => [
1832
2134
  key,
1833
- isSensitiveActionResultKey(key) ? "[REDACTED]" : redactActionResult(item)
2135
+ isSensitiveActionResultKey(key, item) ? "[REDACTED]" : redactActionResult(item)
1834
2136
  ]));
1835
2137
  }
1836
- function isSensitiveActionResultKey(key) {
2138
+ function isSensitiveActionResultKey(key, value) {
1837
2139
  const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
1838
- return ["authorization", "cookie", "setcookie", "proxyauthorization", "capability"].includes(normalized) || /(token|secret|password|privatekey|apikey)$/.test(normalized);
2140
+ if (normalized === "capability") return isCredentialShaped(value);
2141
+ return ["authorization", "cookie", "setcookie", "proxyauthorization"].includes(normalized) || /(token|secret|password|privatekey|apikey)$/.test(normalized);
2142
+ }
2143
+ var PLAIN_ENUM_VALUE = /^[a-z][a-z0-9_-]{0,31}$/;
2144
+ function isCredentialShaped(value) {
2145
+ if (typeof value !== "string") return value !== null && value !== void 0 && typeof value !== "boolean" && typeof value !== "number";
2146
+ const trimmed = value.trim();
2147
+ if (!trimmed) return false;
2148
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) return true;
2149
+ return !PLAIN_ENUM_VALUE.test(trimmed);
1839
2150
  }
1840
2151
  function resolveConfiguredServiceUrl(slug, serviceUrls) {
1841
2152
  for (const serviceKey of serviceKeyCandidates2(slug)) {
@@ -2057,6 +2368,9 @@ function normalizeCredentialAuthorizationMode(value, kind) {
2057
2368
  if (value === "context_rbac" || value === "oauth_scopes" || value === "session_rbac") return value;
2058
2369
  return "unknown";
2059
2370
  }
2371
+ function normalizeAgentPrincipalType(value) {
2372
+ return value === "agent_employee" || value === "external_agent" ? value : null;
2373
+ }
2060
2374
  function describeError(body, fallback) {
2061
2375
  if (body && typeof body === "object") {
2062
2376
  const maybe = body;
@@ -2081,10 +2395,10 @@ function extractRequired(body) {
2081
2395
  if (Array.isArray(maybe.required)) return canonicalTopoloRequired(maybe.required);
2082
2396
  for (const nested of [maybe.details, maybe.error]) {
2083
2397
  if (!nested || typeof nested !== "object" || Array.isArray(nested)) continue;
2084
- const record = nested;
2085
- if (Array.isArray(record.required)) return canonicalTopoloRequired(record.required);
2086
- if (record.details && typeof record.details === "object" && !Array.isArray(record.details)) {
2087
- const required = record.details.required;
2398
+ const record2 = nested;
2399
+ if (Array.isArray(record2.required)) return canonicalTopoloRequired(record2.required);
2400
+ if (record2.details && typeof record2.details === "object" && !Array.isArray(record2.details)) {
2401
+ const required = record2.details.required;
2088
2402
  if (Array.isArray(required)) return canonicalTopoloRequired(required);
2089
2403
  }
2090
2404
  }
@@ -2159,8 +2473,8 @@ function compactResultValue(value, depth, budget) {
2159
2473
  return value.length > ACTION_RESULT_MAX_ITEMS ? { count: value.length, items, omittedItems: value.length - ACTION_RESULT_MAX_ITEMS } : items;
2160
2474
  }
2161
2475
  if (typeof value === "object") {
2162
- const record = value;
2163
- const allKeys = Object.keys(record);
2476
+ const record2 = value;
2477
+ const allKeys = Object.keys(record2);
2164
2478
  const ranked = allKeys.sort((left, right) => resultKeyPriority(left) - resultKeyPriority(right));
2165
2479
  const prioritized = ranked.filter((key) => resultKeyPriority(key) < 2);
2166
2480
  const ordinary = ranked.filter((key) => resultKeyPriority(key) === 2);
@@ -2169,7 +2483,7 @@ function compactResultValue(value, depth, budget) {
2169
2483
  ...prioritized,
2170
2484
  ...ordinary.slice(0, ordinaryLimit)
2171
2485
  ].slice(0, ACTION_RESULT_MAX_KEYS);
2172
- const compact = Object.fromEntries(keys.map((key) => [key, compactResultValue(record[key], depth + 1, budget)]));
2486
+ const compact = Object.fromEntries(keys.map((key) => [key, compactResultValue(record2[key], depth + 1, budget)]));
2173
2487
  if (allKeys.length > keys.length) compact["_omittedKeys"] = allKeys.length - keys.length;
2174
2488
  return compact;
2175
2489
  }
@@ -2390,6 +2704,461 @@ var WorkspacesModule = class {
2390
2704
  return { organizationId: identity.organization.id, appId: service.appId };
2391
2705
  }
2392
2706
  };
2707
+ var nonEmptyString2 = { type: "string", minLength: 1 };
2708
+ var stringArray3 = { type: "array", items: nonEmptyString2 };
2709
+ var actionBinding = {
2710
+ type: "object",
2711
+ properties: {
2712
+ id: nonEmptyString2,
2713
+ label: nonEmptyString2,
2714
+ actionId: nonEmptyString2,
2715
+ resourceType: nonEmptyString2,
2716
+ resourceId: nonEmptyString2,
2717
+ input: { type: "object" },
2718
+ requiresConfirmation: { type: "boolean" },
2719
+ destructive: { type: "boolean" },
2720
+ effects: stringArray3,
2721
+ verification: stringArray3,
2722
+ recovery: {
2723
+ type: "object",
2724
+ properties: {
2725
+ mode: { enum: ["not_applicable", "retry", "compensating_action"] },
2726
+ actionId: nonEmptyString2,
2727
+ instructions: nonEmptyString2
2728
+ },
2729
+ required: ["mode", "instructions"],
2730
+ additionalProperties: false
2731
+ }
2732
+ },
2733
+ required: [
2734
+ "id",
2735
+ "label",
2736
+ "actionId",
2737
+ "resourceType",
2738
+ "input",
2739
+ "requiresConfirmation",
2740
+ "destructive",
2741
+ "effects",
2742
+ "verification",
2743
+ "recovery"
2744
+ ],
2745
+ additionalProperties: false
2746
+ };
2747
+ var dimension = {
2748
+ type: "object",
2749
+ properties: { key: nonEmptyString2, label: nonEmptyString2, value: nonEmptyString2 },
2750
+ required: ["key", "label", "value"],
2751
+ additionalProperties: false
2752
+ };
2753
+ var period = {
2754
+ type: "object",
2755
+ properties: {
2756
+ start: nonEmptyString2,
2757
+ end: nonEmptyString2,
2758
+ timezone: nonEmptyString2
2759
+ },
2760
+ required: ["start", "end", "timezone"],
2761
+ additionalProperties: false
2762
+ };
2763
+ var series = {
2764
+ type: "object",
2765
+ properties: {
2766
+ id: nonEmptyString2,
2767
+ label: nonEmptyString2,
2768
+ unit: nonEmptyString2,
2769
+ points: {
2770
+ type: "array",
2771
+ items: {
2772
+ type: "object",
2773
+ properties: {
2774
+ timestamp: nonEmptyString2,
2775
+ value: { type: "number" },
2776
+ dimensions: { type: "array", items: dimension }
2777
+ },
2778
+ required: ["timestamp", "value", "dimensions"],
2779
+ additionalProperties: false
2780
+ }
2781
+ }
2782
+ },
2783
+ required: ["id", "label", "unit", "points"],
2784
+ additionalProperties: false
2785
+ };
2786
+ var contribution = {
2787
+ type: "object",
2788
+ properties: {
2789
+ summary: nonEmptyString2,
2790
+ identity: {
2791
+ type: "object",
2792
+ properties: { iconSource: { const: "catalog" } },
2793
+ required: ["iconSource"],
2794
+ additionalProperties: false
2795
+ },
2796
+ workspaceSelector: {
2797
+ type: "object",
2798
+ properties: {
2799
+ mode: { enum: ["none", "optional", "required"] },
2800
+ resourceType: nonEmptyString2,
2801
+ label: nonEmptyString2,
2802
+ supportsMultiple: { type: "boolean" }
2803
+ },
2804
+ required: ["mode", "resourceType", "label", "supportsMultiple"],
2805
+ additionalProperties: false
2806
+ },
2807
+ metricDefinitions: {
2808
+ type: "array",
2809
+ items: {
2810
+ type: "object",
2811
+ properties: {
2812
+ key: nonEmptyString2,
2813
+ label: nonEmptyString2,
2814
+ description: nonEmptyString2,
2815
+ unit: nonEmptyString2,
2816
+ semantic: {
2817
+ enum: ["gauge", "counter", "rate", "duration", "currency", "percentage"]
2818
+ },
2819
+ aggregation: {
2820
+ enum: ["last", "sum", "average", "minimum", "maximum", "count", "distinct_count"]
2821
+ }
2822
+ },
2823
+ required: ["key", "label", "description", "unit", "semantic", "aggregation"],
2824
+ additionalProperties: false
2825
+ }
2826
+ },
2827
+ seriesDefinitions: {
2828
+ type: "array",
2829
+ items: {
2830
+ type: "object",
2831
+ properties: {
2832
+ key: nonEmptyString2,
2833
+ label: nonEmptyString2,
2834
+ metricKey: nonEmptyString2,
2835
+ unit: nonEmptyString2
2836
+ },
2837
+ required: ["key", "label", "metricKey", "unit"],
2838
+ additionalProperties: false
2839
+ }
2840
+ },
2841
+ dimensions: {
2842
+ type: "array",
2843
+ items: {
2844
+ type: "object",
2845
+ properties: {
2846
+ key: nonEmptyString2,
2847
+ label: nonEmptyString2,
2848
+ description: nonEmptyString2,
2849
+ valueType: { enum: ["string", "number", "boolean", "date", "datetime"] }
2850
+ },
2851
+ required: ["key", "label", "description", "valueType"],
2852
+ additionalProperties: false
2853
+ }
2854
+ },
2855
+ lifecycleStages: {
2856
+ type: "array",
2857
+ items: {
2858
+ type: "object",
2859
+ properties: {
2860
+ key: nonEmptyString2,
2861
+ label: nonEmptyString2,
2862
+ order: { type: "number" },
2863
+ terminal: { type: "boolean" }
2864
+ },
2865
+ required: ["key", "label", "order", "terminal"],
2866
+ additionalProperties: false
2867
+ }
2868
+ },
2869
+ events: {
2870
+ type: "array",
2871
+ items: {
2872
+ type: "object",
2873
+ properties: {
2874
+ key: nonEmptyString2,
2875
+ label: nonEmptyString2,
2876
+ description: nonEmptyString2
2877
+ },
2878
+ required: ["key", "label", "description"],
2879
+ additionalProperties: false
2880
+ }
2881
+ },
2882
+ datasets: {
2883
+ type: "array",
2884
+ minItems: 1,
2885
+ items: {
2886
+ type: "object",
2887
+ properties: {
2888
+ id: nonEmptyString2,
2889
+ label: nonEmptyString2,
2890
+ description: nonEmptyString2,
2891
+ grain: nonEmptyString2,
2892
+ metricKeys: stringArray3,
2893
+ seriesKeys: stringArray3,
2894
+ dimensionKeys: stringArray3,
2895
+ eventKeys: stringArray3,
2896
+ actionIds: stringArray3
2897
+ },
2898
+ required: [
2899
+ "id",
2900
+ "label",
2901
+ "description",
2902
+ "grain",
2903
+ "metricKeys",
2904
+ "seriesKeys",
2905
+ "dimensionKeys",
2906
+ "eventKeys",
2907
+ "actionIds"
2908
+ ],
2909
+ additionalProperties: false
2910
+ }
2911
+ },
2912
+ compatibleVisualizations: {
2913
+ type: "array",
2914
+ minItems: 1,
2915
+ items: {
2916
+ enum: ["number", "line", "area", "bar", "donut", "table", "funnel", "timeline", "actions"]
2917
+ }
2918
+ },
2919
+ defaultVisualization: {
2920
+ enum: ["number", "line", "area", "bar", "donut", "table", "funnel", "timeline", "actions"]
2921
+ }
2922
+ },
2923
+ required: [
2924
+ "summary",
2925
+ "identity",
2926
+ "workspaceSelector",
2927
+ "metricDefinitions",
2928
+ "seriesDefinitions",
2929
+ "dimensions",
2930
+ "lifecycleStages",
2931
+ "events",
2932
+ "datasets",
2933
+ "compatibleVisualizations",
2934
+ "defaultVisualization"
2935
+ ],
2936
+ additionalProperties: false
2937
+ };
2938
+ var widgetItem = {
2939
+ type: "object",
2940
+ properties: {
2941
+ id: nonEmptyString2,
2942
+ version: nonEmptyString2,
2943
+ appId: nonEmptyString2,
2944
+ serviceName: nonEmptyString2,
2945
+ lastUpdated: nonEmptyString2,
2946
+ type: { enum: ["stats", "chart", "activity", "notifications", "actions"] },
2947
+ presentation: {
2948
+ type: "object",
2949
+ properties: {
2950
+ title: nonEmptyString2,
2951
+ description: nonEmptyString2,
2952
+ contexts: {
2953
+ type: "array",
2954
+ minItems: 1,
2955
+ items: { enum: ["personal", "organization", "workspace", "resource"] }
2956
+ },
2957
+ supportedSizes: {
2958
+ type: "array",
2959
+ minItems: 1,
2960
+ items: { enum: ["compact", "medium", "wide", "full"] }
2961
+ },
2962
+ defaultSize: { enum: ["compact", "medium", "wide", "full"] }
2963
+ },
2964
+ required: ["title", "contexts", "supportedSizes", "defaultSize"],
2965
+ additionalProperties: false
2966
+ },
2967
+ resource: {
2968
+ type: "object",
2969
+ properties: {
2970
+ resourceType: nonEmptyString2,
2971
+ resourceId: nonEmptyString2,
2972
+ requiredPermissions: stringArray3
2973
+ },
2974
+ required: ["resourceType", "requiredPermissions"],
2975
+ additionalProperties: false
2976
+ },
2977
+ state: {
2978
+ type: "object",
2979
+ properties: {
2980
+ status: { enum: ["ready", "empty", "unavailable", "stale", "error"] },
2981
+ observedAt: nonEmptyString2,
2982
+ lastSuccessfulAt: nonEmptyString2,
2983
+ code: nonEmptyString2,
2984
+ message: nonEmptyString2
2985
+ },
2986
+ required: ["status", "observedAt"],
2987
+ additionalProperties: false
2988
+ },
2989
+ refresh: {
2990
+ type: "object",
2991
+ properties: {
2992
+ intervalSeconds: { type: "number" },
2993
+ timeoutSeconds: { type: "number" },
2994
+ maxAgeSeconds: { type: "number" },
2995
+ staleWhileRevalidateSeconds: { type: "number" }
2996
+ },
2997
+ required: ["intervalSeconds", "timeoutSeconds", "maxAgeSeconds", "staleWhileRevalidateSeconds"],
2998
+ additionalProperties: false
2999
+ },
3000
+ configuration: {
3001
+ type: "object",
3002
+ properties: {
3003
+ allowMultipleInstances: { type: "boolean" },
3004
+ fields: {
3005
+ type: "array",
3006
+ items: {
3007
+ type: "object",
3008
+ properties: {
3009
+ key: nonEmptyString2,
3010
+ label: nonEmptyString2,
3011
+ type: { enum: ["string", "number", "boolean", "select", "multi-select", "date-range"] },
3012
+ required: { type: "boolean" },
3013
+ options: {
3014
+ type: "array",
3015
+ items: {
3016
+ type: "object",
3017
+ properties: { value: nonEmptyString2, label: nonEmptyString2 },
3018
+ required: ["value", "label"],
3019
+ additionalProperties: false
3020
+ }
3021
+ }
3022
+ },
3023
+ required: ["key", "label", "type", "required"],
3024
+ additionalProperties: false
3025
+ }
3026
+ },
3027
+ defaults: { type: "object" }
3028
+ },
3029
+ required: ["allowMultipleInstances", "fields", "defaults"],
3030
+ additionalProperties: false
3031
+ },
3032
+ drilldowns: {
3033
+ type: "array",
3034
+ items: {
3035
+ type: "object",
3036
+ properties: { id: nonEmptyString2, label: nonEmptyString2, href: nonEmptyString2 },
3037
+ required: ["id", "label", "href"],
3038
+ additionalProperties: false
3039
+ }
3040
+ },
3041
+ controls: { type: "array", items: actionBinding },
3042
+ localization: {
3043
+ type: "object",
3044
+ properties: {
3045
+ locale: nonEmptyString2,
3046
+ titleKey: nonEmptyString2,
3047
+ descriptionKey: nonEmptyString2,
3048
+ title: nonEmptyString2,
3049
+ description: nonEmptyString2
3050
+ },
3051
+ required: ["locale", "titleKey"],
3052
+ additionalProperties: false
3053
+ },
3054
+ accessibility: {
3055
+ type: "object",
3056
+ properties: { label: nonEmptyString2, description: nonEmptyString2 },
3057
+ required: ["label"],
3058
+ additionalProperties: false
3059
+ },
3060
+ contribution,
3061
+ metrics: {
3062
+ type: "array",
3063
+ items: {
3064
+ type: "object",
3065
+ properties: {
3066
+ key: nonEmptyString2,
3067
+ label: nonEmptyString2,
3068
+ value: { type: "number" },
3069
+ unit: nonEmptyString2,
3070
+ semantic: {
3071
+ enum: ["gauge", "counter", "rate", "duration", "currency", "percentage"]
3072
+ },
3073
+ aggregation: {
3074
+ enum: ["last", "sum", "average", "minimum", "maximum", "count", "distinct_count"]
3075
+ },
3076
+ period,
3077
+ dimensions: { type: "array", items: dimension },
3078
+ series
3079
+ },
3080
+ required: ["key", "label", "value", "unit", "semantic", "aggregation", "period", "dimensions"],
3081
+ additionalProperties: false
3082
+ }
3083
+ },
3084
+ chartType: { enum: ["line", "bar", "area", "pie", "donut"] },
3085
+ series: { type: "array", items: series },
3086
+ activities: { type: "array", items: { type: "object" } },
3087
+ notifications: { type: "array", items: { type: "object" } },
3088
+ unreadCount: { type: "number" },
3089
+ actions: { type: "array", items: actionBinding }
3090
+ },
3091
+ required: [
3092
+ "id",
3093
+ "version",
3094
+ "appId",
3095
+ "serviceName",
3096
+ "lastUpdated",
3097
+ "type",
3098
+ "presentation",
3099
+ "resource",
3100
+ "state",
3101
+ "refresh",
3102
+ "configuration",
3103
+ "drilldowns",
3104
+ "controls",
3105
+ "localization",
3106
+ "accessibility",
3107
+ "contribution"
3108
+ ],
3109
+ allOf: [
3110
+ { if: { properties: { type: { const: "stats" } } }, then: { required: ["metrics"] } },
3111
+ { if: { properties: { type: { const: "chart" } } }, then: { required: ["chartType", "series"] } },
3112
+ { if: { properties: { type: { const: "activity" } } }, then: { required: ["activities"] } },
3113
+ {
3114
+ if: { properties: { type: { const: "notifications" } } },
3115
+ then: { required: ["notifications", "unreadCount"] }
3116
+ },
3117
+ { if: { properties: { type: { const: "actions" } } }, then: { required: ["actions"] } }
3118
+ ],
3119
+ additionalProperties: false
3120
+ };
3121
+ var TOPOLO_WIDGET_OUTPUT_SCHEMA = Object.freeze({
3122
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3123
+ type: "object",
3124
+ properties: {
3125
+ success: { type: "boolean", const: true },
3126
+ contractVersion: { type: "string", const: "3.0.0" },
3127
+ appId: nonEmptyString2,
3128
+ serviceName: nonEmptyString2,
3129
+ generatedAt: nonEmptyString2,
3130
+ widgets: { type: "array", minItems: 1, items: widgetItem },
3131
+ workspace: {
3132
+ anyOf: [
3133
+ {
3134
+ type: "object",
3135
+ properties: {
3136
+ id: { anyOf: [{ type: "string" }, { type: "number" }] },
3137
+ name: nonEmptyString2
3138
+ },
3139
+ required: ["id", "name"],
3140
+ additionalProperties: true
3141
+ },
3142
+ { type: "null" }
3143
+ ]
3144
+ },
3145
+ workspaces: {
3146
+ type: "array",
3147
+ items: {
3148
+ type: "object",
3149
+ properties: {
3150
+ id: { anyOf: [{ type: "string" }, { type: "number" }] },
3151
+ name: nonEmptyString2,
3152
+ isDefault: { type: "boolean" }
3153
+ },
3154
+ required: ["id", "name"],
3155
+ additionalProperties: false
3156
+ }
3157
+ }
3158
+ },
3159
+ required: ["success", "contractVersion", "appId", "serviceName", "generatedAt", "widgets"],
3160
+ additionalProperties: false
3161
+ });
2393
3162
  function createTopolo(options) {
2394
3163
  const client = new TopoloClient(options);
2395
3164
  return {
@@ -2400,7 +3169,7 @@ function createTopolo(options) {
2400
3169
  };
2401
3170
  }
2402
3171
 
2403
- // node_modules/@topolo/sdk/dist/node/credential-store.js
3172
+ // node_modules/.pnpm/@topolo+sdk@0.17.1/node_modules/@topolo/sdk/dist/node/credential-store.js
2404
3173
  import { mkdir, readFile, writeFile, chmod, rm, stat } from "fs/promises";
2405
3174
  import { existsSync } from "fs";
2406
3175
  import { homedir, platform } from "os";
@@ -2523,10 +3292,10 @@ var TopoloAuthError2 = class extends TopoloSdkError2 {
2523
3292
  };
2524
3293
  function extractTopoloServiceErrorCode2(body) {
2525
3294
  if (!body || typeof body !== "object" || Array.isArray(body)) return null;
2526
- const record = body;
2527
- const topLevel = canonicalTopoloErrorCode2(record.code);
3295
+ const record2 = body;
3296
+ const topLevel = canonicalTopoloErrorCode2(record2.code);
2528
3297
  if (topLevel) return topLevel;
2529
- const nested = record.error;
3298
+ const nested = record2.error;
2530
3299
  const nestedString = canonicalTopoloErrorCode2(nested);
2531
3300
  if (nestedString) return nestedString;
2532
3301
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
@@ -2541,14 +3310,14 @@ function serviceErrorCode2(body, fallback) {
2541
3310
  }
2542
3311
  function extractTopoloServiceErrorDetails2(body) {
2543
3312
  if (!body || typeof body !== "object" || Array.isArray(body)) return void 0;
2544
- const record = body;
2545
- let candidate = record.details;
2546
- const nested = record.error;
3313
+ const record2 = body;
3314
+ let candidate = record2.details;
3315
+ const nested = record2.error;
2547
3316
  if (nested && typeof nested === "object" && !Array.isArray(nested)) {
2548
3317
  const nestedRecord = nested;
2549
3318
  if (candidate === void 0) candidate = nestedRecord.details ?? nestedRecord;
2550
3319
  }
2551
- if (candidate === void 0) candidate = record;
3320
+ if (candidate === void 0) candidate = record2;
2552
3321
  if (Array.isArray(candidate)) {
2553
3322
  const paths = canonicalTopoloValidationPaths2(candidate);
2554
3323
  return paths.length ? { paths } : void 0;
@@ -2600,8 +3369,8 @@ function canonicalTopoloValidationPaths2(issues) {
2600
3369
  const paths = [];
2601
3370
  for (const issue of issues) {
2602
3371
  if (!issue || typeof issue !== "object" || Array.isArray(issue)) continue;
2603
- const record = issue;
2604
- const path = canonicalTopoloValidationPath2(record.field) ?? canonicalTopoloValidationPath2(record.path);
3372
+ const record2 = issue;
3373
+ const path = canonicalTopoloValidationPath2(record2.field) ?? canonicalTopoloValidationPath2(record2.path);
2605
3374
  if (path && !paths.includes(path)) paths.push(path);
2606
3375
  if (paths.length === 32) break;
2607
3376
  }
@@ -4040,6 +4809,7 @@ async function runStdioMcp(dependencies = DEFAULT_DEPENDENCIES2) {
4040
4809
  const topolo = dependencies.createTopolo({
4041
4810
  credential,
4042
4811
  environment,
4812
+ actorContext: { channel: "mcp" },
4043
4813
  agent: {
4044
4814
  clientName: "topolo-mcp",
4045
4815
  clientVersion: MCP_VERSION,