@lucern/mcp 0.3.0-alpha.11 → 0.3.0-alpha.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.
package/dist/index.js CHANGED
@@ -1593,6 +1593,35 @@ defineTable({
1593
1593
  { kind: "index", name: "by_source", columns: ["source"] }
1594
1594
  ]
1595
1595
  });
1596
+ defineTable({
1597
+ name: "domainEvents",
1598
+ component: "kernel",
1599
+ category: "events",
1600
+ shape: z.object({
1601
+ "eventId": z.string(),
1602
+ "type": z.string(),
1603
+ "version": z.string(),
1604
+ "timestamp": z.number(),
1605
+ "tenantId": z.string().optional(),
1606
+ "workspaceId": z.string().optional(),
1607
+ "topicId": z.string(),
1608
+ "resourceId": z.string(),
1609
+ "resourceType": z.string(),
1610
+ "actorId": z.string(),
1611
+ "actorType": z.enum(["human", "agent", "service"]),
1612
+ "data": z.record(z.any()),
1613
+ "correlationId": z.string().optional(),
1614
+ "expiresAt": z.number()
1615
+ }),
1616
+ indices: [
1617
+ { kind: "index", name: "by_eventId", columns: ["eventId"] },
1618
+ { kind: "index", name: "by_topic_timestamp", columns: ["topicId", "timestamp"] },
1619
+ { kind: "index", name: "by_tenant_workspace_timestamp", columns: ["tenantId", "workspaceId", "timestamp"] },
1620
+ { kind: "index", name: "by_type_timestamp", columns: ["type", "timestamp"] },
1621
+ { kind: "index", name: "by_resource", columns: ["resourceType", "resourceId", "timestamp"] },
1622
+ { kind: "index", name: "by_expiresAt", columns: ["expiresAt"] }
1623
+ ]
1624
+ });
1596
1625
  defineTable({
1597
1626
  name: "beliefConfidence",
1598
1627
  component: "kernel",
@@ -4891,7 +4920,9 @@ var permitObjectType = z.enum([
4891
4920
  "group",
4892
4921
  "resource_instance",
4893
4922
  "relationship_tuple",
4894
- "role_assignment"
4923
+ "role_assignment",
4924
+ "attribute_binding",
4925
+ "policy_bundle"
4895
4926
  ]);
4896
4927
  var permitOutboxOperation = z.enum([
4897
4928
  "upsert",
@@ -4997,7 +5028,10 @@ defineTable({
4997
5028
  }),
4998
5029
  indices: [
4999
5030
  { kind: "index", name: "by_principalId", columns: ["principalId"] },
5031
+ { kind: "index", name: "by_provider_subject", columns: ["provider", "providerSubjectId"] },
5032
+ { kind: "index", name: "by_provider_project_subject", columns: ["provider", "providerProjectId", "providerSubjectId"] },
5000
5033
  { kind: "index", name: "by_tenant_provider_subject", columns: ["tenantId", "provider", "providerSubjectId"] },
5034
+ { kind: "index", name: "by_tenant_provider_project_subject", columns: ["tenantId", "provider", "providerProjectId", "providerSubjectId"] },
5001
5035
  {
5002
5036
  kind: "index",
5003
5037
  name: "by_tenant_provider_alias",
@@ -8365,6 +8399,40 @@ var GENERATED_INFISICAL_RUNTIME_ENV = {
8365
8399
  ],
8366
8400
  "description": "Canonical Lucern API gateway URL. Canonical Lucern API gateway base URL. Older names remain aliases only."
8367
8401
  },
8402
+ {
8403
+ "secretId": "platform.clerk.webhook-secret",
8404
+ "canonicalName": "LUCERN_CLERK_WEBHOOK_SECRET",
8405
+ "envNames": [
8406
+ "CLERK_WEBHOOK_SECRET",
8407
+ "CLERK_WEBHOOK_SIGNING_SECRET",
8408
+ "LUCERN_CLERK_WEBHOOK_SECRET"
8409
+ ],
8410
+ "aliases": [
8411
+ "CLERK_WEBHOOK_SECRET",
8412
+ "CLERK_WEBHOOK_SIGNING_SECRET"
8413
+ ],
8414
+ "writeNames": [
8415
+ "LUCERN_CLERK_WEBHOOK_SECRET"
8416
+ ],
8417
+ "required": true,
8418
+ "secret": true,
8419
+ "public": false,
8420
+ "sourcePath": "/platform/auth",
8421
+ "environmentPolicy": "environment_specific",
8422
+ "consumers": [
8423
+ "lucern-gateway"
8424
+ ],
8425
+ "destinations": [
8426
+ {
8427
+ "kind": "vercel",
8428
+ "target": "lucern-gateway",
8429
+ "writeNames": [
8430
+ "LUCERN_CLERK_WEBHOOK_SECRET"
8431
+ ]
8432
+ }
8433
+ ],
8434
+ "description": "Lucern-owned Clerk/Svix webhook signing secret used by the gateway to verify Clerk identity and organization events before projecting them into Permit."
8435
+ },
8368
8436
  {
8369
8437
  "canonicalName": "LUCERN_CLI_SESSION_TTL_MS",
8370
8438
  "envNames": [
@@ -8688,6 +8756,54 @@ var GENERATED_INFISICAL_RUNTIME_ENV = {
8688
8756
  ],
8689
8757
  "description": "Optional Permit PDP URL override."
8690
8758
  },
8759
+ {
8760
+ "secretId": "platform.permit.webhook-secret",
8761
+ "canonicalName": "LUCERN_PERMIT_WEBHOOK_SECRET",
8762
+ "envNames": [
8763
+ "LUCERN_PERMIT_WEBHOOK_SECRET",
8764
+ "PERMIT_WEBHOOK_SECRET"
8765
+ ],
8766
+ "aliases": [
8767
+ "PERMIT_WEBHOOK_SECRET"
8768
+ ],
8769
+ "writeNames": [
8770
+ "LUCERN_PERMIT_WEBHOOK_SECRET"
8771
+ ],
8772
+ "required": true,
8773
+ "secret": true,
8774
+ "public": false,
8775
+ "sourcePath": "/platform/permit",
8776
+ "environmentPolicy": "environment_specific",
8777
+ "consumers": [
8778
+ "mc-convex",
8779
+ "lucern-gateway",
8780
+ "mc-operator-tooling"
8781
+ ],
8782
+ "destinations": [
8783
+ {
8784
+ "kind": "convex",
8785
+ "target": "master-control",
8786
+ "writeNames": [
8787
+ "LUCERN_PERMIT_WEBHOOK_SECRET"
8788
+ ]
8789
+ },
8790
+ {
8791
+ "kind": "vercel",
8792
+ "target": "lucern-gateway",
8793
+ "writeNames": [
8794
+ "LUCERN_PERMIT_WEBHOOK_SECRET"
8795
+ ]
8796
+ },
8797
+ {
8798
+ "kind": "operator_local",
8799
+ "target": "mc-credential-maintenance",
8800
+ "writeNames": [
8801
+ "LUCERN_PERMIT_WEBHOOK_SECRET"
8802
+ ]
8803
+ }
8804
+ ],
8805
+ "description": "Permit.io webhook secret used by gateway and MC webhook handlers. Must fail closed if missing."
8806
+ },
8691
8807
  {
8692
8808
  "secretId": "platform.runtime.require-deployment-host-registry",
8693
8809
  "canonicalName": "LUCERN_REQUIRE_DEPLOYMENT_HOST_REGISTRY",
@@ -12776,7 +12892,7 @@ var IDENTITY_WHOAMI = {
12776
12892
  description: "Canonical identity summary for the current session",
12777
12893
  fields: {
12778
12894
  principalId: "string \u2014 canonical federated principal identifier",
12779
- principalType: "string \u2014 human, service, or agent",
12895
+ principalType: "string \u2014 human, service, agent, group, or external_viewer",
12780
12896
  tenantId: "string | undefined \u2014 resolved tenant scope",
12781
12897
  workspaceId: "string | undefined \u2014 resolved workspace scope",
12782
12898
  scopes: "string[] | undefined \u2014 granted scopes for this session",
@@ -12787,6 +12903,49 @@ var IDENTITY_WHOAMI = {
12787
12903
  ontologyPrimitive: "identity",
12788
12904
  tier: "workhorse"
12789
12905
  };
12906
+ var RESOLVE_INTERACTIVE_PRINCIPAL = {
12907
+ name: "resolve_interactive_principal",
12908
+ description: "Read the Permit-backed Lucern principal context for an authenticated Clerk user. Like `git config --get user.email` plus the repository ACL \u2014 resolves the identity alias into the canonical authorization subject.",
12909
+ parameters: {
12910
+ clerkId: {
12911
+ type: "string",
12912
+ description: "Authenticated Clerk subject (`sub`). Clerk proves identity only; it is not the authorization record."
12913
+ },
12914
+ tenantId: {
12915
+ type: "string",
12916
+ description: "Optional tenant scope. Omit only when the Clerk alias is globally unambiguous."
12917
+ },
12918
+ workspaceId: {
12919
+ type: "string",
12920
+ description: "Optional workspace scope. Required when the principal has access to multiple workspaces and no default can be inferred."
12921
+ },
12922
+ providerProjectId: {
12923
+ type: "string",
12924
+ description: "Optional Clerk project or provider instance id for tenants with multiple identity providers."
12925
+ }
12926
+ },
12927
+ required: ["clerkId"],
12928
+ response: {
12929
+ description: "Permit-backed Lucern principal context for tenant SDK bootstrap",
12930
+ fields: {
12931
+ principalId: "string \u2014 canonical Lucern principal identifier",
12932
+ principalType: "string \u2014 human, service, agent, group, or external_viewer",
12933
+ clerkId: "string \u2014 authenticated Clerk subject alias",
12934
+ tenantId: "string \u2014 resolved tenant scope",
12935
+ workspaceId: "string | null \u2014 resolved workspace scope",
12936
+ roles: "string[] \u2014 effective Permit roles",
12937
+ scopes: "string[] \u2014 effective scopes derived from Permit/control-plane projection",
12938
+ groupIds: "string[] \u2014 active Permit group memberships",
12939
+ principalStatus: "string \u2014 active, invited, suspended, disabled, revoked, or missing",
12940
+ tenantStatus: "string \u2014 projected tenant resource status",
12941
+ workspaceStatus: "string \u2014 projected workspace resource status",
12942
+ permit: "object \u2014 Permit subject, tenant, and optional workspace tuple"
12943
+ }
12944
+ },
12945
+ ownerModule: "control-plane",
12946
+ ontologyPrimitive: "identity",
12947
+ tier: "workhorse"
12948
+ };
12790
12949
  var COMPILE_CONTEXT = {
12791
12950
  name: "compile_context",
12792
12951
  description: "Compile a focused reasoning context. If topicId is omitted, Lucern resolves the best topic from the query. Like `git log --graph --decorate` for the reasoning substrate \u2014 returns the canonical Pillar 3 context pack through the public API shape.",
@@ -14689,6 +14848,7 @@ var MCP_TOOL_CONTRACTS = {
14689
14848
  update_worktree_targets: UPDATE_WORKTREE_TARGETS,
14690
14849
  update_worktree_metadata: UPDATE_WORKTREE_METADATA,
14691
14850
  identity_whoami: IDENTITY_WHOAMI,
14851
+ resolve_interactive_principal: RESOLVE_INTERACTIVE_PRINCIPAL,
14692
14852
  compile_context: COMPILE_CONTEXT,
14693
14853
  record_scope_learning: RECORD_SCOPE_LEARNING,
14694
14854
  pipeline_snapshot: PIPELINE_SNAPSHOT,
@@ -14818,6 +14978,7 @@ function entries(names, surfaceClass, surfaceIntent, surfaces, rationale) {
14818
14978
  var MCP_CORE_OPERATION_NAMES = [
14819
14979
  "compile_context",
14820
14980
  "identity_whoami",
14981
+ "resolve_interactive_principal",
14821
14982
  "check_permission",
14822
14983
  "filter_by_permission",
14823
14984
  "create_belief",
@@ -15371,7 +15532,13 @@ function surfaceContract(args) {
15371
15532
  scopes: args.scopes ?? [
15372
15533
  args.kind === "query" ? `${args.domain}.read` : `${args.domain}.write`
15373
15534
  ],
15374
- allowedPrincipalTypes: ["user", "service", "agent"]
15535
+ allowedPrincipalTypes: [
15536
+ "user",
15537
+ "service",
15538
+ "agent",
15539
+ "group",
15540
+ "external_viewer"
15541
+ ]
15375
15542
  },
15376
15543
  convex: args.convex,
15377
15544
  gateway: args.gateway,
@@ -15513,8 +15680,6 @@ var contextContracts = [
15513
15680
  args: observationContextArgs
15514
15681
  })
15515
15682
  ];
15516
-
15517
- // ../contracts/src/function-registry/identity.ts
15518
15683
  var withPrincipal = (input, context) => ({
15519
15684
  ...input,
15520
15685
  tenantId: input.tenantId ?? context.tenantId,
@@ -15540,6 +15705,28 @@ var identityContracts = [
15540
15705
  inputProjection: withPrincipal
15541
15706
  }
15542
15707
  }),
15708
+ surfaceContract({
15709
+ name: "resolve_interactive_principal",
15710
+ kind: "query",
15711
+ domain: "controlPlane",
15712
+ surfaceClass: "platform_public",
15713
+ method: "POST",
15714
+ path: "/control-plane/identity/resolve-interactive-principal",
15715
+ sdkNamespace: "controlPlane.identity",
15716
+ sdkMethod: "resolveInteractivePrincipal",
15717
+ summary: "Resolve an authenticated Clerk user into a Permit-backed Lucern principal context.",
15718
+ args: z.object({
15719
+ clerkId: z.string().min(1),
15720
+ tenantId: z.string().min(1).optional(),
15721
+ workspaceId: z.string().min(1).optional(),
15722
+ providerProjectId: z.string().min(1).optional()
15723
+ }),
15724
+ convex: {
15725
+ module: "identity",
15726
+ functionName: "resolveInteractivePrincipal",
15727
+ kind: "query"
15728
+ }
15729
+ }),
15543
15730
  surfaceContract({
15544
15731
  name: "check_permission",
15545
15732
  kind: "query",
@@ -19344,6 +19531,13 @@ var TENANT_BOOTSTRAP_TABLE_REQUIREMENTS = [
19344
19531
  copyMode: "none",
19345
19532
  description: "Deliberation sessions are created by tenant workflows."
19346
19533
  },
19534
+ {
19535
+ component: "kernel",
19536
+ table: "domainEvents",
19537
+ prepopulation: "runtime_log",
19538
+ copyMode: "none",
19539
+ description: "Domain event rows are append-only runtime audit/exhaust data."
19540
+ },
19347
19541
  {
19348
19542
  component: "kernel",
19349
19543
  table: "epistemicAudit",
@@ -20476,6 +20670,7 @@ __export(src_exports, {
20476
20670
  LUCERN_SDK_VERSION: () => LUCERN_SDK_VERSION,
20477
20671
  LucernAccessControlError: () => LucernAccessControlError,
20478
20672
  LucernApiError: () => LucernApiError,
20673
+ LucernControlPlaneIdentityError: () => LucernControlPlaneIdentityError,
20479
20674
  LucernSdkAuthContextError: () => LucernSdkAuthContextError,
20480
20675
  MANAGE_WRITE_POLICY: () => MANAGE_WRITE_POLICY,
20481
20676
  MATCH_ENTITY_TYPE: () => MATCH_ENTITY_TYPE,
@@ -20507,6 +20702,7 @@ __export(src_exports, {
20507
20702
  REMOVE_EDGES_BETWEEN: () => REMOVE_EDGES_BETWEEN,
20508
20703
  REMOVE_LENS_FROM_TOPIC: () => REMOVE_LENS_FROM_TOPIC,
20509
20704
  RESOLVE_EFFECTIVE_ONTOLOGY: () => RESOLVE_EFFECTIVE_ONTOLOGY,
20705
+ RESOLVE_INTERACTIVE_PRINCIPAL: () => RESOLVE_INTERACTIVE_PRINCIPAL,
20510
20706
  RUN_GRAPH_INTELLIGENCE_QUERY: () => RUN_GRAPH_INTELLIGENCE_QUERY,
20511
20707
  SEARCH_BELIEFS: () => SEARCH_BELIEFS,
20512
20708
  SEARCH_EVIDENCE: () => SEARCH_EVIDENCE,
@@ -20572,6 +20768,8 @@ __export(src_exports, {
20572
20768
  createCanonicalAuthHeaders: () => createCanonicalAuthHeaders,
20573
20769
  createContextClient: () => createContextClient,
20574
20770
  createContextFacade: () => createContextFacade,
20771
+ createControlPlaneClient: () => createControlPlaneClient,
20772
+ createControlPlaneIdentityClient: () => createControlPlaneIdentityClient,
20575
20773
  createDecisionsClient: () => createDecisionsClient,
20576
20774
  createEmbeddingsClient: () => createEmbeddingsClient,
20577
20775
  createEventId: () => createEventId,
@@ -20645,6 +20843,7 @@ __export(src_exports, {
20645
20843
  normalizeDelegationChain: () => normalizeDelegationChain,
20646
20844
  normalizeNodeVerificationStatus: () => normalizeNodeVerificationStatus,
20647
20845
  normalizeNodeWriteInput: () => normalizeNodeWriteInput,
20846
+ normalizeResolvedInteractivePrincipal: () => normalizeResolvedInteractivePrincipal,
20648
20847
  normalizeRetentionDays: () => normalizeRetentionDays,
20649
20848
  normalizeTopicQuery: () => normalizeTopicQuery,
20650
20849
  normalizeWebhookPatterns: () => normalizeWebhookPatterns,
@@ -20734,14 +20933,14 @@ function requireString(value, reason, label) {
20734
20933
  }
20735
20934
  return normalized;
20736
20935
  }
20737
- function requirePrincipalType(principalType) {
20738
- if (!principalType) {
20936
+ function requirePrincipalType(principalType2) {
20937
+ if (!principalType2) {
20739
20938
  throw new LucernSdkAuthContextError(
20740
20939
  "principal_missing",
20741
20940
  "Canonical Lucern SDK auth context is missing principalType."
20742
20941
  );
20743
20942
  }
20744
- return principalType;
20943
+ return principalType2;
20745
20944
  }
20746
20945
  function requireAuthMode(authMode) {
20747
20946
  if (!authMode) {
@@ -20787,7 +20986,7 @@ function normalizeCanonicalLucernAuthContext(input) {
20787
20986
  );
20788
20987
  const roles = cleanStringList(input.roles);
20789
20988
  const scopes = cleanStringList(input.scopes);
20790
- const principalType = requirePrincipalType(input.principalType);
20989
+ const principalType2 = requirePrincipalType(input.principalType);
20791
20990
  const authMode = requireAuthMode(input.authMode);
20792
20991
  const roleBasedInteractiveAuth = authMode === "interactive_user" && roles.length > 0;
20793
20992
  if (roles.length === 0 || scopes.length === 0 && !roleBasedInteractiveAuth) {
@@ -20816,7 +21015,7 @@ function normalizeCanonicalLucernAuthContext(input) {
20816
21015
  principalId,
20817
21016
  tenantId,
20818
21017
  workspaceId,
20819
- principalType,
21018
+ principalType: principalType2,
20820
21019
  authMode,
20821
21020
  roles,
20822
21021
  scopes,
@@ -21805,6 +22004,128 @@ function listResultFromEnvelope(data, legacyKey) {
21805
22004
  );
21806
22005
  }
21807
22006
 
22007
+ // ../sdk/src/control-plane.ts
22008
+ var LucernControlPlaneIdentityError = class extends Error {
22009
+ reason;
22010
+ principalStatus;
22011
+ tenantStatus;
22012
+ workspaceStatus;
22013
+ details;
22014
+ constructor(failure) {
22015
+ super(failure.message);
22016
+ this.name = "LucernControlPlaneIdentityError";
22017
+ this.reason = failure.reason;
22018
+ this.principalStatus = failure.principalStatus;
22019
+ this.tenantStatus = failure.tenantStatus;
22020
+ this.workspaceStatus = failure.workspaceStatus;
22021
+ this.details = failure.details;
22022
+ }
22023
+ };
22024
+ function cleanString3(value) {
22025
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
22026
+ }
22027
+ function stringList(value) {
22028
+ if (!Array.isArray(value)) {
22029
+ return [];
22030
+ }
22031
+ return [
22032
+ ...new Set(
22033
+ value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean)
22034
+ )
22035
+ ];
22036
+ }
22037
+ function principalType(value) {
22038
+ switch (value) {
22039
+ case "service":
22040
+ case "service_principal":
22041
+ return "service";
22042
+ case "agent":
22043
+ return "agent";
22044
+ case "group":
22045
+ return "group";
22046
+ case "external_viewer":
22047
+ case "external_stakeholder":
22048
+ return "external_viewer";
22049
+ default:
22050
+ return "human";
22051
+ }
22052
+ }
22053
+ function adminFlags(roles) {
22054
+ const normalized = roles.map((role) => role.toLowerCase());
22055
+ const isPlatformAdmin = normalized.includes("platform_admin");
22056
+ const isTenantAdmin = isPlatformAdmin || normalized.includes("tenant_admin");
22057
+ const isWorkspaceAdmin = isTenantAdmin || normalized.includes("workspace_admin") || normalized.includes("workspace_owner");
22058
+ return { isPlatformAdmin, isTenantAdmin, isWorkspaceAdmin };
22059
+ }
22060
+ function normalizeResolvedInteractivePrincipal(payload) {
22061
+ if ("ok" in payload && payload.ok === false) {
22062
+ throw new LucernControlPlaneIdentityError(payload);
22063
+ }
22064
+ const principalId = cleanString3(payload.principalId);
22065
+ const clerkId = cleanString3(payload.clerkId);
22066
+ const tenantId = cleanString3(payload.tenantId);
22067
+ if (!principalId || !clerkId || !tenantId) {
22068
+ throw new LucernControlPlaneIdentityError({
22069
+ ok: false,
22070
+ reason: "resolver_unavailable",
22071
+ message: "Control-plane principal resolver returned an incomplete principal context.",
22072
+ principalStatus: payload.principalStatus ?? "missing",
22073
+ tenantStatus: payload.tenantStatus,
22074
+ workspaceStatus: payload.workspaceStatus
22075
+ });
22076
+ }
22077
+ const roles = stringList(payload.roles);
22078
+ const scopes = stringList(payload.scopes);
22079
+ const workspaceId = cleanString3(payload.workspaceId) ?? null;
22080
+ const flags = adminFlags(roles);
22081
+ return {
22082
+ principalId,
22083
+ principalType: principalType(payload.principalType),
22084
+ clerkId,
22085
+ tenantId,
22086
+ workspaceId,
22087
+ roles,
22088
+ scopes,
22089
+ groupIds: stringList(payload.groupIds),
22090
+ permittedToolNames: stringList(payload.permittedToolNames),
22091
+ permittedPackKeys: stringList(payload.permittedPackKeys),
22092
+ principalStatus: cleanString3(payload.principalStatus) ?? "active",
22093
+ tenantStatus: cleanString3(payload.tenantStatus) ?? "active",
22094
+ workspaceStatus: cleanString3(payload.workspaceStatus) ?? (workspaceId ? "active" : "none"),
22095
+ isPlatformAdmin: typeof payload.isPlatformAdmin === "boolean" ? payload.isPlatformAdmin : flags.isPlatformAdmin,
22096
+ isTenantAdmin: typeof payload.isTenantAdmin === "boolean" ? payload.isTenantAdmin : flags.isTenantAdmin,
22097
+ isWorkspaceAdmin: typeof payload.isWorkspaceAdmin === "boolean" ? payload.isWorkspaceAdmin : flags.isWorkspaceAdmin,
22098
+ permit: {
22099
+ subject: cleanString3(payload.permit?.subject) ?? principalId,
22100
+ tenant: cleanString3(payload.permit?.tenant) ?? tenantId,
22101
+ ...workspaceId ? { workspace: cleanString3(payload.permit?.workspace) ?? workspaceId } : {}
22102
+ },
22103
+ authMode: "interactive_user",
22104
+ sessionId: payload.sessionId,
22105
+ delegatedBy: payload.delegatedBy,
22106
+ expiresAt: payload.expiresAt
22107
+ };
22108
+ }
22109
+ function createControlPlaneIdentityClient(config = {}) {
22110
+ const gateway = createGatewayRequestClient(config);
22111
+ return {
22112
+ async resolveInteractivePrincipal(input) {
22113
+ return gateway.request({
22114
+ path: "/api/platform/v1/control-plane/identity/resolve-interactive-principal",
22115
+ method: "POST",
22116
+ body: input
22117
+ }).then(
22118
+ (response) => mapGatewayData(response, normalizeResolvedInteractivePrincipal)
22119
+ );
22120
+ }
22121
+ };
22122
+ }
22123
+ function createControlPlaneClient(config = {}) {
22124
+ return {
22125
+ identity: createControlPlaneIdentityClient(config)
22126
+ };
22127
+ }
22128
+
21808
22129
  // ../sdk/src/identityClient.ts
21809
22130
  function createIdentityWhoamiClient(config = {}) {
21810
22131
  const gateway = createGatewayRequestClient(config);
@@ -21872,13 +22193,25 @@ function createIdentityClient(config = {}) {
21872
22193
  (response) => mapGatewayData(response, (data) => ({
21873
22194
  principalId: data.principalId,
21874
22195
  principalType: data.principalType,
22196
+ clerkId: data.clerkId,
21875
22197
  tenantId: data.tenantId ?? null,
21876
22198
  workspaceId: data.workspaceId ?? null,
21877
22199
  scopes: Array.isArray(data.scopes) ? data.scopes : [],
21878
22200
  roles: Array.isArray(data.roles) ? data.roles : [],
22201
+ groupIds: Array.isArray(data.groupIds) ? data.groupIds : [],
22202
+ permittedToolNames: Array.isArray(data.permittedToolNames) ? data.permittedToolNames : [],
22203
+ permittedPackKeys: Array.isArray(data.permittedPackKeys) ? data.permittedPackKeys : [],
22204
+ principalStatus: data.principalStatus,
22205
+ tenantStatus: data.tenantStatus,
22206
+ workspaceStatus: data.workspaceStatus,
21879
22207
  isPlatformAdmin: data.isPlatformAdmin === true,
21880
22208
  isTenantAdmin: data.isTenantAdmin === true,
21881
22209
  isWorkspaceAdmin: data.isWorkspaceAdmin === true,
22210
+ permit: data.permit ?? (data.tenantId ? {
22211
+ subject: data.principalId,
22212
+ tenant: data.tenantId,
22213
+ ...data.workspaceId ? { workspace: data.workspaceId } : {}
22214
+ } : void 0),
21882
22215
  authMode: data.authMode,
21883
22216
  sessionId: data.sessionId,
21884
22217
  delegatedBy: data.delegatedBy,
@@ -21886,6 +22219,19 @@ function createIdentityClient(config = {}) {
21886
22219
  }))
21887
22220
  );
21888
22221
  },
22222
+ /**
22223
+ * Resolve a Clerk subject through the tenant control-plane Permit projection.
22224
+ * @deprecated Prefer lucern.controlPlane.identity.resolveInteractivePrincipal().
22225
+ */
22226
+ async resolveInteractivePrincipal(input) {
22227
+ return gateway.request({
22228
+ path: "/api/platform/v1/control-plane/identity/resolve-interactive-principal",
22229
+ method: "POST",
22230
+ body: input
22231
+ }).then(
22232
+ (response) => mapGatewayData(response, normalizeResolvedInteractivePrincipal)
22233
+ );
22234
+ },
21889
22235
  /**
21890
22236
  * List principals in the current identity scope.
21891
22237
  */
@@ -22082,7 +22428,7 @@ var LucernAccessControlError = class extends LucernSdkAuthContextError {
22082
22428
  this.policyDecision = policyDecision;
22083
22429
  }
22084
22430
  };
22085
- function cleanString3(value) {
22431
+ function cleanString4(value) {
22086
22432
  const normalized = value?.trim();
22087
22433
  return normalized ? normalized : void 0;
22088
22434
  }
@@ -22097,7 +22443,7 @@ function cleanStringList2(values) {
22097
22443
  ];
22098
22444
  }
22099
22445
  function requireString2(value, reason, label) {
22100
- const normalized = cleanString3(value);
22446
+ const normalized = cleanString4(value);
22101
22447
  if (!normalized) {
22102
22448
  throw new LucernAccessControlError(
22103
22449
  reason,
@@ -22106,13 +22452,19 @@ function requireString2(value, reason, label) {
22106
22452
  }
22107
22453
  return normalized;
22108
22454
  }
22109
- function normalizePrincipalType(principalType) {
22110
- if (principalType === "agent") {
22455
+ function normalizePrincipalType(principalType2) {
22456
+ if (principalType2 === "agent") {
22111
22457
  return "agent";
22112
22458
  }
22113
- if (principalType === "service") {
22459
+ if (principalType2 === "service") {
22114
22460
  return "service";
22115
22461
  }
22462
+ if (principalType2 === "group") {
22463
+ return "group";
22464
+ }
22465
+ if (principalType2 === "external_viewer") {
22466
+ return "external_viewer";
22467
+ }
22116
22468
  return "human";
22117
22469
  }
22118
22470
  function aliasKey(alias) {
@@ -22121,15 +22473,15 @@ function aliasKey(alias) {
22121
22473
  function normalizeAliases(input, canonicalClerkUserId) {
22122
22474
  const aliases = /* @__PURE__ */ new Map();
22123
22475
  for (const alias of input ?? []) {
22124
- const externalSubjectId = cleanString3(alias.externalSubjectId);
22476
+ const externalSubjectId = cleanString4(alias.externalSubjectId);
22125
22477
  if (!externalSubjectId) {
22126
22478
  continue;
22127
22479
  }
22128
22480
  const normalized = {
22129
- provider: cleanString3(alias.provider) ?? "clerk",
22130
- providerProjectId: cleanString3(alias.providerProjectId),
22481
+ provider: cleanString4(alias.provider) ?? "clerk",
22482
+ providerProjectId: cleanString4(alias.providerProjectId),
22131
22483
  externalSubjectId,
22132
- status: cleanString3(alias.status)
22484
+ status: cleanString4(alias.status)
22133
22485
  };
22134
22486
  aliases.set(aliasKey(normalized), normalized);
22135
22487
  }
@@ -22174,10 +22526,10 @@ function normalizeCanonicalPrincipalIdentity(input, options = {}) {
22174
22526
  "principal_missing",
22175
22527
  "principalId"
22176
22528
  );
22177
- const principalType = normalizePrincipalType(principalInput.principalType);
22178
- const observedClerkId = cleanString3(options.observedClerkId);
22179
- const canonicalClerkUserId = cleanString3(principalInput.canonicalClerkUserId) ?? cleanString3(principalInput.clerkId);
22180
- if (principalType === "human" && !canonicalClerkUserId) {
22529
+ const principalType2 = normalizePrincipalType(principalInput.principalType);
22530
+ const observedClerkId = cleanString4(options.observedClerkId);
22531
+ const canonicalClerkUserId = cleanString4(principalInput.canonicalClerkUserId) ?? cleanString4(principalInput.clerkId);
22532
+ if (principalType2 === "human" && !canonicalClerkUserId) {
22181
22533
  throw new LucernAccessControlError(
22182
22534
  "clerk_alias_missing",
22183
22535
  "Human principals require one canonical Clerk user id."
@@ -22199,11 +22551,11 @@ function normalizeCanonicalPrincipalIdentity(input, options = {}) {
22199
22551
  }
22200
22552
  return {
22201
22553
  principalId,
22202
- principalType,
22554
+ principalType: principalType2,
22203
22555
  canonicalClerkUserId,
22204
22556
  clerkIdentityAliases: aliases,
22205
- tenantId: cleanString3(principalInput.tenantId),
22206
- workspaceId: cleanString3(principalInput.workspaceId),
22557
+ tenantId: cleanString4(principalInput.tenantId),
22558
+ workspaceId: cleanString4(principalInput.workspaceId),
22207
22559
  roles: cleanStringList2(principalInput.roles),
22208
22560
  scopes: cleanStringList2(principalInput.scopes)
22209
22561
  };
@@ -22228,7 +22580,7 @@ function buildPolicyInput(identity, input) {
22228
22580
  "tenant_missing",
22229
22581
  "tenantId"
22230
22582
  );
22231
- const workspaceId = cleanString3(input.workspaceId ?? identity.workspaceId);
22583
+ const workspaceId = cleanString4(input.workspaceId ?? identity.workspaceId);
22232
22584
  if (resourceRequiresWorkspace(input.resource) && !workspaceId) {
22233
22585
  throw new LucernAccessControlError(
22234
22586
  "workspace_missing",
@@ -23628,12 +23980,12 @@ function createGraphClient(config = {}) {
23628
23980
  }
23629
23981
 
23630
23982
  // ../sdk/src/topicsClient.ts
23631
- function cleanString4(value) {
23983
+ function cleanString5(value) {
23632
23984
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
23633
23985
  }
23634
23986
  function normalizeTopicRecord(value) {
23635
23987
  const record = asRecord(value);
23636
- const topicId = cleanString4(record.topicId) ?? cleanString4(record.id) ?? cleanString4(record._id);
23988
+ const topicId = cleanString5(record.topicId) ?? cleanString5(record.id) ?? cleanString5(record._id);
23637
23989
  return withTopicAlias({
23638
23990
  ...record,
23639
23991
  ...topicId ? { topicId } : {}
@@ -24846,7 +25198,7 @@ function createEmbeddingsClient(config = {}) {
24846
25198
  }
24847
25199
 
24848
25200
  // ../sdk/src/contextClient.ts
24849
- function cleanString5(value) {
25201
+ function cleanString6(value) {
24850
25202
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
24851
25203
  }
24852
25204
  function cleanNumber(value) {
@@ -24858,11 +25210,11 @@ function cleanBoolean(value) {
24858
25210
  function buildCompileContextRequest(topicIdOrInput = {}, input = {}) {
24859
25211
  const effectiveInput = typeof topicIdOrInput === "string" ? input : topicIdOrInput;
24860
25212
  const payload = {};
24861
- const topicId = typeof topicIdOrInput === "string" ? cleanString5(topicIdOrInput) : cleanString5(effectiveInput.topicId);
25213
+ const topicId = typeof topicIdOrInput === "string" ? cleanString6(topicIdOrInput) : cleanString6(effectiveInput.topicId);
24862
25214
  if (topicId) {
24863
25215
  payload.topicId = topicId;
24864
25216
  }
24865
- const query5 = cleanString5(effectiveInput.query);
25217
+ const query5 = cleanString6(effectiveInput.query);
24866
25218
  if (query5) {
24867
25219
  payload.query = query5;
24868
25220
  }
@@ -24870,7 +25222,7 @@ function buildCompileContextRequest(topicIdOrInput = {}, input = {}) {
24870
25222
  if (budget !== void 0) {
24871
25223
  payload.budget = budget;
24872
25224
  }
24873
- const ranking = cleanString5(effectiveInput.ranking) ?? cleanString5(effectiveInput.rankingProfile);
25225
+ const ranking = cleanString6(effectiveInput.ranking) ?? cleanString6(effectiveInput.rankingProfile);
24874
25226
  if (ranking) {
24875
25227
  payload.ranking = ranking;
24876
25228
  }
@@ -24886,7 +25238,7 @@ function buildCompileContextRequest(topicIdOrInput = {}, input = {}) {
24886
25238
  if (includeEntities !== void 0) {
24887
25239
  payload.includeEntities = includeEntities;
24888
25240
  }
24889
- const mode = cleanString5(effectiveInput.mode);
25241
+ const mode = cleanString6(effectiveInput.mode);
24890
25242
  if (mode) {
24891
25243
  payload.mode = mode;
24892
25244
  }
@@ -24894,11 +25246,11 @@ function buildCompileContextRequest(topicIdOrInput = {}, input = {}) {
24894
25246
  if (includeFailures !== void 0) {
24895
25247
  payload.includeFailures = includeFailures;
24896
25248
  }
24897
- const worktreeId = cleanString5(effectiveInput.worktreeId);
25249
+ const worktreeId = cleanString6(effectiveInput.worktreeId);
24898
25250
  if (worktreeId) {
24899
25251
  payload.worktreeId = worktreeId;
24900
25252
  }
24901
- const sessionId = cleanString5(effectiveInput.sessionId);
25253
+ const sessionId = cleanString6(effectiveInput.sessionId);
24902
25254
  if (sessionId) {
24903
25255
  payload.sessionId = sessionId;
24904
25256
  }
@@ -25907,6 +26259,7 @@ var FUNCTION_SURFACE_METHOD_PATHS = [
25907
26259
  "contracts.evaluateContract",
25908
26260
  "contracts.getContractStatus",
25909
26261
  "contradictions.flagContradiction",
26262
+ "controlPlane.identity.resolveInteractivePrincipal",
25910
26263
  "coordination.broadcastMessage",
25911
26264
  "coordination.claimFiles",
25912
26265
  "coordination.endSession",
@@ -26112,6 +26465,7 @@ var CONTRACTS = {
26112
26465
  "remove_edges_between": { method: "DELETE", path: "/edges/between", kind: "mutation", idempotent: true, surfaceIntent: "mcp_analysis" },
26113
26466
  "remove_lens_from_topic": { method: "DELETE", path: "/lenses/apply", kind: "mutation", idempotent: true, surfaceIntent: "mcp_workflow" },
26114
26467
  "resolve_effective_ontology": { method: "POST", path: "/ontologies/effective", kind: "query", idempotent: false, surfaceIntent: "mcp_workflow" },
26468
+ "resolve_interactive_principal": { method: "POST", path: "/control-plane/identity/resolve-interactive-principal", kind: "query", idempotent: false, surfaceIntent: "mcp_core" },
26115
26469
  "run_graph_intelligence_query": { method: "POST", path: "/graph-intelligence/run", kind: "query", idempotent: false, surfaceIntent: "mcp_analysis" },
26116
26470
  "search_beliefs": { method: "POST", path: "/beliefs/search", kind: "query", idempotent: false, surfaceIntent: "mcp_core" },
26117
26471
  "search_evidence": { method: "POST", path: "/evidence/search", kind: "query", idempotent: false, surfaceIntent: "mcp_core" },
@@ -26494,6 +26848,9 @@ function createFunctionSurfaceClient(config = {}) {
26494
26848
  resolveEffectiveOntology(input = {}, idempotencyKey) {
26495
26849
  return execute("resolve_effective_ontology", input, idempotencyKey);
26496
26850
  },
26851
+ resolveInteractivePrincipal(input = {}, idempotencyKey) {
26852
+ return execute("resolve_interactive_principal", input, idempotencyKey);
26853
+ },
26497
26854
  runGraphIntelligenceQuery(input = {}, idempotencyKey) {
26498
26855
  return execute("run_graph_intelligence_query", input, idempotencyKey);
26499
26856
  },
@@ -26754,7 +27111,7 @@ var ORG_GRAPH_SEARCH_FIELDS = [
26754
27111
  "cursor",
26755
27112
  "provenanceScope"
26756
27113
  ];
26757
- function cleanString6(value, label) {
27114
+ function cleanString7(value, label) {
26758
27115
  const normalized = value?.trim();
26759
27116
  if (!normalized) {
26760
27117
  throw new Error(`${label} is required`);
@@ -26776,9 +27133,9 @@ function searchBody(input) {
26776
27133
  "orgGraphSearch.search"
26777
27134
  );
26778
27135
  return {
26779
- tenantId: cleanString6(input.tenantId, "tenantId"),
26780
- workspaceId: cleanString6(input.workspaceId, "workspaceId"),
26781
- query: cleanString6(input.query, "query"),
27136
+ tenantId: cleanString7(input.tenantId, "tenantId"),
27137
+ workspaceId: cleanString7(input.workspaceId, "workspaceId"),
27138
+ query: cleanString7(input.query, "query"),
26782
27139
  nodeTypes: input.nodeTypes,
26783
27140
  minConfidence: input.minConfidence,
26784
27141
  limit: input.limit,
@@ -26788,8 +27145,8 @@ function searchBody(input) {
26788
27145
  }
26789
27146
  function listQuery2(input) {
26790
27147
  return {
26791
- tenantId: cleanString6(input.tenantId, "tenantId"),
26792
- workspaceId: cleanString6(input.workspaceId, "workspaceId"),
27148
+ tenantId: cleanString7(input.tenantId, "tenantId"),
27149
+ workspaceId: cleanString7(input.workspaceId, "workspaceId"),
26793
27150
  nodeTypes: input.nodeTypes?.join(","),
26794
27151
  minConfidence: input.minConfidence,
26795
27152
  limit: input.limit,
@@ -26823,8 +27180,8 @@ function createOrgGraphSearchClient(config = {}) {
26823
27180
  return gateway.request({
26824
27181
  path: `/api/platform/v1/org-graph-search/nodes/${nodePath}${toQueryString(
26825
27182
  {
26826
- tenantId: cleanString6(input.tenantId, "tenantId"),
26827
- workspaceId: cleanString6(input.workspaceId, "workspaceId"),
27183
+ tenantId: cleanString7(input.tenantId, "tenantId"),
27184
+ workspaceId: cleanString7(input.workspaceId, "workspaceId"),
26828
27185
  globalId: nodeId ? void 0 : globalId
26829
27186
  }
26830
27187
  )}`
@@ -27789,7 +28146,7 @@ function createToolRegistryClient(config = {}) {
27789
28146
  }
27790
28147
 
27791
28148
  // ../sdk/src/version.ts
27792
- var LUCERN_SDK_VERSION = "0.3.0-alpha.11";
28149
+ var LUCERN_SDK_VERSION = "0.3.0-alpha.13";
27793
28150
 
27794
28151
  // ../sdk/src/workflowClient.ts
27795
28152
  function normalizeLensQuery(value) {
@@ -28266,6 +28623,7 @@ function createLucernClient(config = {}) {
28266
28623
  const ontologyLinksClient = createOntologyLinksClient(gatewayConfig);
28267
28624
  const orgGraphSearchClient = createOrgGraphSearchClient(gatewayConfig);
28268
28625
  const functionSurfaceClient = createFunctionSurfaceClient(gatewayConfig);
28626
+ const controlPlaneClient = createControlPlaneClient(gatewayConfig);
28269
28627
  const toolRegistryClient = createToolRegistryClient(gatewayConfig);
28270
28628
  const modelRuntimeClient = createModelRuntimeClient(gatewayConfig);
28271
28629
  const packsClient = createPacksClient(gatewayConfig);
@@ -29929,9 +30287,16 @@ function createLucernClient(config = {}) {
29929
30287
  disable: packsClient.disable
29930
30288
  },
29931
30289
  nodes: nodesNamespace,
30290
+ controlPlane: {
30291
+ identity: {
30292
+ resolveInteractivePrincipal: controlPlaneClient.identity.resolveInteractivePrincipal
30293
+ },
30294
+ raw: controlPlaneClient
30295
+ },
29932
30296
  identity: {
29933
30297
  ...identityFacade,
29934
30298
  access: accessControlClient,
30299
+ resolveInteractivePrincipal: identityClient.resolveInteractivePrincipal,
29935
30300
  evaluatePolicy: identityClient.evaluatePolicy,
29936
30301
  recordPolicyDecision: identityClient.recordPolicyDecision,
29937
30302
  putSecretReference: identityClient.putSecretReference,
@@ -29976,6 +30341,7 @@ function createLucernClient(config = {}) {
29976
30341
  ontologyLinks: ontologyLinksClient,
29977
30342
  orgGraphSearch: orgGraphSearchClient,
29978
30343
  functionSurface: functionSurfaceClient,
30344
+ controlPlane: controlPlaneClient,
29979
30345
  toolRegistry: toolRegistryClient,
29980
30346
  modelRuntime: modelRuntimeClient,
29981
30347
  packs: packsClient,
@@ -29993,7 +30359,7 @@ function createLucernClient(config = {}) {
29993
30359
  }
29994
30360
 
29995
30361
  // ../sdk/src/facade/context.ts
29996
- function cleanString7(value) {
30362
+ function cleanString8(value) {
29997
30363
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
29998
30364
  }
29999
30365
  function cleanNumber2(value) {
@@ -30005,11 +30371,11 @@ function cleanBoolean2(value) {
30005
30371
  function buildCompileContextRequest2(topicIdOrInput = {}, input = {}) {
30006
30372
  const effectiveInput = typeof topicIdOrInput === "string" ? input : topicIdOrInput;
30007
30373
  const payload = {};
30008
- const topicId = typeof topicIdOrInput === "string" ? cleanString7(topicIdOrInput) : cleanString7(effectiveInput.topicId);
30374
+ const topicId = typeof topicIdOrInput === "string" ? cleanString8(topicIdOrInput) : cleanString8(effectiveInput.topicId);
30009
30375
  if (topicId) {
30010
30376
  payload.topicId = topicId;
30011
30377
  }
30012
- const query5 = cleanString7(effectiveInput.query);
30378
+ const query5 = cleanString8(effectiveInput.query);
30013
30379
  if (query5) {
30014
30380
  payload.query = query5;
30015
30381
  }
@@ -30017,7 +30383,7 @@ function buildCompileContextRequest2(topicIdOrInput = {}, input = {}) {
30017
30383
  if (budget !== void 0) {
30018
30384
  payload.budget = budget;
30019
30385
  }
30020
- const ranking = cleanString7(effectiveInput.ranking) ?? cleanString7(effectiveInput.rankingProfile);
30386
+ const ranking = cleanString8(effectiveInput.ranking) ?? cleanString8(effectiveInput.rankingProfile);
30021
30387
  if (ranking) {
30022
30388
  payload.ranking = ranking;
30023
30389
  }
@@ -30033,7 +30399,7 @@ function buildCompileContextRequest2(topicIdOrInput = {}, input = {}) {
30033
30399
  if (includeEntities !== void 0) {
30034
30400
  payload.includeEntities = includeEntities;
30035
30401
  }
30036
- const mode = cleanString7(effectiveInput.mode);
30402
+ const mode = cleanString8(effectiveInput.mode);
30037
30403
  if (mode) {
30038
30404
  payload.mode = mode;
30039
30405
  }
@@ -30041,11 +30407,11 @@ function buildCompileContextRequest2(topicIdOrInput = {}, input = {}) {
30041
30407
  if (includeFailures !== void 0) {
30042
30408
  payload.includeFailures = includeFailures;
30043
30409
  }
30044
- const worktreeId = cleanString7(effectiveInput.worktreeId);
30410
+ const worktreeId = cleanString8(effectiveInput.worktreeId);
30045
30411
  if (worktreeId) {
30046
30412
  payload.worktreeId = worktreeId;
30047
30413
  }
30048
- const sessionId = cleanString7(effectiveInput.sessionId);
30414
+ const sessionId = cleanString8(effectiveInput.sessionId);
30049
30415
  if (sessionId) {
30050
30416
  payload.sessionId = sessionId;
30051
30417
  }
@@ -31467,7 +31833,13 @@ var SESSION_AUTH_MODES = [
31467
31833
  "tenant_api_key",
31468
31834
  "session_token"
31469
31835
  ];
31470
- var SESSION_PRINCIPAL_TYPES = ["human", "service", "agent"];
31836
+ var SESSION_PRINCIPAL_TYPES = [
31837
+ "human",
31838
+ "service",
31839
+ "agent",
31840
+ "group",
31841
+ "external_viewer"
31842
+ ];
31471
31843
  var SESSION_LIFECYCLE_STATUSES = [
31472
31844
  "active",
31473
31845
  "expired",
@@ -31480,6 +31852,12 @@ function inferSessionPrincipalType(principalId) {
31480
31852
  if (principalId.startsWith("agent:")) {
31481
31853
  return "agent";
31482
31854
  }
31855
+ if (principalId.startsWith("group:")) {
31856
+ return "group";
31857
+ }
31858
+ if (principalId.startsWith("external:") || principalId.startsWith("external_viewer:")) {
31859
+ return "external_viewer";
31860
+ }
31483
31861
  return "service";
31484
31862
  }
31485
31863
  function normalizeDelegationChain(args) {
@@ -34595,7 +34973,7 @@ function createLucernStandaloneMcpServer(options) {
34595
34973
  });
34596
34974
  const server = new McpServer({
34597
34975
  name: "lucern-mcp",
34598
- version: "0.3.0-alpha.11"
34976
+ version: "0.3.0-alpha.13"
34599
34977
  });
34600
34978
  registerTools(server, runtime);
34601
34979
  const resources = registerResources(server, runtime, observationStore);