@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.
- package/Dockerfile +1 -1
- package/node_modules/@vellumai/service-contracts/package.json +1 -2
- package/node_modules/@vellumai/service-contracts/src/__tests__/attachment-naming.test.ts +104 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +0 -2
- package/node_modules/@vellumai/service-contracts/src/attachment-naming.ts +118 -0
- package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +3 -5
- package/node_modules/@vellumai/service-contracts/src/index.ts +2 -4
- package/node_modules/@vellumai/service-contracts/src/rpc.ts +4 -447
- package/package.json +2 -3
- package/src/__tests__/bulk-set-credentials.test.ts +1 -1
- package/src/__tests__/local-standalone.test.ts +5 -36
- package/src/__tests__/managed-integration.test.ts +112 -91
- package/src/__tests__/managed-reconnect.test.ts +2 -2
- package/src/__tests__/transport.test.ts +23 -27
- package/src/cli.ts +1 -1
- package/src/index.ts +8 -88
- package/src/main.ts +228 -340
- package/src/paths.ts +4 -20
- package/src/server.ts +52 -469
- package/node_modules/@vellumai/service-contracts/src/__tests__/grants.test.ts +0 -686
- package/node_modules/@vellumai/service-contracts/src/grants.ts +0 -184
- package/node_modules/@vellumai/service-contracts/src/rendering.ts +0 -135
- package/src/__tests__/command-executor.test.ts +0 -1879
- package/src/__tests__/command-validator.test.ts +0 -1405
- package/src/__tests__/command-workspace.test.ts +0 -1050
- package/src/__tests__/grant-store.test.ts +0 -689
- package/src/__tests__/http-executor.test.ts +0 -1336
- package/src/__tests__/http-policy.test.ts +0 -1069
- package/src/__tests__/local-materializers.test.ts +0 -860
- package/src/__tests__/local-token-refresh.test.ts +0 -361
- package/src/__tests__/manage-secure-command-tool.test.ts +0 -134
- package/src/__tests__/managed-lazy-getters.test.ts +0 -359
- package/src/__tests__/managed-materializers.test.ts +0 -1028
- package/src/__tests__/managed-rejection.test.ts +0 -43
- package/src/__tests__/toolstore.test.ts +0 -773
- package/src/audit/store.ts +0 -188
- package/src/commands/auth-adapters.ts +0 -169
- package/src/commands/egress-hooks.ts +0 -203
- package/src/commands/executor.ts +0 -1155
- package/src/commands/output-scan.ts +0 -157
- package/src/commands/profiles.ts +0 -286
- package/src/commands/validator.ts +0 -702
- package/src/commands/workspace.ts +0 -550
- package/src/grants/index.ts +0 -17
- package/src/grants/persistent-store.ts +0 -309
- package/src/grants/rpc-handlers.ts +0 -293
- package/src/grants/temporary-store.ts +0 -289
- package/src/http/audit.ts +0 -84
- package/src/http/executor.ts +0 -684
- package/src/http/path-template.ts +0 -245
- package/src/http/policy.ts +0 -238
- package/src/http/response-filter.ts +0 -233
- package/src/managed-errors.ts +0 -9
- package/src/managed-lazy-getters.ts +0 -106
- package/src/managed-main.ts +0 -822
- package/src/materializers/local-oauth-lookup.ts +0 -98
- package/src/materializers/local-token-refresh.ts +0 -287
- package/src/materializers/local.ts +0 -316
- package/src/materializers/managed-platform.ts +0 -295
- package/src/subjects/local.ts +0 -177
- package/src/subjects/managed.ts +0 -311
- package/src/subjects/policy.ts +0 -79
- package/src/toolstore/integrity.ts +0 -94
- package/src/toolstore/manifest.ts +0 -154
- package/src/toolstore/publish.ts +0 -571
package/Dockerfile
CHANGED
|
@@ -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
|
-
"./
|
|
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
|
+
});
|
|
@@ -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/
|
|
6
|
-
*
|
|
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,
|
|
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,
|
|
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`, `./
|
|
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";
|