poe-code 3.0.257 → 3.0.259-beta.1
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,10 +1,6 @@
|
|
|
1
1
|
import type { SpawnMode, SpawnOptions, SpawnResult, SpawnUsage } from "../../agent-spawn/dist/index.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
stat(path: string): Promise<{
|
|
5
|
-
isFile(): boolean;
|
|
6
|
-
}>;
|
|
7
|
-
}
|
|
2
|
+
import type { AgentTraceFileSystem, AgentTraceSource, CollectHumanPromptsOptions, CollectHumanPromptsResult } from "../../agent-traces/dist/index.js";
|
|
3
|
+
export type GaslightFileSystem = AgentTraceFileSystem;
|
|
8
4
|
export type GaslightSpawn = (agent: string, options: SpawnOptions) => Promise<SpawnResult>;
|
|
9
5
|
export type GaslightEvent = {
|
|
10
6
|
type: "round.started";
|
|
@@ -33,6 +29,7 @@ export interface GaslightOptions {
|
|
|
33
29
|
mode?: Exclude<SpawnMode, "auto">;
|
|
34
30
|
cwd?: string;
|
|
35
31
|
homeDir?: string;
|
|
32
|
+
configPath?: string;
|
|
36
33
|
prompt?: string;
|
|
37
34
|
followups?: string[];
|
|
38
35
|
onEvent?: (event: GaslightEvent) => void;
|
|
@@ -45,3 +42,41 @@ export interface GaslightConfig {
|
|
|
45
42
|
followups: string[];
|
|
46
43
|
path: string;
|
|
47
44
|
}
|
|
45
|
+
export type GaslightCollectHumanPrompts = (options: CollectHumanPromptsOptions) => Promise<CollectHumanPromptsResult>;
|
|
46
|
+
export type GaslightIngestEvent = {
|
|
47
|
+
type: "traces.discovered";
|
|
48
|
+
count: number;
|
|
49
|
+
} | {
|
|
50
|
+
type: "prompts.extracted";
|
|
51
|
+
traces: number;
|
|
52
|
+
prompts: number;
|
|
53
|
+
} | {
|
|
54
|
+
type: "analysis.started";
|
|
55
|
+
agent: string;
|
|
56
|
+
dataPath: string;
|
|
57
|
+
} | {
|
|
58
|
+
type: "config.written";
|
|
59
|
+
path: string;
|
|
60
|
+
};
|
|
61
|
+
export interface GaslightIngestOptions {
|
|
62
|
+
sources?: AgentTraceSource[];
|
|
63
|
+
analysisAgent: string;
|
|
64
|
+
model?: string;
|
|
65
|
+
cwd?: string;
|
|
66
|
+
homeDir?: string;
|
|
67
|
+
since?: string | Date;
|
|
68
|
+
limit?: number;
|
|
69
|
+
allWorkspaces?: boolean;
|
|
70
|
+
outputPath?: string;
|
|
71
|
+
keepDataPath?: string;
|
|
72
|
+
onEvent?: (event: GaslightIngestEvent) => void;
|
|
73
|
+
fs?: GaslightFileSystem;
|
|
74
|
+
spawn?: GaslightSpawn;
|
|
75
|
+
collectHumanPrompts?: GaslightCollectHumanPrompts;
|
|
76
|
+
}
|
|
77
|
+
export interface GaslightIngestResult {
|
|
78
|
+
outputPath: string;
|
|
79
|
+
dataPath: string;
|
|
80
|
+
promptCount: number;
|
|
81
|
+
traceCount: number;
|
|
82
|
+
}
|
|
@@ -3,7 +3,7 @@ import { lstat, mkdir, readFile, rename, unlink, writeFile } from "node:fs/promi
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import { dirname, join, parse, resolve, sep } from "node:path";
|
|
5
5
|
import { resolveRunLogDir } from "@poe-code/agent-harness-tools";
|
|
6
|
-
import { lint, FileSnapshotBackend, createSpawnUsageAccumulator, makeTimeModule,
|
|
6
|
+
import { lint, FileSnapshotBackend, createSpawnUsageAccumulator, makeTimeModule, run, splitFrontmatter, runWithSpawnUsageAccumulator } from "@poe-code/agent-script";
|
|
7
7
|
import { hasOwnErrorCode } from "../error-codes.js";
|
|
8
8
|
import { makeSchemaModule } from "../modules/schema.js";
|
|
9
9
|
import { extractSchema } from "./extract-schema.js";
|
|
@@ -82,6 +82,10 @@ export async function runHarnessPair(mdPath, options) {
|
|
|
82
82
|
const lintOptions = {
|
|
83
83
|
allowedExportNames: ["schema"],
|
|
84
84
|
allowedGlobals: options.allowedGlobals,
|
|
85
|
+
defaultExport: {
|
|
86
|
+
parameters: ["frontmatter"],
|
|
87
|
+
required: true
|
|
88
|
+
},
|
|
85
89
|
filename: pair.ajsPath,
|
|
86
90
|
frontmatterFields: readSchemaTopLevelFields(schema),
|
|
87
91
|
modules: createLintModules(modules)
|
|
@@ -96,8 +100,7 @@ export async function runHarnessPair(mdPath, options) {
|
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
102
|
const diagnostics = [
|
|
99
|
-
...(Array.isArray(lintDiagnostics) ? lintDiagnostics : lintDiagnostics.diagnostics)
|
|
100
|
-
...missingDefaultExportDiagnostics(executableSource, pair.ajsPath)
|
|
103
|
+
...(Array.isArray(lintDiagnostics) ? lintDiagnostics : lintDiagnostics.diagnostics)
|
|
101
104
|
];
|
|
102
105
|
options.onDiagnostics?.(diagnostics);
|
|
103
106
|
throwOnLintErrors(diagnostics);
|
|
@@ -144,24 +147,6 @@ function throwOnLintErrors(diagnostics) {
|
|
|
144
147
|
throw new LintError(errors);
|
|
145
148
|
}
|
|
146
149
|
}
|
|
147
|
-
function missingDefaultExportDiagnostics(source, filename) {
|
|
148
|
-
const module = parseModule(source, filename);
|
|
149
|
-
const hasDefaultExport = module.body.some((statement) => statement.type === "ExportDefaultDeclaration");
|
|
150
|
-
if (hasDefaultExport) {
|
|
151
|
-
return [];
|
|
152
|
-
}
|
|
153
|
-
return [
|
|
154
|
-
{
|
|
155
|
-
code: "AS-EXPORT-DEFAULT-MISSING",
|
|
156
|
-
severity: "error",
|
|
157
|
-
message: "Module must export a default entry point.",
|
|
158
|
-
filename,
|
|
159
|
-
line: module.span.start.line,
|
|
160
|
-
column: module.span.start.column,
|
|
161
|
-
span: module.span
|
|
162
|
-
}
|
|
163
|
-
];
|
|
164
|
-
}
|
|
165
150
|
function readSchemaTopLevelFields(schema) {
|
|
166
151
|
if (schema?.kind !== "object") {
|
|
167
152
|
return undefined;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { type OutputStream } from "./output-stream.js";
|
|
1
2
|
import type { ModuleRegistry } from "./modules/registry.js";
|
|
2
|
-
type CliStream =
|
|
3
|
-
write(chunk: string): void;
|
|
4
|
-
};
|
|
3
|
+
type CliStream = OutputStream;
|
|
5
4
|
type CliProcess = Pick<NodeJS.Process, "off" | "on">;
|
|
6
5
|
type FileStats = {
|
|
7
6
|
isFile(): boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
2
|
import path, { dirname, extname } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { formatWithOptions } from "node:util";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { hasOwnErrorCode } from "./error-codes.js";
|
|
6
6
|
import { formatInterpreterError } from "./error/format.js";
|
|
@@ -15,6 +15,7 @@ import { makeFailModule } from "./modules/fail.js";
|
|
|
15
15
|
import { makeHarnessModule } from "./modules/harness.js";
|
|
16
16
|
import { makeLogModule } from "./modules/log.js";
|
|
17
17
|
import { makeMetricModule } from "./modules/metric.js";
|
|
18
|
+
import { createBrokenPipeState, createSafeOutputStream, withBrokenPipeGuard } from "./output-stream.js";
|
|
18
19
|
import { parseModule } from "./parse/parser.js";
|
|
19
20
|
import { restore } from "./restore.js";
|
|
20
21
|
import { run } from "./run.js";
|
|
@@ -24,38 +25,57 @@ const EXIT_PARSE = 2;
|
|
|
24
25
|
const EXIT_BUDGET = 3;
|
|
25
26
|
const EXIT_SIGINT = 130;
|
|
26
27
|
export async function runCli(argv, options = {}) {
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
const brokenPipe = createBrokenPipeState();
|
|
29
|
+
const stdout = createSafeOutputStream(options.stdout ?? process.stdout, brokenPipe);
|
|
30
|
+
const stderr = createSafeOutputStream(options.stderr ?? process.stderr, brokenPipe);
|
|
31
|
+
return withBrokenPipeGuard([options.stdout ?? process.stdout, options.stderr ?? process.stderr], brokenPipe, async () => {
|
|
32
|
+
try {
|
|
33
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
34
|
+
stdout.write(`${createUsage()}\n`);
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
const parsed = parseArgs(argv);
|
|
38
|
+
if (parsed.filepath === undefined) {
|
|
39
|
+
stderr.write(`${createUsage()}\n`);
|
|
40
|
+
return brokenPipe.closed ? 0 : EXIT_RUNTIME;
|
|
41
|
+
}
|
|
42
|
+
const cwd = options.cwd ?? readCurrentWorkingDirectory();
|
|
43
|
+
const filepath = path.resolve(cwd, parsed.filepath);
|
|
44
|
+
await assertHarnessFile({
|
|
45
|
+
displayPath: parsed.filepath,
|
|
46
|
+
filepath,
|
|
47
|
+
statFile: options.stat ?? stat
|
|
48
|
+
});
|
|
49
|
+
return await runScriptFile(filepath, parsed, {
|
|
50
|
+
cwd,
|
|
51
|
+
modulesFor: options.modulesFor,
|
|
52
|
+
process: options.process ?? process,
|
|
53
|
+
readFile: options.readFile ?? readFile,
|
|
54
|
+
brokenPipe,
|
|
55
|
+
stderr,
|
|
56
|
+
stdout,
|
|
57
|
+
writeFile: options.writeFile ?? writeFile
|
|
58
|
+
});
|
|
34
59
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
60
|
+
catch (error) {
|
|
61
|
+
if (brokenPipe.closed) {
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
stderr.write(`${readErrorMessage(error)}\n`);
|
|
65
|
+
return brokenPipe.closed
|
|
66
|
+
? 0
|
|
67
|
+
: error instanceof CliExitError
|
|
68
|
+
? error.exitCode
|
|
69
|
+
: exitCodeForError(error);
|
|
39
70
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
});
|
|
46
|
-
return await runScriptFile(filepath, parsed, {
|
|
47
|
-
cwd,
|
|
48
|
-
modulesFor: options.modulesFor,
|
|
49
|
-
process: options.process ?? process,
|
|
50
|
-
readFile: options.readFile ?? readFile,
|
|
51
|
-
stderr,
|
|
52
|
-
stdout,
|
|
53
|
-
writeFile: options.writeFile ?? writeFile
|
|
54
|
-
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function readCurrentWorkingDirectory() {
|
|
74
|
+
try {
|
|
75
|
+
return process.cwd();
|
|
55
76
|
}
|
|
56
77
|
catch (error) {
|
|
57
|
-
|
|
58
|
-
return error instanceof CliExitError ? error.exitCode : exitCodeForError(error);
|
|
78
|
+
throw new Error(`Unable to resolve current working directory: ${readErrorMessage(error)}`);
|
|
59
79
|
}
|
|
60
80
|
}
|
|
61
81
|
function parseArgs(argv) {
|
|
@@ -167,11 +187,19 @@ async function runScriptFile(filepath, parsed, options) {
|
|
|
167
187
|
const lintErrors = diagnostics.filter((diagnostic) => diagnostic.severity === "error");
|
|
168
188
|
if (lintErrors.length > 0) {
|
|
169
189
|
options.stderr.write(`Lint failed:\n${formatDiagnostics(lintErrors)}\n`);
|
|
170
|
-
|
|
190
|
+
if (options.brokenPipe.closed) {
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
return lintErrors.some((diagnostic) => diagnostic.code === "AS001")
|
|
194
|
+
? EXIT_PARSE
|
|
195
|
+
: EXIT_RUNTIME;
|
|
171
196
|
}
|
|
172
197
|
const lintWarnings = diagnostics.filter((diagnostic) => diagnostic.severity === "warning");
|
|
173
198
|
if (lintWarnings.length > 0) {
|
|
174
199
|
options.stderr.write(`Lint warnings:\n${formatDiagnostics(lintWarnings)}\n`);
|
|
200
|
+
if (options.brokenPipe.closed) {
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
175
203
|
}
|
|
176
204
|
const snapshot = await readRestoreSnapshot(parsed.restorePath, options);
|
|
177
205
|
if (snapshot !== undefined) {
|
|
@@ -204,6 +232,9 @@ async function runScriptFile(filepath, parsed, options) {
|
|
|
204
232
|
});
|
|
205
233
|
const result = await runPromise;
|
|
206
234
|
await signalSnapshotWrite;
|
|
235
|
+
if (options.brokenPipe.closed) {
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
207
238
|
if (parsed.snapshotPath !== undefined) {
|
|
208
239
|
await writeSnapshot(parsed.snapshotPath, await dump(result), options);
|
|
209
240
|
}
|
|
@@ -212,18 +243,24 @@ async function runScriptFile(filepath, parsed, options) {
|
|
|
212
243
|
filename: filepath,
|
|
213
244
|
source: executableSource
|
|
214
245
|
})}\n`);
|
|
246
|
+
if (options.brokenPipe.closed) {
|
|
247
|
+
return 0;
|
|
248
|
+
}
|
|
215
249
|
return interrupted ? EXIT_SIGINT : exitCodeForError(result.error);
|
|
216
250
|
}
|
|
217
251
|
options.stdout.write(`${JSON.stringify({ ok: true, returnValue: result.returnValue })}\n`);
|
|
218
|
-
return interrupted ? EXIT_SIGINT : 0;
|
|
252
|
+
return options.brokenPipe.closed ? 0 : interrupted ? EXIT_SIGINT : 0;
|
|
219
253
|
}
|
|
220
254
|
catch (error) {
|
|
221
255
|
await signalSnapshotWrite;
|
|
256
|
+
if (options.brokenPipe.closed) {
|
|
257
|
+
return 0;
|
|
258
|
+
}
|
|
222
259
|
options.stderr.write(`${formatInterpreterError(error, {
|
|
223
260
|
filename: filepath,
|
|
224
261
|
source: executableSource
|
|
225
262
|
})}\n`);
|
|
226
|
-
return interrupted ? EXIT_SIGINT : exitCodeForError(error);
|
|
263
|
+
return options.brokenPipe.closed ? 0 : interrupted ? EXIT_SIGINT : exitCodeForError(error);
|
|
227
264
|
}
|
|
228
265
|
finally {
|
|
229
266
|
options.process.off("SIGINT", onSigint);
|
|
@@ -367,10 +404,7 @@ function createConsoleSink(stdout, stderr) {
|
|
|
367
404
|
};
|
|
368
405
|
}
|
|
369
406
|
function formatConsoleArgs(args) {
|
|
370
|
-
return
|
|
371
|
-
}
|
|
372
|
-
function formatConsoleArg(value) {
|
|
373
|
-
return typeof value === "string" ? value : inspect(value, { colors: false, depth: 4 });
|
|
407
|
+
return formatWithOptions({ colors: false, depth: 4 }, ...args);
|
|
374
408
|
}
|
|
375
409
|
function createUsage() {
|
|
376
410
|
return [
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
3
|
-
};
|
|
1
|
+
import { type OutputStream } from "./output-stream.js";
|
|
2
|
+
type CliStream = OutputStream;
|
|
4
3
|
export type ReadMarkdownFile = (filepath: string, encoding: "utf8") => Promise<string>;
|
|
5
4
|
export type WriteMarkdownFile = (filepath: string, source: string, options: {
|
|
6
5
|
encoding: "utf8";
|
|
@@ -9,6 +9,7 @@ import { makeFailModule } from "./modules/fail.js";
|
|
|
9
9
|
import { makeHarnessModule } from "./modules/harness.js";
|
|
10
10
|
import { makeLogModule } from "./modules/log.js";
|
|
11
11
|
import { makeMetricModule } from "./modules/metric.js";
|
|
12
|
+
import { createBrokenPipeState, createSafeOutputStream, withBrokenPipeGuard } from "./output-stream.js";
|
|
12
13
|
import { parseModule } from "./parse/parser.js";
|
|
13
14
|
import { run } from "./run.js";
|
|
14
15
|
async function main(argv) {
|
|
@@ -20,68 +21,80 @@ async function main(argv) {
|
|
|
20
21
|
return await runExampleFile(filepath, { fix });
|
|
21
22
|
}
|
|
22
23
|
export async function runExampleFile(filepath, options = {}) {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
24
|
+
const brokenPipe = createBrokenPipeState();
|
|
25
|
+
const stdout = createSafeOutputStream(options.stdout ?? process.stdout, brokenPipe);
|
|
26
|
+
const stderr = createSafeOutputStream(options.stderr ?? process.stderr, brokenPipe);
|
|
25
27
|
const readMarkdownFile = options.readFile ?? readFile;
|
|
26
28
|
const writeMarkdownFile = options.writeFile ?? writeFile;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
return withBrokenPipeGuard([options.stdout ?? process.stdout, options.stderr ?? process.stderr], brokenPipe, async () => {
|
|
30
|
+
try {
|
|
31
|
+
const rawSource = await readMarkdownFile(filepath, "utf8");
|
|
32
|
+
const loaded = loadExecutableSource(rawSource);
|
|
33
|
+
const { frontmatter, hasScriptBlock } = loaded;
|
|
34
|
+
let executableSource = loaded.executableSource;
|
|
35
|
+
const meta = {
|
|
36
|
+
filepath,
|
|
37
|
+
kind: frontmatter.kind,
|
|
38
|
+
version: frontmatter.version
|
|
39
|
+
};
|
|
40
|
+
const runtime = createExampleRuntime(frontmatter, meta, stdout);
|
|
41
|
+
if (!hasScriptBlock) {
|
|
42
|
+
const returnValue = await runDemoFallback(frontmatter, runtime);
|
|
43
|
+
stdout.write(`${JSON.stringify({ ok: true, returnValue })}\n`);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
const lintOptions = {
|
|
47
|
+
allowedExportNames: ["schema"],
|
|
48
|
+
filename: filepath,
|
|
49
|
+
modules: createLintModulesFromRuntimeRegistry(runtime.registry)
|
|
50
|
+
};
|
|
51
|
+
const lintResult = options.fix
|
|
52
|
+
? lint(executableSource, { ...lintOptions, fix: true })
|
|
53
|
+
: lint(executableSource, lintOptions);
|
|
54
|
+
const diagnostics = Array.isArray(lintResult) ? lintResult : lintResult.diagnostics;
|
|
55
|
+
if (!Array.isArray(lintResult)) {
|
|
56
|
+
executableSource = lintResult.fixed;
|
|
57
|
+
if (lintResult.fixed !== loaded.executableSource) {
|
|
58
|
+
await writeMarkdownFile(filepath, replaceExecutableSource(rawSource, loaded, lintResult.fixed), {
|
|
59
|
+
encoding: "utf8"
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const lintErrors = diagnostics.filter((diagnostic) => diagnostic.severity === "error");
|
|
64
|
+
if (lintErrors.length > 0) {
|
|
65
|
+
stderr.write(`Lint failed:\n${formatDiagnostics(lintErrors)}\n`);
|
|
66
|
+
return brokenPipe.closed ? 0 : 1;
|
|
67
|
+
}
|
|
68
|
+
const lintWarnings = diagnostics.filter((diagnostic) => diagnostic.severity === "warning");
|
|
69
|
+
if (lintWarnings.length > 0) {
|
|
70
|
+
stderr.write(`Lint warnings:\n${formatDiagnostics(lintWarnings)}\n`);
|
|
71
|
+
if (brokenPipe.closed) {
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const result = await run(executableSource, {
|
|
76
|
+
entryPointArgs: hasDefaultExport(executableSource, filepath) ? [] : undefined,
|
|
77
|
+
filename: filepath,
|
|
78
|
+
modules: runtime.registry
|
|
79
|
+
});
|
|
80
|
+
if (brokenPipe.closed) {
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
if (!result.ok) {
|
|
84
|
+
stderr.write(`${readErrorMessage(result.error)}\n`);
|
|
85
|
+
return brokenPipe.closed ? 0 : 1;
|
|
86
|
+
}
|
|
87
|
+
stdout.write(`${JSON.stringify({ ok: true, returnValue: result.returnValue })}\n`);
|
|
41
88
|
return 0;
|
|
42
89
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
modules: createLintModulesFromRuntimeRegistry(runtime.registry)
|
|
47
|
-
};
|
|
48
|
-
const lintResult = options.fix
|
|
49
|
-
? lint(executableSource, { ...lintOptions, fix: true })
|
|
50
|
-
: lint(executableSource, lintOptions);
|
|
51
|
-
const diagnostics = Array.isArray(lintResult) ? lintResult : lintResult.diagnostics;
|
|
52
|
-
if (!Array.isArray(lintResult)) {
|
|
53
|
-
executableSource = lintResult.fixed;
|
|
54
|
-
if (lintResult.fixed !== loaded.executableSource) {
|
|
55
|
-
await writeMarkdownFile(filepath, replaceExecutableSource(rawSource, loaded, lintResult.fixed), {
|
|
56
|
-
encoding: "utf8"
|
|
57
|
-
});
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (brokenPipe.closed) {
|
|
92
|
+
return 0;
|
|
58
93
|
}
|
|
94
|
+
stderr.write(`${readErrorMessage(error)}\n`);
|
|
95
|
+
return brokenPipe.closed ? 0 : 1;
|
|
59
96
|
}
|
|
60
|
-
|
|
61
|
-
if (lintErrors.length > 0) {
|
|
62
|
-
stderr.write(`Lint failed:\n${formatDiagnostics(lintErrors)}\n`);
|
|
63
|
-
return 1;
|
|
64
|
-
}
|
|
65
|
-
const lintWarnings = diagnostics.filter((diagnostic) => diagnostic.severity === "warning");
|
|
66
|
-
if (lintWarnings.length > 0) {
|
|
67
|
-
stderr.write(`Lint warnings:\n${formatDiagnostics(lintWarnings)}\n`);
|
|
68
|
-
}
|
|
69
|
-
const result = await run(executableSource, {
|
|
70
|
-
entryPointArgs: hasDefaultExport(executableSource, filepath) ? [] : undefined,
|
|
71
|
-
filename: filepath,
|
|
72
|
-
modules: runtime.registry
|
|
73
|
-
});
|
|
74
|
-
if (!result.ok) {
|
|
75
|
-
stderr.write(`${readErrorMessage(result.error)}\n`);
|
|
76
|
-
return 1;
|
|
77
|
-
}
|
|
78
|
-
stdout.write(`${JSON.stringify({ ok: true, returnValue: result.returnValue })}\n`);
|
|
79
|
-
return 0;
|
|
80
|
-
}
|
|
81
|
-
catch (error) {
|
|
82
|
-
stderr.write(`${readErrorMessage(error)}\n`);
|
|
83
|
-
return 1;
|
|
84
|
-
}
|
|
97
|
+
});
|
|
85
98
|
}
|
|
86
99
|
function loadExecutableSource(source) {
|
|
87
100
|
const { frontmatter, body } = splitFrontmatter(source);
|
|
@@ -315,7 +315,7 @@ function getPatternBindingNames(pattern) {
|
|
|
315
315
|
async function bindPattern(pattern, value, context, evaluateNode) {
|
|
316
316
|
switch (pattern.type) {
|
|
317
317
|
case "Identifier":
|
|
318
|
-
context.scope.declare(pattern.name, "
|
|
318
|
+
context.scope.declare(pattern.name, "let", value);
|
|
319
319
|
return { ok: true };
|
|
320
320
|
case "MemberExpression":
|
|
321
321
|
throw new TypeError("Catch bindings do not support member expressions.");
|
|
@@ -2,7 +2,7 @@ import type { Budget } from "../budget.js";
|
|
|
2
2
|
import { type SandboxClosure, type SandboxObject } from "../values.js";
|
|
3
3
|
export type ObjectArrayGlobals = {
|
|
4
4
|
Object: SandboxObject;
|
|
5
|
-
Array:
|
|
5
|
+
Array: SandboxClosure;
|
|
6
6
|
String: SandboxClosure;
|
|
7
7
|
Number: SandboxClosure;
|
|
8
8
|
Boolean: SandboxClosure;
|
|
@@ -45,20 +45,25 @@ export function createObjectArrayGlobals(options) {
|
|
|
45
45
|
name: "assign"
|
|
46
46
|
})
|
|
47
47
|
},
|
|
48
|
-
Array: {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
Array: createSandboxClosure({
|
|
49
|
+
call: (args) => createArrayFromConstructorArgs(args, options.budget),
|
|
50
|
+
construct: (args) => createArrayFromConstructorArgs(args, options.budget),
|
|
51
|
+
name: "Array",
|
|
52
|
+
properties: {
|
|
53
|
+
isArray: createSandboxClosure({
|
|
54
|
+
call: ([value]) => Array.isArray(value),
|
|
55
|
+
name: "isArray"
|
|
56
|
+
}),
|
|
57
|
+
from: createSandboxClosure({
|
|
58
|
+
call: (args) => arrayFromSandboxValues(args, options.budget),
|
|
59
|
+
name: "from"
|
|
60
|
+
}),
|
|
61
|
+
of: createSandboxClosure({
|
|
62
|
+
call: (args) => budgetSandboxValue(Reflect.apply(Array.of, Array, [...args]), options.budget),
|
|
63
|
+
name: "of"
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}),
|
|
62
67
|
String: createSandboxClosure({
|
|
63
68
|
call: ([value]) => options.budget.allocateString(String(value)),
|
|
64
69
|
name: "String",
|
|
@@ -152,13 +157,13 @@ function isAssignableSandboxTarget(value) {
|
|
|
152
157
|
async function arrayFromSandboxValues(args, budget) {
|
|
153
158
|
const [items, mapFn] = args;
|
|
154
159
|
const iterator = getSandboxIterator(items);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const values = iterator?.generator === true
|
|
159
|
-
? await collectIteratorValues(iterator)
|
|
160
|
-
: Reflect.apply(Array.from, Array, [items]);
|
|
160
|
+
const values = iterator === undefined
|
|
161
|
+
? Reflect.apply(Array.from, Array, [items])
|
|
162
|
+
: await collectIteratorValues(iterator);
|
|
161
163
|
if (mapFn === undefined || !isSandboxClosure(mapFn)) {
|
|
164
|
+
if (mapFn !== undefined) {
|
|
165
|
+
throw new TypeError("Array.from mapping callback must be a function.");
|
|
166
|
+
}
|
|
162
167
|
return budgetSandboxValue(values, budget);
|
|
163
168
|
}
|
|
164
169
|
const mappedValues = [];
|
|
@@ -168,6 +173,20 @@ async function arrayFromSandboxValues(args, budget) {
|
|
|
168
173
|
}
|
|
169
174
|
return budgetSandboxValue(mappedValues, budget);
|
|
170
175
|
}
|
|
176
|
+
function createArrayFromConstructorArgs(args, budget) {
|
|
177
|
+
if (args.length !== 1) {
|
|
178
|
+
return budgetSandboxValue(Reflect.apply(Array, Array, [...args]), budget);
|
|
179
|
+
}
|
|
180
|
+
const [lengthOrValue] = args;
|
|
181
|
+
if (typeof lengthOrValue !== "number") {
|
|
182
|
+
return budgetSandboxValue([lengthOrValue], budget);
|
|
183
|
+
}
|
|
184
|
+
if (!Number.isInteger(lengthOrValue) || lengthOrValue < 0 || lengthOrValue > 0xffffffff) {
|
|
185
|
+
throw new RangeError("Invalid array length.");
|
|
186
|
+
}
|
|
187
|
+
budget.allocateArrayLength(lengthOrValue);
|
|
188
|
+
return new Array(lengthOrValue);
|
|
189
|
+
}
|
|
171
190
|
async function collectIteratorValues(iterator) {
|
|
172
191
|
const values = [];
|
|
173
192
|
while (true) {
|
|
@@ -475,7 +475,7 @@ function readStringProperty(value, key) {
|
|
|
475
475
|
}
|
|
476
476
|
function copyFunctionProperties(callable, stackFrames, options, state, path) {
|
|
477
477
|
const properties = {};
|
|
478
|
-
for (const key of Object.
|
|
478
|
+
for (const key of Object.getOwnPropertyNames(callable)) {
|
|
479
479
|
const descriptor = Object.getOwnPropertyDescriptor(callable, key);
|
|
480
480
|
if (descriptor === undefined) {
|
|
481
481
|
continue;
|