@vellumai/credential-executor 0.6.5 → 0.7.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 (46) hide show
  1. package/Dockerfile +5 -5
  2. package/bun.lock +15 -7
  3. package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
  4. package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
  5. package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
  6. package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
  7. package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
  8. package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
  9. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
  10. package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
  11. package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
  12. package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
  13. package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
  14. package/package.json +3 -3
  15. package/src/__tests__/bulk-set-credentials.test.ts +1 -1
  16. package/src/__tests__/command-executor.test.ts +2 -2
  17. package/src/__tests__/http-executor.test.ts +1 -1
  18. package/src/__tests__/local-materializers.test.ts +1 -1
  19. package/src/__tests__/managed-integration.test.ts +1 -1
  20. package/src/__tests__/managed-lazy-getters.test.ts +1 -1
  21. package/src/__tests__/managed-materializers.test.ts +1 -1
  22. package/src/__tests__/managed-rejection.test.ts +1 -1
  23. package/src/__tests__/transport.test.ts +1 -1
  24. package/src/audit/store.ts +2 -2
  25. package/src/commands/executor.ts +2 -2
  26. package/src/grants/rpc-handlers.ts +1 -1
  27. package/src/http/audit.ts +1 -1
  28. package/src/http/executor.ts +2 -2
  29. package/src/http/policy.ts +1 -1
  30. package/src/main.ts +1 -1
  31. package/src/managed-errors.ts +2 -2
  32. package/src/managed-lazy-getters.ts +4 -4
  33. package/src/managed-main.ts +3 -3
  34. package/src/materializers/local.ts +1 -1
  35. package/src/server.ts +2 -2
  36. package/src/subjects/local.ts +2 -2
  37. package/src/subjects/managed.ts +1 -1
  38. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
  39. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
  40. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
  41. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
  42. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
  43. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
  44. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
  45. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
  46. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/tsconfig.json +0 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Trust rule types shared between the assistant daemon and the gateway.
3
+ *
4
+ * These are extracted from `assistant/src/permissions/types.ts` and
5
+ * `assistant/src/permissions/trust-store.ts` so that both packages can
6
+ * reference a single canonical definition.
7
+ *
8
+ * Tools are grouped into "families" based on how their permission candidates
9
+ * are constructed and matched:
10
+ *
11
+ * - **Scoped**: tools whose candidates include a filesystem path and obey
12
+ * directory-boundary scope constraints (`file_read`, `file_write`,
13
+ * `file_edit`, `host_file_read`, `host_file_write`, `host_file_edit`,
14
+ * `host_file_transfer`, `bash`, `host_bash`).
15
+ * - **URL**: tools whose candidates include a URL (`web_fetch`,
16
+ * `network_request`).
17
+ * - **Managed skill**: tools that manage first-party skill packages
18
+ * (`scaffold_managed_skill`, `delete_managed_skill`).
19
+ * - **Skill load**: the `skill_load` tool, which uses a distinct candidate
20
+ * namespace (`skill_load:selector` or `skill_load_dynamic:selector`).
21
+ * - **Generic**: everything else (computer-use tools, UI surface tools,
22
+ * recall, skill_execute, etc.).
23
+ */
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Trust decision
27
+ // ---------------------------------------------------------------------------
28
+
29
+ /** The possible decisions a trust rule can make. */
30
+ export type TrustDecision = "allow" | "deny" | "ask";
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Tool family constants
34
+ // ---------------------------------------------------------------------------
35
+
36
+ /**
37
+ * Tools whose permission candidates are scoped to a filesystem path and obey
38
+ * directory-boundary scope constraints.
39
+ */
40
+ export const SCOPED_TOOLS = [
41
+ "file_read",
42
+ "file_write",
43
+ "file_edit",
44
+ "host_file_read",
45
+ "host_file_write",
46
+ "host_file_edit",
47
+ "host_file_transfer",
48
+ "bash",
49
+ "host_bash",
50
+ ] as const;
51
+
52
+ /**
53
+ * Tools whose permission candidates include a URL.
54
+ */
55
+ export const URL_TOOLS = ["web_fetch", "network_request"] as const;
56
+
57
+ /**
58
+ * Tools that manage first-party skill packages (scaffold/delete).
59
+ */
60
+ export const MANAGED_SKILL_TOOLS = [
61
+ "scaffold_managed_skill",
62
+ "delete_managed_skill",
63
+ ] as const;
64
+
65
+ /**
66
+ * The skill_load tool name. Separated from the array constants because
67
+ * skill_load is a singleton, not a family with multiple members.
68
+ */
69
+ export const SKILL_LOAD_TOOL = "skill_load" as const;
70
+
71
+ /** Set for O(1) lookups when classifying tool names. */
72
+ const SCOPED_TOOLS_SET: ReadonlySet<string> = new Set(SCOPED_TOOLS);
73
+ const URL_TOOLS_SET: ReadonlySet<string> = new Set(URL_TOOLS);
74
+ const MANAGED_SKILL_TOOLS_SET: ReadonlySet<string> = new Set(
75
+ MANAGED_SKILL_TOOLS,
76
+ );
77
+
78
+ // ---------------------------------------------------------------------------
79
+ // Type guards
80
+ // ---------------------------------------------------------------------------
81
+
82
+ /** Returns true when the rule's tool belongs to the scoped-tool family. */
83
+ export function isScopedRule(rule: { tool: string }): boolean {
84
+ return SCOPED_TOOLS_SET.has(rule.tool);
85
+ }
86
+
87
+ /** Returns true when the rule's tool belongs to the URL-tool family. */
88
+ export function isUrlRule(rule: { tool: string }): boolean {
89
+ return URL_TOOLS_SET.has(rule.tool);
90
+ }
91
+
92
+ /** Returns true when the rule's tool belongs to the managed-skill-tool family. */
93
+ export function isManagedSkillRule(rule: { tool: string }): boolean {
94
+ return MANAGED_SKILL_TOOLS_SET.has(rule.tool);
95
+ }
96
+
97
+ /** Returns true when the rule's tool is the skill_load tool. */
98
+ export function isSkillLoadRule(rule: { tool: string }): boolean {
99
+ return rule.tool === SKILL_LOAD_TOOL;
100
+ }
101
+
102
+ // ---------------------------------------------------------------------------
103
+ // Scope helper
104
+ // ---------------------------------------------------------------------------
105
+
106
+ /**
107
+ * Return the effective scope for any trust rule. Only scoped rules carry a
108
+ * `scope` field; all other rule families return `"everywhere"`.
109
+ */
110
+ export function ruleScope(rule: { tool: string; scope?: string }): string {
111
+ if (isScopedRule(rule)) {
112
+ return rule.scope ?? "everywhere";
113
+ }
114
+ return "everywhere";
115
+ }
116
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/credential-executor",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -18,14 +18,14 @@
18
18
  "prepack": "node ../scripts/prepack-bundled-deps.mjs"
19
19
  },
20
20
  "dependencies": {
21
- "@vellumai/ces-contracts": "file:../packages/ces-contracts",
21
+ "@vellumai/service-contracts": "file:../packages/service-contracts",
22
22
  "@vellumai/credential-storage": "file:../packages/credential-storage",
23
23
  "@vellumai/egress-proxy": "file:../packages/egress-proxy",
24
24
  "pino": "9.14.0",
25
25
  "pino-pretty": "13.1.3"
26
26
  },
27
27
  "bundledDependencies": [
28
- "@vellumai/ces-contracts",
28
+ "@vellumai/service-contracts",
29
29
  "@vellumai/credential-storage",
30
30
  "@vellumai/egress-proxy"
31
31
  ],
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { describe, expect, test } from "bun:test";
9
9
 
10
- import { CesRpcMethod } from "@vellumai/ces-contracts";
10
+ import { CesRpcMethod } from "@vellumai/service-contracts/credential-rpc";
11
11
  import type { SecureKeyBackend } from "@vellumai/credential-storage";
12
12
 
13
13
  // ---------------------------------------------------------------------------
@@ -45,7 +45,7 @@ import {
45
45
  } from "../toolstore/publish.js";
46
46
  import { getCesToolStoreDir, getCesDataRoot } from "../paths.js";
47
47
  import { computeDigest } from "../toolstore/integrity.js";
48
- import { hashProposal, type CommandGrantProposal } from "@vellumai/ces-contracts";
48
+ import { hashProposal, type CommandGrantProposal } from "@vellumai/service-contracts/credential-rpc";
49
49
 
50
50
  // ---------------------------------------------------------------------------
51
51
  // Test helpers
@@ -244,7 +244,7 @@ function addCommandGrant(
244
244
  * Add a temporary command grant.
245
245
  *
246
246
  * Constructs the same CommandGrantProposal shape that the executor builds
247
- * and hashes it with `hashProposal` from `@vellumai/ces-contracts` so the
247
+ * and hashes it with `hashProposal` from `@vellumai/service-contracts` so the
248
248
  * hashes align.
249
249
  */
250
250
  function addTemporaryCommandGrant(
@@ -24,7 +24,7 @@ import {
24
24
  localStaticHandle,
25
25
  localOAuthHandle,
26
26
  platformOAuthHandle,
27
- } from "@vellumai/ces-contracts";
27
+ } from "@vellumai/service-contracts/credential-rpc";
28
28
  import {
29
29
  type OAuthConnectionRecord,
30
30
  type SecureKeyBackend,
@@ -19,7 +19,7 @@ import {
19
19
  localStaticHandle,
20
20
  localOAuthHandle,
21
21
  platformOAuthHandle,
22
- } from "@vellumai/ces-contracts";
22
+ } from "@vellumai/service-contracts/credential-rpc";
23
23
  import {
24
24
  type OAuthConnectionRecord,
25
25
  type SecureKeyBackend,
@@ -34,7 +34,7 @@ import {
34
34
  type DeleteCredentialResponse,
35
35
  type ListCredentialsResponse,
36
36
  type RpcEnvelope,
37
- } from "@vellumai/ces-contracts";
37
+ } from "@vellumai/service-contracts/credential-rpc";
38
38
 
39
39
  import { PersistentGrantStore } from "../grants/persistent-store.js";
40
40
  import { TemporaryGrantStore } from "../grants/temporary-store.js";
@@ -260,7 +260,7 @@ describe("managed lazy getters — missing platform config fields", () => {
260
260
  /**
261
261
  * Verifies that updating assistantIdRef.current after buildLazyGetters
262
262
  * makes previously-undefined options become defined — the core fix for
263
- * warm-pool pods where PLATFORM_ASSISTANT_ID is empty at CES startup.
263
+ * warm-pool pods where the assistant ID is empty at CES startup.
264
264
  */
265
265
 
266
266
  // GIVEN an API key is available but assistant ID is empty (warm-pool startup)
@@ -14,7 +14,7 @@
14
14
 
15
15
  import { describe, expect, test } from "bun:test";
16
16
 
17
- import { platformOAuthHandle } from "@vellumai/ces-contracts";
17
+ import { platformOAuthHandle } from "@vellumai/service-contracts/credential-rpc";
18
18
 
19
19
  import {
20
20
  type ManagedSubject,
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { describe, expect, test } from "bun:test";
11
11
 
12
- import { HandleType, localStaticHandle, parseHandle } from "@vellumai/ces-contracts";
12
+ import { HandleType, localStaticHandle, parseHandle } from "@vellumai/service-contracts/credential-rpc";
13
13
 
14
14
  import { MANAGED_LOCAL_STATIC_REJECTION_ERROR } from "../managed-errors.js";
15
15
 
@@ -21,7 +21,7 @@ import {
21
21
  CES_PROTOCOL_VERSION,
22
22
  type HandshakeAck,
23
23
  type RpcEnvelope,
24
- } from "@vellumai/ces-contracts";
24
+ } from "@vellumai/service-contracts/credential-rpc";
25
25
 
26
26
  import { getCesDataRoot, getBootstrapSocketPath, getHealthPort } from "../paths.js";
27
27
  import { CesRpcServer, type RpcHandlerRegistry } from "../server.js";
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Persists token-free audit record summaries to `audit.jsonl` inside
5
5
  * the CES-private data root. Each line is a self-contained JSON object
6
- * conforming to the `AuditRecordSummary` schema from `@vellumai/ces-contracts`.
6
+ * conforming to the `AuditRecordSummary` schema from `@vellumai/service-contracts`.
7
7
  *
8
8
  * Design principles:
9
9
  * - **Append-only**: Records are appended one per line. The file is never
@@ -27,7 +27,7 @@ import {
27
27
  } from "node:fs";
28
28
  import { dirname, join } from "node:path";
29
29
 
30
- import type { AuditRecordSummary } from "@vellumai/ces-contracts";
30
+ import type { AuditRecordSummary } from "@vellumai/service-contracts/credential-rpc";
31
31
 
32
32
  import { getCesAuditDir } from "../paths.js";
33
33
 
@@ -74,7 +74,7 @@ import {
74
74
  type WorkspaceOutput,
75
75
  type CopybackResult,
76
76
  } from "./workspace.js";
77
- import { hashProposal, type AuditRecordSummary, type CommandGrantProposal } from "@vellumai/ces-contracts";
77
+ import { hashProposal, type AuditRecordSummary, type CommandGrantProposal } from "@vellumai/service-contracts/credential-rpc";
78
78
 
79
79
  import type { AuditStore } from "../audit/store.js";
80
80
  import type { PersistentGrantStore } from "../grants/persistent-store.js";
@@ -737,7 +737,7 @@ function checkGrant(
737
737
 
738
738
  // Check temporary grants — build the same proposal shape that the
739
739
  // approval bridge produces, then hash with the canonical algorithm
740
- // from `@vellumai/ces-contracts` so the hashes align.
740
+ // from `@vellumai/service-contracts` so the hashes align.
741
741
  const tempProposal: CommandGrantProposal = {
742
742
  type: "command",
743
743
  credentialHandle: request.credentialHandle,
@@ -23,7 +23,7 @@ import type {
23
23
  ListAuditRecords,
24
24
  ListAuditRecordsResponse,
25
25
  PersistentGrantRecord,
26
- } from "@vellumai/ces-contracts";
26
+ } from "@vellumai/service-contracts/credential-rpc";
27
27
 
28
28
  import type { PersistentGrantStore, PersistentGrant } from "./persistent-store.js";
29
29
  import type { TemporaryGrantStore } from "./temporary-store.js";
package/src/http/audit.ts CHANGED
@@ -15,7 +15,7 @@
15
15
 
16
16
  import { randomUUID } from "node:crypto";
17
17
 
18
- import type { AuditRecordSummary } from "@vellumai/ces-contracts";
18
+ import type { AuditRecordSummary } from "@vellumai/service-contracts/credential-rpc";
19
19
  import { derivePathTemplate } from "./path-template.js";
20
20
 
21
21
  // ---------------------------------------------------------------------------
@@ -26,8 +26,8 @@
26
26
  import type {
27
27
  MakeAuthenticatedRequest,
28
28
  MakeAuthenticatedRequestResponse,
29
- } from "@vellumai/ces-contracts";
30
- import { HandleType, parseHandle, hashProposal } from "@vellumai/ces-contracts";
29
+ } from "@vellumai/service-contracts/credential-rpc";
30
+ import { HandleType, parseHandle, hashProposal } from "@vellumai/service-contracts/credential-rpc";
31
31
  import type { InjectionTemplate } from "@vellumai/credential-storage";
32
32
 
33
33
  import { evaluateHttpPolicy, type PolicyResult } from "./policy.js";
@@ -18,7 +18,7 @@
18
18
  * credential.
19
19
  */
20
20
 
21
- import { hashProposal, type HttpGrantProposal } from "@vellumai/ces-contracts";
21
+ import { hashProposal, type HttpGrantProposal } from "@vellumai/service-contracts/credential-rpc";
22
22
 
23
23
  import type { PersistentGrant, PersistentGrantStore } from "../grants/persistent-store.js";
24
24
  import type { TemporaryGrantStore } from "../grants/temporary-store.js";
package/src/main.ts CHANGED
@@ -23,7 +23,7 @@ import { mkdirSync } from "node:fs";
23
23
  import { homedir } from "node:os";
24
24
  import { join } from "node:path";
25
25
 
26
- import { CES_PROTOCOL_VERSION, CesRpcMethod } from "@vellumai/ces-contracts";
26
+ import { CES_PROTOCOL_VERSION, CesRpcMethod } from "@vellumai/service-contracts/credential-rpc";
27
27
  import { StaticCredentialMetadataStore } from "@vellumai/credential-storage";
28
28
 
29
29
  import { AuditStore } from "./audit/store.js";
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Error message constants for managed-mode CES.
3
3
  *
4
- * Re-exported from @vellumai/ces-contracts so both the assistant and
4
+ * Re-exported from @vellumai/service-contracts so both the assistant and
5
5
  * credential-executor can share the constant via the approved shared-code
6
6
  * path without violating the hard process-boundary isolation.
7
7
  */
8
8
 
9
- export { MANAGED_LOCAL_STATIC_REJECTION_ERROR } from "@vellumai/ces-contracts";
9
+ export { MANAGED_LOCAL_STATIC_REJECTION_ERROR } from "@vellumai/service-contracts/credential-rpc";
@@ -23,10 +23,10 @@ export interface ApiKeyRef {
23
23
  }
24
24
 
25
25
  /**
26
- * Mutable reference to the platform assistant ID. For warm-pool pods the
27
- * PLATFORM_ASSISTANT_ID env var is empty at startup; the assistant forwards
28
- * the ID via the handshake or update_managed_credential RPC after
29
- * provisioning, and `.current` is updated so lazy getters pick it up.
26
+ * Mutable reference to the platform assistant ID. The assistant ID is not
27
+ * available at CES startup (warm-pool pods); the assistant forwards it via
28
+ * the handshake or update_managed_credential RPC after provisioning, and
29
+ * `.current` is updated so lazy getters pick it up.
30
30
  */
31
31
  export interface AssistantIdRef {
32
32
  current: string;
@@ -22,7 +22,7 @@ import { createServer as createNetServer, type Socket } from "node:net";
22
22
  import { dirname, join } from "node:path";
23
23
  import { Readable, Writable } from "node:stream";
24
24
 
25
- import { CES_PROTOCOL_VERSION, CesRpcMethod } from "@vellumai/ces-contracts";
25
+ import { CES_PROTOCOL_VERSION, CesRpcMethod } from "@vellumai/service-contracts/credential-rpc";
26
26
 
27
27
  import { AuditStore } from "./audit/store.js";
28
28
  import { PersistentGrantStore } from "./grants/persistent-store.js";
@@ -56,7 +56,7 @@ import { validateSourceUrl } from "./toolstore/manifest.js";
56
56
  import { buildCesEgressHooks } from "./commands/egress-hooks.js";
57
57
  import { resolveManagedSubject } from "./subjects/managed.js";
58
58
  import { materializeManagedToken } from "./materializers/managed-platform.js";
59
- import { HandleType, parseHandle } from "@vellumai/ces-contracts";
59
+ import { HandleType, parseHandle } from "@vellumai/service-contracts/credential-rpc";
60
60
  import { buildLazyGetters, type ApiKeyRef, type AssistantIdRef } from "./managed-lazy-getters.js";
61
61
  import { MANAGED_LOCAL_STATIC_REJECTION_ERROR } from "./managed-errors.js";
62
62
  import type { SecureKeyBackend } from "@vellumai/credential-storage";
@@ -586,7 +586,7 @@ async function main(): Promise<void> {
586
586
  // are available to handlers at call time (after the handshake completes).
587
587
  const sessionIdRef: SessionIdRef = { current: `ces-managed-${Date.now()}` };
588
588
  const apiKeyRef: ApiKeyRef = { current: "" };
589
- const assistantIdRef: AssistantIdRef = { current: process.env["PLATFORM_ASSISTANT_ID"] ?? "" };
589
+ const assistantIdRef: AssistantIdRef = { current: "" };
590
590
  const handlers = buildHandlers(sessionIdRef, apiKeyRef, assistantIdRef, secureKeyBackend);
591
591
 
592
592
  const rpcLog = getLogger("rpc");
@@ -32,7 +32,7 @@ import {
32
32
  RefreshDeduplicator,
33
33
  persistRefreshedTokens,
34
34
  } from "@vellumai/credential-storage";
35
- import { HandleType } from "@vellumai/ces-contracts";
35
+ import { HandleType } from "@vellumai/service-contracts/credential-rpc";
36
36
 
37
37
  import type {
38
38
  ResolvedLocalSubject,
package/src/server.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * CES RPC server.
3
3
  *
4
4
  * Implements the server-side of the CES wire protocol defined in
5
- * `@vellumai/ces-contracts`. The server reads newline-delimited JSON
5
+ * `@vellumai/service-contracts`. The server reads newline-delimited JSON
6
6
  * messages from a readable stream, dispatches them through the RPC
7
7
  * contract, and writes responses back to a writable stream.
8
8
  *
@@ -32,7 +32,7 @@ import {
32
32
  type RunAuthenticatedCommandResponse,
33
33
  type TransportMessage,
34
34
  TransportMessageSchema,
35
- } from "@vellumai/ces-contracts";
35
+ } from "@vellumai/service-contracts/credential-rpc";
36
36
 
37
37
  import { resolve } from "node:path";
38
38
 
@@ -7,7 +7,7 @@
7
7
  * operates independently — it never imports from the assistant daemon.
8
8
  *
9
9
  * Subject resolution is the first phase of credential materialisation:
10
- * 1. Parse the handle (via `@vellumai/ces-contracts`)
10
+ * 1. Parse the handle (via `@vellumai/service-contracts`)
11
11
  * 2. Look up the metadata/connection record in local storage
12
12
  * 3. Return a resolved subject that the materialiser can consume
13
13
  *
@@ -26,7 +26,7 @@ import {
26
26
  parseHandle,
27
27
  type LocalOAuthHandle,
28
28
  type LocalStaticHandle,
29
- } from "@vellumai/ces-contracts";
29
+ } from "@vellumai/service-contracts/credential-rpc";
30
30
 
31
31
  // ---------------------------------------------------------------------------
32
32
  // Resolved subject types
@@ -24,7 +24,7 @@ import {
24
24
  HandleType,
25
25
  parseHandle,
26
26
  type PlatformOAuthHandle,
27
- } from "@vellumai/ces-contracts";
27
+ } from "@vellumai/service-contracts/credential-rpc";
28
28
 
29
29
  // ---------------------------------------------------------------------------
30
30
  // Common subject interface