poe-code 8.0.0 → 9.0.0
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/harness.js +12 -3
- package/dist/cli/commands/harness.js.map +1 -1
- package/dist/index.js +1515 -712
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +15 -2
- package/packages/safejs/dist/chunks/chunk-4YIDX44G.js +40 -0
- package/packages/safejs/dist/chunks/chunk-4YIDX44G.js.map +7 -0
- package/packages/safejs/dist/chunks/chunk-55ZK3CR7.js +7802 -0
- package/packages/safejs/dist/chunks/chunk-55ZK3CR7.js.map +7 -0
- package/packages/safejs/dist/chunks/chunk-GQBEEFVQ.js +28798 -0
- package/packages/safejs/dist/chunks/chunk-GQBEEFVQ.js.map +7 -0
- package/packages/safejs/dist/chunks/chunk-NI4WFFTL.js +5701 -0
- package/packages/safejs/dist/chunks/chunk-NI4WFFTL.js.map +7 -0
- package/packages/safejs/dist/chunks/inMemory-RLZ4QGDZ.js +48 -0
- package/packages/safejs/dist/chunks/inMemory-RLZ4QGDZ.js.map +7 -0
- package/packages/safejs/dist/chunks/server-3SNT3RE2.js +12518 -0
- package/packages/safejs/dist/chunks/server-3SNT3RE2.js.map +7 -0
- package/packages/safejs/dist/chunks/types-BTF37PZ6.js +348 -0
- package/packages/safejs/dist/chunks/types-BTF37PZ6.js.map +7 -0
- package/packages/safejs/dist/cli.d.ts +2 -0
- package/packages/safejs/dist/cli.js +550 -491
- package/packages/safejs/dist/cli.js.map +7 -0
- package/packages/safejs/dist/core.js +14 -4
- package/packages/safejs/dist/core.js.map +7 -0
- package/packages/safejs/dist/index.d.ts +3 -0
- package/packages/safejs/dist/index.js +791 -30
- package/packages/safejs/dist/index.js.map +7 -0
- package/packages/safejs/dist/interp/host-bridge.d.ts +2 -0
- package/packages/safejs/dist/interp/host-bridge.js +20 -9
- package/packages/safejs/dist/interp/host-call.d.ts +5 -0
- package/packages/safejs/dist/interp/host-call.js +48 -3
- package/packages/safejs/dist/interp/resources.d.ts +7 -0
- package/packages/safejs/dist/interp/resources.js +36 -0
- package/packages/safejs/dist/modules/mcp-transport.d.ts +26 -0
- package/packages/safejs/dist/modules/mcp-transport.js +259 -0
- package/packages/safejs/dist/modules/mcp.d.ts +15 -1
- package/packages/safejs/dist/modules/mcp.js +107 -0
- package/packages/safejs/dist/run.js +6 -3
- package/packages/safejs/dist/snapshot/dump-format.d.ts +1 -1
- package/packages/safejs/dist/snapshot/dump-format.js +1 -1
- package/packages/safejs/dist/snapshot/replay-data.d.ts +1 -0
- package/packages/safejs/dist/snapshot/replay-data.js +3 -1
- package/packages/safejs/dist/snapshot/replay-inputs.d.ts +2 -2
- package/packages/safejs/dist/snapshot/replay-inputs.js +2 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/runner/run-harness.ts", "../src/loader/find-exported.ts", "../src/modules/env.ts", "../src/modules/git.ts", "../src/modules/time.ts"],
|
|
4
|
+
"sourcesContent": ["import { readFile, stat } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\n\nimport { supportsSpawnMode } from \"@poe-code/agent-spawn/configs\";\nimport { SPAWN_MODES, type SpawnMode } from \"@poe-code/agent-spawn/types\";\nimport { hasOwnErrorCode } from \"../error-codes.js\";\nimport { countLineBreaks, extractBlock } from \"../loader/extract-block.js\";\nimport { splitFrontmatter } from \"../loader/frontmatter.js\";\nimport { lint, type Diagnostic } from \"../lint.js\";\nimport { createLintModulesFromRuntimeRegistry } from \"../lint/runtime-modules.js\";\nimport type { ModuleExports, ModuleRegistry } from \"../modules/registry.js\";\nimport type { OtelSink } from \"../observability/otel.js\";\nimport { parseModule } from \"../parse/parser.js\";\nimport { run, type RunResult } from \"../run.js\";\nimport type { SnapshotBackend } from \"../snapshot/backend.js\";\n\ntype HarnessMeta = {\n filepath: string;\n kind: unknown;\n version: unknown;\n};\n\nexport type RunHarnessOptions = {\n modulesFor: (frontmatter: Record<string, unknown>, meta: HarnessMeta) => ModuleRegistry;\n otelSink?: OtelSink;\n signal?: AbortSignal;\n snapshotBackend?: SnapshotBackend;\n snapshotIntervalMs?: number;\n snapshotPath?: string;\n};\n\nexport type RunHarnessExecutionErrorResult = {\n aborted?: true;\n error: unknown;\n ok: false;\n};\n\nexport type RunHarnessResult = RunResult | RunHarnessExecutionErrorResult;\n\nfunction getOwnEntry(record: Record<string, unknown>, key: string): unknown {\n return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;\n}\n\nfunction createHarnessMeta(filepath: string, frontmatter: Record<string, unknown>): HarnessMeta {\n return {\n filepath,\n kind: getOwnEntry(frontmatter, \"kind\"),\n version: getOwnEntry(frontmatter, \"version\")\n };\n}\n\nfunction assertFrontmatterAgentModes(frontmatter: Record<string, unknown>): void {\n const agents = getOwnEntry(frontmatter, \"agents\");\n if (typeof agents !== \"object\" || agents === null || Array.isArray(agents)) {\n return;\n }\n\n for (const [name, definition] of Object.entries(agents)) {\n if (typeof definition !== \"object\" || definition === null || Array.isArray(definition)) {\n continue;\n }\n\n const record = definition as Record<string, unknown>;\n const agent = getOwnEntry(record, \"agent\");\n const mode = getOwnEntry(record, \"mode\");\n if (typeof agent !== \"string\" || typeof mode !== \"string\") {\n continue;\n }\n\n // Malformed mode strings are reported by the agent module's own validation.\n if (!SPAWN_MODES.includes(mode as SpawnMode)) {\n continue;\n }\n\n if (!supportsSpawnMode(agent, mode as SpawnMode)) {\n throw new Error(`Harness agent \"${name}\": agent \"${agent}\" does not support mode \"${mode}\".`);\n }\n }\n}\n\nexport class LintError extends Error {\n readonly diagnostics: readonly Diagnostic[];\n\n constructor(diagnostics: readonly Diagnostic[]) {\n super(formatLintErrorMessage(diagnostics));\n this.name = \"LintError\";\n this.diagnostics = diagnostics;\n }\n}\n\nexport async function runHarness(\n filepath: string,\n options: RunHarnessOptions\n): Promise<RunHarnessResult> {\n const rawSource = stripByteOrderMark(await readHarnessFile(filepath));\n const { executableSource, frontmatter, isRawScript } = loadExecutableSource(filepath, rawSource);\n assertFrontmatterAgentModes(frontmatter);\n const meta = createHarnessMeta(filepath, frontmatter);\n const modules = excludeHarnessModule(options.modulesFor(frontmatter, meta), isRawScript);\n const diagnostics = lint(executableSource, {\n filename: filepath,\n modules: createLintModulesFromRuntimeRegistry(modules)\n });\n const lintErrors = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\");\n\n if (lintErrors.length > 0) {\n throw new LintError(lintErrors);\n }\n\n return runHarnessSource(executableSource, {\n entryPointArgs: hasDefaultExport(executableSource, filepath) ? [] : undefined,\n filename: filepath,\n modules,\n otelSink: options.otelSink,\n signal: options.signal,\n snapshotBackend: options.snapshotBackend,\n snapshotIntervalMs: options.snapshotIntervalMs,\n snapshotPath: options.snapshotPath\n });\n}\n\nexport async function runHarnessPair(\n filepath: string,\n options: RunHarnessOptions\n): Promise<RunHarnessResult> {\n const pair = resolveHarnessPair(filepath);\n const [rawMarkdown, rawScript] = await Promise.all([\n readHarnessFile(pair.markdownPath),\n readHarnessFile(pair.scriptPath)\n ]);\n const { frontmatter, body } = splitFrontmatter(stripByteOrderMark(rawMarkdown));\n assertFrontmatterAgentModes(frontmatter);\n const executableSource = stripByteOrderMark(rawScript);\n const meta = createHarnessMeta(pair.markdownPath, frontmatter);\n const modules = options.modulesFor(frontmatter, meta);\n const diagnostics = lint(executableSource, {\n allowedExportNames: [\"schema\"],\n defaultExport: {\n parameters: [\"frontmatter\"],\n required: true\n },\n filename: pair.scriptPath,\n frontmatterFields: Object.keys(frontmatter),\n modules: createLintModulesFromRuntimeRegistry(modules)\n });\n const lintErrors = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\");\n\n if (lintErrors.length > 0) {\n throw new LintError(lintErrors);\n }\n\n return runHarnessSource(executableSource, {\n entryPointArgs: [frontmatter],\n filename: pair.scriptPath,\n importMeta: {\n body,\n filepath: pair.markdownPath,\n kind: meta.kind,\n version: meta.version\n },\n modules,\n otelSink: options.otelSink,\n signal: options.signal,\n snapshotBackend: options.snapshotBackend,\n snapshotIntervalMs: options.snapshotIntervalMs,\n snapshotPath: options.snapshotPath\n });\n}\n\nasync function readHarnessFile(filepath: string): Promise<string> {\n try {\n const stats = await stat(filepath);\n if (!stats.isFile()) {\n throw new Error(`Harness path must point to a file: ${filepath}`);\n }\n\n return await readFile(filepath, \"utf8\");\n } catch (error) {\n if (hasOwnErrorCode(error, \"ENOENT\") || hasOwnErrorCode(error, \"ENOTDIR\")) {\n throw new Error(`Harness file not found: ${filepath}`);\n }\n\n throw error;\n }\n}\n\nfunction loadExecutableSource(\n filepath: string,\n source: string\n): {\n executableSource: string;\n frontmatter: Record<string, unknown>;\n isRawScript: boolean;\n} {\n if (isRawScriptPath(filepath)) {\n if (source.length === 0) {\n throw new Error(`No code block found in empty harness file: ${filepath}`);\n }\n\n return {\n executableSource: source,\n frontmatter: {},\n isRawScript: true\n };\n }\n\n const { frontmatter, body } = splitFrontmatter(source);\n if (source.length === 0 || body.trim().length === 0) {\n throw new Error(`No code block found in empty harness file: ${filepath}`);\n }\n\n const bodyStartOffset = source.length - body.length;\n const { source: executableBlock, startOffset } = extractBlock(\n body,\n countLineBreaks(source, 0, bodyStartOffset) + 1\n );\n const absoluteLineOffset = countLineBreaks(source, 0, bodyStartOffset + startOffset);\n\n return {\n executableSource: createLineOffsetSource(stripHashbang(executableBlock), absoluteLineOffset),\n frontmatter,\n isRawScript: false\n };\n}\n\nfunction resolveHarnessPair(filepath: string): { markdownPath: string; scriptPath: string } {\n const extension = extname(filepath);\n const basename = extension.length === 0 ? filepath : filepath.slice(0, -extension.length);\n\n if (isRawScriptExtension(extension)) {\n return {\n markdownPath: `${basename}.md`,\n scriptPath: filepath\n };\n }\n\n return {\n markdownPath: filepath,\n scriptPath: `${basename}.ajs`\n };\n}\n\nfunction isRawScriptPath(filepath: string): boolean {\n return isRawScriptExtension(extname(filepath));\n}\n\nfunction isRawScriptExtension(extension: string): boolean {\n return extension === \".safejs\" || extension === \".ajs\";\n}\n\nasync function runHarnessSource(\n executableSource: string,\n options: Parameters<typeof run>[1]\n): Promise<RunHarnessResult> {\n try {\n return await run(executableSource, options);\n } catch (error) {\n if (isSetupError(error)) {\n throw error;\n }\n\n return {\n ...(isAbortError(error) ? { aborted: true as const } : {}),\n error,\n ok: false\n };\n }\n}\n\nfunction isSetupError(error: unknown): boolean {\n return error instanceof Error && error.name === \"ParseError\";\n}\n\nfunction isAbortError(error: unknown): boolean {\n if (error instanceof Error) {\n return error.name === \"AbortError\";\n }\n\n return (\n typeof error === \"object\" &&\n error !== null &&\n Object.prototype.hasOwnProperty.call(error, \"name\") &&\n (error as { name?: unknown }).name === \"AbortError\"\n );\n}\n\nfunction hasDefaultExport(source: string, filename: string): boolean {\n return parseModule(source, filename).body.some(\n (statement) => statement.type === \"ExportDefaultDeclaration\"\n );\n}\n\nfunction excludeHarnessModule(modules: ModuleRegistry, isRawScript: boolean): ModuleRegistry {\n if (!isRawScript) {\n return modules;\n }\n\n if (modules instanceof Map) {\n const rawModules = new Map(modules);\n rawModules.delete(\"harness\");\n return rawModules;\n }\n\n const rawModules: Record<string, ModuleExports> = {};\n\n for (const [moduleName, moduleExports] of Object.entries(modules)) {\n if (moduleName !== \"harness\") {\n rawModules[moduleName] = moduleExports;\n }\n }\n\n return rawModules;\n}\n\nfunction stripByteOrderMark(source: string): string {\n return source.startsWith(\"\\uFEFF\") ? source.slice(1) : source;\n}\n\nfunction stripHashbang(source: string): string {\n if (!source.startsWith(\"#!\")) {\n return source;\n }\n\n let end = 2;\n while (end < source.length && source[end] !== \"\\n\" && source[end] !== \"\\r\") end += 1;\n return `${\" \".repeat(end)}${source.slice(end)}`;\n}\n\nfunction createLineOffsetSource(source: string, lineOffset: number): string {\n return `${\"\\n\".repeat(Math.max(lineOffset, 0))}${source}`;\n}\n\nfunction formatLintErrorMessage(diagnostics: readonly Diagnostic[]): string {\n if (diagnostics.length === 0) {\n return \"Script lint failed.\";\n }\n\n return diagnostics\n .map(\n (diagnostic) =>\n `${diagnostic.filename}:${diagnostic.line}:${diagnostic.column} ${diagnostic.code} ${diagnostic.message}`\n )\n .join(\"\\n\");\n}\n", "import type { Expression, Module } from \"../parse/parser.js\";\n\nexport function findExportedConstInitializer(module: Module, name: string): Expression | undefined {\n for (const statement of module.body) {\n if (statement.type === \"ExportDefaultDeclaration\") {\n if (name === \"default\") {\n return statement.declaration;\n }\n\n continue;\n }\n\n if (statement.type !== \"ExportNamedDeclaration\") {\n continue;\n }\n\n const declaration = statement.declaration;\n if (declaration.kind !== \"const\") {\n throw new Error(`Exported '${name}' must be declared with const.`);\n }\n\n if (declaration.declarations.length !== 1) {\n throw new Error(\"Exported const declarations must contain exactly one declarator.\");\n }\n\n const declarator = declaration.declarations[0]!;\n if (declarator.id.type !== \"Identifier\") {\n throw new Error(\"Destructured exported const bindings are not supported.\");\n }\n\n if (declarator.id.name !== name) {\n continue;\n }\n\n if (declarator.init === undefined) {\n throw new Error(`Exported const '${name}' must have an initializer.`);\n }\n\n return declarator.init;\n }\n\n return undefined;\n}\n", "export function makeEnvModule(allowList: readonly string[]): {\n get(name: string): string | undefined;\n} {\n const allowedNames = normalizeAllowList(allowList);\n\n return {\n get(name) {\n const normalizedName = readNonEmptyString(name, \"Environment variable name\");\n\n if (!allowedNames.has(normalizedName)) {\n return undefined;\n }\n\n return process.env[normalizedName];\n }\n };\n}\n\nfunction normalizeAllowList(allowList: readonly string[]): ReadonlySet<string> {\n if (!Array.isArray(allowList)) {\n throw new Error(\"Environment allow list must be an array of non-empty strings.\");\n }\n\n return new Set(\n allowList.map((entry, index) => readNonEmptyString(entry, `Environment allow list[${index}]`))\n );\n}\n\nfunction readNonEmptyString(value: unknown, label: string): string {\n if (typeof value !== \"string\") {\n throw new Error(`${label} must be a non-empty string.`);\n }\n\n const normalizedValue = value.trim();\n\n if (normalizedValue.length === 0) {\n throw new Error(`${label} must be a non-empty string.`);\n }\n\n return normalizedValue;\n}\n", "import { execFile } from \"node:child_process\";\nimport { mkdir, readlink, realpath, rm, stat } from \"node:fs/promises\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { containsPath, isSamePath, resolveCanonicalPath } from \"./canonical-path.js\";\n\nexport type GitSavepoint = {\n head: string;\n stashRef?: string;\n};\n\nexport type GitCommitOptions = {\n message: string;\n files?: string[];\n};\n\nexport type GitWorktree = {\n path: string;\n branch: string;\n};\n\nexport type GitWorktreeCreateOptions = {\n base?: string;\n path?: string;\n};\n\ntype ExecFileResult = {\n stdout: string;\n stderr: string;\n};\n\nconst GIT_EXEC_MAX_BUFFER = 10 * 1024 * 1024;\nconst SAVEPOINT_REF_PREFIX = \"refs/poe-code/checkpoints/\";\n\nexport function makeGitModule(cwd: string): {\n head(): Promise<string>;\n checkpoint(): Promise<GitSavepoint>;\n commit(options: GitCommitOptions): Promise<string>;\n revert(savepoint: GitSavepoint): Promise<void>;\n diff(): Promise<string>;\n worktreeCreate(branch: string, options?: GitWorktreeCreateOptions): Promise<GitWorktree>;\n worktreeRemove(path: string): Promise<void>;\n worktreeList(): Promise<GitWorktree[]>;\n} {\n const normalizedCwd = readNonEmptyString(cwd, \"Git module cwd\");\n\n return {\n async head() {\n return runGitAndTrim(normalizedCwd, [\"rev-parse\", \"HEAD\"]);\n },\n\n async checkpoint() {\n const currentHead = await runGitAndTrim(normalizedCwd, [\"rev-parse\", \"HEAD\"]);\n const status = await runGitAndTrim(normalizedCwd, [\"status\", \"--porcelain\"]);\n\n if (status.length === 0) {\n return {\n head: currentHead\n };\n }\n\n const stashRef = createSavepointRef();\n const stashMessage = `poe-code checkpoint ${stashRef}`;\n\n await runGit(normalizedCwd, [\n \"stash\",\n \"push\",\n \"--include-untracked\",\n \"--message\",\n stashMessage\n ]);\n\n try {\n const stashOid = await runGitAndTrim(normalizedCwd, [\"rev-parse\", \"stash@{0}\"]);\n await runGit(normalizedCwd, [\"update-ref\", stashRef, stashOid]);\n await runGit(normalizedCwd, [\"stash\", \"apply\", \"--index\", stashRef]);\n await runGit(normalizedCwd, [\"stash\", \"drop\", \"stash@{0}\"]);\n\n return {\n head: currentHead,\n stashRef\n };\n } catch (error) {\n await cleanupFailedCheckpoint(normalizedCwd, stashRef);\n throw error;\n }\n },\n\n async commit(options) {\n const normalizedOptions = normalizeCommitOptions(options);\n\n if (normalizedOptions.files === undefined) {\n await runGit(normalizedCwd, [\"add\", \"--all\"]);\n await runGit(normalizedCwd, [\"commit\", \"--message\", normalizedOptions.message]);\n } else {\n await runGit(normalizedCwd, [\"add\", \"--\", ...normalizedOptions.files]);\n await runGit(normalizedCwd, [\n \"commit\",\n \"--message\",\n normalizedOptions.message,\n \"--\",\n ...normalizedOptions.files\n ]);\n }\n return runGitAndTrim(normalizedCwd, [\"rev-parse\", \"HEAD\"]);\n },\n\n async revert(savepoint) {\n const normalizedSavepoint = normalizeSavepoint(savepoint);\n\n try {\n await runGit(normalizedCwd, [\"reset\", \"--hard\", normalizedSavepoint.head]);\n await runGit(normalizedCwd, [\"clean\", \"--force\", \"-d\"]);\n\n if (normalizedSavepoint.stashRef !== undefined) {\n await runGit(normalizedCwd, [\"stash\", \"apply\", \"--index\", normalizedSavepoint.stashRef]);\n }\n } finally {\n if (normalizedSavepoint.stashRef !== undefined) {\n await deleteSavepointRef(normalizedCwd, normalizedSavepoint.stashRef);\n }\n }\n },\n\n async diff() {\n const { stdout } = await runGit(normalizedCwd, [\"diff\", \"HEAD\", \"--\"]);\n return stdout;\n },\n\n async worktreeCreate(branch, options) {\n const normalizedBranch = readNonEmptyString(branch, \"Git worktree branch\");\n const normalizedOptions = normalizeWorktreeCreateOptions(options);\n const repoRoot = await getRepoRoot(normalizedCwd);\n const worktreePath = await resolveWorktreePath(\n repoRoot,\n normalizedOptions.path ?? createDefaultWorktreePath(repoRoot, normalizedBranch),\n \"Git worktree path\"\n );\n\n if (await gitRefExists(normalizedCwd, `refs/heads/${normalizedBranch}`)) {\n throw new Error(`Git worktree branch '${normalizedBranch}' already exists.`);\n }\n\n await mkdir(dirname(worktreePath), { recursive: true });\n\n try {\n await runGit(normalizedCwd, [\n \"worktree\",\n \"add\",\n \"-b\",\n normalizedBranch,\n worktreePath,\n normalizedOptions.base\n ]);\n } catch (error) {\n if (isBranchAlreadyExistsError(error, normalizedBranch)) {\n throw new Error(`Git worktree branch '${normalizedBranch}' already exists.`);\n }\n\n throw error;\n }\n\n return {\n path: worktreePath,\n branch: normalizedBranch\n };\n },\n\n async worktreeRemove(path) {\n const repoRoot = await getRepoRoot(normalizedCwd);\n const worktreePath = await resolveWorktreePath(repoRoot, path, \"Git worktree path\");\n const worktrees = await listWorktrees(normalizedCwd);\n\n if (!worktrees.some((worktree) => resolve(worktree.path) === worktreePath)) {\n return;\n }\n\n await runGit(normalizedCwd, [\"worktree\", \"remove\", \"--force\", worktreePath]);\n await rm(worktreePath, { recursive: true, force: true });\n },\n\n async worktreeList() {\n return listWorktrees(normalizedCwd);\n }\n };\n}\n\nfunction normalizeCommitOptions(options: GitCommitOptions | unknown): GitCommitOptions {\n if (!isRecord(options)) {\n throw new Error(\"Git commit options must be an object.\");\n }\n\n const files = getOwnProperty(options, \"files\");\n\n return {\n message: readNonEmptyString(getOwnProperty(options, \"message\"), \"Git commit options message\"),\n files:\n files === undefined ? undefined : readNonEmptyStringArray(files, \"Git commit options files\")\n };\n}\n\nfunction normalizeSavepoint(savepoint: GitSavepoint | unknown): GitSavepoint {\n if (!isRecord(savepoint)) {\n throw new Error(\"Git savepoint must be an object.\");\n }\n\n const stashRefValue = getOwnProperty(savepoint, \"stashRef\");\n const stashRef =\n stashRefValue === undefined\n ? undefined\n : readNonEmptyString(stashRefValue, \"Git savepoint stashRef\");\n if (stashRef !== undefined && !stashRef.startsWith(SAVEPOINT_REF_PREFIX)) {\n throw new Error(\"Git savepoint stashRef must be a Poe checkpoint ref.\");\n }\n\n return {\n head: readNonEmptyString(getOwnProperty(savepoint, \"head\"), \"Git savepoint head\"),\n stashRef\n };\n}\n\nfunction normalizeWorktreeCreateOptions(\n options: GitWorktreeCreateOptions | unknown\n): GitWorktreeCreateOptions & {\n base: string;\n} {\n if (options === undefined) {\n return {\n base: \"HEAD\"\n };\n }\n\n if (!isRecord(options)) {\n throw new Error(\"Git worktree create options must be an object.\");\n }\n\n const base = getOwnProperty(options, \"base\");\n const path = getOwnProperty(options, \"path\");\n\n return {\n base:\n base === undefined ? \"HEAD\" : readNonEmptyString(base, \"Git worktree create options base\"),\n path:\n path === undefined ? undefined : readNonEmptyString(path, \"Git worktree create options path\")\n };\n}\n\nfunction createSavepointRef(): string {\n return `${SAVEPOINT_REF_PREFIX}${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction createDefaultWorktreePath(repoRoot: string, branch: string): string {\n return resolve(repoRoot, \".poe-code\", \"worktrees\", createSafeBranchDirectoryName(branch));\n}\n\nfunction createSafeBranchDirectoryName(branch: string): string {\n return encodeURIComponent(branch);\n}\n\nasync function getRepoRoot(cwd: string): Promise<string> {\n return runGitAndTrim(cwd, [\"rev-parse\", \"--show-toplevel\"]);\n}\n\nasync function gitRefExists(cwd: string, ref: string): Promise<boolean> {\n try {\n await runGit(cwd, [\"show-ref\", \"--verify\", \"--quiet\", ref]);\n return true;\n } catch (error) {\n void error;\n return false;\n }\n}\n\nasync function listWorktrees(cwd: string): Promise<GitWorktree[]> {\n const { stdout } = await runGit(cwd, [\"worktree\", \"list\", \"--porcelain\"]);\n return parseWorktreeList(stdout);\n}\n\nfunction parseWorktreeList(output: string): GitWorktree[] {\n const worktrees: GitWorktree[] = [];\n let current: Partial<GitWorktree> = {};\n\n const finishCurrent = () => {\n if (current.path !== undefined && current.branch !== undefined) {\n worktrees.push({\n path: current.path,\n branch: current.branch\n });\n }\n\n current = {};\n };\n\n for (const line of output.split(\"\\n\")) {\n if (line.length === 0) {\n finishCurrent();\n continue;\n }\n\n if (line.startsWith(\"worktree \")) {\n current.path = line.slice(\"worktree \".length);\n continue;\n }\n\n if (line.startsWith(\"branch \")) {\n current.branch = parseBranchRef(line.slice(\"branch \".length));\n }\n }\n\n finishCurrent();\n return worktrees;\n}\n\nfunction parseBranchRef(ref: string): string {\n const branchPrefix = \"refs/heads/\";\n return ref.startsWith(branchPrefix) ? ref.slice(branchPrefix.length) : ref;\n}\n\nasync function resolveWorktreePath(repoRoot: string, path: string, label: string): Promise<string> {\n const resolvedRoot = resolve(repoRoot);\n const resolvedPath = isAbsolute(path) ? resolve(path) : resolve(resolvedRoot, path);\n const canonicalRoot = await realpath(resolvedRoot);\n const canonicalPath = await resolveCanonicalPath({ realpath, readlink }, resolvedPath);\n\n // A worktree lives somewhere under the repository, never at the repository root\n // itself, so root-itself is rejected alongside anything outside it. Both answers\n // come from the filesystem rather than the spelling: on a case-insensitive\n // filesystem a differently cased path still names the repository root.\n const [inside, isRootItself] = await Promise.all([\n containsPath(stat, canonicalRoot, canonicalPath),\n isSamePath(stat, canonicalPath, canonicalRoot)\n ]);\n\n if (!inside || isRootItself) {\n throw new Error(`${label} must be inside the git repository.`);\n }\n\n return canonicalPath;\n}\n\nfunction isBranchAlreadyExistsError(error: unknown, branch: string): boolean {\n return (\n error instanceof Error &&\n error.message.includes(branch) &&\n error.message.includes(\"already exists\")\n );\n}\n\nasync function runGitAndTrim(cwd: string, args: string[]): Promise<string> {\n const { stdout } = await runGit(cwd, args);\n return stdout.trim();\n}\n\nasync function runGit(cwd: string, args: string[]): Promise<ExecFileResult> {\n return new Promise((resolve, reject) => {\n execFile(\n \"git\",\n args,\n {\n cwd,\n encoding: \"utf8\",\n maxBuffer: GIT_EXEC_MAX_BUFFER\n },\n (error, stdout, stderr) => {\n if (error) {\n reject(\n new Error(\n `${formatGitCommand(args)} failed: ${pickGitFailureMessage(stdout, stderr, error)}`\n )\n );\n return;\n }\n\n resolve({\n stdout,\n stderr\n });\n }\n );\n });\n}\n\nasync function cleanupFailedCheckpoint(cwd: string, stashRef: string): Promise<void> {\n await deleteSavepointRef(cwd, stashRef);\n const restored = await tryRunGit(cwd, [\"stash\", \"apply\", \"--index\", \"stash@{0}\"]);\n if (restored) {\n await tryRunGit(cwd, [\"stash\", \"drop\", \"stash@{0}\"]);\n }\n}\n\nasync function deleteSavepointRef(cwd: string, stashRef: string): Promise<void> {\n await tryRunGit(cwd, [\"update-ref\", \"--delete\", stashRef]);\n}\n\nasync function tryRunGit(cwd: string, args: string[]): Promise<boolean> {\n try {\n await runGit(cwd, args);\n return true;\n } catch (error) {\n void error;\n return false;\n }\n}\n\nfunction formatGitCommand(args: string[]): string {\n return [\"git\", ...args].join(\" \");\n}\n\nfunction pickGitFailureMessage(stdout: string, stderr: string, error: Error): string {\n const stderrText = stderr.trim();\n\n if (stderrText.length > 0) {\n return stderrText;\n }\n\n const stdoutText = stdout.trim();\n\n if (stdoutText.length > 0) {\n return stdoutText;\n }\n\n return error.message;\n}\n\nfunction readNonEmptyString(value: unknown, label: string): string {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new Error(`${label} must be a non-empty string.`);\n }\n\n return value;\n}\n\nfunction readNonEmptyStringArray(value: unknown, label: string): string[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new Error(`${label} must be a non-empty array of strings.`);\n }\n\n const entries = value.map((entry, index) => readNonEmptyString(entry, `${label}[${index}]`));\n return [...entries];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction getOwnProperty<Name extends PropertyKey>(value: object, name: Name): unknown {\n return hasOwnProperty(value, name) ? value[name] : undefined;\n}\n\nfunction hasOwnProperty<Name extends PropertyKey>(\n value: object,\n name: Name\n): value is Record<Name, unknown> {\n return Object.prototype.hasOwnProperty.call(value, name);\n}\n", "import { createSeededRandom } from \"../interp/globals/math.js\";\n\nexport type TimeModuleOptions = {\n now?: () => number;\n random?: () => number;\n seed?: number;\n signal?: AbortSignal;\n};\n\nexport function makeTimeModule(options: TimeModuleOptions = {}): {\n random: () => number;\n now: () => number;\n sleep: (ms: number) => Promise<void>;\n uuid: () => string;\n} {\n const hasDeterministicRandom = options.random !== undefined || options.seed !== undefined;\n const random =\n options.random ??\n (options.seed === undefined ? () => Math.random() : createSeededRandom(options.seed).next);\n const now = options.now ?? (() => Date.now());\n const signal = options.signal;\n\n async function sleep(ms: number): Promise<void> {\n assertSleepDelay(ms);\n\n return await new Promise<void>((resolve, reject) => {\n if (signal?.aborted === true) {\n reject(createSleepAbortError());\n return;\n }\n\n const start = performance.now();\n let timeout = setTimeout(resolveSleep, ms);\n\n function cleanup(): void {\n clearTimeout(timeout);\n signal?.removeEventListener(\"abort\", rejectSleep);\n }\n\n function resolveSleep(): void {\n const remainingMs = ms - (performance.now() - start);\n if (remainingMs > 0) {\n timeout = setTimeout(resolveSleep, remainingMs);\n return;\n }\n\n cleanup();\n resolve();\n }\n\n function rejectSleep(): void {\n cleanup();\n reject(createSleepAbortError());\n }\n\n signal?.addEventListener(\"abort\", rejectSleep, { once: true });\n });\n }\n\n return {\n random,\n now,\n sleep,\n uuid: hasDeterministicRandom ? () => createRandomUuid(random) : () => crypto.randomUUID()\n };\n}\n\nfunction createRandomUuid(random: () => number): string {\n const bytes = Array.from({ length: 16 }, () => Math.floor(readRandomUnit(random()) * 256));\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n const hex = bytes.map((byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20)\n ].join(\"-\");\n}\n\nfunction readRandomUnit(value: number): number {\n if (Number.isFinite(value) && value >= 0 && value < 1) {\n return value;\n }\n\n throw new RangeError(\"time.uuid() random source must return a number in [0, 1).\");\n}\n\nfunction assertSleepDelay(ms: number): void {\n if (Number.isFinite(ms) && ms >= 0) {\n return;\n }\n\n throw new RangeError(\"time.sleep(ms) requires a non-negative finite millisecond delay.\");\n}\n\nfunction createSleepAbortError(): Error {\n return new Error(\"time.sleep aborted.\");\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["rawModules", "stat", "readNonEmptyString", "stat", "resolve", "resolve"]
|
|
7
|
+
}
|
|
@@ -7,6 +7,8 @@ type CallerInjectedFunction = {
|
|
|
7
7
|
bivarianceHack(...args: readonly unknown[]): unknown;
|
|
8
8
|
}["bivarianceHack"];
|
|
9
9
|
type HostBridgeOptions = {
|
|
10
|
+
registerCapabilities?: boolean;
|
|
11
|
+
capabilityPath?: readonly string[];
|
|
10
12
|
budget: Budget;
|
|
11
13
|
hostCalls?: HostCallJournal;
|
|
12
14
|
moduleId?: string;
|
|
@@ -29,18 +29,19 @@ export function readHostOperationPolicy(operation) {
|
|
|
29
29
|
return hostOperationPolicies.get(operation);
|
|
30
30
|
}
|
|
31
31
|
export function wrapCallerInjectedBindings(bindings, options) {
|
|
32
|
+
options = { ...options, registerCapabilities: true };
|
|
32
33
|
const state = { seen: new WeakMap() };
|
|
33
34
|
const copied = Object.fromEntries(Object.entries(bindings).map(([name, value]) => [
|
|
34
35
|
name,
|
|
35
36
|
typeof value === "function"
|
|
36
|
-
? wrapCallerInjectedFunction(name, value, options, state)
|
|
37
|
-
: copyHostValueToSandbox(value, [], { ...options, operation: name }, state, "<root>")
|
|
37
|
+
? wrapCallerInjectedFunction(name, value, { ...options, capabilityPath: [name] }, state)
|
|
38
|
+
: copyHostValueToSandbox(value, [], { ...options, operation: name, capabilityPath: [name] }, state, "<root>")
|
|
38
39
|
]));
|
|
39
40
|
options.budget.provisionDataUsage(measureSandboxData(Object.values(copied)));
|
|
40
41
|
return copied;
|
|
41
42
|
}
|
|
42
43
|
function wrapCallerInjectedFunction(name, value, options, state) {
|
|
43
|
-
const existing = state.seen.get(value);
|
|
44
|
+
const existing = state.seen.get(value) ?? options.hostCalls?.nativeClosures.get(value);
|
|
44
45
|
if (existing !== undefined)
|
|
45
46
|
return existing;
|
|
46
47
|
const bindingName = name === "default" && value.name.length > 0 ? value.name : name;
|
|
@@ -132,6 +133,12 @@ function wrapCallerInjectedFunction(name, value, options, state) {
|
|
|
132
133
|
name: bindingName,
|
|
133
134
|
properties: (closure) => {
|
|
134
135
|
state.seen.set(value, closure);
|
|
136
|
+
if (options.registerCapabilities) {
|
|
137
|
+
options.hostCalls?.registerHostCapability(JSON.stringify([
|
|
138
|
+
options.moduleId ?? "<bindings>",
|
|
139
|
+
...(options.capabilityPath ?? [bindingName])
|
|
140
|
+
]), closure, value);
|
|
141
|
+
}
|
|
135
142
|
return (copyFunctionProperties(callable, [], options, state, options.operation ?? bindingName) ?? {});
|
|
136
143
|
}
|
|
137
144
|
});
|
|
@@ -316,7 +323,7 @@ function isAbortReason(reason) {
|
|
|
316
323
|
("code" in reason && reason.code === "aborted")));
|
|
317
324
|
}
|
|
318
325
|
function copyHostResultToSandbox(result, stackFrames, options) {
|
|
319
|
-
const value = copyHostValueToSandbox(result, stackFrames, options, {
|
|
326
|
+
const value = copyHostValueToSandbox(result, stackFrames, { ...options, registerCapabilities: false }, {
|
|
320
327
|
seen: new WeakMap()
|
|
321
328
|
}, "<root>");
|
|
322
329
|
options.budget.provisionDataUsage(measureSandboxData([value]));
|
|
@@ -603,7 +610,7 @@ function copyHostValueToSandbox(value, stackFrames, options, state, path) {
|
|
|
603
610
|
if (!("value" in descriptor)) {
|
|
604
611
|
throw new TypeError(`Unsupported sandbox value at ${path}[${index}]: accessor property`);
|
|
605
612
|
}
|
|
606
|
-
copy[index] = copyHostValueToSandbox(descriptor.value, stackFrames, options, state, `${path}[${index}]`);
|
|
613
|
+
copy[index] = copyHostValueToSandbox(descriptor.value, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), String(index)] }, state, `${path}[${index}]`);
|
|
607
614
|
}
|
|
608
615
|
return copy;
|
|
609
616
|
}
|
|
@@ -616,7 +623,8 @@ function copyHostValueToSandbox(value, stackFrames, options, state, path) {
|
|
|
616
623
|
state.seen.set(value, copy);
|
|
617
624
|
budget.allocateCollectionEntries(value.size);
|
|
618
625
|
for (const [key, entry] of value) {
|
|
619
|
-
copy.entries.
|
|
626
|
+
const ordinal = copy.entries.size;
|
|
627
|
+
copy.entries.set(copyHostValueToSandbox(key, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), `key:${ordinal}`] }, state, `${path}.<key>`), copyHostValueToSandbox(entry, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), `value:${ordinal}`] }, state, `${path}.<value>`));
|
|
620
628
|
}
|
|
621
629
|
return copy;
|
|
622
630
|
}
|
|
@@ -629,7 +637,10 @@ function copyHostValueToSandbox(value, stackFrames, options, state, path) {
|
|
|
629
637
|
state.seen.set(value, copy);
|
|
630
638
|
budget.allocateCollectionEntries(value.size);
|
|
631
639
|
for (const entry of value) {
|
|
632
|
-
copy.values.add(copyHostValueToSandbox(entry, stackFrames,
|
|
640
|
+
copy.values.add(copyHostValueToSandbox(entry, stackFrames, {
|
|
641
|
+
...options,
|
|
642
|
+
capabilityPath: [...(options.capabilityPath ?? []), String(copy.values.size)]
|
|
643
|
+
}, state, `${path}.<value>`));
|
|
633
644
|
}
|
|
634
645
|
return copy;
|
|
635
646
|
}
|
|
@@ -653,7 +664,7 @@ function copyHostValueToSandbox(value, stackFrames, options, state, path) {
|
|
|
653
664
|
enumerable: true,
|
|
654
665
|
configurable: true,
|
|
655
666
|
writable: true,
|
|
656
|
-
value: copyHostValueToSandbox(descriptor.value, stackFrames, options, state, joinPath(path, key))
|
|
667
|
+
value: copyHostValueToSandbox(descriptor.value, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), key] }, state, joinPath(path, key))
|
|
657
668
|
});
|
|
658
669
|
}
|
|
659
670
|
return copy;
|
|
@@ -725,7 +736,7 @@ function copyFunctionProperties(callable, stackFrames, options, state, path) {
|
|
|
725
736
|
if (typeof descriptor.value !== "function") {
|
|
726
737
|
continue;
|
|
727
738
|
}
|
|
728
|
-
properties[key] = copyHostValueToSandbox(descriptor.value, stackFrames, options, state, joinPath(path, key));
|
|
739
|
+
properties[key] = copyHostValueToSandbox(descriptor.value, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), key] }, state, joinPath(path, key));
|
|
729
740
|
}
|
|
730
741
|
return Object.keys(properties).length > 0 ? properties : undefined;
|
|
731
742
|
}
|
|
@@ -83,8 +83,10 @@ export declare class HostCallJournal {
|
|
|
83
83
|
private retainedSize;
|
|
84
84
|
private readonly outcomeSizes;
|
|
85
85
|
private readonly capabilities;
|
|
86
|
+
private readonly requiredHostCapabilities;
|
|
86
87
|
private readonly capabilityIds;
|
|
87
88
|
readonly nativeClosures: WeakMap<object, SandboxClosure>;
|
|
89
|
+
private readonly hostSources;
|
|
88
90
|
private readonly encodedOutcomes;
|
|
89
91
|
private readonly callbackSizes;
|
|
90
92
|
private readonly completedCallbackOwners;
|
|
@@ -110,6 +112,9 @@ export declare class HostCallJournal {
|
|
|
110
112
|
snapshot(): HostCallRecord[];
|
|
111
113
|
dispose(): void;
|
|
112
114
|
registerCallbackFunction(record: HostCallRecord, id: number, closure: SandboxClosure, native: object): void;
|
|
115
|
+
registerHostCapability(path: string, closure: SandboxClosure, native: object): void;
|
|
116
|
+
rebindHostCapability(original: SandboxClosure, restored: SandboxClosure): void;
|
|
117
|
+
validateHostCapabilities(): void;
|
|
113
118
|
waitForCapability(id: string): Promise<void>;
|
|
114
119
|
trackCallbackCompletion(record: HostCallRecord, callbacks: readonly Promise<unknown>[]): void;
|
|
115
120
|
recordCallback(record: HostCallRecord, id: number, args: SandboxValue[], step: number): string;
|
|
@@ -36,8 +36,10 @@ export class HostCallJournal {
|
|
|
36
36
|
retainedSize = 0;
|
|
37
37
|
outcomeSizes = new Map();
|
|
38
38
|
capabilities = new Map();
|
|
39
|
+
requiredHostCapabilities = new Set();
|
|
39
40
|
capabilityIds = new WeakMap();
|
|
40
41
|
nativeClosures = new WeakMap();
|
|
42
|
+
hostSources = new WeakMap();
|
|
41
43
|
encodedOutcomes = new Map();
|
|
42
44
|
callbackSizes = new Map();
|
|
43
45
|
completedCallbackOwners = new Set();
|
|
@@ -55,7 +57,7 @@ export class HostCallJournal {
|
|
|
55
57
|
this.budget = budget;
|
|
56
58
|
this.recordedReplay = replay !== undefined;
|
|
57
59
|
if (replay !== undefined) {
|
|
58
|
-
const replayRecords = restoreReplayCalls(replay, this.encodedOutcomes, this.callbackSizes);
|
|
60
|
+
const replayRecords = restoreReplayCalls(replay, this.encodedOutcomes, this.callbackSizes, this.requiredHostCapabilities);
|
|
59
61
|
const restoredRunId = replayRecords[0]?.runId ?? records[0]?.runId ?? randomUUID();
|
|
60
62
|
validateRestoredRecords(records, restoredRunId, sourceHash);
|
|
61
63
|
for (const record of records) {
|
|
@@ -221,6 +223,34 @@ export class HostCallJournal {
|
|
|
221
223
|
this.capabilityIds.set(closure, identity);
|
|
222
224
|
this.nativeClosures.set(native, closure);
|
|
223
225
|
}
|
|
226
|
+
registerHostCapability(path, closure, native) {
|
|
227
|
+
const identity = `host:${path}`;
|
|
228
|
+
const existing = this.capabilities.get(identity);
|
|
229
|
+
if (existing !== undefined && existing !== closure)
|
|
230
|
+
throw new TypeError(`Conflicting replay capability '${identity}'.`);
|
|
231
|
+
this.capabilities.set(identity, closure);
|
|
232
|
+
if (!this.capabilityIds.has(closure))
|
|
233
|
+
this.capabilityIds.set(closure, identity);
|
|
234
|
+
if (!this.nativeClosures.has(native))
|
|
235
|
+
this.nativeClosures.set(native, closure);
|
|
236
|
+
this.hostSources.set(closure, native);
|
|
237
|
+
}
|
|
238
|
+
rebindHostCapability(original, restored) {
|
|
239
|
+
const identity = this.capabilityIds.get(original);
|
|
240
|
+
const source = this.hostSources.get(original);
|
|
241
|
+
if (identity === undefined || source === undefined)
|
|
242
|
+
return;
|
|
243
|
+
this.capabilities.set(identity, restored);
|
|
244
|
+
this.capabilityIds.set(restored, identity);
|
|
245
|
+
this.nativeClosures.set(source, restored);
|
|
246
|
+
this.hostSources.set(restored, source);
|
|
247
|
+
}
|
|
248
|
+
validateHostCapabilities() {
|
|
249
|
+
for (const identity of this.requiredHostCapabilities) {
|
|
250
|
+
if (!this.capabilities.has(identity))
|
|
251
|
+
throw new UnresolvedReplayCapabilityError(identity);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
224
254
|
waitForCapability(id) {
|
|
225
255
|
if (this.capabilities.has(id))
|
|
226
256
|
return Promise.resolve();
|
|
@@ -338,7 +368,7 @@ function copyOutcome(outcome) {
|
|
|
338
368
|
? { status: "fulfilled", value: deepCopyToSandbox(outcome.value) }
|
|
339
369
|
: { status: "rejected", reason: deepCopyToSandbox(outcome.reason) };
|
|
340
370
|
}
|
|
341
|
-
function restoreReplayCalls(input, encodedOutcomes, callbackSizes) {
|
|
371
|
+
function restoreReplayCalls(input, encodedOutcomes, callbackSizes, requiredHostCapabilities = new Set()) {
|
|
342
372
|
validateSnapshotData(input);
|
|
343
373
|
if (input === null ||
|
|
344
374
|
typeof input !== "object" ||
|
|
@@ -364,7 +394,22 @@ function restoreReplayCalls(input, encodedOutcomes, callbackSizes) {
|
|
|
364
394
|
}));
|
|
365
395
|
}
|
|
366
396
|
}
|
|
367
|
-
const resolveCapability = (id) =>
|
|
397
|
+
const resolveCapability = (id) => {
|
|
398
|
+
if (!capabilities.has(id) && id.startsWith("host:")) {
|
|
399
|
+
const path = JSON.parse(id.slice(5));
|
|
400
|
+
if (!Array.isArray(path) ||
|
|
401
|
+
path.length < 2 ||
|
|
402
|
+
path.some((value) => typeof value !== "string"))
|
|
403
|
+
throw new TypeError("Invalid host capability identity.");
|
|
404
|
+
requiredHostCapabilities.add(id);
|
|
405
|
+
capabilities.set(id, createSandboxClosure({
|
|
406
|
+
call: () => {
|
|
407
|
+
throw new TypeError("Host capability has not been reconstructed.");
|
|
408
|
+
}
|
|
409
|
+
}));
|
|
410
|
+
}
|
|
411
|
+
return capabilities.get(id);
|
|
412
|
+
};
|
|
368
413
|
return input.calls.map((entry, index) => {
|
|
369
414
|
if (entry === null || typeof entry !== "object" || Array.isArray(entry))
|
|
370
415
|
throw new TypeError("Invalid replay call.");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
export type RunResources = {
|
|
3
|
+
signal: AbortSignal;
|
|
4
|
+
add(close: () => Promise<void>): void;
|
|
5
|
+
};
|
|
6
|
+
export declare const runResources: AsyncLocalStorage<RunResources>;
|
|
7
|
+
export declare function withRunResources<Result>(signal: AbortSignal | undefined, execute: () => Promise<Result>): Promise<Result>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
export const runResources = new AsyncLocalStorage();
|
|
3
|
+
export async function withRunResources(signal, execute) {
|
|
4
|
+
const controller = new AbortController();
|
|
5
|
+
const cancel = () => controller.abort(signal?.reason);
|
|
6
|
+
const cleanups = new Set();
|
|
7
|
+
const resources = {
|
|
8
|
+
signal: controller.signal,
|
|
9
|
+
add(close) {
|
|
10
|
+
cleanups.add(close);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
14
|
+
if (signal?.aborted)
|
|
15
|
+
cancel();
|
|
16
|
+
let result;
|
|
17
|
+
let failure;
|
|
18
|
+
let errors = [];
|
|
19
|
+
try {
|
|
20
|
+
result = await runResources.run(resources, execute);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
failure = { reason: error };
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
signal?.removeEventListener("abort", cancel);
|
|
27
|
+
controller.abort(new Error("SafeJS run finished."));
|
|
28
|
+
const outcomes = await Promise.allSettled([...cleanups].map((close) => Promise.resolve().then(close)));
|
|
29
|
+
errors = outcomes.flatMap((outcome) => (outcome.status === "rejected" ? [outcome.reason] : []));
|
|
30
|
+
}
|
|
31
|
+
if (failure !== undefined)
|
|
32
|
+
throw failure.reason;
|
|
33
|
+
if (errors.length > 0)
|
|
34
|
+
throw new AggregateError(errors, "SafeJS resource cleanup failed.");
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { McpClient, type HttpTransportFetch, type StdioSpawn } from "../../../tiny-mcp-client/dist/index.js";
|
|
2
|
+
export type McpServerConfig = {
|
|
3
|
+
command: string;
|
|
4
|
+
args?: string[];
|
|
5
|
+
cwd?: string;
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
} | {
|
|
8
|
+
url: string;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
};
|
|
11
|
+
export type McpModuleOptions = {
|
|
12
|
+
servers: Record<string, McpServerConfig>;
|
|
13
|
+
requestTimeoutMs?: number;
|
|
14
|
+
closeTimeoutMs?: number;
|
|
15
|
+
maxToolPages?: number;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
fetch?: HttpTransportFetch;
|
|
18
|
+
spawn?: StdioSpawn;
|
|
19
|
+
};
|
|
20
|
+
export type ManagedMcpConnection = {
|
|
21
|
+
ready: Promise<McpClient>;
|
|
22
|
+
close(): Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
export declare function parseMcpConfig(source: string, directory: string): McpModuleOptions;
|
|
25
|
+
export declare function normalizeMcpOptions(value: unknown, keys?: string[]): McpModuleOptions;
|
|
26
|
+
export declare function connectMcpTransport(server: McpServerConfig, options: McpModuleOptions, signal?: AbortSignal): ManagedMcpConnection;
|