poe-code 3.0.258 → 3.0.259
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/cli/commands/gaslight.js +84 -1
- package/dist/cli/commands/gaslight.js.map +1 -1
- package/dist/cli/poe-theme.d.ts +1 -0
- package/dist/cli/poe-theme.js +5 -0
- package/dist/cli/poe-theme.js.map +1 -0
- package/dist/cli/program.js +1 -0
- package/dist/cli/program.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2753 -1123
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/dist/sdk/gaslight.d.ts +1 -1
- package/dist/sdk/gaslight.js +1 -1
- package/dist/sdk/gaslight.js.map +1 -1
- package/package.json +3 -1
- package/packages/agent-gaslight/dist/config.d.ts +5 -1
- package/packages/agent-gaslight/dist/config.js +32 -11
- package/packages/agent-gaslight/dist/index.d.ts +3 -2
- package/packages/agent-gaslight/dist/index.js +2 -1
- package/packages/agent-gaslight/dist/ingest.d.ts +2 -0
- package/packages/agent-gaslight/dist/ingest.js +486 -0
- package/packages/agent-gaslight/dist/run.js +1 -1
- package/packages/agent-gaslight/dist/types.d.ts +41 -6
- package/packages/agent-harness/dist/loader/run.js +6 -21
- package/packages/agent-script/dist/cli.d.ts +2 -3
- package/packages/agent-script/dist/cli.js +70 -36
- package/packages/agent-script/dist/example-runner.d.ts +2 -3
- package/packages/agent-script/dist/example-runner.js +69 -56
- package/packages/agent-script/dist/interp/exceptions.js +1 -1
- package/packages/agent-script/dist/interp/globals/object-array.d.ts +1 -1
- package/packages/agent-script/dist/interp/globals/object-array.js +39 -20
- package/packages/agent-script/dist/interp/host-bridge.js +1 -1
- package/packages/agent-script/dist/interp/interpreter.js +83 -17
- package/packages/agent-script/dist/interp/methods/array.js +25 -2
- package/packages/agent-script/dist/interp/methods/regex.js +1 -1
- package/packages/agent-script/dist/interp/promise-tracker.d.ts +16 -0
- package/packages/agent-script/dist/interp/promise-tracker.js +58 -0
- package/packages/agent-script/dist/interp/promise.js +38 -7
- package/packages/agent-script/dist/interp/scope.d.ts +1 -0
- package/packages/agent-script/dist/interp/scope.js +3 -0
- package/packages/agent-script/dist/interp/values.js +2 -0
- package/packages/agent-script/dist/lint/index.d.ts +2 -0
- package/packages/agent-script/dist/lint/index.js +2 -0
- package/packages/agent-script/dist/lint/rules/AS-export-import-meta.d.ts +6 -1
- package/packages/agent-script/dist/lint/rules/AS-export-import-meta.js +33 -4
- package/packages/agent-script/dist/modules/agent.js +10 -1
- package/packages/agent-script/dist/modules/log.js +5 -1
- package/packages/agent-script/dist/modules/registry.js +9 -3
- package/packages/agent-script/dist/output-stream.d.ts +12 -0
- package/packages/agent-script/dist/output-stream.js +50 -0
- package/packages/agent-script/dist/parse/parser.d.ts +1 -1
- package/packages/agent-script/dist/parse/parser.js +151 -45
- package/packages/agent-script/dist/parse/tokenizer.js +26 -3
- package/packages/agent-script/dist/run.js +14 -3
- package/packages/agent-script/dist/runner/run-harness.js +28 -5
- package/packages/agent-traces/dist/collect.d.ts +4 -0
- package/packages/agent-traces/dist/collect.js +102 -0
- package/packages/agent-traces/dist/index.d.ts +4 -0
- package/packages/agent-traces/dist/index.js +3 -0
- package/packages/agent-traces/dist/jsonl.d.ts +2 -0
- package/packages/agent-traces/dist/jsonl.js +7 -0
- package/packages/agent-traces/dist/line-json.d.ts +4 -0
- package/packages/agent-traces/dist/line-json.js +40 -0
- package/packages/agent-traces/dist/readers/claude.d.ts +2 -0
- package/packages/agent-traces/dist/readers/claude.js +192 -0
- package/packages/agent-traces/dist/readers/codex.d.ts +2 -0
- package/packages/agent-traces/dist/readers/codex.js +266 -0
- package/packages/agent-traces/dist/readers/index.d.ts +5 -0
- package/packages/agent-traces/dist/readers/index.js +4 -0
- package/packages/agent-traces/dist/types.d.ts +84 -0
- package/packages/agent-traces/dist/types.js +1 -0
- package/packages/package-lint/dist/model.js +5 -1
- package/packages/package-lint/dist/source-imports.d.ts +11 -1
- package/packages/package-lint/dist/source-imports.js +30 -4
- package/packages/tiny-stdio-mcp-test-server/dist/cli.js +41 -0
- package/packages/tiny-stdio-mcp-test-server/dist/index.js +8 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { addBrokenPipeListener, createBrokenPipeState, createSafeOutputStream } from "../output-stream.js";
|
|
1
2
|
export function makeLogModule(sink = createJsonlStdoutSink()) {
|
|
2
3
|
const normalizedSink = readSink(sink);
|
|
3
4
|
return {
|
|
@@ -26,8 +27,11 @@ export function makeLogModule(sink = createJsonlStdoutSink()) {
|
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
function createJsonlStdoutSink() {
|
|
30
|
+
const brokenPipe = createBrokenPipeState();
|
|
31
|
+
const stdout = createSafeOutputStream(process.stdout, brokenPipe);
|
|
32
|
+
addBrokenPipeListener(process.stdout, brokenPipe);
|
|
29
33
|
return (entry) => {
|
|
30
|
-
|
|
34
|
+
stdout.write(`${JSON.stringify(toJsonValue(entry, new WeakSet()))}\n`);
|
|
31
35
|
};
|
|
32
36
|
}
|
|
33
37
|
function readNonEmptyString(value, label) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { attachErrorSpan } from "../error/shape.js";
|
|
1
2
|
import { wrapCancelableBindings } from "../interp/cancel.js";
|
|
2
3
|
import { readHostOperationPolicy, wrapCallerInjectedBindings } from "../interp/host-bridge.js";
|
|
3
4
|
import { registerPendingHostCallPolicy } from "../snapshot/policy.js";
|
|
@@ -29,7 +30,7 @@ function bindImportDeclaration(declaration, registry, wrappedModules, bindings,
|
|
|
29
30
|
const moduleName = declaration.source.value;
|
|
30
31
|
const moduleExports = registry.get(moduleName);
|
|
31
32
|
if (moduleExports === undefined) {
|
|
32
|
-
throw
|
|
33
|
+
throw createModuleImportError(createUnknownModuleMessage(moduleName, [...registry.keys()]), declaration.source.span);
|
|
33
34
|
}
|
|
34
35
|
const wrappedExports = wrappedModules.get(moduleName) ??
|
|
35
36
|
wrapCancelableBindings(wrapCallerInjectedBindings(Object.fromEntries(moduleExports), {
|
|
@@ -42,7 +43,7 @@ function bindImportDeclaration(declaration, registry, wrappedModules, bindings,
|
|
|
42
43
|
for (const specifier of declaration.specifiers) {
|
|
43
44
|
const localName = specifier.local.name;
|
|
44
45
|
if (Object.hasOwn(bindings, localName)) {
|
|
45
|
-
throw
|
|
46
|
+
throw createModuleImportError(`Cannot redeclare imported binding '${localName}'.`, specifier.local.span);
|
|
46
47
|
}
|
|
47
48
|
bindings[localName] = resolveImportSpecifier(moduleName, specifier, wrappedExports);
|
|
48
49
|
}
|
|
@@ -56,7 +57,12 @@ function resolveImportSpecifier(moduleName, specifier, wrappedExports) {
|
|
|
56
57
|
if (exportedValue !== undefined || Object.hasOwn(wrappedExports, exportName)) {
|
|
57
58
|
return exportedValue;
|
|
58
59
|
}
|
|
59
|
-
throw
|
|
60
|
+
throw createModuleImportError(createUnknownExportMessage(moduleName, exportName, Object.keys(wrappedExports).sort()), specifier.span);
|
|
61
|
+
}
|
|
62
|
+
function createModuleImportError(message, span) {
|
|
63
|
+
const error = new Error(message);
|
|
64
|
+
attachErrorSpan(error, span);
|
|
65
|
+
return error;
|
|
60
66
|
}
|
|
61
67
|
function normalizeModuleRegistry(modules) {
|
|
62
68
|
if (modules === undefined) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type OutputStream = {
|
|
2
|
+
off?(event: "error", listener: (error: unknown) => void): void;
|
|
3
|
+
on?(event: "error", listener: (error: unknown) => void): void;
|
|
4
|
+
write(chunk: string): void;
|
|
5
|
+
};
|
|
6
|
+
export type BrokenPipeState = {
|
|
7
|
+
closed: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare function createBrokenPipeState(): BrokenPipeState;
|
|
10
|
+
export declare function createSafeOutputStream(stream: OutputStream, brokenPipe: BrokenPipeState): OutputStream;
|
|
11
|
+
export declare function withBrokenPipeGuard<TResult>(streams: readonly OutputStream[], brokenPipe: BrokenPipeState, callback: () => Promise<TResult>): Promise<TResult>;
|
|
12
|
+
export declare function addBrokenPipeListener(stream: OutputStream, brokenPipe: BrokenPipeState): () => void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { hasOwnErrorCode } from "./error-codes.js";
|
|
2
|
+
export function createBrokenPipeState() {
|
|
3
|
+
return { closed: false };
|
|
4
|
+
}
|
|
5
|
+
export function createSafeOutputStream(stream, brokenPipe) {
|
|
6
|
+
return {
|
|
7
|
+
write(chunk) {
|
|
8
|
+
if (brokenPipe.closed) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
stream.write(chunk);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (isBrokenPipeError(error)) {
|
|
16
|
+
brokenPipe.closed = true;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export async function withBrokenPipeGuard(streams, brokenPipe, callback) {
|
|
25
|
+
const removeListeners = streams.map((stream) => addBrokenPipeListener(stream, brokenPipe));
|
|
26
|
+
try {
|
|
27
|
+
return await callback();
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
for (const removeListener of removeListeners) {
|
|
31
|
+
removeListener();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function addBrokenPipeListener(stream, brokenPipe) {
|
|
36
|
+
const onError = (error) => {
|
|
37
|
+
if (isBrokenPipeError(error)) {
|
|
38
|
+
brokenPipe.closed = true;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
throw error;
|
|
42
|
+
};
|
|
43
|
+
stream.on?.("error", onError);
|
|
44
|
+
return () => {
|
|
45
|
+
stream.off?.("error", onError);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function isBrokenPipeError(error) {
|
|
49
|
+
return hasOwnErrorCode(error, "EPIPE");
|
|
50
|
+
}
|
|
@@ -4,6 +4,8 @@ import { formatParseError } from "./format-error.js";
|
|
|
4
4
|
import { createExportDefaultDeclaration, createExportNamedDeclaration } from "./parse-export.js";
|
|
5
5
|
import { createImportMeta, isImportMetaTokenSequence } from "./parse-import-meta.js";
|
|
6
6
|
import { parseRegex } from "../interp/regex/parse.js";
|
|
7
|
+
const MAX_CONDITIONAL_EXPRESSION_DEPTH = 256;
|
|
8
|
+
const MAX_IF_STATEMENT_DEPTH = 2_048;
|
|
7
9
|
export class DisallowedSyntaxError extends Error {
|
|
8
10
|
constructor(syntax, position) {
|
|
9
11
|
super(`Disallowed syntax '${syntax}' at line ${position.line}, column ${position.column}.`);
|
|
@@ -18,6 +20,7 @@ const MULTIPLICATIVE_OPERATORS = new Set(["*", "/", "%"]);
|
|
|
18
20
|
const BITWISE_OR_OPERATORS = new Set(["|"]);
|
|
19
21
|
const BITWISE_XOR_OPERATORS = new Set(["^"]);
|
|
20
22
|
const BITWISE_AND_OPERATORS = new Set(["&"]);
|
|
23
|
+
const MAX_UNICODE_CODE_POINT = 0x10ffff;
|
|
21
24
|
const TOP_LEVEL_STATEMENT_KEYWORDS = new Set([
|
|
22
25
|
"break",
|
|
23
26
|
"const",
|
|
@@ -96,6 +99,8 @@ class Parser {
|
|
|
96
99
|
tokens;
|
|
97
100
|
index = 0;
|
|
98
101
|
breakableDepth = 0;
|
|
102
|
+
conditionalExpressionDepth = 0;
|
|
103
|
+
ifStatementDepth = 0;
|
|
99
104
|
loopDepth = 0;
|
|
100
105
|
generatorBody = false;
|
|
101
106
|
scopes = [new Map()];
|
|
@@ -254,23 +259,33 @@ class Parser {
|
|
|
254
259
|
};
|
|
255
260
|
}
|
|
256
261
|
parseConditionalExpression() {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
262
|
+
if (this.conditionalExpressionDepth >= MAX_CONDITIONAL_EXPRESSION_DEPTH) {
|
|
263
|
+
const token = this.currentToken();
|
|
264
|
+
throw new Error(`Conditional expression nesting limit exceeded at line ${token.start.line}, column ${token.start.column}.`);
|
|
265
|
+
}
|
|
266
|
+
this.conditionalExpressionDepth += 1;
|
|
267
|
+
try {
|
|
268
|
+
const test = this.parseCoalesceExpression();
|
|
269
|
+
if (this.consumePunctuator("?") === undefined) {
|
|
270
|
+
return test;
|
|
271
|
+
}
|
|
272
|
+
const consequent = this.parseExpression();
|
|
273
|
+
this.expectPunctuator(":");
|
|
274
|
+
const alternate = this.parseConditionalExpression();
|
|
275
|
+
return {
|
|
276
|
+
node: {
|
|
277
|
+
type: "ConditionalExpression",
|
|
278
|
+
test: test.node,
|
|
279
|
+
consequent: consequent.node,
|
|
280
|
+
alternate: alternate.node,
|
|
281
|
+
span: createSpan(test.node.span.start, alternate.node.span.end)
|
|
282
|
+
},
|
|
283
|
+
parenthesized: false
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
finally {
|
|
287
|
+
this.conditionalExpressionDepth -= 1;
|
|
260
288
|
}
|
|
261
|
-
const consequent = this.parseExpression();
|
|
262
|
-
this.expectPunctuator(":");
|
|
263
|
-
const alternate = this.parseConditionalExpression();
|
|
264
|
-
return {
|
|
265
|
-
node: {
|
|
266
|
-
type: "ConditionalExpression",
|
|
267
|
-
test: test.node,
|
|
268
|
-
consequent: consequent.node,
|
|
269
|
-
alternate: alternate.node,
|
|
270
|
-
span: createSpan(test.node.span.start, alternate.node.span.end)
|
|
271
|
-
},
|
|
272
|
-
parenthesized: false
|
|
273
|
-
};
|
|
274
289
|
}
|
|
275
290
|
parseArrowFunctionBody() {
|
|
276
291
|
if (this.currentToken().type === "punctuator" && this.currentToken().value === "{") {
|
|
@@ -436,28 +451,38 @@ class Parser {
|
|
|
436
451
|
throw new DisallowedSyntaxError("label", firstLabelToken.start);
|
|
437
452
|
}
|
|
438
453
|
parseIfStatement() {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
454
|
+
if (this.ifStatementDepth >= MAX_IF_STATEMENT_DEPTH) {
|
|
455
|
+
const token = this.currentToken();
|
|
456
|
+
throw new Error(`If statement nesting limit exceeded at line ${token.start.line}, column ${token.start.column}.`);
|
|
457
|
+
}
|
|
458
|
+
this.ifStatementDepth += 1;
|
|
459
|
+
try {
|
|
460
|
+
const ifToken = this.expectKeyword("if");
|
|
461
|
+
this.expectPunctuator("(");
|
|
462
|
+
const test = this.parseExpression({ allowSequence: true }).node;
|
|
463
|
+
this.expectPunctuator(")");
|
|
464
|
+
const consequent = this.parseStatement();
|
|
465
|
+
if (consequent.type !== "BlockStatement") {
|
|
466
|
+
while (this.currentToken().type === "punctuator" &&
|
|
467
|
+
this.currentToken().value === ";" &&
|
|
468
|
+
this.peekToken(1).type === "keyword" &&
|
|
469
|
+
this.peekToken(1).value === "else") {
|
|
470
|
+
this.index += 1;
|
|
471
|
+
}
|
|
450
472
|
}
|
|
473
|
+
const elseToken = this.consumeKeyword("else");
|
|
474
|
+
const alternate = elseToken === undefined ? undefined : this.parseStatement();
|
|
475
|
+
return {
|
|
476
|
+
type: "IfStatement",
|
|
477
|
+
test,
|
|
478
|
+
consequent,
|
|
479
|
+
alternate,
|
|
480
|
+
span: createSpan(ifToken.start, alternate?.span.end ?? consequent.span.end)
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
finally {
|
|
484
|
+
this.ifStatementDepth -= 1;
|
|
451
485
|
}
|
|
452
|
-
const elseToken = this.consumeKeyword("else");
|
|
453
|
-
const alternate = elseToken === undefined ? undefined : this.parseStatement();
|
|
454
|
-
return {
|
|
455
|
-
type: "IfStatement",
|
|
456
|
-
test,
|
|
457
|
-
consequent,
|
|
458
|
-
alternate,
|
|
459
|
-
span: createSpan(ifToken.start, alternate?.span.end ?? consequent.span.end)
|
|
460
|
-
};
|
|
461
486
|
}
|
|
462
487
|
parseSwitchStatement() {
|
|
463
488
|
const switchToken = this.currentToken();
|
|
@@ -784,7 +809,7 @@ class Parser {
|
|
|
784
809
|
}
|
|
785
810
|
parseExportDefaultDeclaration(exportToken) {
|
|
786
811
|
this.index += 1;
|
|
787
|
-
if (this.currentToken().value === "
|
|
812
|
+
if (this.currentToken().value === "class") {
|
|
788
813
|
throw new DisallowedSyntaxError(`export default ${this.currentToken().value}`, this.currentToken().start);
|
|
789
814
|
}
|
|
790
815
|
const declaration = this.parseExpression().node;
|
|
@@ -1447,7 +1472,7 @@ class Parser {
|
|
|
1447
1472
|
const next = this.currentToken();
|
|
1448
1473
|
const hasArgument = delegate ||
|
|
1449
1474
|
(!hasLineBreakBetween(token, next) &&
|
|
1450
|
-
!(next.type === "punctuator" && (next.value
|
|
1475
|
+
!(next.type === "punctuator" && isYieldArgumentTerminator(next.value)) &&
|
|
1451
1476
|
next.type !== "eof");
|
|
1452
1477
|
const argument = hasArgument ? this.parseAssignmentExpression().node : undefined;
|
|
1453
1478
|
if (delegate && argument === undefined) {
|
|
@@ -1591,7 +1616,7 @@ class Parser {
|
|
|
1591
1616
|
continue;
|
|
1592
1617
|
}
|
|
1593
1618
|
if (this.currentToken().type === "template") {
|
|
1594
|
-
const quasi = createTemplateLiteral(this.currentToken());
|
|
1619
|
+
const quasi = createTemplateLiteral(this.currentToken(), { allowMalformedEscapes: true });
|
|
1595
1620
|
this.index += 1;
|
|
1596
1621
|
expression = {
|
|
1597
1622
|
node: {
|
|
@@ -1679,7 +1704,7 @@ class Parser {
|
|
|
1679
1704
|
if (token.type === "template") {
|
|
1680
1705
|
this.index += 1;
|
|
1681
1706
|
return {
|
|
1682
|
-
node: createTemplateLiteral(token),
|
|
1707
|
+
node: createTemplateLiteral(token, { allowMalformedEscapes: false }),
|
|
1683
1708
|
parenthesized: false
|
|
1684
1709
|
};
|
|
1685
1710
|
}
|
|
@@ -2834,6 +2859,9 @@ function isAssignmentOperator(value) {
|
|
|
2834
2859
|
return false;
|
|
2835
2860
|
}
|
|
2836
2861
|
}
|
|
2862
|
+
function isYieldArgumentTerminator(value) {
|
|
2863
|
+
return value === ";" || value === "}" || value === ")" || value === "]" || value === ",";
|
|
2864
|
+
}
|
|
2837
2865
|
function createNumericLiteral(token) {
|
|
2838
2866
|
return {
|
|
2839
2867
|
type: "NumericLiteral",
|
|
@@ -2915,7 +2943,7 @@ function createLiteralFromToken(token) {
|
|
|
2915
2943
|
}
|
|
2916
2944
|
return createKeywordLiteral(token);
|
|
2917
2945
|
}
|
|
2918
|
-
function createTemplateLiteral(token) {
|
|
2946
|
+
function createTemplateLiteral(token, options = { allowMalformedEscapes: false }) {
|
|
2919
2947
|
const raw = token.value;
|
|
2920
2948
|
const expressions = [];
|
|
2921
2949
|
const quasis = [];
|
|
@@ -2928,7 +2956,7 @@ function createTemplateLiteral(token) {
|
|
|
2928
2956
|
continue;
|
|
2929
2957
|
}
|
|
2930
2958
|
if (char === "$" && raw[cursor + 1] === "{") {
|
|
2931
|
-
quasis.push(createTemplateElement(token.start, raw, quasiStart, cursor, false));
|
|
2959
|
+
quasis.push(createTemplateElement(token.start, raw, quasiStart, cursor, false, options));
|
|
2932
2960
|
const expressionStart = cursor + 2;
|
|
2933
2961
|
const expressionEnd = findTemplateExpressionEnd(raw, expressionStart);
|
|
2934
2962
|
expressions.push(parseEmbeddedExpression(raw.slice(expressionStart, expressionEnd), positionWithinRaw(token.start, raw, expressionStart)));
|
|
@@ -2938,7 +2966,7 @@ function createTemplateLiteral(token) {
|
|
|
2938
2966
|
}
|
|
2939
2967
|
cursor += 1;
|
|
2940
2968
|
}
|
|
2941
|
-
quasis.push(createTemplateElement(token.start, raw, quasiStart, raw.length - 1, true));
|
|
2969
|
+
quasis.push(createTemplateElement(token.start, raw, quasiStart, raw.length - 1, true, options));
|
|
2942
2970
|
return {
|
|
2943
2971
|
type: "TemplateLiteral",
|
|
2944
2972
|
expressions,
|
|
@@ -2997,18 +3025,96 @@ function isDecimalDigit(value) {
|
|
|
2997
3025
|
function isHexDigit(value) {
|
|
2998
3026
|
return isDecimalDigit(value) || (value >= "a" && value <= "f") || (value >= "A" && value <= "F");
|
|
2999
3027
|
}
|
|
3000
|
-
function
|
|
3028
|
+
function isOctalDigit(value) {
|
|
3029
|
+
return value >= "0" && value <= "7";
|
|
3030
|
+
}
|
|
3031
|
+
function createTemplateElement(templateStart, rawTemplate, rawStart, rawEnd, tail, options) {
|
|
3001
3032
|
const rawValue = rawTemplate.slice(rawStart, rawEnd);
|
|
3033
|
+
const cooked = decodeTemplateElementCooked(rawValue, options.allowMalformedEscapes);
|
|
3034
|
+
if (cooked.invalid !== undefined && !options.allowMalformedEscapes) {
|
|
3035
|
+
const position = positionWithinRaw(templateStart, rawTemplate, rawStart + cooked.invalid.index);
|
|
3036
|
+
throw new Error(`${cooked.invalid.message} at line ${position.line}, column ${position.column}.`);
|
|
3037
|
+
}
|
|
3002
3038
|
return {
|
|
3003
3039
|
type: "TemplateElement",
|
|
3004
3040
|
tail,
|
|
3005
3041
|
value: {
|
|
3006
3042
|
raw: rawValue,
|
|
3007
|
-
cooked:
|
|
3043
|
+
cooked: cooked.invalid === undefined ? cooked.value : undefined
|
|
3008
3044
|
},
|
|
3009
3045
|
span: createSpan(positionWithinRaw(templateStart, rawTemplate, rawStart), positionWithinRaw(templateStart, rawTemplate, rawEnd))
|
|
3010
3046
|
};
|
|
3011
3047
|
}
|
|
3048
|
+
function decodeTemplateElementCooked(value, allowMalformedEscapes) {
|
|
3049
|
+
const normalized = normalizeTemplateLineTerminators(value);
|
|
3050
|
+
const invalid = findMalformedTemplateEscape(normalized);
|
|
3051
|
+
if (invalid !== undefined) {
|
|
3052
|
+
return allowMalformedEscapes ? { invalid } : { invalid };
|
|
3053
|
+
}
|
|
3054
|
+
return {
|
|
3055
|
+
value: decodeEscapedText(normalized)
|
|
3056
|
+
};
|
|
3057
|
+
}
|
|
3058
|
+
function findMalformedTemplateEscape(value) {
|
|
3059
|
+
let index = 0;
|
|
3060
|
+
while (index < value.length) {
|
|
3061
|
+
if (value[index] !== "\\") {
|
|
3062
|
+
index += 1;
|
|
3063
|
+
continue;
|
|
3064
|
+
}
|
|
3065
|
+
const next = value[index + 1];
|
|
3066
|
+
if (next === undefined || next === "\n") {
|
|
3067
|
+
index += 2;
|
|
3068
|
+
continue;
|
|
3069
|
+
}
|
|
3070
|
+
if (next === "u") {
|
|
3071
|
+
if (!isValidUnicodeEscape(value, index)) {
|
|
3072
|
+
return { index, message: "Invalid unicode escape" };
|
|
3073
|
+
}
|
|
3074
|
+
index += 2;
|
|
3075
|
+
continue;
|
|
3076
|
+
}
|
|
3077
|
+
if (next === "x") {
|
|
3078
|
+
const hex = value.slice(index + 2, index + 4);
|
|
3079
|
+
if (hex.length !== 2 || ![...hex].every(isHexDigit)) {
|
|
3080
|
+
return { index, message: "Invalid hex escape" };
|
|
3081
|
+
}
|
|
3082
|
+
index += 4;
|
|
3083
|
+
continue;
|
|
3084
|
+
}
|
|
3085
|
+
if (next === "0") {
|
|
3086
|
+
if (isDecimalDigit(value[index + 2] ?? "")) {
|
|
3087
|
+
return { index, message: "Legacy octal escape sequences are not supported" };
|
|
3088
|
+
}
|
|
3089
|
+
index += 2;
|
|
3090
|
+
continue;
|
|
3091
|
+
}
|
|
3092
|
+
if (isOctalDigit(next)) {
|
|
3093
|
+
return { index, message: "Legacy octal escape sequences are not supported" };
|
|
3094
|
+
}
|
|
3095
|
+
index += 2;
|
|
3096
|
+
}
|
|
3097
|
+
return undefined;
|
|
3098
|
+
}
|
|
3099
|
+
function isValidUnicodeEscape(value, start) {
|
|
3100
|
+
let index = start + 2;
|
|
3101
|
+
if (value[index] === "{") {
|
|
3102
|
+
index += 1;
|
|
3103
|
+
const codePointStart = index;
|
|
3104
|
+
while (index < value.length && value[index] !== "}") {
|
|
3105
|
+
if (!isHexDigit(value[index] ?? "")) {
|
|
3106
|
+
return false;
|
|
3107
|
+
}
|
|
3108
|
+
index += 1;
|
|
3109
|
+
}
|
|
3110
|
+
if (index === codePointStart || value[index] !== "}") {
|
|
3111
|
+
return false;
|
|
3112
|
+
}
|
|
3113
|
+
return Number.parseInt(value.slice(codePointStart, index), 16) <= MAX_UNICODE_CODE_POINT;
|
|
3114
|
+
}
|
|
3115
|
+
const hex = value.slice(index, index + 4);
|
|
3116
|
+
return hex.length === 4 && [...hex].every(isHexDigit);
|
|
3117
|
+
}
|
|
3012
3118
|
function findTemplateExpressionEnd(raw, start) {
|
|
3013
3119
|
let depth = 1;
|
|
3014
3120
|
let index = start;
|
|
@@ -164,6 +164,10 @@ class Lexer {
|
|
|
164
164
|
skipTrivia() {
|
|
165
165
|
while (!this.isAtEnd()) {
|
|
166
166
|
const char = this.currentChar();
|
|
167
|
+
if (this.isHashbangCommentStart()) {
|
|
168
|
+
this.skipLineComment();
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
167
171
|
if (isWhitespace(char) || isLineBreak(char)) {
|
|
168
172
|
this.advance();
|
|
169
173
|
continue;
|
|
@@ -244,7 +248,7 @@ class Lexer {
|
|
|
244
248
|
return;
|
|
245
249
|
}
|
|
246
250
|
if (char === "\\") {
|
|
247
|
-
this.
|
|
251
|
+
this.skipEscapedTemplateCharacter();
|
|
248
252
|
continue;
|
|
249
253
|
}
|
|
250
254
|
if (char === "$" && this.peekChar(1) === "{") {
|
|
@@ -405,7 +409,7 @@ class Lexer {
|
|
|
405
409
|
return;
|
|
406
410
|
}
|
|
407
411
|
if (char === "\\") {
|
|
408
|
-
this.
|
|
412
|
+
this.skipEscapedTemplateCharacter();
|
|
409
413
|
continue;
|
|
410
414
|
}
|
|
411
415
|
if (char === "$" && this.peekChar(1) === "{") {
|
|
@@ -706,6 +710,10 @@ class Lexer {
|
|
|
706
710
|
isHtmlStyleCommentDelimiter() {
|
|
707
711
|
return this.source.startsWith("<!--", this.index) || this.source.startsWith("-->", this.index);
|
|
708
712
|
}
|
|
713
|
+
isHashbangCommentStart() {
|
|
714
|
+
return (this.source.startsWith("#!", this.index) &&
|
|
715
|
+
(this.index === 0 || (this.index === 1 && this.source[0] === "\uFEFF")));
|
|
716
|
+
}
|
|
709
717
|
readUnicodeEscape() {
|
|
710
718
|
const escapeStart = this.position();
|
|
711
719
|
this.advance();
|
|
@@ -760,6 +768,21 @@ class Lexer {
|
|
|
760
768
|
}
|
|
761
769
|
this.advance();
|
|
762
770
|
}
|
|
771
|
+
skipEscapedTemplateCharacter() {
|
|
772
|
+
this.advance();
|
|
773
|
+
if (this.isAtEnd()) {
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
const escaped = this.currentChar();
|
|
777
|
+
if (escaped === "\r") {
|
|
778
|
+
this.advance();
|
|
779
|
+
if (this.currentChar() === "\n") {
|
|
780
|
+
this.advance();
|
|
781
|
+
}
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
this.advance();
|
|
785
|
+
}
|
|
763
786
|
readExtendedUnicodeEscape(escapeStart) {
|
|
764
787
|
this.advance();
|
|
765
788
|
const codePointStart = this.position();
|
|
@@ -852,7 +875,7 @@ function isOctalDigit(char) {
|
|
|
852
875
|
return char >= "0" && char <= "7";
|
|
853
876
|
}
|
|
854
877
|
function isWhitespace(char) {
|
|
855
|
-
return char === " " || char === "\t" || char === "\v" || char === "\f";
|
|
878
|
+
return char === " " || char === "\t" || char === "\v" || char === "\f" || char === "\uFEFF";
|
|
856
879
|
}
|
|
857
880
|
function isLineBreak(char) {
|
|
858
881
|
return char === "\n" || char === "\r";
|
|
@@ -5,6 +5,7 @@ import { restore } from "./restore.js";
|
|
|
5
5
|
import { Budget } from "./interp/budget.js";
|
|
6
6
|
import { wrapCancelableBindings } from "./interp/cancel.js";
|
|
7
7
|
import { enterSnapshotRun } from "./interp/running-state.js";
|
|
8
|
+
import { createSandboxPromiseRejectionTracker, observeSandboxPromise, withSandboxPromiseRejectionTracker } from "./interp/promise-tracker.js";
|
|
8
9
|
import { HostCallJournal } from "./interp/host-call.js";
|
|
9
10
|
import { createConsoleJsonGlobals } from "./interp/globals/console-json.js";
|
|
10
11
|
import { createCollectionGlobals } from "./interp/globals/collections.js";
|
|
@@ -33,10 +34,12 @@ export class UnhandledRejectionError extends Error {
|
|
|
33
34
|
replaceErrorStack(this);
|
|
34
35
|
}
|
|
35
36
|
}
|
|
37
|
+
const DEFAULT_MAX_CALL_DEPTH = 1_000;
|
|
36
38
|
export function run(source, options = {}) {
|
|
37
39
|
const lifecycle = { hostCallbackDepth: 0 };
|
|
38
40
|
const dumpController = createDumpController(lifecycle);
|
|
39
|
-
const
|
|
41
|
+
const promiseTracker = createSandboxPromiseRejectionTracker();
|
|
42
|
+
const result = withSandboxPromiseRejectionTracker(promiseTracker, async () => {
|
|
40
43
|
const deactivateOtelSink = activateOtelSink(options.otelSink);
|
|
41
44
|
let leaveSnapshotRun;
|
|
42
45
|
let createFailureSnapshot;
|
|
@@ -46,7 +49,7 @@ export function run(source, options = {}) {
|
|
|
46
49
|
if (restoredSnapshot !== undefined) {
|
|
47
50
|
leaveSnapshotRun = enterSnapshotRun(restoredSnapshot);
|
|
48
51
|
}
|
|
49
|
-
const budget = options.budget ?? new Budget();
|
|
52
|
+
const budget = options.budget ?? new Budget({ maxCallDepth: DEFAULT_MAX_CALL_DEPTH });
|
|
50
53
|
budget.reset();
|
|
51
54
|
const filename = options.filename ?? "<input>";
|
|
52
55
|
const module = parseExecutableModule(source, filename);
|
|
@@ -189,6 +192,7 @@ export function run(source, options = {}) {
|
|
|
189
192
|
});
|
|
190
193
|
dumpController.finalize(snapshot);
|
|
191
194
|
await throwIfReturnedPromiseRejected(result);
|
|
195
|
+
await throwIfUnhandledPromiseRejected(promiseTracker);
|
|
192
196
|
return {
|
|
193
197
|
...result,
|
|
194
198
|
snapshot
|
|
@@ -218,13 +222,14 @@ export function run(source, options = {}) {
|
|
|
218
222
|
leaveSnapshotRun?.();
|
|
219
223
|
deactivateOtelSink();
|
|
220
224
|
}
|
|
221
|
-
})
|
|
225
|
+
});
|
|
222
226
|
return attachDumpController(result, dumpController);
|
|
223
227
|
}
|
|
224
228
|
async function throwIfReturnedPromiseRejected(result) {
|
|
225
229
|
if (!result.ok || !isSandboxPromise(result.returnValue)) {
|
|
226
230
|
return;
|
|
227
231
|
}
|
|
232
|
+
observeSandboxPromise(result.returnValue);
|
|
228
233
|
let rejected = false;
|
|
229
234
|
let rejectionReason;
|
|
230
235
|
result.returnValue.promise.then(() => undefined, (reason) => {
|
|
@@ -240,6 +245,12 @@ async function throwIfReturnedPromiseRejected(result) {
|
|
|
240
245
|
throw new UnhandledRejectionError(rejectionReason, result.returnValue.span);
|
|
241
246
|
}
|
|
242
247
|
}
|
|
248
|
+
async function throwIfUnhandledPromiseRejected(tracker) {
|
|
249
|
+
const unhandled = await tracker.findUnhandledRejection();
|
|
250
|
+
if (unhandled !== undefined) {
|
|
251
|
+
throw new UnhandledRejectionError(unhandled.reason, unhandled.span);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
243
254
|
async function callEntryPoint(input) {
|
|
244
255
|
const defaultExport = input.scope.lookup("default");
|
|
245
256
|
if (!defaultExport.found) {
|
|
@@ -2,6 +2,7 @@ import { readFile, stat } from "node:fs/promises";
|
|
|
2
2
|
import { extname } from "node:path";
|
|
3
3
|
import { supportsSpawnMode } from "@poe-code/agent-spawn/configs";
|
|
4
4
|
import { SPAWN_MODES } from "@poe-code/agent-spawn/types";
|
|
5
|
+
import { hasOwnErrorCode } from "../error-codes.js";
|
|
5
6
|
import { extractBlock } from "../loader/extract-block.js";
|
|
6
7
|
import { splitFrontmatter } from "../loader/frontmatter.js";
|
|
7
8
|
import { lint } from "../lint.js";
|
|
@@ -86,6 +87,10 @@ export async function runHarnessPair(filepath, options) {
|
|
|
86
87
|
const modules = options.modulesFor(frontmatter, meta);
|
|
87
88
|
const diagnostics = lint(executableSource, {
|
|
88
89
|
allowedExportNames: ["schema"],
|
|
90
|
+
defaultExport: {
|
|
91
|
+
parameters: ["frontmatter"],
|
|
92
|
+
required: true
|
|
93
|
+
},
|
|
89
94
|
filename: pair.scriptPath,
|
|
90
95
|
frontmatterFields: Object.keys(frontmatter),
|
|
91
96
|
modules: createLintModulesFromRuntimeRegistry(modules)
|
|
@@ -112,11 +117,19 @@ export async function runHarnessPair(filepath, options) {
|
|
|
112
117
|
});
|
|
113
118
|
}
|
|
114
119
|
async function readHarnessFile(filepath) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
try {
|
|
121
|
+
const stats = await stat(filepath);
|
|
122
|
+
if (!stats.isFile()) {
|
|
123
|
+
throw new Error(`Harness path must point to a file: ${filepath}`);
|
|
124
|
+
}
|
|
125
|
+
return await readFile(filepath, "utf8");
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
if (hasOwnErrorCode(error, "ENOENT") || hasOwnErrorCode(error, "ENOTDIR")) {
|
|
129
|
+
throw new Error(`Harness file not found: ${filepath}`);
|
|
130
|
+
}
|
|
131
|
+
throw error;
|
|
118
132
|
}
|
|
119
|
-
return readFile(filepath, "utf8");
|
|
120
133
|
}
|
|
121
134
|
function loadExecutableSource(filepath, source) {
|
|
122
135
|
if (extname(filepath) === ".ajs") {
|
|
@@ -136,7 +149,7 @@ function loadExecutableSource(filepath, source) {
|
|
|
136
149
|
const { source: executableBlock, lineOffset } = extractBlock(body);
|
|
137
150
|
const absoluteLineOffset = countLineBreaks(source.slice(0, source.length - body.length)) + lineOffset;
|
|
138
151
|
return {
|
|
139
|
-
executableSource: createLineOffsetSource(executableBlock, absoluteLineOffset),
|
|
152
|
+
executableSource: createLineOffsetSource(stripHashbang(executableBlock), absoluteLineOffset),
|
|
140
153
|
frontmatter,
|
|
141
154
|
isRawScript: false
|
|
142
155
|
};
|
|
@@ -202,6 +215,16 @@ function excludeHarnessModule(modules, isRawScript) {
|
|
|
202
215
|
function stripByteOrderMark(source) {
|
|
203
216
|
return source.startsWith("\uFEFF") ? source.slice(1) : source;
|
|
204
217
|
}
|
|
218
|
+
function stripHashbang(source) {
|
|
219
|
+
if (!source.startsWith("#!")) {
|
|
220
|
+
return source;
|
|
221
|
+
}
|
|
222
|
+
const lineBreakIndex = source.indexOf("\n");
|
|
223
|
+
if (lineBreakIndex === -1) {
|
|
224
|
+
return "";
|
|
225
|
+
}
|
|
226
|
+
return source.slice(lineBreakIndex + 1);
|
|
227
|
+
}
|
|
205
228
|
function countLineBreaks(source) {
|
|
206
229
|
let count = 0;
|
|
207
230
|
for (const character of source) {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CollectHumanPromptsOptions, CollectHumanPromptsResult, HumanPromptRecord, TraceReader } from "./types.js";
|
|
2
|
+
export declare function collectHumanPromptsFromReaders(readers: TraceReader[], options?: CollectHumanPromptsOptions): Promise<CollectHumanPromptsResult>;
|
|
3
|
+
export declare function collectHumanPrompts(options?: CollectHumanPromptsOptions): Promise<HumanPromptRecord[]>;
|
|
4
|
+
export declare function collectHumanPromptsWithStats(options?: CollectHumanPromptsOptions): Promise<CollectHumanPromptsResult>;
|