@vellumai/credential-executor 0.10.7 → 0.10.8-dev.202607102228.5945895

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/Dockerfile +1 -1
  2. package/node_modules/@vellumai/service-contracts/package.json +1 -2
  3. package/node_modules/@vellumai/service-contracts/src/__tests__/attachment-naming.test.ts +104 -0
  4. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +0 -2
  5. package/node_modules/@vellumai/service-contracts/src/attachment-naming.ts +118 -0
  6. package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +3 -5
  7. package/node_modules/@vellumai/service-contracts/src/index.ts +2 -4
  8. package/node_modules/@vellumai/service-contracts/src/rpc.ts +4 -447
  9. package/package.json +2 -3
  10. package/src/__tests__/bulk-set-credentials.test.ts +1 -1
  11. package/src/__tests__/local-standalone.test.ts +5 -36
  12. package/src/__tests__/managed-integration.test.ts +112 -91
  13. package/src/__tests__/managed-reconnect.test.ts +2 -2
  14. package/src/__tests__/transport.test.ts +23 -27
  15. package/src/cli.ts +1 -1
  16. package/src/index.ts +8 -88
  17. package/src/main.ts +228 -340
  18. package/src/paths.ts +4 -20
  19. package/src/server.ts +52 -469
  20. package/node_modules/@vellumai/service-contracts/src/__tests__/grants.test.ts +0 -686
  21. package/node_modules/@vellumai/service-contracts/src/grants.ts +0 -184
  22. package/node_modules/@vellumai/service-contracts/src/rendering.ts +0 -135
  23. package/src/__tests__/command-executor.test.ts +0 -1879
  24. package/src/__tests__/command-validator.test.ts +0 -1405
  25. package/src/__tests__/command-workspace.test.ts +0 -1050
  26. package/src/__tests__/grant-store.test.ts +0 -689
  27. package/src/__tests__/http-executor.test.ts +0 -1336
  28. package/src/__tests__/http-policy.test.ts +0 -1069
  29. package/src/__tests__/local-materializers.test.ts +0 -860
  30. package/src/__tests__/local-token-refresh.test.ts +0 -361
  31. package/src/__tests__/manage-secure-command-tool.test.ts +0 -134
  32. package/src/__tests__/managed-lazy-getters.test.ts +0 -359
  33. package/src/__tests__/managed-materializers.test.ts +0 -1028
  34. package/src/__tests__/managed-rejection.test.ts +0 -43
  35. package/src/__tests__/toolstore.test.ts +0 -773
  36. package/src/audit/store.ts +0 -188
  37. package/src/commands/auth-adapters.ts +0 -169
  38. package/src/commands/egress-hooks.ts +0 -203
  39. package/src/commands/executor.ts +0 -1155
  40. package/src/commands/output-scan.ts +0 -157
  41. package/src/commands/profiles.ts +0 -286
  42. package/src/commands/validator.ts +0 -702
  43. package/src/commands/workspace.ts +0 -550
  44. package/src/grants/index.ts +0 -17
  45. package/src/grants/persistent-store.ts +0 -309
  46. package/src/grants/rpc-handlers.ts +0 -293
  47. package/src/grants/temporary-store.ts +0 -289
  48. package/src/http/audit.ts +0 -84
  49. package/src/http/executor.ts +0 -684
  50. package/src/http/path-template.ts +0 -245
  51. package/src/http/policy.ts +0 -238
  52. package/src/http/response-filter.ts +0 -233
  53. package/src/managed-errors.ts +0 -9
  54. package/src/managed-lazy-getters.ts +0 -106
  55. package/src/managed-main.ts +0 -822
  56. package/src/materializers/local-oauth-lookup.ts +0 -98
  57. package/src/materializers/local-token-refresh.ts +0 -287
  58. package/src/materializers/local.ts +0 -316
  59. package/src/materializers/managed-platform.ts +0 -295
  60. package/src/subjects/local.ts +0 -177
  61. package/src/subjects/managed.ts +0 -311
  62. package/src/subjects/policy.ts +0 -79
  63. package/src/toolstore/integrity.ts +0 -94
  64. package/src/toolstore/manifest.ts +0 -154
  65. package/src/toolstore/publish.ts +0 -571
package/Dockerfile CHANGED
@@ -80,4 +80,4 @@ EXPOSE 8090
80
80
  ENV CES_MODE=managed
81
81
  ENV CES_HEALTH_PORT=8090
82
82
 
83
- CMD ["bun", "run", "src/managed-main.ts"]
83
+ CMD ["bun", "run", "src/main.ts"]
@@ -13,9 +13,8 @@
13
13
  "./twilio-ingress": "./src/twilio-ingress.ts",
14
14
  "./trust-rules": "./src/trust-rules.ts",
15
15
  "./handles": "./src/handles.ts",
16
- "./grants": "./src/grants.ts",
17
16
  "./rpc": "./src/rpc.ts",
18
- "./rendering": "./src/rendering.ts",
17
+ "./attachment-naming": "./src/attachment-naming.ts",
19
18
  "./error": "./src/error.ts"
20
19
  },
21
20
  "scripts": {
@@ -0,0 +1,104 @@
1
+ import { describe, expect, test } from "bun:test";
2
+
3
+ import {
4
+ inferMimeType,
5
+ resolveAttachmentFilename,
6
+ } from "../attachment-naming.js";
7
+
8
+ describe("inferMimeType", () => {
9
+ test("maps known extensions case-insensitively", () => {
10
+ expect(inferMimeType("shot.PNG")).toBe("image/png");
11
+ expect(inferMimeType("report.pdf")).toBe("application/pdf");
12
+ });
13
+
14
+ test("falls back to octet-stream for unknown or missing extensions", () => {
15
+ expect(inferMimeType("desktop")).toBe("application/octet-stream");
16
+ expect(inferMimeType("archive.xyz")).toBe("application/octet-stream");
17
+ });
18
+ });
19
+
20
+ describe("resolveAttachmentFilename", () => {
21
+ test("uses explicit filenames verbatim", () => {
22
+ expect(
23
+ resolveAttachmentFilename("custom.dat", "/tmp/shot.png", "explicit"),
24
+ ).toBe("custom.dat");
25
+ });
26
+
27
+ test("honors labels with recognized extensions", () => {
28
+ expect(
29
+ resolveAttachmentFilename("nice-name.png", "/tmp/shot.png", "label"),
30
+ ).toBe("nice-name.png");
31
+ });
32
+
33
+ test("keeps bare labels and appends the POSIX path extension", () => {
34
+ expect(resolveAttachmentFilename("desktop", "/tmp/shot.png", "label")).toBe(
35
+ "desktop.png",
36
+ );
37
+ });
38
+
39
+ test("keeps bare labels and appends the Windows path extension", () => {
40
+ expect(
41
+ resolveAttachmentFilename(
42
+ "desktop",
43
+ "C:\\Users\\user1\\Pictures\\shot.png",
44
+ "label",
45
+ ),
46
+ ).toBe("desktop.png");
47
+ });
48
+
49
+ test("bare labels to files sharing a basename resolve to unique names", () => {
50
+ expect(
51
+ resolveAttachmentFilename("first", "/workspace/a/result.png", "label"),
52
+ ).toBe("first.png");
53
+ expect(
54
+ resolveAttachmentFilename("second", "/workspace/b/result.png", "label"),
55
+ ).toBe("second.png");
56
+ });
57
+
58
+ test("does not duplicate an unknown extension the label already has", () => {
59
+ expect(
60
+ resolveAttachmentFilename(
61
+ "report.xlsx",
62
+ "/workspace/report.xlsx",
63
+ "label",
64
+ ),
65
+ ).toBe("report.xlsx");
66
+ });
67
+
68
+ test("matches the existing extension case-insensitively", () => {
69
+ expect(
70
+ resolveAttachmentFilename("data.YAML", "/workspace/data.yaml", "label"),
71
+ ).toBe("data.YAML");
72
+ });
73
+
74
+ test("still appends when the label ends differently", () => {
75
+ expect(
76
+ resolveAttachmentFilename(
77
+ "summary.v2",
78
+ "/workspace/data.parquet",
79
+ "label",
80
+ ),
81
+ ).toBe("summary.v2.parquet");
82
+ });
83
+
84
+ test("falls back to the basename when the path has no extension", () => {
85
+ expect(resolveAttachmentFilename("label", "/tmp/rawfile", "label")).toBe(
86
+ "rawfile",
87
+ );
88
+ });
89
+
90
+ test("uses the basename when no preferred name is given", () => {
91
+ expect(
92
+ resolveAttachmentFilename(undefined, "C:\\temp\\report.pdf", "label"),
93
+ ).toBe("report.pdf");
94
+ expect(resolveAttachmentFilename(undefined, "/tmp/report.pdf")).toBe(
95
+ "report.pdf",
96
+ );
97
+ });
98
+
99
+ test("ignores trailing separators", () => {
100
+ expect(resolveAttachmentFilename(undefined, "/tmp/dir/", "label")).toBe(
101
+ "dir",
102
+ );
103
+ });
104
+ });
@@ -27,9 +27,7 @@ describe("package independence", () => {
27
27
  const sourceFiles = [
28
28
  "../index.ts",
29
29
  "../handles.ts",
30
- "../grants.ts",
31
30
  "../rpc.ts",
32
- "../rendering.ts",
33
31
  "../transport.ts",
34
32
  "../credential-rpc.ts",
35
33
  "../trust-rules.ts",
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Attachment filename contract shared by the daemon (which materializes
3
+ * `vellum://` links and `<vellum-attachment>` directives into stored
4
+ * attachments) and the web client (which resolves clicked links back to
5
+ * those attachments). Both sides must agree on the stored filename, so the
6
+ * naming rule lives here once.
7
+ */
8
+
9
+ const EXTENSION_MIME_MAP: Record<string, string> = {
10
+ // Images
11
+ png: "image/png",
12
+ jpg: "image/jpeg",
13
+ jpeg: "image/jpeg",
14
+ gif: "image/gif",
15
+ webp: "image/webp",
16
+ svg: "image/svg+xml",
17
+ ico: "image/x-icon",
18
+ bmp: "image/bmp",
19
+ heic: "image/heic",
20
+ heif: "image/heif",
21
+
22
+ // Documents
23
+ pdf: "application/pdf",
24
+ json: "application/json",
25
+ xml: "application/xml",
26
+ csv: "text/csv",
27
+ txt: "text/plain",
28
+ md: "text/markdown",
29
+ html: "text/html",
30
+ css: "text/css",
31
+ js: "text/javascript",
32
+ ts: "text/typescript",
33
+
34
+ // Audio
35
+ mp3: "audio/mpeg",
36
+ wav: "audio/wav",
37
+ ogg: "audio/ogg",
38
+ flac: "audio/flac",
39
+ aac: "audio/aac",
40
+ m4a: "audio/x-m4a",
41
+ opus: "audio/opus",
42
+
43
+ // Video
44
+ mp4: "video/mp4",
45
+ webm: "video/webm",
46
+ mov: "video/quicktime",
47
+ mpeg: "video/mpeg",
48
+
49
+ // Archives
50
+ zip: "application/zip",
51
+ gz: "application/gzip",
52
+ tar: "application/x-tar",
53
+ };
54
+
55
+ /**
56
+ * Infer a MIME type from a filename extension.
57
+ * Returns `application/octet-stream` when the extension is unrecognised.
58
+ */
59
+ export function inferMimeType(filename: string): string {
60
+ const dot = filename.lastIndexOf(".");
61
+ if (dot === -1) {
62
+ return "application/octet-stream";
63
+ }
64
+ const ext = filename.slice(dot + 1).toLowerCase();
65
+ return EXTENSION_MIME_MAP[ext] ?? "application/octet-stream";
66
+ }
67
+
68
+ /**
69
+ * Pick the stored attachment filename for a materialized file directive.
70
+ *
71
+ * Explicit filenames (`<vellum-attachment filename="..." />` attributes)
72
+ * are an authoring contract and always used verbatim. Link display text
73
+ * (`[label](vellum://...)`) is cosmetic: it is only honored as the filename
74
+ * when it carries a recognized extension. A bare label
75
+ * (e.g. `[desktop](vellum://.../shot.png)`) would otherwise produce an
76
+ * extensionless download with an `application/octet-stream` MIME type,
77
+ * which macOS opens as raw text. In that case the label keeps the path's
78
+ * extension (`desktop.png`), staying unique per link even when several
79
+ * links share a basename; the raw basename is the last resort.
80
+ *
81
+ * The basename fallback splits on both `/` and `\\` so it handles POSIX
82
+ * sandbox paths, `vellum://` URL paths, and Windows host paths alike.
83
+ * Splitting on both separators regardless of the runtime platform also
84
+ * covers Windows host paths resolved by a non-Windows daemon, which
85
+ * platform-selected `node:path` semantics cannot.
86
+ */
87
+ export function resolveAttachmentFilename(
88
+ preferred: string | undefined,
89
+ resolvedPath: string,
90
+ filenameSource: "explicit" | "label" = "explicit",
91
+ ): string {
92
+ const fallback =
93
+ resolvedPath.split(/[\\/]/).filter(Boolean).pop() ?? resolvedPath;
94
+ if (!preferred) {
95
+ return fallback;
96
+ }
97
+ if (filenameSource === "explicit") {
98
+ return preferred;
99
+ }
100
+ if (inferMimeType(preferred) !== "application/octet-stream") {
101
+ return preferred;
102
+ }
103
+ // Bare label: keep the label as a per-link disambiguator (two links to
104
+ // different files sharing a basename must not collide, because the
105
+ // transcript resolves clicks by filename) and append the path's
106
+ // extension so the stored name carries the correct type. Skip the
107
+ // append when the label already ends with that extension (a label like
108
+ // `report.xlsx` for `report.xlsx` must not become `report.xlsx.xlsx`).
109
+ const dot = fallback.lastIndexOf(".");
110
+ if (dot > 0 && dot < fallback.length - 1) {
111
+ const ext = fallback.slice(dot + 1);
112
+ if (preferred.toLowerCase().endsWith(`.${ext.toLowerCase()}`)) {
113
+ return preferred;
114
+ }
115
+ return `${preferred}.${ext}`;
116
+ }
117
+ return fallback;
118
+ }
@@ -2,13 +2,13 @@
2
2
  * @vellumai/service-contracts/credential-rpc
3
3
  *
4
4
  * Domain entrypoint for the CES (Credential Execution Service) transport and
5
- * RPC surface. Re-exports the transport/RPC/handles/grants/rendering/error
6
- * contracts without the trust-rule helpers.
5
+ * RPC surface. Re-exports the transport/RPC/handles/error contracts without
6
+ * the trust-rule helpers.
7
7
  *
8
8
  * Prefer this subpath over the root `.` import when you only need the
9
9
  * credential RPC surface:
10
10
  *
11
- * import { CesRpcMethod, MakeAuthenticatedRequestSchema } from "@vellumai/service-contracts/credential-rpc";
11
+ * import { CesRpcMethod, GetCredentialSchema } from "@vellumai/service-contracts/credential-rpc";
12
12
  *
13
13
  * For trust-rule types use the dedicated subpath:
14
14
  *
@@ -18,6 +18,4 @@
18
18
  export * from "./transport.js";
19
19
  export * from "./error.js";
20
20
  export * from "./handles.js";
21
- export * from "./grants.js";
22
- export * from "./rendering.js";
23
21
  export * from "./rpc.js";
@@ -4,13 +4,13 @@
4
4
  * This is a compatibility aggregate that re-exports everything from all
5
5
  * submodules. Prefer the explicit domain subpaths for new code:
6
6
  *
7
- * - `@vellumai/service-contracts/credential-rpc` — transport, RPC, handles, grants, rendering, error
7
+ * - `@vellumai/service-contracts/credential-rpc` — transport, RPC, handles, error
8
8
  * - `@vellumai/service-contracts/trust-rules` — trust-rule types and parsing helpers
9
9
  * - `@vellumai/service-contracts/twilio-ingress` — shared Twilio ingress config constants
10
10
  * - `@vellumai/service-contracts/ingress` — shared public ingress URL helpers
11
11
  *
12
12
  * Fine-grained subpaths are also available for low-friction migration:
13
- * `./rpc`, `./handles`, `./grants`, `./rendering`, `./error`, `./trust-rules`, `./ingress`, `./twilio-ingress`
13
+ * `./rpc`, `./handles`, `./error`, `./trust-rules`, `./ingress`, `./twilio-ingress`
14
14
  *
15
15
  * Neutral wire-protocol contracts for communication between the assistant
16
16
  * daemon and the Credential Execution Service (CES). This package is
@@ -23,9 +23,7 @@ export * from "./client-metadata.js";
23
23
  export * from "./transport.js";
24
24
  export * from "./error.js";
25
25
  export * from "./handles.js";
26
- export * from "./grants.js";
27
26
  export * from "./rpc.js";
28
- export * from "./rendering.js";
29
27
  export * from "./trust-rules.js";
30
28
  export * from "./ingress.js";
31
29
  export * from "./twilio-ingress.js";