@workbench-ai/workbench-protocol 0.0.42 → 0.0.44
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/adapter-definition.d.ts +46 -0
- package/dist/adapter-definition.d.ts.map +1 -0
- package/dist/adapter-definition.js +172 -0
- package/dist/adapter-manifest.d.ts +20 -6
- package/dist/adapter-manifest.d.ts.map +1 -1
- package/dist/adapter-manifest.js +149 -43
- package/dist/adapter-protocol.d.ts +47 -41
- package/dist/adapter-protocol.d.ts.map +1 -1
- package/dist/adapter-protocol.js +139 -125
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/task-source-result.d.ts +29 -0
- package/dist/task-source-result.d.ts.map +1 -0
- package/dist/task-source-result.js +160 -0
- package/package.json +2 -2
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export function normalizeWorkbenchTaskSourceResult(value, label = "tasks.resolve result") {
|
|
3
|
+
const record = requiredRecord(value, label);
|
|
4
|
+
if (!Array.isArray(record.tasks)) {
|
|
5
|
+
throw new Error(`${label}.tasks must be an array.`);
|
|
6
|
+
}
|
|
7
|
+
const tasks = record.tasks.map((entry, index) => normalizeWorkbenchTaskBundle(entry, `${label}.tasks[${index}]`));
|
|
8
|
+
const duplicate = firstDuplicate(tasks.map((task) => task.id));
|
|
9
|
+
if (duplicate) {
|
|
10
|
+
throw new Error(`${label} contains duplicate task id: ${duplicate}`);
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
tasks,
|
|
14
|
+
...(record.environment !== undefined
|
|
15
|
+
? { environment: normalizeTaskEnvironment(record.environment, `${label}.environment`) }
|
|
16
|
+
: {}),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function normalizeWorkbenchTaskBundle(value, label) {
|
|
20
|
+
const record = requiredRecord(value, label);
|
|
21
|
+
if (typeof record.id !== "string" || record.id.trim().length === 0) {
|
|
22
|
+
throw new Error(`${label}.id must be a non-empty string.`);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
id: normalizeRelativePath(record.id, `${label}.id`),
|
|
26
|
+
task: normalizeWorkbenchTaskSpec(record.task, `${label}.task`),
|
|
27
|
+
publicFiles: normalizeTaskSourceFiles(record.publicFiles, `${label}.publicFiles`),
|
|
28
|
+
testFiles: normalizeTaskSourceFiles(record.testFiles, `${label}.testFiles`),
|
|
29
|
+
...(record.solutionFiles !== undefined
|
|
30
|
+
? { solutionFiles: normalizeTaskSourceFiles(record.solutionFiles, `${label}.solutionFiles`) }
|
|
31
|
+
: {}),
|
|
32
|
+
...(record.sourceFiles !== undefined
|
|
33
|
+
? { sourceFiles: normalizeTaskSourceFiles(record.sourceFiles, `${label}.sourceFiles`) }
|
|
34
|
+
: {}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function normalizeWorkbenchTaskSpec(value, label) {
|
|
38
|
+
const record = requiredRecord(value, label);
|
|
39
|
+
if (record.version !== 2) {
|
|
40
|
+
throw new Error(`${label}.version must be 2.`);
|
|
41
|
+
}
|
|
42
|
+
if (typeof record.task !== "string" || record.task.trim().length === 0) {
|
|
43
|
+
throw new Error(`${label}.task must be a non-empty string.`);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
version: 2,
|
|
47
|
+
task: record.task,
|
|
48
|
+
...(record.environment !== undefined
|
|
49
|
+
? { environment: normalizeTaskEnvironment(record.environment, `${label}.environment`) }
|
|
50
|
+
: {}),
|
|
51
|
+
...(record.score !== undefined
|
|
52
|
+
? { score: normalizeAdapterInvocation(record.score, `${label}.score`) }
|
|
53
|
+
: {}),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function normalizeTaskEnvironment(value, label) {
|
|
57
|
+
const record = requiredRecord(value, label);
|
|
58
|
+
const resources = record.resources === undefined
|
|
59
|
+
? undefined
|
|
60
|
+
: normalizeTaskResources(record.resources, `${label}.resources`);
|
|
61
|
+
const network = record.network === undefined
|
|
62
|
+
? undefined
|
|
63
|
+
: normalizeNetworkPolicy(record.network, `${label}.network`);
|
|
64
|
+
return {
|
|
65
|
+
...(typeof record.dockerfile === "string" && record.dockerfile.trim()
|
|
66
|
+
? { dockerfile: record.dockerfile }
|
|
67
|
+
: {}),
|
|
68
|
+
...(typeof record.workdir === "string" && record.workdir.trim()
|
|
69
|
+
? { workdir: record.workdir }
|
|
70
|
+
: {}),
|
|
71
|
+
...(resources ? { resources } : {}),
|
|
72
|
+
...(network ? { network } : {}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function normalizeTaskResources(value, label) {
|
|
76
|
+
const record = requiredRecord(value, label);
|
|
77
|
+
return {
|
|
78
|
+
...(typeof record.cpu === "number" ? { cpu: record.cpu } : {}),
|
|
79
|
+
...(typeof record.memoryGb === "number" ? { memoryGb: record.memoryGb } : {}),
|
|
80
|
+
...(typeof record.diskGb === "number" ? { diskGb: record.diskGb } : {}),
|
|
81
|
+
...(typeof record.timeoutMinutes === "number" ? { timeoutMinutes: record.timeoutMinutes } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function normalizeNetworkPolicy(value, label) {
|
|
85
|
+
const record = requiredRecord(value, label);
|
|
86
|
+
if (record.egress !== "none" &&
|
|
87
|
+
record.egress !== "allowlist" &&
|
|
88
|
+
record.egress !== "open") {
|
|
89
|
+
throw new Error(`${label}.egress must be none, allowlist, or open.`);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
egress: record.egress,
|
|
93
|
+
...(Array.isArray(record.allow)
|
|
94
|
+
? { allow: record.allow.filter((entry) => typeof entry === "string") }
|
|
95
|
+
: {}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function normalizeAdapterInvocation(value, label) {
|
|
99
|
+
const record = requiredRecord(value, label);
|
|
100
|
+
if (typeof record.use !== "string" || record.use.trim().length === 0) {
|
|
101
|
+
throw new Error(`${label}.use must be a non-empty string.`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
use: record.use,
|
|
105
|
+
with: record.with === undefined ? {} : record.with,
|
|
106
|
+
...(record.auth !== undefined ? { auth: record.auth } : {}),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function normalizeTaskSourceFiles(value, label) {
|
|
110
|
+
if (value === undefined) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
if (!Array.isArray(value)) {
|
|
114
|
+
throw new Error(`${label} must be an array.`);
|
|
115
|
+
}
|
|
116
|
+
return value.map((entry, index) => {
|
|
117
|
+
const record = requiredRecord(entry, `${label}[${index}]`);
|
|
118
|
+
if (typeof record.path !== "string" || record.path.trim().length === 0) {
|
|
119
|
+
throw new Error(`${label}[${index}].path must be a non-empty string.`);
|
|
120
|
+
}
|
|
121
|
+
if (typeof record.content !== "string") {
|
|
122
|
+
throw new Error(`${label}[${index}].content must be a string.`);
|
|
123
|
+
}
|
|
124
|
+
const encoding = record.encoding === "base64" ? "base64" : "utf8";
|
|
125
|
+
const kind = record.kind === "binary" || encoding === "base64" ? "binary" : "text";
|
|
126
|
+
return {
|
|
127
|
+
path: normalizeRelativePath(record.path, `${label}[${index}].path`),
|
|
128
|
+
kind,
|
|
129
|
+
encoding,
|
|
130
|
+
content: record.content,
|
|
131
|
+
executable: record.executable === true,
|
|
132
|
+
};
|
|
133
|
+
}).sort((left, right) => left.path.localeCompare(right.path));
|
|
134
|
+
}
|
|
135
|
+
function normalizeRelativePath(filePath, label) {
|
|
136
|
+
const normalized = path.posix.normalize(filePath.replace(/\\/gu, "/").replace(/^\/+/u, ""));
|
|
137
|
+
if (!normalized || normalized === "." || normalized.includes("\0")) {
|
|
138
|
+
throw new Error(`${label} must be a non-empty relative path.`);
|
|
139
|
+
}
|
|
140
|
+
if (normalized === ".." || normalized.startsWith("../") || path.posix.isAbsolute(normalized)) {
|
|
141
|
+
throw new Error(`${label} must not escape the task-source result.`);
|
|
142
|
+
}
|
|
143
|
+
return normalized;
|
|
144
|
+
}
|
|
145
|
+
function requiredRecord(value, label) {
|
|
146
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
147
|
+
throw new Error(`${label} must be an object.`);
|
|
148
|
+
}
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
function firstDuplicate(values) {
|
|
152
|
+
const seen = new Set();
|
|
153
|
+
for (const value of values) {
|
|
154
|
+
if (seen.has(value)) {
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
seen.add(value);
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workbench-ai/workbench-protocol",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.44",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"yaml": "^2.8.2",
|
|
23
|
-
"@workbench-ai/workbench-contract": "0.0.
|
|
23
|
+
"@workbench-ai/workbench-contract": "0.0.44"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^24.3.1",
|