@jigging/jig 0.1.0-alpha.25 → 0.1.0-alpha.27
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/README.md +6 -2
- package/THIRD_PARTY_NOTICES +13 -6
- package/bin/jig +59 -10
- package/dist/index.js +3989 -29
- package/libexec/agent/claude-agent-acp.js +34 -34
- package/libexec/agent/claude-agent-launcher.js +2 -0
- package/libexec/agent/codex-acp.js +22 -0
- package/libexec/agent/codex-agent-launcher.js +35 -14
- package/libexec/agent/pi-acp.js +2 -2
- package/libexec/agent/pi-agent-launcher.js +5 -3
- package/libexec/evaluator/project-evaluator-sdk.bundle.js +3989 -29
- package/libexec/evaluator/project-evaluator-worker.js +421 -10
- package/libexec/http-request-worker.js +3 -1
- package/libexec/installed-cli.js +22931 -13090
- package/libexec/linux-rootless-supervisor.js +54 -0
- package/libexec/macos-descriptor-bridge.dylib +0 -0
- package/libexec/macos-exec +0 -0
- package/libexec/macos-native-supervisor.js +2218 -0
- package/libexec/markdown-runtime.js +4391 -46
- package/libexec/preparation/bun-native-preparation-worker.js +4048 -48
- package/package.json +11 -7
|
@@ -21,6 +21,267 @@ class Json1Error extends Error {
|
|
|
21
21
|
this.name = "Json1Error";
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
class Parser {
|
|
26
|
+
source;
|
|
27
|
+
position = 0;
|
|
28
|
+
nodes = 0;
|
|
29
|
+
constructor(source) {
|
|
30
|
+
this.source = source;
|
|
31
|
+
}
|
|
32
|
+
parse() {
|
|
33
|
+
this.skipWhitespace();
|
|
34
|
+
const value = this.parseValue(1);
|
|
35
|
+
this.skipWhitespace();
|
|
36
|
+
if (this.position !== this.source.length)
|
|
37
|
+
this.fail("unexpected trailing characters");
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
parseValue(depth) {
|
|
41
|
+
if (depth > JSON_1_LIMITS.depth)
|
|
42
|
+
this.fail("maximum value depth exceeded");
|
|
43
|
+
this.nodes += 1;
|
|
44
|
+
if (this.nodes > JSON_1_LIMITS.nodes)
|
|
45
|
+
this.fail("maximum value nodes exceeded");
|
|
46
|
+
const char = this.source[this.position];
|
|
47
|
+
if (char === '"')
|
|
48
|
+
return this.parseString(false);
|
|
49
|
+
if (char === "{")
|
|
50
|
+
return this.parseObject(depth);
|
|
51
|
+
if (char === "[")
|
|
52
|
+
return this.parseArray(depth);
|
|
53
|
+
if (char === "t")
|
|
54
|
+
return this.parseLiteral("true", true);
|
|
55
|
+
if (char === "f")
|
|
56
|
+
return this.parseLiteral("false", false);
|
|
57
|
+
if (char === "n")
|
|
58
|
+
return this.parseLiteral("null", null);
|
|
59
|
+
if (char === "-" || char !== undefined && char >= "0" && char <= "9") {
|
|
60
|
+
return this.parseNumber();
|
|
61
|
+
}
|
|
62
|
+
return this.fail("expected a JSON value");
|
|
63
|
+
}
|
|
64
|
+
parseObject(depth) {
|
|
65
|
+
this.position += 1;
|
|
66
|
+
const result = Object.create(null);
|
|
67
|
+
const keys = new Set;
|
|
68
|
+
this.skipWhitespace();
|
|
69
|
+
if (this.consume("}"))
|
|
70
|
+
return result;
|
|
71
|
+
let members = 0;
|
|
72
|
+
while (true) {
|
|
73
|
+
if (this.source[this.position] !== '"')
|
|
74
|
+
this.fail("expected an object member name");
|
|
75
|
+
const key = this.parseString(true);
|
|
76
|
+
if (keys.has(key))
|
|
77
|
+
this.fail(`duplicate object member ${key}`);
|
|
78
|
+
keys.add(key);
|
|
79
|
+
members += 1;
|
|
80
|
+
if (members > JSON_1_LIMITS.containerEntries) {
|
|
81
|
+
this.fail("maximum object members exceeded");
|
|
82
|
+
}
|
|
83
|
+
this.skipWhitespace();
|
|
84
|
+
if (!this.consume(":"))
|
|
85
|
+
this.fail("expected ':' after member name");
|
|
86
|
+
this.skipWhitespace();
|
|
87
|
+
result[key] = this.parseValue(depth + 1);
|
|
88
|
+
this.skipWhitespace();
|
|
89
|
+
if (this.consume("}"))
|
|
90
|
+
return result;
|
|
91
|
+
if (!this.consume(","))
|
|
92
|
+
this.fail("expected ',' or '}'");
|
|
93
|
+
this.skipWhitespace();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
parseArray(depth) {
|
|
97
|
+
this.position += 1;
|
|
98
|
+
const result = [];
|
|
99
|
+
this.skipWhitespace();
|
|
100
|
+
if (this.consume("]"))
|
|
101
|
+
return result;
|
|
102
|
+
while (true) {
|
|
103
|
+
if (result.length >= JSON_1_LIMITS.containerEntries) {
|
|
104
|
+
this.fail("maximum array items exceeded");
|
|
105
|
+
}
|
|
106
|
+
result.push(this.parseValue(depth + 1));
|
|
107
|
+
this.skipWhitespace();
|
|
108
|
+
if (this.consume("]"))
|
|
109
|
+
return result;
|
|
110
|
+
if (!this.consume(","))
|
|
111
|
+
this.fail("expected ',' or ']'");
|
|
112
|
+
this.skipWhitespace();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
parseString(memberName) {
|
|
116
|
+
this.position += 1;
|
|
117
|
+
const parts = [];
|
|
118
|
+
let segmentStart = this.position;
|
|
119
|
+
while (this.position < this.source.length) {
|
|
120
|
+
const char = this.source[this.position];
|
|
121
|
+
this.position += 1;
|
|
122
|
+
if (char === '"') {
|
|
123
|
+
parts.push(this.source.slice(segmentStart, this.position - 1));
|
|
124
|
+
const value = parts.join("");
|
|
125
|
+
const limit = memberName ? JSON_1_LIMITS.memberNameBytes : JSON_1_LIMITS.stringBytes;
|
|
126
|
+
if (encoder.encode(value).byteLength > limit)
|
|
127
|
+
this.fail("maximum string bytes exceeded");
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
if (char === "\\") {
|
|
131
|
+
parts.push(this.source.slice(segmentStart, this.position - 1));
|
|
132
|
+
parts.push(this.parseEscape());
|
|
133
|
+
segmentStart = this.position;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (char === undefined || char.charCodeAt(0) <= 31) {
|
|
137
|
+
this.fail("invalid character in string");
|
|
138
|
+
}
|
|
139
|
+
const code = char.charCodeAt(0);
|
|
140
|
+
if (code >= 55296 && code <= 57343) {
|
|
141
|
+
const next = this.source[this.position];
|
|
142
|
+
if (code > 56319 || next === undefined || next.charCodeAt(0) < 56320 || next.charCodeAt(0) > 57343)
|
|
143
|
+
this.fail("lone Unicode surrogate");
|
|
144
|
+
this.position += 1;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return this.fail("unterminated string");
|
|
148
|
+
}
|
|
149
|
+
parseEscape() {
|
|
150
|
+
const escape = this.source[this.position];
|
|
151
|
+
this.position += 1;
|
|
152
|
+
switch (escape) {
|
|
153
|
+
case '"':
|
|
154
|
+
case "\\":
|
|
155
|
+
case "/":
|
|
156
|
+
return escape;
|
|
157
|
+
case "b":
|
|
158
|
+
return "\b";
|
|
159
|
+
case "f":
|
|
160
|
+
return "\f";
|
|
161
|
+
case "n":
|
|
162
|
+
return `
|
|
163
|
+
`;
|
|
164
|
+
case "r":
|
|
165
|
+
return "\r";
|
|
166
|
+
case "t":
|
|
167
|
+
return "\t";
|
|
168
|
+
case "u": {
|
|
169
|
+
const first = this.parseHexCodeUnit();
|
|
170
|
+
if (first >= 55296 && first <= 56319) {
|
|
171
|
+
if (this.source.slice(this.position, this.position + 2) !== "\\u") {
|
|
172
|
+
this.fail("high surrogate without low surrogate");
|
|
173
|
+
}
|
|
174
|
+
this.position += 2;
|
|
175
|
+
const second = this.parseHexCodeUnit();
|
|
176
|
+
if (second < 56320 || second > 57343) {
|
|
177
|
+
this.fail("high surrogate without low surrogate");
|
|
178
|
+
}
|
|
179
|
+
return String.fromCharCode(first, second);
|
|
180
|
+
}
|
|
181
|
+
if (first >= 56320 && first <= 57343)
|
|
182
|
+
this.fail("lone low surrogate");
|
|
183
|
+
return String.fromCharCode(first);
|
|
184
|
+
}
|
|
185
|
+
default:
|
|
186
|
+
return this.fail("invalid string escape");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
parseHexCodeUnit() {
|
|
190
|
+
const token = this.source.slice(this.position, this.position + 4);
|
|
191
|
+
if (!/^[0-9A-Fa-f]{4}$/.test(token))
|
|
192
|
+
this.fail("invalid Unicode escape");
|
|
193
|
+
this.position += 4;
|
|
194
|
+
return Number.parseInt(token, 16);
|
|
195
|
+
}
|
|
196
|
+
parseNumber() {
|
|
197
|
+
const start = this.position;
|
|
198
|
+
this.consume("-");
|
|
199
|
+
if (this.consume("0")) {
|
|
200
|
+
const next = this.source[this.position];
|
|
201
|
+
if (next !== undefined && next >= "0" && next <= "9") {
|
|
202
|
+
this.fail("leading zero in number");
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
if (!this.consumeDigit("1", "9"))
|
|
206
|
+
this.fail("invalid number");
|
|
207
|
+
while (this.consumeDigit("0", "9")) {}
|
|
208
|
+
}
|
|
209
|
+
if (this.consume(".")) {
|
|
210
|
+
if (!this.consumeDigit("0", "9"))
|
|
211
|
+
this.fail("fraction requires a digit");
|
|
212
|
+
while (this.consumeDigit("0", "9")) {}
|
|
213
|
+
}
|
|
214
|
+
const exponent = this.source[this.position];
|
|
215
|
+
if (exponent === "e" || exponent === "E") {
|
|
216
|
+
this.position += 1;
|
|
217
|
+
const sign = this.source[this.position];
|
|
218
|
+
if (sign === "+" || sign === "-")
|
|
219
|
+
this.position += 1;
|
|
220
|
+
if (!this.consumeDigit("0", "9"))
|
|
221
|
+
this.fail("exponent requires a digit");
|
|
222
|
+
while (this.consumeDigit("0", "9")) {}
|
|
223
|
+
}
|
|
224
|
+
const token = this.source.slice(start, this.position);
|
|
225
|
+
if (token.length > JSON_1_LIMITS.numberTokenBytes) {
|
|
226
|
+
this.fail("maximum number token bytes exceeded");
|
|
227
|
+
}
|
|
228
|
+
const value = Number(token);
|
|
229
|
+
if (!Number.isFinite(value))
|
|
230
|
+
this.fail("non-finite number");
|
|
231
|
+
if (Number.isInteger(value) && !Number.isSafeInteger(value)) {
|
|
232
|
+
this.fail("integral number outside safe range");
|
|
233
|
+
}
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
parseLiteral(token, value) {
|
|
237
|
+
if (this.source.slice(this.position, this.position + token.length) !== token) {
|
|
238
|
+
this.fail(`invalid literal ${token}`);
|
|
239
|
+
}
|
|
240
|
+
this.position += token.length;
|
|
241
|
+
return value;
|
|
242
|
+
}
|
|
243
|
+
consume(expected) {
|
|
244
|
+
if (this.source[this.position] !== expected)
|
|
245
|
+
return false;
|
|
246
|
+
this.position += 1;
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
consumeDigit(minimum, maximum) {
|
|
250
|
+
const char = this.source[this.position];
|
|
251
|
+
if (char === undefined || char < minimum || char > maximum)
|
|
252
|
+
return false;
|
|
253
|
+
this.position += 1;
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
skipWhitespace() {
|
|
257
|
+
while (true) {
|
|
258
|
+
const char = this.source[this.position];
|
|
259
|
+
if (char !== " " && char !== `
|
|
260
|
+
` && char !== "\r" && char !== "\t")
|
|
261
|
+
return;
|
|
262
|
+
this.position += 1;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
fail(message) {
|
|
266
|
+
throw new Json1Error(`${message} at character ${this.position}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function decodeJson1(bytes) {
|
|
270
|
+
if (bytes.byteLength === 0)
|
|
271
|
+
throw new Json1Error("empty JSON/0 document");
|
|
272
|
+
if (bytes.byteLength > JSON_1_LIMITS.bytes)
|
|
273
|
+
throw new Json1Error("maximum bytes exceeded");
|
|
274
|
+
if (bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) {
|
|
275
|
+
throw new Json1Error("UTF-8 BOM is not allowed");
|
|
276
|
+
}
|
|
277
|
+
let text;
|
|
278
|
+
try {
|
|
279
|
+
text = decoder.decode(bytes);
|
|
280
|
+
} catch {
|
|
281
|
+
throw new Json1Error("invalid UTF-8");
|
|
282
|
+
}
|
|
283
|
+
return new Parser(text).parse();
|
|
284
|
+
}
|
|
24
285
|
function validateJson1(value) {
|
|
25
286
|
visitJson(value, 1, { nodes: 0, encodedBytes: 0, active: new WeakSet }, false);
|
|
26
287
|
}
|
|
@@ -127,11 +388,125 @@ function compareUtf16(left, right) {
|
|
|
127
388
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
128
389
|
}
|
|
129
390
|
|
|
391
|
+
// src/internal/project-evaluator-child.ts
|
|
392
|
+
import { spawn } from "child_process";
|
|
393
|
+
|
|
394
|
+
// src/internal/project-evaluator-policy.ts
|
|
395
|
+
var PRIVATE_AUTHOR_EVALUATOR_PROTOCOL = "jig-author-evaluator/1";
|
|
396
|
+
var PRIVATE_AUTHOR_EVALUATOR_MAX_ENTRIES = 256;
|
|
397
|
+
var PRIVATE_AUTHOR_EVALUATOR_ENTRY_MS = 3000;
|
|
398
|
+
var PRIVATE_AUTHOR_EVALUATOR_MACOS_ENTRY_MS = 1e4;
|
|
399
|
+
var PRIVATE_AUTHOR_EVALUATOR_DIRECTORY = "/jig-input/evaluator";
|
|
400
|
+
var PRIVATE_AUTHOR_EVALUATOR_WORKER = `${PRIVATE_AUTHOR_EVALUATOR_DIRECTORY}/project-evaluator-worker.js`;
|
|
401
|
+
var PRIVATE_AUTHOR_EVALUATOR_LIMITS = Object.freeze({
|
|
402
|
+
memoryBytes: 256 * 1024 * 1024,
|
|
403
|
+
pids: 64,
|
|
404
|
+
cpuQuotaMicros: 50000,
|
|
405
|
+
cpuPeriodMicros: 1e5,
|
|
406
|
+
wallClockCeilingMs: PRIVATE_AUTHOR_EVALUATOR_ENTRY_MS,
|
|
407
|
+
cancellationGraceMs: 1000,
|
|
408
|
+
cleanupTimeoutMs: 5000
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
// src/internal/project-evaluator-child.ts
|
|
412
|
+
class PrivateAuthorEvaluatorChildError extends Error {
|
|
413
|
+
code;
|
|
414
|
+
constructor(code, message) {
|
|
415
|
+
super(message);
|
|
416
|
+
this.code = code;
|
|
417
|
+
this.name = "PrivateAuthorEvaluatorChildError";
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
async function runPrivateAuthorEvaluatorChild(request, workerPath = PRIVATE_AUTHOR_EVALUATOR_WORKER, sdkPath) {
|
|
421
|
+
const entryWallClockCeilingMs = process.platform === "darwin" ? PRIVATE_AUTHOR_EVALUATOR_MACOS_ENTRY_MS : PRIVATE_AUTHOR_EVALUATOR_ENTRY_MS;
|
|
422
|
+
const started = performance.now();
|
|
423
|
+
const child = spawn(process.execPath, ["--no-env-file", "--no-install", "--config=/dev/null", workerPath], {
|
|
424
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
425
|
+
env: sdkPath === undefined ? process.env : { ...process.env, JIG_EVALUATOR_SDK: sdkPath }
|
|
426
|
+
});
|
|
427
|
+
let timedOut = false;
|
|
428
|
+
let closed = false;
|
|
429
|
+
const exited = new Promise((resolve, reject) => {
|
|
430
|
+
child.once("error", reject);
|
|
431
|
+
child.once("close", (code, signal) => {
|
|
432
|
+
closed = true;
|
|
433
|
+
resolve({ code, signal });
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
const timer = setTimeout(() => {
|
|
437
|
+
timedOut = true;
|
|
438
|
+
child.kill("SIGKILL");
|
|
439
|
+
}, entryWallClockCeilingMs);
|
|
440
|
+
const stdout = collect(child.stdout, JSON_1_LIMITS.bytes);
|
|
441
|
+
const stderr = collect(child.stderr, 64 * 1024);
|
|
442
|
+
const input = new Promise((resolve, reject) => {
|
|
443
|
+
child.stdin.once("error", reject);
|
|
444
|
+
child.stdin.end(request, () => resolve());
|
|
445
|
+
});
|
|
446
|
+
try {
|
|
447
|
+
const [output, , exit] = await Promise.all([stdout, stderr, exited, input]);
|
|
448
|
+
if (timedOut || performance.now() - started >= entryWallClockCeilingMs) {
|
|
449
|
+
throw failure("PROJECT_EVALUATOR_DEADLINE", "declaration reached its hard wall deadline");
|
|
450
|
+
}
|
|
451
|
+
if (exit.code !== 0 || exit.signal !== null) {
|
|
452
|
+
throw failure("PROJECT_EVALUATION_FAILED", "declaration worker did not exit successfully");
|
|
453
|
+
}
|
|
454
|
+
return output;
|
|
455
|
+
} catch (error) {
|
|
456
|
+
if (timedOut) {
|
|
457
|
+
throw failure("PROJECT_EVALUATOR_DEADLINE", "declaration reached its hard wall deadline");
|
|
458
|
+
}
|
|
459
|
+
throw error;
|
|
460
|
+
} finally {
|
|
461
|
+
clearTimeout(timer);
|
|
462
|
+
if (!closed)
|
|
463
|
+
child.kill("SIGKILL");
|
|
464
|
+
await Promise.allSettled([stdout, stderr, exited, input]);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
async function collect(stream, maximum) {
|
|
468
|
+
const chunks = [];
|
|
469
|
+
let size = 0;
|
|
470
|
+
for await (const chunk of stream) {
|
|
471
|
+
size += chunk.byteLength;
|
|
472
|
+
if (size > maximum)
|
|
473
|
+
throw failure("PROJECT_EVALUATION_LIMIT", "declaration output exceeds its byte bound");
|
|
474
|
+
chunks.push(chunk.slice());
|
|
475
|
+
}
|
|
476
|
+
const bytes = new Uint8Array(size);
|
|
477
|
+
let offset = 0;
|
|
478
|
+
for (const chunk of chunks) {
|
|
479
|
+
bytes.set(chunk, offset);
|
|
480
|
+
offset += chunk.byteLength;
|
|
481
|
+
}
|
|
482
|
+
return bytes;
|
|
483
|
+
}
|
|
484
|
+
function failure(code, message) {
|
|
485
|
+
return new PrivateAuthorEvaluatorChildError(code, message);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// src/internal/project-evaluator-modules.ts
|
|
489
|
+
function reachableAuthorModules(modules, entryProjectPath) {
|
|
490
|
+
const byPath = new Map(modules.map((module) => [module.projectPath, module]));
|
|
491
|
+
const reachable = new Set;
|
|
492
|
+
const pending = [entryProjectPath];
|
|
493
|
+
while (pending.length > 0) {
|
|
494
|
+
const path = pending.pop();
|
|
495
|
+
if (reachable.has(path))
|
|
496
|
+
continue;
|
|
497
|
+
reachable.add(path);
|
|
498
|
+
for (const edge of byPath.get(path).imports)
|
|
499
|
+
pending.push(edge.projectPath);
|
|
500
|
+
}
|
|
501
|
+
return modules.filter((module) => reachable.has(module.projectPath));
|
|
502
|
+
}
|
|
503
|
+
|
|
130
504
|
// src/internal/project-evaluator-worker.ts
|
|
131
|
-
var PROTOCOL =
|
|
505
|
+
var PROTOCOL = PRIVATE_AUTHOR_EVALUATOR_PROTOCOL;
|
|
132
506
|
var MAX_REQUEST_BYTES = 2 * 1024 * 1024;
|
|
133
507
|
var VM_TIMEOUT_MS = 1000;
|
|
134
|
-
var SDK_ENTRY =
|
|
508
|
+
var SDK_ENTRY = process.env.JIG_EVALUATOR_SDK ?? `${PRIVATE_AUTHOR_EVALUATOR_DIRECTORY}/project-evaluator-sdk.bundle.js`;
|
|
509
|
+
delete process.env.JIG_EVALUATOR_SDK;
|
|
135
510
|
var EVALUATION_CODES = new Set([
|
|
136
511
|
"PROJECT_AUTHORING_VALUE",
|
|
137
512
|
"PROJECT_DEFAULT_EXPORT",
|
|
@@ -142,15 +517,26 @@ var EVALUATION_CODES = new Set([
|
|
|
142
517
|
"PROJECT_EVALUATOR_PROTOCOL"
|
|
143
518
|
]);
|
|
144
519
|
var runtime = globalThis.Bun;
|
|
520
|
+
var entryIndex = null;
|
|
145
521
|
try {
|
|
146
522
|
const request = await readRequest();
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
523
|
+
const values = [];
|
|
524
|
+
let resultBytes = 0;
|
|
525
|
+
for (let index = 0;index < request.entries.length; index += 1) {
|
|
526
|
+
entryIndex = index;
|
|
527
|
+
const value = request.entries.length === 1 ? evaluate(await build(request, request.entries[index])) : await evaluateEntry(request, index);
|
|
528
|
+
resultBytes += canonicalJson(value).byteLength + 1;
|
|
529
|
+
if (resultBytes > JSON_1_LIMITS.bytes - 128) {
|
|
530
|
+
throw tagged("PROJECT_EVALUATION_LIMIT", "declaration batch exceeds its aggregate output bound");
|
|
531
|
+
}
|
|
532
|
+
values.push(value);
|
|
533
|
+
}
|
|
534
|
+
write({ protocol: PROTOCOL, status: "ok", values });
|
|
150
535
|
} catch (error) {
|
|
151
536
|
write({
|
|
152
537
|
protocol: PROTOCOL,
|
|
153
538
|
status: "error",
|
|
539
|
+
entryIndex,
|
|
154
540
|
code: errorCode(error),
|
|
155
541
|
message: boundedMessage(error)
|
|
156
542
|
});
|
|
@@ -166,7 +552,7 @@ async function readRequest() {
|
|
|
166
552
|
} catch {
|
|
167
553
|
throw tagged("PROJECT_EVALUATOR_PROTOCOL", "evaluator request is not valid JSON");
|
|
168
554
|
}
|
|
169
|
-
if (!isRecord(value) || value.protocol !== PROTOCOL || !isAuthoringProfile(value.authoringProfile) ||
|
|
555
|
+
if (!isRecord(value) || value.protocol !== PROTOCOL || !isAuthoringProfile(value.authoringProfile) || !Array.isArray(value.entries) || value.entries.length === 0 || value.entries.length > PRIVATE_AUTHOR_EVALUATOR_MAX_ENTRIES || !value.entries.every((entry) => typeof entry === "string") || new Set(value.entries).size !== value.entries.length || !Array.isArray(value.modules) || Object.keys(value).length !== 4) {
|
|
170
556
|
throw tagged("PROJECT_EVALUATOR_PROTOCOL", "evaluator request has an invalid shape");
|
|
171
557
|
}
|
|
172
558
|
const paths = new Set;
|
|
@@ -195,7 +581,7 @@ async function readRequest() {
|
|
|
195
581
|
imports
|
|
196
582
|
});
|
|
197
583
|
}
|
|
198
|
-
if (!paths.has(
|
|
584
|
+
if (!value.entries.every((entry) => paths.has(entry))) {
|
|
199
585
|
throw tagged("PROJECT_EVALUATOR_PROTOCOL", "evaluator entry is absent from its module closure");
|
|
200
586
|
}
|
|
201
587
|
for (const module of modules) {
|
|
@@ -208,11 +594,34 @@ async function readRequest() {
|
|
|
208
594
|
return {
|
|
209
595
|
protocol: PROTOCOL,
|
|
210
596
|
authoringProfile: value.authoringProfile,
|
|
211
|
-
|
|
597
|
+
entries: value.entries,
|
|
212
598
|
modules
|
|
213
599
|
};
|
|
214
600
|
}
|
|
215
|
-
async function
|
|
601
|
+
async function evaluateEntry(request, index) {
|
|
602
|
+
const entryProjectPath = request.entries[index];
|
|
603
|
+
const output = await runPrivateAuthorEvaluatorChild(canonicalJson({
|
|
604
|
+
...request,
|
|
605
|
+
entries: [entryProjectPath],
|
|
606
|
+
modules: reachableAuthorModules(request.modules, entryProjectPath)
|
|
607
|
+
}), process.argv[1], SDK_ENTRY);
|
|
608
|
+
const response = decodeJson1(output);
|
|
609
|
+
if (!isRecord(response) || response.protocol !== PROTOCOL) {
|
|
610
|
+
throw tagged("PROJECT_EVALUATOR_PROTOCOL", "declaration worker returned an invalid envelope");
|
|
611
|
+
}
|
|
612
|
+
if (response.status === "error" && exactKeys(response, ["code", "entryIndex", "message", "protocol", "status"]) && response.entryIndex === 0 && typeof response.code === "string" && EVALUATION_CODES.has(response.code) && typeof response.message === "string") {
|
|
613
|
+
throw tagged(response.code, response.message);
|
|
614
|
+
}
|
|
615
|
+
if (response.status !== "ok" || !exactKeys(response, ["protocol", "status", "values"]) || !Array.isArray(response.values) || response.values.length !== 1) {
|
|
616
|
+
throw tagged("PROJECT_EVALUATOR_PROTOCOL", "declaration worker returned an invalid result");
|
|
617
|
+
}
|
|
618
|
+
return response.values[0];
|
|
619
|
+
}
|
|
620
|
+
function exactKeys(value, expected) {
|
|
621
|
+
const keys = Object.keys(value).sort();
|
|
622
|
+
return keys.length === expected.length && keys.every((key, index) => key === expected[index]);
|
|
623
|
+
}
|
|
624
|
+
async function build(request, entryProjectPath) {
|
|
216
625
|
const sdkSource = await runtime.file(SDK_ENTRY).text();
|
|
217
626
|
const modules = new Map(request.modules.map((module) => [module.projectPath, module]));
|
|
218
627
|
const edges = new Map;
|
|
@@ -254,7 +663,7 @@ async function build(request) {
|
|
|
254
663
|
if (arguments_.kind !== "import-statement" || arguments_.importer !== "jig-author:bridge") {
|
|
255
664
|
throw deniedImport(arguments_.path);
|
|
256
665
|
}
|
|
257
|
-
return { path:
|
|
666
|
+
return { path: entryProjectPath, namespace: "jig-project" };
|
|
258
667
|
});
|
|
259
668
|
builder.onResolve({ filter: /^jig-author:/ }, (arguments_) => {
|
|
260
669
|
throw deniedImport(arguments_.path);
|
|
@@ -405,6 +814,8 @@ function tagged(code, message) {
|
|
|
405
814
|
return Object.assign(new Error(message), { code });
|
|
406
815
|
}
|
|
407
816
|
function errorCode(error) {
|
|
817
|
+
if (error instanceof PrivateAuthorEvaluatorChildError)
|
|
818
|
+
return error.code;
|
|
408
819
|
if (typeof error === "object" && error !== null && "code" in error && error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
|
|
409
820
|
return "PROJECT_EVALUATION_LIMIT";
|
|
410
821
|
}
|
|
@@ -1459,7 +1459,9 @@ async function requestGrantedHttp(value) {
|
|
|
1459
1459
|
finish({ failure: "UNCERTAIN" });
|
|
1460
1460
|
});
|
|
1461
1461
|
});
|
|
1462
|
-
request.on("error", () => finish({
|
|
1462
|
+
request.on("error", (error) => finish({
|
|
1463
|
+
failure: error.code === "HPE_HEADER_OVERFLOW" ? "RESOURCE_EXHAUSTED" : "UNCERTAIN"
|
|
1464
|
+
}));
|
|
1463
1465
|
request.on("upgrade", (_response, socket) => {
|
|
1464
1466
|
socket.destroy();
|
|
1465
1467
|
finish({ failure: "INVALID_RESULT" });
|