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
|
@@ -86,15 +86,16 @@ export async function interpret(node, options = {}) {
|
|
|
86
86
|
peakDataSize: { enumerable: false, value: 0, writable: true }
|
|
87
87
|
});
|
|
88
88
|
const activeLoopIterations = new Map();
|
|
89
|
+
const microtasks = [];
|
|
89
90
|
hoistVarDeclarations(node, scope);
|
|
90
|
-
const
|
|
91
|
+
const context = {
|
|
91
92
|
budget,
|
|
92
93
|
callStack: [],
|
|
93
94
|
onYield: options.onYield,
|
|
94
95
|
rootNode: node,
|
|
95
96
|
scope,
|
|
96
97
|
stats,
|
|
97
|
-
microtasks
|
|
98
|
+
microtasks,
|
|
98
99
|
activeLoopIterations,
|
|
99
100
|
restoredLoopIterations: new Map(Object.entries(options.snapshot?.loopIterations ?? {}).map(([nodeId, iteration]) => [
|
|
100
101
|
Number(nodeId),
|
|
@@ -102,7 +103,9 @@ export async function interpret(node, options = {}) {
|
|
|
102
103
|
])),
|
|
103
104
|
generatorResume: options.generatorResume,
|
|
104
105
|
generatorYield: options.generatorYield
|
|
105
|
-
}
|
|
106
|
+
};
|
|
107
|
+
const evaluation = await evaluateNode(node, context);
|
|
108
|
+
await drainMicrotasks(context);
|
|
106
109
|
const snapshot = scope.snapshot();
|
|
107
110
|
reconcileDataBudget(budget, stats, scope, "hasValue" in evaluation && evaluation.hasValue ? evaluation.value : undefined);
|
|
108
111
|
if (evaluation.kind === "error") {
|
|
@@ -143,6 +146,21 @@ export async function interpret(node, options = {}) {
|
|
|
143
146
|
};
|
|
144
147
|
}
|
|
145
148
|
export { Scope } from "./scope.js";
|
|
149
|
+
async function drainMicrotasks(context) {
|
|
150
|
+
let idleTurns = 0;
|
|
151
|
+
while (idleTurns < 20) {
|
|
152
|
+
const task = context.microtasks.shift();
|
|
153
|
+
if (task === undefined) {
|
|
154
|
+
idleTurns += 1;
|
|
155
|
+
await Promise.resolve();
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
idleTurns = 0;
|
|
159
|
+
context.budget.visitNode();
|
|
160
|
+
task();
|
|
161
|
+
await Promise.resolve();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
146
164
|
async function evaluateNode(node, context) {
|
|
147
165
|
context.budget.visitNode();
|
|
148
166
|
context.stats.nodeVisits += 1;
|
|
@@ -225,7 +243,7 @@ async function evaluateArrayExpression(node, context) {
|
|
|
225
243
|
if (!spreadValues.ok) {
|
|
226
244
|
return spreadValues.result;
|
|
227
245
|
}
|
|
228
|
-
values
|
|
246
|
+
appendArrayValues(values, spreadValues.value);
|
|
229
247
|
context.budget.allocateArrayLength(values.length);
|
|
230
248
|
continue;
|
|
231
249
|
}
|
|
@@ -263,6 +281,9 @@ async function evaluateObjectExpression(node, context) {
|
|
|
263
281
|
if (value.kind !== "normal") {
|
|
264
282
|
return value;
|
|
265
283
|
}
|
|
284
|
+
if (isObjectPrototypeSetterProperty(property, key.value)) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
266
287
|
defineSandboxProperty(object, String(key.value), value.value);
|
|
267
288
|
}
|
|
268
289
|
return {
|
|
@@ -271,6 +292,9 @@ async function evaluateObjectExpression(node, context) {
|
|
|
271
292
|
value: object
|
|
272
293
|
};
|
|
273
294
|
}
|
|
295
|
+
function isObjectPrototypeSetterProperty(property, key) {
|
|
296
|
+
return !property.computed && !property.shorthand && key === "__proto__";
|
|
297
|
+
}
|
|
274
298
|
async function evaluateTemplateLiteral(node, context) {
|
|
275
299
|
let value = context.budget.allocateString(node.quasis[0]?.value.cooked ?? "");
|
|
276
300
|
for (let index = 0; index < node.expressions.length; index += 1) {
|
|
@@ -326,7 +350,9 @@ async function evaluateTemplateExpressionValues(node, context) {
|
|
|
326
350
|
}
|
|
327
351
|
function createTaggedTemplateStrings(node, context) {
|
|
328
352
|
context.budget.allocateArrayLength(node.quasis.length);
|
|
329
|
-
const strings = node.quasis.map((quasi) =>
|
|
353
|
+
const strings = node.quasis.map((quasi) => quasi.value.cooked === undefined
|
|
354
|
+
? undefined
|
|
355
|
+
: context.budget.allocateString(quasi.value.cooked));
|
|
330
356
|
context.budget.allocateArrayLength(node.quasis.length);
|
|
331
357
|
const raw = node.quasis.map((quasi) => context.budget.allocateString(quasi.value.raw));
|
|
332
358
|
Object.defineProperty(strings, "raw", {
|
|
@@ -565,7 +591,7 @@ async function evaluateIdentifier(node, context) {
|
|
|
565
591
|
if (!binding.found) {
|
|
566
592
|
return {
|
|
567
593
|
kind: "error",
|
|
568
|
-
error: createError("UNBOUND_IDENTIFIER", node, `Identifier '${node.name}' is not defined
|
|
594
|
+
error: createError("UNBOUND_IDENTIFIER", node, `Identifier '${node.name}' is not defined.`, context.callStack)
|
|
569
595
|
};
|
|
570
596
|
}
|
|
571
597
|
return {
|
|
@@ -609,6 +635,12 @@ async function evaluateVariableDeclaration(node, context) {
|
|
|
609
635
|
predeclareDeclarationBindings(node, context.scope);
|
|
610
636
|
}
|
|
611
637
|
for (const declarator of node.declarations) {
|
|
638
|
+
if (node.kind === "var" &&
|
|
639
|
+
declarator.init === undefined &&
|
|
640
|
+
declarator.id.type === "Identifier" &&
|
|
641
|
+
context.scope.lookup(declarator.id.name).found) {
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
612
644
|
const restoredValue = declarator.id.type === "Identifier"
|
|
613
645
|
? context.scope.consumeRestoredBinding(declarator.id.name)
|
|
614
646
|
: { found: false };
|
|
@@ -774,11 +806,21 @@ function predeclareStatementListBindings(statements, context) {
|
|
|
774
806
|
for (const statement of statements) {
|
|
775
807
|
if (statement.type === "FunctionDeclaration") {
|
|
776
808
|
const name = statement.id.name;
|
|
777
|
-
if (names.has(name)
|
|
809
|
+
if (names.has(name)) {
|
|
810
|
+
throw new Error(`Cannot redeclare binding '${name}' in the same scope.`);
|
|
811
|
+
}
|
|
812
|
+
const closure = createInterpretedClosure(statement, context, evaluateNode);
|
|
813
|
+
const ownBindingKind = scope.getOwnBindingKind(name);
|
|
814
|
+
if (ownBindingKind === "var") {
|
|
815
|
+
names.add(name);
|
|
816
|
+
scope.assign(name, closure);
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
if (ownBindingKind !== undefined) {
|
|
778
820
|
throw new Error(`Cannot redeclare binding '${name}' in the same scope.`);
|
|
779
821
|
}
|
|
780
822
|
names.add(name);
|
|
781
|
-
scope.declare(name, "const",
|
|
823
|
+
scope.declare(name, "const", closure);
|
|
782
824
|
continue;
|
|
783
825
|
}
|
|
784
826
|
if (statement.type !== "VariableDeclaration" || statement.kind === "var") {
|
|
@@ -1380,7 +1422,7 @@ async function evaluateUnaryExpression(node, context) {
|
|
|
1380
1422
|
return {
|
|
1381
1423
|
kind: "normal",
|
|
1382
1424
|
hasValue: true,
|
|
1383
|
-
value: applyUnaryOperator(node.operator, argument.value)
|
|
1425
|
+
value: await applyUnaryOperator(node.operator, argument.value, context)
|
|
1384
1426
|
};
|
|
1385
1427
|
}
|
|
1386
1428
|
async function evaluateDeleteExpression(node, context) {
|
|
@@ -1634,8 +1676,9 @@ function getConstructorName(callee) {
|
|
|
1634
1676
|
function formatStackFrame(node, name) {
|
|
1635
1677
|
return ` at ${name ?? "<anonymous>"} (line ${node.span.start.line}, column ${node.span.start.column})`;
|
|
1636
1678
|
}
|
|
1637
|
-
function createError(code, node, message) {
|
|
1679
|
+
function createError(code, node, message, stackFrames = []) {
|
|
1638
1680
|
const name = code === "UNBOUND_IDENTIFIER" ? "ReferenceError" : "Error";
|
|
1681
|
+
const stack = [...stackFrames, formatStackFrame(node, undefined)];
|
|
1639
1682
|
return {
|
|
1640
1683
|
code,
|
|
1641
1684
|
message,
|
|
@@ -1643,7 +1686,7 @@ function createError(code, node, message) {
|
|
|
1643
1686
|
nodeId: node.nodeId,
|
|
1644
1687
|
nodeType: node.type,
|
|
1645
1688
|
span: node.span,
|
|
1646
|
-
stack: formatErrorStack(name, message,
|
|
1689
|
+
stack: formatErrorStack(name, message, stack)
|
|
1647
1690
|
};
|
|
1648
1691
|
}
|
|
1649
1692
|
function attachFatalSandboxErrorContext(error, node, stackFrames) {
|
|
@@ -1900,7 +1943,7 @@ async function evaluateSetMethodCall(node, target, methodName, context) {
|
|
|
1900
1943
|
leaveCall();
|
|
1901
1944
|
}
|
|
1902
1945
|
}
|
|
1903
|
-
function applyUnaryOperator(operator, value) {
|
|
1946
|
+
async function applyUnaryOperator(operator, value, context) {
|
|
1904
1947
|
switch (operator) {
|
|
1905
1948
|
case "!":
|
|
1906
1949
|
return !value;
|
|
@@ -1911,11 +1954,11 @@ function applyUnaryOperator(operator, value) {
|
|
|
1911
1954
|
case "void":
|
|
1912
1955
|
return undefined;
|
|
1913
1956
|
case "+":
|
|
1914
|
-
return toNumber(value);
|
|
1957
|
+
return toNumber(await toNumericPrimitive(value, context));
|
|
1915
1958
|
case "-":
|
|
1916
|
-
return -toNumber(value);
|
|
1959
|
+
return -toNumber(await toNumericPrimitive(value, context));
|
|
1917
1960
|
case "~":
|
|
1918
|
-
return ~toNumber(value);
|
|
1961
|
+
return ~toNumber(await toNumericPrimitive(value, context));
|
|
1919
1962
|
}
|
|
1920
1963
|
}
|
|
1921
1964
|
function describeTypeofValue(value) {
|
|
@@ -1928,7 +1971,7 @@ function describeTypeofValue(value) {
|
|
|
1928
1971
|
return typeof value;
|
|
1929
1972
|
}
|
|
1930
1973
|
function isTruthy(value) {
|
|
1931
|
-
return
|
|
1974
|
+
return Boolean(value);
|
|
1932
1975
|
}
|
|
1933
1976
|
function applyBinaryOperator(node, left, right, context) {
|
|
1934
1977
|
switch (node.operator) {
|
|
@@ -2112,6 +2155,24 @@ function toPrimitive(value) {
|
|
|
2112
2155
|
}
|
|
2113
2156
|
return toString(value);
|
|
2114
2157
|
}
|
|
2158
|
+
async function toNumericPrimitive(value, context) {
|
|
2159
|
+
if (isPrimitiveCoercionType(getCoercionType(value))) {
|
|
2160
|
+
return value;
|
|
2161
|
+
}
|
|
2162
|
+
if (isIndexableSandboxValue(value)) {
|
|
2163
|
+
for (const methodName of ["valueOf", "toString"]) {
|
|
2164
|
+
const method = getMemberValue(value, methodName, context);
|
|
2165
|
+
if (!isSandboxClosure(method)) {
|
|
2166
|
+
continue;
|
|
2167
|
+
}
|
|
2168
|
+
const result = await invokeSandboxClosure(method, [], context, context.callStack, undefined, value);
|
|
2169
|
+
if (isPrimitiveCoercionType(getCoercionType(result))) {
|
|
2170
|
+
return result;
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
return toString(value);
|
|
2175
|
+
}
|
|
2115
2176
|
function toNumber(value) {
|
|
2116
2177
|
if (typeof value === "number") {
|
|
2117
2178
|
return value;
|
|
@@ -2144,6 +2205,11 @@ function toString(value) {
|
|
|
2144
2205
|
function isIndexableSandboxValue(value) {
|
|
2145
2206
|
return Array.isArray(value) || isPlainSandboxObject(value);
|
|
2146
2207
|
}
|
|
2208
|
+
function appendArrayValues(target, values) {
|
|
2209
|
+
for (const value of values) {
|
|
2210
|
+
target.push(value);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2147
2213
|
function isPlainSandboxObject(value) {
|
|
2148
2214
|
return (typeof value === "object" &&
|
|
2149
2215
|
value !== null &&
|
|
@@ -2287,7 +2353,7 @@ async function evaluateCallArguments(args, context) {
|
|
|
2287
2353
|
if (!spreadValues.ok) {
|
|
2288
2354
|
return spreadValues;
|
|
2289
2355
|
}
|
|
2290
|
-
values
|
|
2356
|
+
appendArrayValues(values, spreadValues.value);
|
|
2291
2357
|
context.budget.allocateArrayLength(values.length);
|
|
2292
2358
|
continue;
|
|
2293
2359
|
}
|
|
@@ -180,7 +180,8 @@ async function callArrayMethodUnlocked(value, methodName, args, options, stack)
|
|
|
180
180
|
return budgetProducedValue(result, options.budget);
|
|
181
181
|
}
|
|
182
182
|
case "push": {
|
|
183
|
-
|
|
183
|
+
appendArrayValues(value, args);
|
|
184
|
+
const nextLength = value.length;
|
|
184
185
|
budgetProducedValue(value, options.budget);
|
|
185
186
|
return nextLength;
|
|
186
187
|
}
|
|
@@ -189,12 +190,34 @@ async function callArrayMethodUnlocked(value, methodName, args, options, stack)
|
|
|
189
190
|
case "shift":
|
|
190
191
|
return budgetProducedValue(value.shift(), options.budget);
|
|
191
192
|
case "unshift": {
|
|
192
|
-
|
|
193
|
+
prependArrayValues(value, args);
|
|
194
|
+
const nextLength = value.length;
|
|
193
195
|
budgetProducedValue(value, options.budget);
|
|
194
196
|
return nextLength;
|
|
195
197
|
}
|
|
196
198
|
}
|
|
197
199
|
}
|
|
200
|
+
function appendArrayValues(target, values) {
|
|
201
|
+
for (const value of values) {
|
|
202
|
+
target.push(value);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function prependArrayValues(target, values) {
|
|
206
|
+
const originalLength = target.length;
|
|
207
|
+
target.length = originalLength + values.length;
|
|
208
|
+
for (let index = originalLength - 1; index >= 0; index -= 1) {
|
|
209
|
+
const targetIndex = index + values.length;
|
|
210
|
+
if (Object.hasOwn(target, index)) {
|
|
211
|
+
target[targetIndex] = target[index];
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
delete target[targetIndex];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
218
|
+
target[index] = values[index];
|
|
219
|
+
}
|
|
220
|
+
}
|
|
198
221
|
function isCallbackArrayMethod(methodName) {
|
|
199
222
|
return (methodName === "map" ||
|
|
200
223
|
methodName === "filter" ||
|
|
@@ -39,6 +39,6 @@ export function toMatchArray(match, input) {
|
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
const result = [match.text, ...match.captures];
|
|
42
|
-
Object.assign(result, { index: match.index, input });
|
|
42
|
+
Object.assign(result, { groups: undefined, index: match.index, input });
|
|
43
43
|
return result;
|
|
44
44
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ErrorSourceSpan } from "../error/shape.js";
|
|
2
|
+
import type { SandboxPromise, SandboxValue } from "./values.js";
|
|
3
|
+
export declare class SandboxPromiseRejectionTracker {
|
|
4
|
+
private readonly records;
|
|
5
|
+
private readonly recordsByPromise;
|
|
6
|
+
observe(promise: SandboxPromise): void;
|
|
7
|
+
track(promise: SandboxPromise): void;
|
|
8
|
+
findUnhandledRejection(): Promise<{
|
|
9
|
+
reason: SandboxValue | undefined;
|
|
10
|
+
span: ErrorSourceSpan | undefined;
|
|
11
|
+
} | undefined>;
|
|
12
|
+
}
|
|
13
|
+
export declare function createSandboxPromiseRejectionTracker(): SandboxPromiseRejectionTracker;
|
|
14
|
+
export declare function observeSandboxPromise(promise: SandboxPromise): void;
|
|
15
|
+
export declare function trackSandboxPromise(promise: SandboxPromise): void;
|
|
16
|
+
export declare function withSandboxPromiseRejectionTracker<TResult>(tracker: SandboxPromiseRejectionTracker, callback: () => TResult): TResult;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
export class SandboxPromiseRejectionTracker {
|
|
3
|
+
records = new Set();
|
|
4
|
+
recordsByPromise = new WeakMap();
|
|
5
|
+
observe(promise) {
|
|
6
|
+
const record = this.recordsByPromise.get(promise);
|
|
7
|
+
if (record !== undefined) {
|
|
8
|
+
record.observed = true;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
track(promise) {
|
|
12
|
+
if (this.recordsByPromise.has(promise)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const record = {
|
|
16
|
+
observed: false,
|
|
17
|
+
promise,
|
|
18
|
+
rejected: false
|
|
19
|
+
};
|
|
20
|
+
this.records.add(record);
|
|
21
|
+
this.recordsByPromise.set(promise, record);
|
|
22
|
+
promise.promise.then(() => undefined, (reason) => {
|
|
23
|
+
record.rejected = true;
|
|
24
|
+
record.rejectionReason = reason;
|
|
25
|
+
});
|
|
26
|
+
promise.promise.catch(() => undefined);
|
|
27
|
+
}
|
|
28
|
+
async findUnhandledRejection() {
|
|
29
|
+
await flushPromiseJobs();
|
|
30
|
+
for (const record of this.records) {
|
|
31
|
+
if (record.rejected && !record.observed) {
|
|
32
|
+
return {
|
|
33
|
+
reason: record.rejectionReason,
|
|
34
|
+
span: record.promise.span
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const activePromiseTracker = new AsyncLocalStorage();
|
|
42
|
+
export function createSandboxPromiseRejectionTracker() {
|
|
43
|
+
return new SandboxPromiseRejectionTracker();
|
|
44
|
+
}
|
|
45
|
+
export function observeSandboxPromise(promise) {
|
|
46
|
+
activePromiseTracker.getStore()?.observe(promise);
|
|
47
|
+
}
|
|
48
|
+
export function trackSandboxPromise(promise) {
|
|
49
|
+
activePromiseTracker.getStore()?.track(promise);
|
|
50
|
+
}
|
|
51
|
+
export function withSandboxPromiseRejectionTracker(tracker, callback) {
|
|
52
|
+
return activePromiseTracker.run(tracker, callback);
|
|
53
|
+
}
|
|
54
|
+
async function flushPromiseJobs() {
|
|
55
|
+
for (let index = 0; index < 20; index += 1) {
|
|
56
|
+
await Promise.resolve();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SandboxError } from "./budget.js";
|
|
2
|
+
import { observeSandboxPromise } from "./promise-tracker.js";
|
|
2
3
|
import { createSandboxClosure, createSandboxPromise, isSandboxClosure, isSandboxPromise } from "./values.js";
|
|
3
4
|
export function createPromiseGlobals(options) {
|
|
4
5
|
return {
|
|
@@ -54,21 +55,33 @@ export function getPromiseMember(target, property, budget, enqueue = (task) => P
|
|
|
54
55
|
if (property === "then") {
|
|
55
56
|
return createSandboxClosure({
|
|
56
57
|
async: true,
|
|
57
|
-
call: ([onFulfilled, onRejected]) =>
|
|
58
|
+
call: ([onFulfilled, onRejected]) => {
|
|
59
|
+
observeSandboxPromise(target);
|
|
60
|
+
const chained = createSandboxPromise(enqueue(() => target.promise.then((value) => runPromiseReaction(onFulfilled, value, "fulfilled", budget, chained), (reason) => runPromiseReaction(onRejected, reason, "rejected", budget, chained))));
|
|
61
|
+
return chained;
|
|
62
|
+
},
|
|
58
63
|
name: "then"
|
|
59
64
|
});
|
|
60
65
|
}
|
|
61
66
|
if (property === "catch") {
|
|
62
67
|
return createSandboxClosure({
|
|
63
68
|
async: true,
|
|
64
|
-
call: ([onRejected]) =>
|
|
69
|
+
call: ([onRejected]) => {
|
|
70
|
+
observeSandboxPromise(target);
|
|
71
|
+
const chained = createSandboxPromise(enqueue(() => target.promise.then((value) => runPromiseReaction(undefined, value, "fulfilled", budget, chained), (reason) => runPromiseReaction(onRejected, reason, "rejected", budget, chained))));
|
|
72
|
+
return chained;
|
|
73
|
+
},
|
|
65
74
|
name: "catch"
|
|
66
75
|
});
|
|
67
76
|
}
|
|
68
77
|
if (property === "finally") {
|
|
69
78
|
return createSandboxClosure({
|
|
70
79
|
async: true,
|
|
71
|
-
call: ([onFinally]) =>
|
|
80
|
+
call: ([onFinally]) => {
|
|
81
|
+
observeSandboxPromise(target);
|
|
82
|
+
const chained = createSandboxPromise(enqueue(() => target.promise.then((value) => runPromiseFinally(onFinally, value, "fulfilled", budget, chained), (reason) => runPromiseFinally(onFinally, reason, "rejected", budget, chained))));
|
|
83
|
+
return chained;
|
|
84
|
+
},
|
|
72
85
|
name: "finally"
|
|
73
86
|
});
|
|
74
87
|
}
|
|
@@ -140,6 +153,7 @@ function resolveSandboxValueNow(value, options, seenThenables) {
|
|
|
140
153
|
return Promise.resolve(value).then((resolved) => resolveSandboxValueNow(resolved, options, seenThenables), (reason) => Promise.reject(budgetIfNeeded(reason, options.budget)));
|
|
141
154
|
}
|
|
142
155
|
if (isSandboxPromise(value)) {
|
|
156
|
+
observeSandboxPromise(value);
|
|
143
157
|
return value.promise.then((resolved) => {
|
|
144
158
|
value.hostCallJournal?.consume(value.hostCall);
|
|
145
159
|
return resolveSandboxValueNow(resolved, options, seenThenables);
|
|
@@ -226,30 +240,47 @@ function resolveThenable(value, then, options, seenThenables) {
|
|
|
226
240
|
}
|
|
227
241
|
}).then((resolved) => budgetIfNeeded(resolved, options.budget));
|
|
228
242
|
}
|
|
229
|
-
function runPromiseReaction(handler, value, state, budget) {
|
|
243
|
+
function runPromiseReaction(handler, value, state, budget, self) {
|
|
230
244
|
if (!isSandboxClosure(handler)) {
|
|
231
245
|
return state === "fulfilled"
|
|
232
246
|
? Promise.resolve(value)
|
|
233
247
|
: Promise.reject(budgetSandboxValue(value, budget));
|
|
234
248
|
}
|
|
235
249
|
try {
|
|
236
|
-
|
|
250
|
+
const result = handler.call([value]);
|
|
251
|
+
return resolveReactionResult(result, budget, self);
|
|
237
252
|
}
|
|
238
253
|
catch (error) {
|
|
239
254
|
return Promise.reject(error);
|
|
240
255
|
}
|
|
241
256
|
}
|
|
242
|
-
function runPromiseFinally(handler, value, state, budget) {
|
|
257
|
+
function runPromiseFinally(handler, value, state, budget, self) {
|
|
243
258
|
if (!isSandboxClosure(handler)) {
|
|
244
259
|
return runPromiseReaction(undefined, value, state, budget);
|
|
245
260
|
}
|
|
246
261
|
try {
|
|
247
|
-
|
|
262
|
+
const result = handler.call([]);
|
|
263
|
+
return resolveReactionResult(result, budget, self).then(() => runPromiseReaction(undefined, value, state, budget));
|
|
248
264
|
}
|
|
249
265
|
catch (error) {
|
|
250
266
|
return Promise.reject(error);
|
|
251
267
|
}
|
|
252
268
|
}
|
|
269
|
+
function resolveReactionResult(result, budget, self) {
|
|
270
|
+
return Promise.resolve(result).then((resolved) => {
|
|
271
|
+
if (isSelfResolution(resolved, self)) {
|
|
272
|
+
return Promise.reject({
|
|
273
|
+
message: "Promise cannot resolve to itself.",
|
|
274
|
+
name: "TypeError"
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
return resolveSandboxValue(resolved, { budget });
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function isSelfResolution(result, self) {
|
|
281
|
+
return (self !== undefined &&
|
|
282
|
+
(result === self || (isSandboxPromise(result) && result.promise === self.promise)));
|
|
283
|
+
}
|
|
253
284
|
function getThenable(value) {
|
|
254
285
|
if (typeof value !== "object" ||
|
|
255
286
|
value === null ||
|
|
@@ -25,6 +25,7 @@ export declare class Scope {
|
|
|
25
25
|
found: false;
|
|
26
26
|
};
|
|
27
27
|
hasOwnBinding(name: string): boolean;
|
|
28
|
+
getOwnBindingKind(name: string): VariableDeclarationKind | undefined;
|
|
28
29
|
isFunctionBoundary(): boolean;
|
|
29
30
|
iterationChild(names: readonly string[]): Scope;
|
|
30
31
|
lookupImportMeta(): InterpreterValue;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
|
|
2
2
|
import { SandboxError } from "./budget.js";
|
|
3
|
+
import { trackSandboxPromise } from "./promise-tracker.js";
|
|
3
4
|
import { parseRegex } from "./regex/parse.js";
|
|
4
5
|
import { assertSandboxDataDepth } from "../graph-depth.js";
|
|
5
6
|
const sandboxClosureBrand = Symbol("SandboxClosure");
|
|
@@ -57,6 +58,7 @@ export function createSandboxPromise(promise, metadata = {}) {
|
|
|
57
58
|
value: metadata.hostCallJournal
|
|
58
59
|
});
|
|
59
60
|
}
|
|
61
|
+
trackSandboxPromise(sandboxPromise);
|
|
60
62
|
return Object.freeze(sandboxPromise);
|
|
61
63
|
}
|
|
62
64
|
export function createSandboxGenerator(channel, metadata = undefined) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DefaultExportSignature } from "./rules/AS-export-import-meta.js";
|
|
1
2
|
import { type SourceSpan } from "../parse/parser.js";
|
|
2
3
|
import type { Modules } from "./rules/module-registry.js";
|
|
3
4
|
export type Diagnostic = {
|
|
@@ -18,6 +19,7 @@ export type Fix = {
|
|
|
18
19
|
export type LintOptions = {
|
|
19
20
|
allowedExportNames?: readonly string[];
|
|
20
21
|
allowedGlobals?: readonly string[];
|
|
22
|
+
defaultExport?: DefaultExportSignature;
|
|
21
23
|
fix?: boolean;
|
|
22
24
|
filename?: string;
|
|
23
25
|
largeLiteralThreshold?: number;
|
|
@@ -77,9 +77,11 @@ const KNOWN_DIAGNOSTIC_CODES = new Set([
|
|
|
77
77
|
"AS015",
|
|
78
78
|
"AS-ASYNC-NOT-NEEDED",
|
|
79
79
|
"AS-AWAIT-NON-PROMISE",
|
|
80
|
+
"AS-EXPORT-DEFAULT-MISSING",
|
|
80
81
|
"AS-DESTRUCTURE-NULL-DEFAULT",
|
|
81
82
|
"AS-EXPORT-DEFAULT-MULTIPLE",
|
|
82
83
|
"AS-EXPORT-DEFAULT-NOT-ARROW",
|
|
84
|
+
"AS-EXPORT-DEFAULT-SIGNATURE",
|
|
83
85
|
"AS-EXPORT-IMPORT-META",
|
|
84
86
|
"AS-EXPORT-UNKNOWN",
|
|
85
87
|
"AS-FLOATING-PROMISE",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type SourceSpan } from "../../parse/parser.js";
|
|
2
|
-
type DiagnosticCode = "AS-EXPORT-DEFAULT-MULTIPLE" | "AS-EXPORT-DEFAULT-NOT-ARROW" | "AS-EXPORT-UNKNOWN" | "AS-IMPORT-META-ASSIGN" | "AS-RETURN-AT-TOP";
|
|
2
|
+
type DiagnosticCode = "AS-EXPORT-DEFAULT-MISSING" | "AS-EXPORT-DEFAULT-MULTIPLE" | "AS-EXPORT-DEFAULT-NOT-ARROW" | "AS-EXPORT-DEFAULT-SIGNATURE" | "AS-EXPORT-UNKNOWN" | "AS-IMPORT-META-ASSIGN" | "AS-RETURN-AT-TOP";
|
|
3
3
|
export type Diagnostic = {
|
|
4
4
|
code: DiagnosticCode;
|
|
5
5
|
severity: "error" | "warning";
|
|
@@ -9,8 +9,13 @@ export type Diagnostic = {
|
|
|
9
9
|
column: number;
|
|
10
10
|
span: SourceSpan;
|
|
11
11
|
};
|
|
12
|
+
export type DefaultExportSignature = {
|
|
13
|
+
parameters?: readonly string[];
|
|
14
|
+
required?: boolean;
|
|
15
|
+
};
|
|
12
16
|
export declare function AS_EXPORT_IMPORT_META(source: string, options?: {
|
|
13
17
|
allowedExportNames?: readonly string[];
|
|
18
|
+
defaultExport?: DefaultExportSignature;
|
|
14
19
|
filename?: string;
|
|
15
20
|
}): Diagnostic[];
|
|
16
21
|
export {};
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { parseModule } from "../../parse/parser.js";
|
|
2
2
|
export function AS_EXPORT_IMPORT_META(source, options = {}) {
|
|
3
|
-
return new Scanner(options.filename ?? "<input>", new Set(options.allowedExportNames ?? [])).scan(source);
|
|
3
|
+
return new Scanner(options.filename ?? "<input>", new Set(options.allowedExportNames ?? []), options.defaultExport).scan(source);
|
|
4
4
|
}
|
|
5
5
|
class Scanner {
|
|
6
6
|
filename;
|
|
7
7
|
allowedExportNames;
|
|
8
|
+
defaultExport;
|
|
8
9
|
diagnostics = [];
|
|
9
|
-
constructor(filename, allowedExportNames) {
|
|
10
|
+
constructor(filename, allowedExportNames, defaultExport) {
|
|
10
11
|
this.filename = filename;
|
|
11
12
|
this.allowedExportNames = allowedExportNames;
|
|
13
|
+
this.defaultExport = defaultExport;
|
|
12
14
|
}
|
|
13
15
|
scan(source) {
|
|
14
16
|
this.visitModule(parseModule(source, this.filename));
|
|
@@ -17,6 +19,9 @@ class Scanner {
|
|
|
17
19
|
visitModule(node) {
|
|
18
20
|
const defaultExports = node.body.filter((statement) => statement.type === "ExportDefaultDeclaration");
|
|
19
21
|
const hasDefaultExport = defaultExports.length > 0;
|
|
22
|
+
if (!hasDefaultExport && this.defaultExport?.required === true) {
|
|
23
|
+
this.pushDiagnostic("AS-EXPORT-DEFAULT-MISSING", "error", "Module must export a default entry point.", node.span);
|
|
24
|
+
}
|
|
20
25
|
for (const [index, statement] of defaultExports.entries()) {
|
|
21
26
|
if (index > 0) {
|
|
22
27
|
this.pushDiagnostic("AS-EXPORT-DEFAULT-MULTIPLE", "error", "Module contains more than one export default declaration.", statement.span);
|
|
@@ -35,8 +40,11 @@ class Scanner {
|
|
|
35
40
|
this.visitExportNamedDeclaration(node.declaration);
|
|
36
41
|
return;
|
|
37
42
|
case "ExportDefaultDeclaration":
|
|
38
|
-
if (node.declaration
|
|
39
|
-
this.pushDiagnostic("AS-EXPORT-DEFAULT-NOT-ARROW", "error", "Export default initializer must be an arrow expression.", node.declaration.span);
|
|
43
|
+
if (!isDefaultExportCallable(node.declaration)) {
|
|
44
|
+
this.pushDiagnostic("AS-EXPORT-DEFAULT-NOT-ARROW", "error", "Export default initializer must be an arrow or function expression.", node.declaration.span);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.visitDefaultExportSignature(node.declaration);
|
|
40
48
|
}
|
|
41
49
|
this.visitExpression(node.declaration);
|
|
42
50
|
return;
|
|
@@ -89,6 +97,15 @@ class Scanner {
|
|
|
89
97
|
}
|
|
90
98
|
this.visitVariableDeclaration(node);
|
|
91
99
|
}
|
|
100
|
+
visitDefaultExportSignature(node) {
|
|
101
|
+
const parameters = this.defaultExport?.parameters;
|
|
102
|
+
if (parameters === undefined) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (!hasParameterNames(node, parameters)) {
|
|
106
|
+
this.pushDiagnostic("AS-EXPORT-DEFAULT-SIGNATURE", "error", `Default export must declare signature (${parameters.join(", ")}).`, node.span);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
92
109
|
visitIfStatement(node) {
|
|
93
110
|
this.visitExpression(node.test);
|
|
94
111
|
this.visitStatement(node.consequent);
|
|
@@ -162,6 +179,9 @@ class Scanner {
|
|
|
162
179
|
this.visitExpression(node.body);
|
|
163
180
|
}
|
|
164
181
|
return;
|
|
182
|
+
case "FunctionExpression":
|
|
183
|
+
this.visitStatement(node.body);
|
|
184
|
+
return;
|
|
165
185
|
case "AwaitExpression":
|
|
166
186
|
this.visitExpression(node.argument);
|
|
167
187
|
return;
|
|
@@ -314,6 +334,15 @@ class Scanner {
|
|
|
314
334
|
});
|
|
315
335
|
}
|
|
316
336
|
}
|
|
337
|
+
function isDefaultExportCallable(node) {
|
|
338
|
+
return node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression";
|
|
339
|
+
}
|
|
340
|
+
function hasParameterNames(node, names) {
|
|
341
|
+
if (node.params.length !== names.length) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
return node.params.every((param, index) => param.type === "Identifier" && param.name === names[index]);
|
|
345
|
+
}
|
|
317
346
|
function isImportMetaReference(node) {
|
|
318
347
|
if (node.type === "MetaProperty") {
|
|
319
348
|
return true;
|
|
@@ -147,10 +147,11 @@ async function runSpawnAttempt(spawnAgent, input, onEvent, spawnId) {
|
|
|
147
147
|
}
|
|
148
148
|
function runObservedSpawn(moduleSink, input, operation) {
|
|
149
149
|
const otelSink = input.otelSink ?? moduleSink ?? getActiveOtelSink();
|
|
150
|
+
const cwd = input.cwd ?? readCurrentWorkingDirectory();
|
|
150
151
|
const span = safeStartSpan(otelSink, "agent.spawn", {
|
|
151
152
|
agent: input.agent,
|
|
152
153
|
mode: input.mode ?? "yolo",
|
|
153
|
-
cwd
|
|
154
|
+
cwd
|
|
154
155
|
});
|
|
155
156
|
const deactivateSpan = activateOtelSpan(span);
|
|
156
157
|
safeAddEvent(span, "prompt", { prompt: input.prompt });
|
|
@@ -176,6 +177,14 @@ function runObservedSpawn(moduleSink, input, operation) {
|
|
|
176
177
|
bindOtelSpan(promise, span);
|
|
177
178
|
return promise;
|
|
178
179
|
}
|
|
180
|
+
function readCurrentWorkingDirectory() {
|
|
181
|
+
try {
|
|
182
|
+
return process.cwd();
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
throw new Error(`Unable to resolve current working directory: ${formatSpawnError(error)}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
179
188
|
async function runSpawnRetry(spawnAgent, input, retryOptions, onEvent, spawnId, throwOnResultFailure = true) {
|
|
180
189
|
const task = resolveTaskLabel(input);
|
|
181
190
|
const startedAt = Date.now();
|