@earendil-works/pi-codemode 1.0.4 → 1.1.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/README.md CHANGED
@@ -39,7 +39,7 @@ await sandbox.close();
39
39
 
40
40
  - `tools.<name>(args)` returns a promise. Arguments and results make a JSON round trip. A tool that throws rejects with an `Error` carrying the same message. Tool names are also exposed as identifiers: characters that are not valid in identifiers become `_` (`toCodemodeIdentifier`), so `my-tool` is `tools.my_tool` as well as `tools["my-tool"]`.
41
41
  - `ALL_TOOLS` lists `{ name, description }` for every tool, with `name` as the identifier.
42
- - `text(value)` appends a text item to `result.output`; values other than strings are JSON-stringified. `console.log/info/warn/error/debug` append text items too.
42
+ - `text(value)` appends a text item to `result.output`; values other than strings are JSON-stringified. `console.log/info/warn/error/debug` append text items with `console: true`.
43
43
  - `image(urlOrItem)` appends an image item. It accepts a base64 `data:` URL, `{ image_url }`, or an MCP `ImageContent` block (`{ type: "image", data, mimeType }`). Remote URLs are rejected.
44
44
  - `exit()` ends the script successfully right away, keeping its output and store writes.
45
45
  - `globals` passed to the sandbox are called as top-level functions, for example a host helper `image(ref)`. They behave like tools but are not recorded in `result.calls`. A name like `models.classify` puts the function on a frozen `models` object. With `spread: true`, `execute` receives all call arguments as an array instead of the first one, and `signature` replaces the declaration generated from the schemas.
@@ -10,7 +10,7 @@
10
10
  * Output helpers: `text(value)` appends a text item (non-strings are
11
11
  * JSON-stringified), `image(urlOrItem)` appends an image from a base64 `data:` URL, an
12
12
  * `{ image_url }` object, or an MCP `ImageContent` block, and `exit()` ends the script
13
- * successfully. `console.*` appends text items like `text()`.
13
+ * successfully. `console.*` appends text items marked as console output.
14
14
  *
15
15
  * `store(key, value)` and `load(key)` are synchronous: they work on a snapshot of
16
16
  * JSON text passed in as `storeJson`, and the keys the script wrote are reported
@@ -23,7 +23,7 @@
23
23
  * or I/O in the VM, nothing can ever resume it.
24
24
  * `globalsJson` lists `{ name, spread }`; `a.b` names are grouped into a frozen `a` object.
25
25
  * `bridge(kind, a, b, c)` with kind "call" or "global" (id, name, argsJson),
26
- * "output" ("text", text) or ("image", data, mimeType), or "done" (ok, valueJsonOrErrorJson, writesJson).
26
+ * "output" ("text" or "console", text) or ("image", data, mimeType), or "done" (ok, valueJsonOrErrorJson, writesJson).
27
27
  *
28
28
  * Before anything else the prelude freezes the built-ins and makes the built-in globals read-only.
29
29
  * The prelude shares them with the script, so a script that patched one (for example
@@ -10,7 +10,7 @@
10
10
  * Output helpers: `text(value)` appends a text item (non-strings are
11
11
  * JSON-stringified), `image(urlOrItem)` appends an image from a base64 `data:` URL, an
12
12
  * `{ image_url }` object, or an MCP `ImageContent` block, and `exit()` ends the script
13
- * successfully. `console.*` appends text items like `text()`.
13
+ * successfully. `console.*` appends text items marked as console output.
14
14
  *
15
15
  * `store(key, value)` and `load(key)` are synchronous: they work on a snapshot of
16
16
  * JSON text passed in as `storeJson`, and the keys the script wrote are reported
@@ -23,7 +23,7 @@
23
23
  * or I/O in the VM, nothing can ever resume it.
24
24
  * `globalsJson` lists `{ name, spread }`; `a.b` names are grouped into a frozen `a` object.
25
25
  * `bridge(kind, a, b, c)` with kind "call" or "global" (id, name, argsJson),
26
- * "output" ("text", text) or ("image", data, mimeType), or "done" (ok, valueJsonOrErrorJson, writesJson).
26
+ * "output" ("text" or "console", text) or ("image", data, mimeType), or "done" (ok, valueJsonOrErrorJson, writesJson).
27
27
  *
28
28
  * Before anything else the prelude freezes the built-ins and makes the built-in globals read-only.
29
29
  * The prelude shares them with the script, so a script that patched one (for example
@@ -438,7 +438,7 @@ export const PRELUDE_SOURCE = `(function (bridge, toolsJson, globalsJson, storeJ
438
438
  const console = {};
439
439
  for (const level of ["log", "info", "warn", "error", "debug"]) {
440
440
  console[level] = (...args) => {
441
- output("text", args.map(format).join(" "));
441
+ output("console", args.map(format).join(" "));
442
442
  };
443
443
  }
444
444
  Object.freeze(console);
@@ -1 +1 @@
1
- {"version":3,"file":"prelude-source.js","sourceRoot":"","sources":["../../src/runtime/prelude-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,GAAG,IAAI,CAAC;AAChD,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAAC;AACjD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AACjD,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC,MAAM,oBAAoB,GACzB,gGAAgG,CAAC;AAElG,MAAM,CAAC,MAAM,cAAc,GAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAgQhB,qBAAqB;;8GAEmE,qBAAqB;;;;;eAKpH,qBAAqB;;iDAEa,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAiChD,gBAAgB,qBAAqB,gBAAgB;;2CAEhC,gBAAgB,kBAAkB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BA+BhE,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;sEAGK,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;gEAG1C,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;4CAoBxD,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6G7E,CAAC","sourcesContent":["/**\n * JavaScript evaluated inside the QuickJS VM before the script runs.\n *\n * The VM is its own wasm instance, so nothing here guards a realm boundary.\n * The prelude keeps the host bridge in a closure so the script cannot call it\n * directly, and builds `tools`, `ALL_TOOLS`, the output helpers (`text`, `image`,\n * `exit`, `console`), and globals on top of it. Tool arguments and results cross\n * as JSON strings and are parsed on this side.\n *\n * Output helpers: `text(value)` appends a text item (non-strings are\n * JSON-stringified), `image(urlOrItem)` appends an image from a base64 `data:` URL, an\n * `{ image_url }` object, or an MCP `ImageContent` block, and `exit()` ends the script\n * successfully. `console.*` appends text items like `text()`.\n *\n * `store(key, value)` and `load(key)` are synchronous: they work on a snapshot of\n * JSON text passed in as `storeJson`, and the keys the script wrote are reported\n * with a successful \"done\".\n *\n * Evaluates to a function `(bridge, toolsJson, globalsJson, storeJson) => { settle, run, stalled }`.\n * `toolsJson` lists `{ name, jsName, description }`: `tools[jsName]` and `tools[name]` call the\n * tool, and `ALL_TOOLS` lists `{ name: jsName, description }`.\n * `stalled()` reports a script that has not finished while no host call is pending: with no timers\n * or I/O in the VM, nothing can ever resume it.\n * `globalsJson` lists `{ name, spread }`; `a.b` names are grouped into a frozen `a` object.\n * `bridge(kind, a, b, c)` with kind \"call\" or \"global\" (id, name, argsJson),\n * \"output\" (\"text\", text) or (\"image\", data, mimeType), or \"done\" (ok, valueJsonOrErrorJson, writesJson).\n *\n * Before anything else the prelude freezes the built-ins and makes the built-in globals read-only.\n * The prelude shares them with the script, so a script that patched one (for example\n * `Array.prototype.toJSON`) could otherwise corrupt what the prelude reports to the host.\n */\nexport const MAX_STORE_VALUE_CHARS = 256 * 1024;\nexport const MAX_STORE_TOTAL_CHARS = 1024 * 1024;\n/**\n * Output one script may produce with `text()`, `image()`, and `console.*`: characters of text and\n * base64 image data, and items. The host keeps all output until the script ends, so without a\n * limit a script that prints in a loop grows the host's memory until it crashes. The item limit\n * covers loops that print empty strings.\n */\nexport const MAX_OUTPUT_CHARS = 16 * 1024 * 1024;\nexport const MAX_OUTPUT_ITEMS = 100_000;\n\nconst IMAGE_HELPER_EXPECTS =\n\t\"image expects a non-empty image URL string, an object with image_url, or a raw MCP image block\";\n\nexport const PRELUDE_SOURCE: string = `(function (bridge, toolsJson, globalsJson, storeJson) {\n\t\"use strict\";\n\n\t// Freeze every object reachable from the built-in globals, plus the intrinsics that are only\n\t// reachable from instances (iterator and generator prototypes, %TypedArray%).\n\t//\n\t// Freezing alone breaks ordinary code through the \"override mistake\": a data property that is\n\t// read-only on a prototype cannot be assigned on an instance either, so\n\t// this.name = \"MyError\" in an Error subclass would throw. Commonly overridden properties\n\t// become accessors whose setter defines an own property on the instance instead.\n\t(function lockdown() {\n\t\tconst OVERRIDABLE = new Set([\"constructor\", \"name\", \"message\", \"toString\", \"toLocaleString\", \"valueOf\", \"toJSON\"]);\n\t\tconst seen = new Set([globalThis]);\n\t\tconst queue = [];\n\t\tconst add = (value) => {\n\t\t\tif ((typeof value === \"object\" && value !== null) || typeof value === \"function\") {\n\t\t\t\tif (!seen.has(value)) {\n\t\t\t\t\tseen.add(value);\n\t\t\t\t\tqueue.push(value);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Accessors from an object literal have no own prototype object, unlike function expressions,\n\t\t// whose prototype.constructor would be converted again without end.\n\t\tfunction allowOverride(object, key, value, enumerable) {\n\t\t\tconst { get, set } = Object.getOwnPropertyDescriptor(\n\t\t\t\t{\n\t\t\t\t\tget accessor() {\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t},\n\t\t\t\t\tset accessor(next) {\n\t\t\t\t\t\tif (this === object) {\n\t\t\t\t\t\t\tthrow new TypeError(\"Cannot assign to read only property '\" + String(key) + \"' of a built-in\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ((typeof this !== \"object\" || this === null) && typeof this !== \"function\") return;\n\t\t\t\t\t\tObject.defineProperty(this, key, { value: next, writable: true, enumerable: true, configurable: true });\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"accessor\",\n\t\t\t);\n\t\t\tObject.defineProperty(object, key, { get, set, enumerable, configurable: false });\n\t\t\tadd(get);\n\t\t\tadd(set);\n\t\t}\n\n\t\tfor (const key of Reflect.ownKeys(globalThis)) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(globalThis, key);\n\t\t\tadd(descriptor.value);\n\t\t\tadd(descriptor.get);\n\t\t\tadd(descriptor.set);\n\t\t\tif (\"value\" in descriptor && descriptor.configurable) {\n\t\t\t\tObject.defineProperty(globalThis, key, { writable: false, configurable: false });\n\t\t\t}\n\t\t}\n\t\tadd(Object.getPrototypeOf(function* () {}));\n\t\tadd(Object.getPrototypeOf(async function () {}));\n\t\tadd(Object.getPrototypeOf(async function* () {}));\n\t\tadd(Object.getPrototypeOf(Int8Array));\n\t\tadd(Object.getPrototypeOf([][Symbol.iterator]()));\n\t\tadd(Object.getPrototypeOf(new Map()[Symbol.iterator]()));\n\t\tadd(Object.getPrototypeOf(new Set()[Symbol.iterator]()));\n\t\tadd(Object.getPrototypeOf(\"\"[Symbol.iterator]()));\n\t\tadd(Object.getPrototypeOf(/a/[Symbol.matchAll](\"\")));\n\t\tif (typeof Iterator === \"function\") {\n\t\t\tif (typeof Iterator.prototype.map === \"function\") add(Object.getPrototypeOf([].values().map((x) => x)));\n\t\t\tif (typeof Iterator.from === \"function\") add(Object.getPrototypeOf(Iterator.from({ next() {} })));\n\t\t}\n\n\t\twhile (queue.length > 0) {\n\t\t\tconst object = queue.pop();\n\t\t\tadd(Object.getPrototypeOf(object));\n\t\t\tconst descriptors = Object.getOwnPropertyDescriptors(object);\n\t\t\tfor (const key of Reflect.ownKeys(descriptors)) {\n\t\t\t\tconst descriptor = descriptors[key];\n\t\t\t\tif (\"value\" in descriptor) {\n\t\t\t\t\tadd(descriptor.value);\n\t\t\t\t\tif (\n\t\t\t\t\t\tdescriptor.writable &&\n\t\t\t\t\t\tdescriptor.configurable &&\n\t\t\t\t\t\t(object === Object.prototype || OVERRIDABLE.has(key))\n\t\t\t\t\t) {\n\t\t\t\t\t\tallowOverride(object, key, descriptor.value, descriptor.enumerable);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tadd(descriptor.get);\n\t\t\t\t\tadd(descriptor.set);\n\t\t\t\t}\n\t\t\t}\n\t\t\tObject.freeze(object);\n\t\t}\n\t})();\n\tconst stringify = JSON.stringify;\n\tconst parse = JSON.parse;\n\tconst promiseThen = Promise.prototype.then;\n\tconst ErrorCtor = Error;\n\tconst TypeErrorCtor = TypeError;\n\tconst RangeErrorCtor = RangeError;\n\tconst pending = new Map();\n\tlet nextId = 1;\n\tlet finished = false;\n\t// Thrown by exit() to unwind the script after it already reported success.\n\tconst EXIT = Object.freeze({});\n\n\tfunction done(ok, payload, writes) {\n\t\tif (finished) return;\n\t\tfinished = true;\n\t\tbridge(\"done\", ok, payload, writes);\n\t}\n\n\tfunction serialize(value) {\n\t\treturn value === undefined ? undefined : stringify(value);\n\t}\n\n\t// QuickJS stacks list frames only. Prefix \"Name: message\" like V8 so the\n\t// text reads the same as a Node error, and drop this prelude's frames.\n\tfunction errorText(error) {\n\t\tconst head = error.message ? error.name + \": \" + error.message : String(error.name);\n\t\tconst frames =\n\t\t\ttypeof error.stack === \"string\"\n\t\t\t\t? error.stack.split(\"\\\\n\").filter((line) => line.trim() && !line.includes(\"codemode-prelude.js\"))\n\t\t\t\t: [];\n\t\treturn [head, ...frames].join(\"\\\\n\");\n\t}\n\n\tfunction format(value) {\n\t\tif (typeof value === \"string\") return value;\n\t\tif (value instanceof ErrorCtor) return errorText(value);\n\t\ttry {\n\t\t\tconst json = stringify(value);\n\t\t\treturn json === undefined ? String(value) : json;\n\t\t} catch {\n\t\t\treturn String(value);\n\t\t}\n\t}\n\n\t// The host requires string fields. A script can set an error's name or message to anything, so\n\t// they are coerced, and a value whose coercion throws gets a placeholder.\n\tfunction describeError(error) {\n\t\ttry {\n\t\t\tif (error instanceof ErrorCtor) {\n\t\t\t\treturn stringify({ name: String(error.name), message: String(error.message), stack: errorText(error) });\n\t\t\t}\n\t\t\treturn stringify({ message: String(format(error)) });\n\t\t} catch {\n\t\t\treturn stringify({ message: \"The script threw a value that cannot be described\" });\n\t\t}\n\t}\n\n\tfunction caller(kind, name, spread) {\n\t\treturn (...args) =>\n\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\tlet json;\n\t\t\t\ttry {\n\t\t\t\t\tjson = serialize(spread ? args : args[0]);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treject(error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst id = nextId++;\n\t\t\t\tpending.set(id, { resolve, reject });\n\t\t\t\tbridge(kind, id, name, json);\n\t\t\t});\n\t}\n\n\tconst tools = Object.create(null);\n\tconst allTools = [];\n\tfor (const { name, jsName, description } of parse(toolsJson)) {\n\t\tconst fn = caller(\"call\", name);\n\t\t// The first tool wins when two names normalize to the same identifier.\n\t\tif (!(jsName in tools)) {\n\t\t\ttools[jsName] = fn;\n\t\t\tallTools.push(Object.freeze({ name: jsName, description }));\n\t\t}\n\t\tif (!(name in tools)) tools[name] = fn;\n\t}\n\tObject.freeze(tools);\n\tObject.freeze(allTools);\n\n\t// Reading a member that does not exist throws an error that names the close matches, instead of\n\t// a later \"not a function\". \\`in\\` checks still work.\n\tconst comparable = (name) => name.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n\tfunction guard(target, label, names, hint) {\n\t\treturn new Proxy(target, {\n\t\t\tget(object, property, receiver) {\n\t\t\t\tif (typeof property !== \"string\" || property in object || property in Object.prototype || property === \"then\" || property === \"toJSON\") {\n\t\t\t\t\treturn Reflect.get(object, property, receiver);\n\t\t\t\t}\n\t\t\t\tconst wanted = comparable(property);\n\t\t\t\tconst exact = names.filter((name) => comparable(name) === wanted);\n\t\t\t\tconst close = exact.length > 0 ? exact : names.filter((name) => wanted && (comparable(name).includes(wanted) || wanted.includes(comparable(name))));\n\t\t\t\tlet message = label + \".\" + property + \" does not exist.\";\n\t\t\t\tif (close.length > 0) message += \" Did you mean \" + close.slice(0, 5).map((name) => label + \".\" + name).join(\", \") + \"?\";\n\t\t\t\telse if (names.length <= 20) message += \" Available: \" + names.join(\", \") + \".\";\n\t\t\t\tif (hint) message += \" \" + hint;\n\t\t\t\tmessage += ' Check for a member with \"' + property + '\" in ' + label + \".\";\n\t\t\t\tthrow new TypeErrorCtor(message);\n\t\t\t},\n\t\t});\n\t}\n\tconst toolsProxy = guard(\n\t\ttools,\n\t\t\"tools\",\n\t\tallTools.map((tool) => tool.name),\n\t\t\"ALL_TOOLS lists every tool; searchTools(query) finds tools by topic.\",\n\t);\n\n\tconst namespaces = new Map();\n\tfor (const { name, spread } of parse(globalsJson)) {\n\t\tconst fn = caller(\"global\", name, spread);\n\t\tconst dot = name.indexOf(\".\");\n\t\tif (dot === -1) {\n\t\t\tObject.defineProperty(globalThis, name, { value: fn, enumerable: true });\n\t\t\tcontinue;\n\t\t}\n\t\tconst namespace = name.slice(0, dot);\n\t\tif (!namespaces.has(namespace)) namespaces.set(namespace, Object.create(null));\n\t\tnamespaces.get(namespace)[name.slice(dot + 1)] = fn;\n\t}\n\tfor (const [namespace, members] of namespaces) {\n\t\tObject.freeze(members);\n\t\tconst value = guard(members, namespace, Object.keys(members));\n\t\tObject.defineProperty(globalThis, namespace, { value, enumerable: true });\n\t}\n\n\t// key -> JSON text. Sizes count key and JSON characters.\n\tconst stored = new Map(Object.entries(parse(storeJson)));\n\tconst writes = new Map();\n\tlet storedChars = 0;\n\tfor (const [key, json] of stored) storedChars += key.length + json.length;\n\n\tconst STORE_HINT =\n\t\t\"store() is for small state such as IDs or summaries. Show images with image(), keep large data in variables, or write it to a file with a tool.\";\n\n\tfunction checkKey(name, key) {\n\t\tif (typeof key !== \"string\") throw new TypeError(name + \"() key must be a string\");\n\t}\n\n\tfunction store(key, value) {\n\t\tcheckKey(\"store\", key);\n\t\tconst previous = stored.has(key) ? key.length + stored.get(key).length : 0;\n\t\tif (value === undefined) {\n\t\t\tstored.delete(key);\n\t\t\tstoredChars -= previous;\n\t\t\twrites.set(key, undefined);\n\t\t\treturn;\n\t\t}\n\t\tlet json;\n\t\ttry {\n\t\t\tjson = stringify(value);\n\t\t} catch (error) {\n\t\t\tthrow new TypeError(\"store(\" + stringify(key) + \") value is not JSON-serializable: \" + format(error));\n\t\t}\n\t\tif (json === undefined) {\n\t\t\tthrow new TypeError(\"store(\" + stringify(key) + \") value is not JSON-serializable\");\n\t\t}\n\t\tif (json.length > ${MAX_STORE_VALUE_CHARS}) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"store(\" + stringify(key) + \") value has \" + json.length + \" characters of JSON, more than the limit of ${MAX_STORE_VALUE_CHARS}. \" +\n\t\t\t\t\tSTORE_HINT,\n\t\t\t);\n\t\t}\n\t\tconst next = storedChars - previous + key.length + json.length;\n\t\tif (next > ${MAX_STORE_TOTAL_CHARS}) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"store is full: stored values would exceed ${MAX_STORE_TOTAL_CHARS} characters of JSON. Delete keys with store(key, undefined). \" +\n\t\t\t\t\tSTORE_HINT,\n\t\t\t);\n\t\t}\n\t\tstored.set(key, json);\n\t\tstoredChars = next;\n\t\twrites.set(key, json);\n\t}\n\n\tfunction load(key) {\n\t\tcheckKey(\"load\", key);\n\t\tconst json = stored.get(key);\n\t\treturn json === undefined ? undefined : parse(json);\n\t}\n\n\tfunction serializeWrites() {\n\t\tconst entries = [];\n\t\tfor (const [key, json] of writes) entries.push(json === undefined ? [key] : [key, json]);\n\t\treturn stringify(entries);\n\t}\n\n\tObject.defineProperty(globalThis, \"store\", { value: store, enumerable: true });\n\tObject.defineProperty(globalThis, \"load\", { value: load, enumerable: true });\n\n\tlet outputChars = 0;\n\tlet outputItems = 0;\n\n\t// Past the output limits the script fails: done() reports the error, so catching it does not\n\t// resume output, and the host ends the script.\n\tfunction output(kind, data, mimeType) {\n\t\tif (finished) return;\n\t\toutputChars += data.length;\n\t\toutputItems++;\n\t\tif (outputChars > ${MAX_OUTPUT_CHARS} || outputItems > ${MAX_OUTPUT_ITEMS}) {\n\t\t\tconst error = new RangeErrorCtor(\n\t\t\t\t\"script output exceeded the limit of ${MAX_OUTPUT_CHARS} characters or ${MAX_OUTPUT_ITEMS} text(), image(), and console calls. \" +\n\t\t\t\t\t\"Print a summary instead, or write large data to a file with a tool.\",\n\t\t\t);\n\t\t\tdone(false, describeError(error));\n\t\t\tthrow error;\n\t\t}\n\t\tbridge(\"output\", kind, data, mimeType);\n\t}\n\n\t// Primitives become their string form, everything else JSON.\n\tfunction outputText(value) {\n\t\tif (value === undefined || value === null || typeof value !== \"object\" && typeof value !== \"function\") {\n\t\t\treturn String(value);\n\t\t}\n\t\tconst json = stringify(value);\n\t\treturn json === undefined ? String(value) : json;\n\t}\n\n\tfunction text(value) {\n\t\tlet rendered;\n\t\ttry {\n\t\t\trendered = outputText(value);\n\t\t} catch (error) {\n\t\t\tthrow new TypeErrorCtor(error instanceof ErrorCtor ? error.message : String(error));\n\t\t}\n\t\toutput(\"text\", rendered);\n\t}\n\n\tfunction imageUrl(value) {\n\t\tif (typeof value === \"string\") return value;\n\t\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\t\tthrow new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});\n\t\t}\n\t\tif (value.image_url !== undefined) {\n\t\t\tif (typeof value.image_url !== \"string\") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});\n\t\t\treturn value.image_url;\n\t\t}\n\t\tif (typeof value.type !== \"string\") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});\n\t\tif (value.type !== \"image\") {\n\t\t\tthrow new TypeErrorCtor('image only accepts MCP image blocks, got \"' + value.type + '\"');\n\t\t}\n\t\tif (typeof value.data !== \"string\" || value.data === \"\") throw new TypeErrorCtor(\"image expected MCP image data\");\n\t\tif (value.data.toLowerCase().startsWith(\"data:\")) return value.data;\n\t\treturn \"data:;base64,\" + value.data;\n\t}\n\n\t// Base64 of the signatures of the formats providers accept inline (PNG, JPEG except\n\t// JPEG-LS, GIF, \"RIFF....WEBP\"). Signatures start at byte 0, so their encodings are prefixes.\n\tconst IMAGE_SIGNATURES = [\n\t\t[\"image/png\", /^iVBORw0KGg/],\n\t\t[\"image/jpeg\", /^[/]9j[/](?!9)/],\n\t\t[\"image/gif\", /^R0lGOD[dl]h/],\n\t\t[\"image/webp\", /^UklG.{8}RUJQ/],\n\t];\n\n\tfunction image(value) {\n\t\tconst url = imageUrl(value);\n\t\tif (url === \"\") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});\n\t\tconst colon = url.indexOf(\":\");\n\t\tconst scheme = colon === -1 ? \"\" : url.slice(0, colon).toLowerCase();\n\t\tif (scheme === \"http\" || scheme === \"https\") {\n\t\t\tthrow new TypeErrorCtor(\"remote image URLs are not supported in tool outputs. Pass a base64 data URI instead\");\n\t\t}\n\t\tconst comma = url.indexOf(\",\");\n\t\tconst header = comma === -1 ? [] : url.slice(colon + 1, comma).split(\";\");\n\t\tif (scheme !== \"data\" || comma === -1 || header.slice(1).every((part) => part.toLowerCase() !== \"base64\")) {\n\t\t\tthrow new TypeErrorCtor(\"invalid image output. Pass a base64 data URI instead\");\n\t\t}\n\t\t// Providers reject the whole request on a bad image, and a persisted image block would be\n\t\t// resent on every later turn. Line breaks from wrapped base64 are dropped. The declared type\n\t\t// is ignored in favor of the detected one, as providers also reject mismatches.\n\t\tconst data = url.slice(comma + 1).replace(/\\\\s+/g, \"\");\n\t\tif (data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data)) {\n\t\t\tthrow new TypeErrorCtor(\"invalid image output. The image data is not valid base64 (truncated or corrupted?)\");\n\t\t}\n\t\tconst head = data.slice(0, 16);\n\t\tconst signature = IMAGE_SIGNATURES.find(([, pattern]) => pattern.test(head));\n\t\tif (!signature) {\n\t\t\tthrow new TypeErrorCtor(\"invalid image output. The image data is not a PNG, JPEG, GIF, or WebP image\");\n\t\t}\n\t\toutput(\"image\", data, signature[0]);\n\t}\n\n\tfunction exit() {\n\t\tlet writesJson;\n\t\ttry {\n\t\t\twritesJson = serializeWrites();\n\t\t} catch (error) {\n\t\t\tdone(false, describeError(error));\n\t\t\tthrow EXIT;\n\t\t}\n\t\tdone(true, undefined, writesJson);\n\t\tthrow EXIT;\n\t}\n\n\tconst console = {};\n\tfor (const level of [\"log\", \"info\", \"warn\", \"error\", \"debug\"]) {\n\t\tconsole[level] = (...args) => {\n\t\t\toutput(\"text\", args.map(format).join(\" \"));\n\t\t};\n\t}\n\tObject.freeze(console);\n\n\tObject.defineProperty(globalThis, \"tools\", { value: toolsProxy, enumerable: true });\n\tObject.defineProperty(globalThis, \"ALL_TOOLS\", { value: allTools, enumerable: true });\n\tObject.defineProperty(globalThis, \"console\", { value: console, enumerable: true });\n\tObject.defineProperty(globalThis, \"text\", { value: text, enumerable: true });\n\tObject.defineProperty(globalThis, \"image\", { value: image, enumerable: true });\n\tObject.defineProperty(globalThis, \"exit\", { value: exit, enumerable: true });\n\n\treturn {\n\t\tsettle(id, ok, payload) {\n\t\t\tconst entry = pending.get(id);\n\t\t\tif (!entry) return;\n\t\t\tpending.delete(id);\n\t\t\tif (!ok) {\n\t\t\t\tentry.reject(new ErrorCtor(payload));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet value;\n\t\t\ttry {\n\t\t\t\tvalue = payload === undefined ? undefined : parse(payload);\n\t\t\t} catch (error) {\n\t\t\t\tentry.reject(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tentry.resolve(value);\n\t\t},\n\t\trun(fn) {\n\t\t\tlet promise;\n\t\t\ttry {\n\t\t\t\tpromise = fn(toolsProxy, console);\n\t\t\t} catch (error) {\n\t\t\t\tdone(false, describeError(error));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpromiseThen.call(\n\t\t\t\tpromise,\n\t\t\t\t(value) => {\n\t\t\t\t\tlet json;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tjson = serialize(value);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdone(false, describeError(error));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdone(true, json, serializeWrites());\n\t\t\t\t},\n\t\t\t\t(error) => {\n\t\t\t\t\tdone(false, describeError(error));\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\tstalled() {\n\t\t\tif (finished || pending.size > 0) return false;\n\t\t\tdone(\n\t\t\t\tfalse,\n\t\t\t\tstringify({\n\t\t\t\t\tname: \"Error\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"The script is waiting on a promise that can never settle: no tool call is pending, and timers do not exist here.\",\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn true;\n\t\t},\n\t};\n})`;\n"]}
1
+ {"version":3,"file":"prelude-source.js","sourceRoot":"","sources":["../../src/runtime/prelude-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,GAAG,IAAI,CAAC;AAChD,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,GAAG,IAAI,CAAC;AACjD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AACjD,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC,MAAM,oBAAoB,GACzB,gGAAgG,CAAC;AAElG,MAAM,CAAC,MAAM,cAAc,GAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAgQhB,qBAAqB;;8GAEmE,qBAAqB;;;;;eAKpH,qBAAqB;;iDAEa,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAiChD,gBAAgB,qBAAqB,gBAAgB;;2CAEhC,gBAAgB,kBAAkB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BA+BhE,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;sEAGK,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;gEAG1C,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;4CAoBxD,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6G7E,CAAC","sourcesContent":["/**\n * JavaScript evaluated inside the QuickJS VM before the script runs.\n *\n * The VM is its own wasm instance, so nothing here guards a realm boundary.\n * The prelude keeps the host bridge in a closure so the script cannot call it\n * directly, and builds `tools`, `ALL_TOOLS`, the output helpers (`text`, `image`,\n * `exit`, `console`), and globals on top of it. Tool arguments and results cross\n * as JSON strings and are parsed on this side.\n *\n * Output helpers: `text(value)` appends a text item (non-strings are\n * JSON-stringified), `image(urlOrItem)` appends an image from a base64 `data:` URL, an\n * `{ image_url }` object, or an MCP `ImageContent` block, and `exit()` ends the script\n * successfully. `console.*` appends text items marked as console output.\n *\n * `store(key, value)` and `load(key)` are synchronous: they work on a snapshot of\n * JSON text passed in as `storeJson`, and the keys the script wrote are reported\n * with a successful \"done\".\n *\n * Evaluates to a function `(bridge, toolsJson, globalsJson, storeJson) => { settle, run, stalled }`.\n * `toolsJson` lists `{ name, jsName, description }`: `tools[jsName]` and `tools[name]` call the\n * tool, and `ALL_TOOLS` lists `{ name: jsName, description }`.\n * `stalled()` reports a script that has not finished while no host call is pending: with no timers\n * or I/O in the VM, nothing can ever resume it.\n * `globalsJson` lists `{ name, spread }`; `a.b` names are grouped into a frozen `a` object.\n * `bridge(kind, a, b, c)` with kind \"call\" or \"global\" (id, name, argsJson),\n * \"output\" (\"text\" or \"console\", text) or (\"image\", data, mimeType), or \"done\" (ok, valueJsonOrErrorJson, writesJson).\n *\n * Before anything else the prelude freezes the built-ins and makes the built-in globals read-only.\n * The prelude shares them with the script, so a script that patched one (for example\n * `Array.prototype.toJSON`) could otherwise corrupt what the prelude reports to the host.\n */\nexport const MAX_STORE_VALUE_CHARS = 256 * 1024;\nexport const MAX_STORE_TOTAL_CHARS = 1024 * 1024;\n/**\n * Output one script may produce with `text()`, `image()`, and `console.*`: characters of text and\n * base64 image data, and items. The host keeps all output until the script ends, so without a\n * limit a script that prints in a loop grows the host's memory until it crashes. The item limit\n * covers loops that print empty strings.\n */\nexport const MAX_OUTPUT_CHARS = 16 * 1024 * 1024;\nexport const MAX_OUTPUT_ITEMS = 100_000;\n\nconst IMAGE_HELPER_EXPECTS =\n\t\"image expects a non-empty image URL string, an object with image_url, or a raw MCP image block\";\n\nexport const PRELUDE_SOURCE: string = `(function (bridge, toolsJson, globalsJson, storeJson) {\n\t\"use strict\";\n\n\t// Freeze every object reachable from the built-in globals, plus the intrinsics that are only\n\t// reachable from instances (iterator and generator prototypes, %TypedArray%).\n\t//\n\t// Freezing alone breaks ordinary code through the \"override mistake\": a data property that is\n\t// read-only on a prototype cannot be assigned on an instance either, so\n\t// this.name = \"MyError\" in an Error subclass would throw. Commonly overridden properties\n\t// become accessors whose setter defines an own property on the instance instead.\n\t(function lockdown() {\n\t\tconst OVERRIDABLE = new Set([\"constructor\", \"name\", \"message\", \"toString\", \"toLocaleString\", \"valueOf\", \"toJSON\"]);\n\t\tconst seen = new Set([globalThis]);\n\t\tconst queue = [];\n\t\tconst add = (value) => {\n\t\t\tif ((typeof value === \"object\" && value !== null) || typeof value === \"function\") {\n\t\t\t\tif (!seen.has(value)) {\n\t\t\t\t\tseen.add(value);\n\t\t\t\t\tqueue.push(value);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Accessors from an object literal have no own prototype object, unlike function expressions,\n\t\t// whose prototype.constructor would be converted again without end.\n\t\tfunction allowOverride(object, key, value, enumerable) {\n\t\t\tconst { get, set } = Object.getOwnPropertyDescriptor(\n\t\t\t\t{\n\t\t\t\t\tget accessor() {\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t},\n\t\t\t\t\tset accessor(next) {\n\t\t\t\t\t\tif (this === object) {\n\t\t\t\t\t\t\tthrow new TypeError(\"Cannot assign to read only property '\" + String(key) + \"' of a built-in\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ((typeof this !== \"object\" || this === null) && typeof this !== \"function\") return;\n\t\t\t\t\t\tObject.defineProperty(this, key, { value: next, writable: true, enumerable: true, configurable: true });\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"accessor\",\n\t\t\t);\n\t\t\tObject.defineProperty(object, key, { get, set, enumerable, configurable: false });\n\t\t\tadd(get);\n\t\t\tadd(set);\n\t\t}\n\n\t\tfor (const key of Reflect.ownKeys(globalThis)) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(globalThis, key);\n\t\t\tadd(descriptor.value);\n\t\t\tadd(descriptor.get);\n\t\t\tadd(descriptor.set);\n\t\t\tif (\"value\" in descriptor && descriptor.configurable) {\n\t\t\t\tObject.defineProperty(globalThis, key, { writable: false, configurable: false });\n\t\t\t}\n\t\t}\n\t\tadd(Object.getPrototypeOf(function* () {}));\n\t\tadd(Object.getPrototypeOf(async function () {}));\n\t\tadd(Object.getPrototypeOf(async function* () {}));\n\t\tadd(Object.getPrototypeOf(Int8Array));\n\t\tadd(Object.getPrototypeOf([][Symbol.iterator]()));\n\t\tadd(Object.getPrototypeOf(new Map()[Symbol.iterator]()));\n\t\tadd(Object.getPrototypeOf(new Set()[Symbol.iterator]()));\n\t\tadd(Object.getPrototypeOf(\"\"[Symbol.iterator]()));\n\t\tadd(Object.getPrototypeOf(/a/[Symbol.matchAll](\"\")));\n\t\tif (typeof Iterator === \"function\") {\n\t\t\tif (typeof Iterator.prototype.map === \"function\") add(Object.getPrototypeOf([].values().map((x) => x)));\n\t\t\tif (typeof Iterator.from === \"function\") add(Object.getPrototypeOf(Iterator.from({ next() {} })));\n\t\t}\n\n\t\twhile (queue.length > 0) {\n\t\t\tconst object = queue.pop();\n\t\t\tadd(Object.getPrototypeOf(object));\n\t\t\tconst descriptors = Object.getOwnPropertyDescriptors(object);\n\t\t\tfor (const key of Reflect.ownKeys(descriptors)) {\n\t\t\t\tconst descriptor = descriptors[key];\n\t\t\t\tif (\"value\" in descriptor) {\n\t\t\t\t\tadd(descriptor.value);\n\t\t\t\t\tif (\n\t\t\t\t\t\tdescriptor.writable &&\n\t\t\t\t\t\tdescriptor.configurable &&\n\t\t\t\t\t\t(object === Object.prototype || OVERRIDABLE.has(key))\n\t\t\t\t\t) {\n\t\t\t\t\t\tallowOverride(object, key, descriptor.value, descriptor.enumerable);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tadd(descriptor.get);\n\t\t\t\t\tadd(descriptor.set);\n\t\t\t\t}\n\t\t\t}\n\t\t\tObject.freeze(object);\n\t\t}\n\t})();\n\tconst stringify = JSON.stringify;\n\tconst parse = JSON.parse;\n\tconst promiseThen = Promise.prototype.then;\n\tconst ErrorCtor = Error;\n\tconst TypeErrorCtor = TypeError;\n\tconst RangeErrorCtor = RangeError;\n\tconst pending = new Map();\n\tlet nextId = 1;\n\tlet finished = false;\n\t// Thrown by exit() to unwind the script after it already reported success.\n\tconst EXIT = Object.freeze({});\n\n\tfunction done(ok, payload, writes) {\n\t\tif (finished) return;\n\t\tfinished = true;\n\t\tbridge(\"done\", ok, payload, writes);\n\t}\n\n\tfunction serialize(value) {\n\t\treturn value === undefined ? undefined : stringify(value);\n\t}\n\n\t// QuickJS stacks list frames only. Prefix \"Name: message\" like V8 so the\n\t// text reads the same as a Node error, and drop this prelude's frames.\n\tfunction errorText(error) {\n\t\tconst head = error.message ? error.name + \": \" + error.message : String(error.name);\n\t\tconst frames =\n\t\t\ttypeof error.stack === \"string\"\n\t\t\t\t? error.stack.split(\"\\\\n\").filter((line) => line.trim() && !line.includes(\"codemode-prelude.js\"))\n\t\t\t\t: [];\n\t\treturn [head, ...frames].join(\"\\\\n\");\n\t}\n\n\tfunction format(value) {\n\t\tif (typeof value === \"string\") return value;\n\t\tif (value instanceof ErrorCtor) return errorText(value);\n\t\ttry {\n\t\t\tconst json = stringify(value);\n\t\t\treturn json === undefined ? String(value) : json;\n\t\t} catch {\n\t\t\treturn String(value);\n\t\t}\n\t}\n\n\t// The host requires string fields. A script can set an error's name or message to anything, so\n\t// they are coerced, and a value whose coercion throws gets a placeholder.\n\tfunction describeError(error) {\n\t\ttry {\n\t\t\tif (error instanceof ErrorCtor) {\n\t\t\t\treturn stringify({ name: String(error.name), message: String(error.message), stack: errorText(error) });\n\t\t\t}\n\t\t\treturn stringify({ message: String(format(error)) });\n\t\t} catch {\n\t\t\treturn stringify({ message: \"The script threw a value that cannot be described\" });\n\t\t}\n\t}\n\n\tfunction caller(kind, name, spread) {\n\t\treturn (...args) =>\n\t\t\tnew Promise((resolve, reject) => {\n\t\t\t\tlet json;\n\t\t\t\ttry {\n\t\t\t\t\tjson = serialize(spread ? args : args[0]);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treject(error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst id = nextId++;\n\t\t\t\tpending.set(id, { resolve, reject });\n\t\t\t\tbridge(kind, id, name, json);\n\t\t\t});\n\t}\n\n\tconst tools = Object.create(null);\n\tconst allTools = [];\n\tfor (const { name, jsName, description } of parse(toolsJson)) {\n\t\tconst fn = caller(\"call\", name);\n\t\t// The first tool wins when two names normalize to the same identifier.\n\t\tif (!(jsName in tools)) {\n\t\t\ttools[jsName] = fn;\n\t\t\tallTools.push(Object.freeze({ name: jsName, description }));\n\t\t}\n\t\tif (!(name in tools)) tools[name] = fn;\n\t}\n\tObject.freeze(tools);\n\tObject.freeze(allTools);\n\n\t// Reading a member that does not exist throws an error that names the close matches, instead of\n\t// a later \"not a function\". \\`in\\` checks still work.\n\tconst comparable = (name) => name.toLowerCase().replace(/[^a-z0-9]/g, \"\");\n\tfunction guard(target, label, names, hint) {\n\t\treturn new Proxy(target, {\n\t\t\tget(object, property, receiver) {\n\t\t\t\tif (typeof property !== \"string\" || property in object || property in Object.prototype || property === \"then\" || property === \"toJSON\") {\n\t\t\t\t\treturn Reflect.get(object, property, receiver);\n\t\t\t\t}\n\t\t\t\tconst wanted = comparable(property);\n\t\t\t\tconst exact = names.filter((name) => comparable(name) === wanted);\n\t\t\t\tconst close = exact.length > 0 ? exact : names.filter((name) => wanted && (comparable(name).includes(wanted) || wanted.includes(comparable(name))));\n\t\t\t\tlet message = label + \".\" + property + \" does not exist.\";\n\t\t\t\tif (close.length > 0) message += \" Did you mean \" + close.slice(0, 5).map((name) => label + \".\" + name).join(\", \") + \"?\";\n\t\t\t\telse if (names.length <= 20) message += \" Available: \" + names.join(\", \") + \".\";\n\t\t\t\tif (hint) message += \" \" + hint;\n\t\t\t\tmessage += ' Check for a member with \"' + property + '\" in ' + label + \".\";\n\t\t\t\tthrow new TypeErrorCtor(message);\n\t\t\t},\n\t\t});\n\t}\n\tconst toolsProxy = guard(\n\t\ttools,\n\t\t\"tools\",\n\t\tallTools.map((tool) => tool.name),\n\t\t\"ALL_TOOLS lists every tool; searchTools(query) finds tools by topic.\",\n\t);\n\n\tconst namespaces = new Map();\n\tfor (const { name, spread } of parse(globalsJson)) {\n\t\tconst fn = caller(\"global\", name, spread);\n\t\tconst dot = name.indexOf(\".\");\n\t\tif (dot === -1) {\n\t\t\tObject.defineProperty(globalThis, name, { value: fn, enumerable: true });\n\t\t\tcontinue;\n\t\t}\n\t\tconst namespace = name.slice(0, dot);\n\t\tif (!namespaces.has(namespace)) namespaces.set(namespace, Object.create(null));\n\t\tnamespaces.get(namespace)[name.slice(dot + 1)] = fn;\n\t}\n\tfor (const [namespace, members] of namespaces) {\n\t\tObject.freeze(members);\n\t\tconst value = guard(members, namespace, Object.keys(members));\n\t\tObject.defineProperty(globalThis, namespace, { value, enumerable: true });\n\t}\n\n\t// key -> JSON text. Sizes count key and JSON characters.\n\tconst stored = new Map(Object.entries(parse(storeJson)));\n\tconst writes = new Map();\n\tlet storedChars = 0;\n\tfor (const [key, json] of stored) storedChars += key.length + json.length;\n\n\tconst STORE_HINT =\n\t\t\"store() is for small state such as IDs or summaries. Show images with image(), keep large data in variables, or write it to a file with a tool.\";\n\n\tfunction checkKey(name, key) {\n\t\tif (typeof key !== \"string\") throw new TypeError(name + \"() key must be a string\");\n\t}\n\n\tfunction store(key, value) {\n\t\tcheckKey(\"store\", key);\n\t\tconst previous = stored.has(key) ? key.length + stored.get(key).length : 0;\n\t\tif (value === undefined) {\n\t\t\tstored.delete(key);\n\t\t\tstoredChars -= previous;\n\t\t\twrites.set(key, undefined);\n\t\t\treturn;\n\t\t}\n\t\tlet json;\n\t\ttry {\n\t\t\tjson = stringify(value);\n\t\t} catch (error) {\n\t\t\tthrow new TypeError(\"store(\" + stringify(key) + \") value is not JSON-serializable: \" + format(error));\n\t\t}\n\t\tif (json === undefined) {\n\t\t\tthrow new TypeError(\"store(\" + stringify(key) + \") value is not JSON-serializable\");\n\t\t}\n\t\tif (json.length > ${MAX_STORE_VALUE_CHARS}) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"store(\" + stringify(key) + \") value has \" + json.length + \" characters of JSON, more than the limit of ${MAX_STORE_VALUE_CHARS}. \" +\n\t\t\t\t\tSTORE_HINT,\n\t\t\t);\n\t\t}\n\t\tconst next = storedChars - previous + key.length + json.length;\n\t\tif (next > ${MAX_STORE_TOTAL_CHARS}) {\n\t\t\tthrow new RangeError(\n\t\t\t\t\"store is full: stored values would exceed ${MAX_STORE_TOTAL_CHARS} characters of JSON. Delete keys with store(key, undefined). \" +\n\t\t\t\t\tSTORE_HINT,\n\t\t\t);\n\t\t}\n\t\tstored.set(key, json);\n\t\tstoredChars = next;\n\t\twrites.set(key, json);\n\t}\n\n\tfunction load(key) {\n\t\tcheckKey(\"load\", key);\n\t\tconst json = stored.get(key);\n\t\treturn json === undefined ? undefined : parse(json);\n\t}\n\n\tfunction serializeWrites() {\n\t\tconst entries = [];\n\t\tfor (const [key, json] of writes) entries.push(json === undefined ? [key] : [key, json]);\n\t\treturn stringify(entries);\n\t}\n\n\tObject.defineProperty(globalThis, \"store\", { value: store, enumerable: true });\n\tObject.defineProperty(globalThis, \"load\", { value: load, enumerable: true });\n\n\tlet outputChars = 0;\n\tlet outputItems = 0;\n\n\t// Past the output limits the script fails: done() reports the error, so catching it does not\n\t// resume output, and the host ends the script.\n\tfunction output(kind, data, mimeType) {\n\t\tif (finished) return;\n\t\toutputChars += data.length;\n\t\toutputItems++;\n\t\tif (outputChars > ${MAX_OUTPUT_CHARS} || outputItems > ${MAX_OUTPUT_ITEMS}) {\n\t\t\tconst error = new RangeErrorCtor(\n\t\t\t\t\"script output exceeded the limit of ${MAX_OUTPUT_CHARS} characters or ${MAX_OUTPUT_ITEMS} text(), image(), and console calls. \" +\n\t\t\t\t\t\"Print a summary instead, or write large data to a file with a tool.\",\n\t\t\t);\n\t\t\tdone(false, describeError(error));\n\t\t\tthrow error;\n\t\t}\n\t\tbridge(\"output\", kind, data, mimeType);\n\t}\n\n\t// Primitives become their string form, everything else JSON.\n\tfunction outputText(value) {\n\t\tif (value === undefined || value === null || typeof value !== \"object\" && typeof value !== \"function\") {\n\t\t\treturn String(value);\n\t\t}\n\t\tconst json = stringify(value);\n\t\treturn json === undefined ? String(value) : json;\n\t}\n\n\tfunction text(value) {\n\t\tlet rendered;\n\t\ttry {\n\t\t\trendered = outputText(value);\n\t\t} catch (error) {\n\t\t\tthrow new TypeErrorCtor(error instanceof ErrorCtor ? error.message : String(error));\n\t\t}\n\t\toutput(\"text\", rendered);\n\t}\n\n\tfunction imageUrl(value) {\n\t\tif (typeof value === \"string\") return value;\n\t\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\t\tthrow new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});\n\t\t}\n\t\tif (value.image_url !== undefined) {\n\t\t\tif (typeof value.image_url !== \"string\") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});\n\t\t\treturn value.image_url;\n\t\t}\n\t\tif (typeof value.type !== \"string\") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});\n\t\tif (value.type !== \"image\") {\n\t\t\tthrow new TypeErrorCtor('image only accepts MCP image blocks, got \"' + value.type + '\"');\n\t\t}\n\t\tif (typeof value.data !== \"string\" || value.data === \"\") throw new TypeErrorCtor(\"image expected MCP image data\");\n\t\tif (value.data.toLowerCase().startsWith(\"data:\")) return value.data;\n\t\treturn \"data:;base64,\" + value.data;\n\t}\n\n\t// Base64 of the signatures of the formats providers accept inline (PNG, JPEG except\n\t// JPEG-LS, GIF, \"RIFF....WEBP\"). Signatures start at byte 0, so their encodings are prefixes.\n\tconst IMAGE_SIGNATURES = [\n\t\t[\"image/png\", /^iVBORw0KGg/],\n\t\t[\"image/jpeg\", /^[/]9j[/](?!9)/],\n\t\t[\"image/gif\", /^R0lGOD[dl]h/],\n\t\t[\"image/webp\", /^UklG.{8}RUJQ/],\n\t];\n\n\tfunction image(value) {\n\t\tconst url = imageUrl(value);\n\t\tif (url === \"\") throw new TypeErrorCtor(${JSON.stringify(IMAGE_HELPER_EXPECTS)});\n\t\tconst colon = url.indexOf(\":\");\n\t\tconst scheme = colon === -1 ? \"\" : url.slice(0, colon).toLowerCase();\n\t\tif (scheme === \"http\" || scheme === \"https\") {\n\t\t\tthrow new TypeErrorCtor(\"remote image URLs are not supported in tool outputs. Pass a base64 data URI instead\");\n\t\t}\n\t\tconst comma = url.indexOf(\",\");\n\t\tconst header = comma === -1 ? [] : url.slice(colon + 1, comma).split(\";\");\n\t\tif (scheme !== \"data\" || comma === -1 || header.slice(1).every((part) => part.toLowerCase() !== \"base64\")) {\n\t\t\tthrow new TypeErrorCtor(\"invalid image output. Pass a base64 data URI instead\");\n\t\t}\n\t\t// Providers reject the whole request on a bad image, and a persisted image block would be\n\t\t// resent on every later turn. Line breaks from wrapped base64 are dropped. The declared type\n\t\t// is ignored in favor of the detected one, as providers also reject mismatches.\n\t\tconst data = url.slice(comma + 1).replace(/\\\\s+/g, \"\");\n\t\tif (data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data)) {\n\t\t\tthrow new TypeErrorCtor(\"invalid image output. The image data is not valid base64 (truncated or corrupted?)\");\n\t\t}\n\t\tconst head = data.slice(0, 16);\n\t\tconst signature = IMAGE_SIGNATURES.find(([, pattern]) => pattern.test(head));\n\t\tif (!signature) {\n\t\t\tthrow new TypeErrorCtor(\"invalid image output. The image data is not a PNG, JPEG, GIF, or WebP image\");\n\t\t}\n\t\toutput(\"image\", data, signature[0]);\n\t}\n\n\tfunction exit() {\n\t\tlet writesJson;\n\t\ttry {\n\t\t\twritesJson = serializeWrites();\n\t\t} catch (error) {\n\t\t\tdone(false, describeError(error));\n\t\t\tthrow EXIT;\n\t\t}\n\t\tdone(true, undefined, writesJson);\n\t\tthrow EXIT;\n\t}\n\n\tconst console = {};\n\tfor (const level of [\"log\", \"info\", \"warn\", \"error\", \"debug\"]) {\n\t\tconsole[level] = (...args) => {\n\t\t\toutput(\"console\", args.map(format).join(\" \"));\n\t\t};\n\t}\n\tObject.freeze(console);\n\n\tObject.defineProperty(globalThis, \"tools\", { value: toolsProxy, enumerable: true });\n\tObject.defineProperty(globalThis, \"ALL_TOOLS\", { value: allTools, enumerable: true });\n\tObject.defineProperty(globalThis, \"console\", { value: console, enumerable: true });\n\tObject.defineProperty(globalThis, \"text\", { value: text, enumerable: true });\n\tObject.defineProperty(globalThis, \"image\", { value: image, enumerable: true });\n\tObject.defineProperty(globalThis, \"exit\", { value: exit, enumerable: true });\n\n\treturn {\n\t\tsettle(id, ok, payload) {\n\t\t\tconst entry = pending.get(id);\n\t\t\tif (!entry) return;\n\t\t\tpending.delete(id);\n\t\t\tif (!ok) {\n\t\t\t\tentry.reject(new ErrorCtor(payload));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet value;\n\t\t\ttry {\n\t\t\t\tvalue = payload === undefined ? undefined : parse(payload);\n\t\t\t} catch (error) {\n\t\t\t\tentry.reject(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tentry.resolve(value);\n\t\t},\n\t\trun(fn) {\n\t\t\tlet promise;\n\t\t\ttry {\n\t\t\t\tpromise = fn(toolsProxy, console);\n\t\t\t} catch (error) {\n\t\t\t\tdone(false, describeError(error));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpromiseThen.call(\n\t\t\t\tpromise,\n\t\t\t\t(value) => {\n\t\t\t\t\tlet json;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tjson = serialize(value);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdone(false, describeError(error));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdone(true, json, serializeWrites());\n\t\t\t\t},\n\t\t\t\t(error) => {\n\t\t\t\t\tdone(false, describeError(error));\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\tstalled() {\n\t\t\tif (finished || pending.size > 0) return false;\n\t\t\tdone(\n\t\t\t\tfalse,\n\t\t\t\tstringify({\n\t\t\t\t\tname: \"Error\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"The script is waiting on a promise that can never settle: no tool call is pending, and timers do not exist here.\",\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn true;\n\t\t},\n\t};\n})`;\n"]}
@@ -73,7 +73,9 @@ async function main(data) {
73
73
  type: "output",
74
74
  item: a.toString() === "image"
75
75
  ? { type: "image", data: b.toString(), mimeType: c.toString() }
76
- : { type: "text", text: b.toString() },
76
+ : a.toString() === "console"
77
+ ? { type: "text", text: b.toString(), console: true }
78
+ : { type: "text", text: b.toString() },
77
79
  });
78
80
  break;
79
81
  case "done":
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/runtime/worker.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Worker thread entry. One worker runs one script inside a fresh QuickJS VM\n * (a separate wasm instance), relays tool calls and output to the host, and\n * reports the result. The host terminates the worker when the script settles,\n * times out, or is aborted; the worker exists so that a spinning script never\n * blocks the host thread.\n *\n * Importing this module starts the worker. Hosts that bundle their code (for\n * example a Bun compiled executable) add a file that imports\n * `@earendil-works/pi-codemode/worker` as a separate entrypoint and pass its URL\n * or embedded-module string specifier as `workerUrl`.\n */\nimport { parentPort, workerData } from \"node:worker_threads\";\nimport { JSException, type JSValueHandle, MAX_STACK_SIZE, QuickJS } from \"quickjs-wasi\";\nimport { PRELUDE_SOURCE } from \"./prelude-source.ts\";\nimport { isHostToWorkerMessage, type WorkerData, type WorkerToHostMessage } from \"./protocol.ts\";\n\nfunction post(message: WorkerToHostMessage): void {\n\tparentPort?.postMessage(message);\n}\n\nfunction crash(error: unknown): void {\n\tpost({ type: \"crash\", message: error instanceof Error ? `${error.name}: ${error.message}` : String(error) });\n}\n\n/**\n * QuickJS writes engine diagnostics to fd 1 and 2, which the default shim\n * forwards to the host's stdout and stderr. That output belongs to the host\n * application (for example a TUI), so it is discarded. Reporting every byte as\n * written keeps libc from retrying.\n */\nfunction discardOutput(memory: { readonly buffer: ArrayBufferLike }) {\n\treturn {\n\t\tfd_write(_fd: number, iovsPtr: number, iovsLen: number, nwrittenPtr: number): number {\n\t\t\tconst view = new DataView(memory.buffer);\n\t\t\tlet written = 0;\n\t\t\tfor (let i = 0; i < iovsLen; i++) {\n\t\t\t\twritten += view.getUint32(iovsPtr + i * 8 + 4, true);\n\t\t\t}\n\t\t\tview.setUint32(nwrittenPtr, written, true);\n\t\t\treturn 0;\n\t\t},\n\t};\n}\n\nfunction describeException(error: JSException): string {\n\tconst head = error.message ? `${error.name}: ${error.message}` : error.name;\n\tconst stack = error.stack?.trimEnd();\n\treturn JSON.stringify({ name: error.name, message: error.message, stack: stack ? `${head}\\n${stack}` : head });\n}\n\nasync function main(data: WorkerData): Promise<void> {\n\tconst interrupt = new Int32Array(data.interrupt);\n\tconst vm = await QuickJS.create({\n\t\twasm: data.wasm,\n\t\tmemoryLimit: data.memoryLimitBytes,\n\t\t// Without a guard, deep recursion overflows the wasm stack and traps instead of throwing a\n\t\t// catchable RangeError.\n\t\tmaxStackSize: MAX_STACK_SIZE,\n\t\tinterruptHandler: () => Atomics.load(interrupt, 0) !== 0,\n\t\twasi: discardOutput,\n\t});\n\n\t// Called from the prelude with primitives only.\n\tconst bridge = vm.newFunction(\"bridge\", (kind, a, b, c) => {\n\t\tswitch (kind.toString()) {\n\t\t\tcase \"call\":\n\t\t\tcase \"global\":\n\t\t\t\tpost({\n\t\t\t\t\ttype: \"call\",\n\t\t\t\t\tid: a.toNumber(),\n\t\t\t\t\ttarget: kind.toString() === \"call\" ? \"tool\" : \"global\",\n\t\t\t\t\tname: b.toString(),\n\t\t\t\t\targs: c === undefined || c.isUndefined ? undefined : c.toString(),\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"output\":\n\t\t\t\tpost({\n\t\t\t\t\ttype: \"output\",\n\t\t\t\t\titem:\n\t\t\t\t\t\ta.toString() === \"image\"\n\t\t\t\t\t\t\t? { type: \"image\", data: b.toString(), mimeType: c.toString() }\n\t\t\t\t\t\t\t: { type: \"text\", text: b.toString() },\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"done\":\n\t\t\t\tif (a.toBoolean()) {\n\t\t\t\t\tpost({\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tvalue: b === undefined || b.isUndefined ? undefined : b.toString(),\n\t\t\t\t\t\twrites: c.toString(),\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tpost({ type: \"done\", ok: false, error: b.toString() });\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t\treturn vm.undefined;\n\t});\n\n\t// The VM lives until the host terminates the worker, so these handles are never disposed.\n\tconst api = vm.withScope((scope) =>\n\t\tscope.escape(\n\t\t\tvm.callFunction(\n\t\t\t\tvm.evalCode(PRELUDE_SOURCE, \"codemode-prelude.js\"),\n\t\t\t\tvm.undefined,\n\t\t\t\tbridge,\n\t\t\t\tvm.newString(JSON.stringify(data.tools)),\n\t\t\t\tvm.newString(JSON.stringify(data.globals)),\n\t\t\t\tvm.newString(JSON.stringify(data.store)),\n\t\t\t),\n\t\t),\n\t);\n\tconst settle = api.getProp(\"settle\");\n\tconst run = api.getProp(\"run\");\n\tconst stalled = api.getProp(\"stalled\");\n\t/** Run queued jobs, then fail a script that waits on nothing that can ever resume it. */\n\tconst drain = () => {\n\t\tvm.executePendingJobs();\n\t\tvm.callFunction(stalled, api).dispose();\n\t};\n\n\tparentPort?.on(\"message\", (message: unknown) => {\n\t\tif (!isHostToWorkerMessage(message)) return;\n\t\ttry {\n\t\t\tvm.withScope(() => {\n\t\t\t\tvm.callFunction(\n\t\t\t\t\tsettle,\n\t\t\t\t\tapi,\n\t\t\t\t\tvm.newNumber(message.id),\n\t\t\t\t\tmessage.ok ? vm.true : vm.false,\n\t\t\t\t\tmessage.payload === undefined ? vm.undefined : vm.newString(message.payload),\n\t\t\t\t);\n\t\t\t});\n\t\t\tdrain();\n\t\t} catch (error) {\n\t\t\tcrash(error);\n\t\t}\n\t});\n\n\t// The prefix shares the first line with the script so reported line numbers\n\t// match the script as written.\n\tlet fn: JSValueHandle;\n\ttry {\n\t\tfn = vm.evalCode(`(async (tools, console) => {${data.code}\\n})`, \"codemode.js\");\n\t} catch (error) {\n\t\tif (!(error instanceof JSException)) throw error;\n\t\tpost({ type: \"done\", ok: false, error: describeException(error) });\n\t\treturn;\n\t}\n\tvm.callFunction(run, api, fn).dispose();\n\tfn.dispose();\n\tdrain();\n}\n\nif (parentPort) {\n\tmain(workerData as WorkerData).catch(crash);\n}\n"]}
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/runtime/worker.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Worker thread entry. One worker runs one script inside a fresh QuickJS VM\n * (a separate wasm instance), relays tool calls and output to the host, and\n * reports the result. The host terminates the worker when the script settles,\n * times out, or is aborted; the worker exists so that a spinning script never\n * blocks the host thread.\n *\n * Importing this module starts the worker. Hosts that bundle their code (for\n * example a Bun compiled executable) add a file that imports\n * `@earendil-works/pi-codemode/worker` as a separate entrypoint and pass its URL\n * or embedded-module string specifier as `workerUrl`.\n */\nimport { parentPort, workerData } from \"node:worker_threads\";\nimport { JSException, type JSValueHandle, MAX_STACK_SIZE, QuickJS } from \"quickjs-wasi\";\nimport { PRELUDE_SOURCE } from \"./prelude-source.ts\";\nimport { isHostToWorkerMessage, type WorkerData, type WorkerToHostMessage } from \"./protocol.ts\";\n\nfunction post(message: WorkerToHostMessage): void {\n\tparentPort?.postMessage(message);\n}\n\nfunction crash(error: unknown): void {\n\tpost({ type: \"crash\", message: error instanceof Error ? `${error.name}: ${error.message}` : String(error) });\n}\n\n/**\n * QuickJS writes engine diagnostics to fd 1 and 2, which the default shim\n * forwards to the host's stdout and stderr. That output belongs to the host\n * application (for example a TUI), so it is discarded. Reporting every byte as\n * written keeps libc from retrying.\n */\nfunction discardOutput(memory: { readonly buffer: ArrayBufferLike }) {\n\treturn {\n\t\tfd_write(_fd: number, iovsPtr: number, iovsLen: number, nwrittenPtr: number): number {\n\t\t\tconst view = new DataView(memory.buffer);\n\t\t\tlet written = 0;\n\t\t\tfor (let i = 0; i < iovsLen; i++) {\n\t\t\t\twritten += view.getUint32(iovsPtr + i * 8 + 4, true);\n\t\t\t}\n\t\t\tview.setUint32(nwrittenPtr, written, true);\n\t\t\treturn 0;\n\t\t},\n\t};\n}\n\nfunction describeException(error: JSException): string {\n\tconst head = error.message ? `${error.name}: ${error.message}` : error.name;\n\tconst stack = error.stack?.trimEnd();\n\treturn JSON.stringify({ name: error.name, message: error.message, stack: stack ? `${head}\\n${stack}` : head });\n}\n\nasync function main(data: WorkerData): Promise<void> {\n\tconst interrupt = new Int32Array(data.interrupt);\n\tconst vm = await QuickJS.create({\n\t\twasm: data.wasm,\n\t\tmemoryLimit: data.memoryLimitBytes,\n\t\t// Without a guard, deep recursion overflows the wasm stack and traps instead of throwing a\n\t\t// catchable RangeError.\n\t\tmaxStackSize: MAX_STACK_SIZE,\n\t\tinterruptHandler: () => Atomics.load(interrupt, 0) !== 0,\n\t\twasi: discardOutput,\n\t});\n\n\t// Called from the prelude with primitives only.\n\tconst bridge = vm.newFunction(\"bridge\", (kind, a, b, c) => {\n\t\tswitch (kind.toString()) {\n\t\t\tcase \"call\":\n\t\t\tcase \"global\":\n\t\t\t\tpost({\n\t\t\t\t\ttype: \"call\",\n\t\t\t\t\tid: a.toNumber(),\n\t\t\t\t\ttarget: kind.toString() === \"call\" ? \"tool\" : \"global\",\n\t\t\t\t\tname: b.toString(),\n\t\t\t\t\targs: c === undefined || c.isUndefined ? undefined : c.toString(),\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"output\":\n\t\t\t\tpost({\n\t\t\t\t\ttype: \"output\",\n\t\t\t\t\titem:\n\t\t\t\t\t\ta.toString() === \"image\"\n\t\t\t\t\t\t\t? { type: \"image\", data: b.toString(), mimeType: c.toString() }\n\t\t\t\t\t\t\t: a.toString() === \"console\"\n\t\t\t\t\t\t\t\t? { type: \"text\", text: b.toString(), console: true }\n\t\t\t\t\t\t\t\t: { type: \"text\", text: b.toString() },\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"done\":\n\t\t\t\tif (a.toBoolean()) {\n\t\t\t\t\tpost({\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tvalue: b === undefined || b.isUndefined ? undefined : b.toString(),\n\t\t\t\t\t\twrites: c.toString(),\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tpost({ type: \"done\", ok: false, error: b.toString() });\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t\treturn vm.undefined;\n\t});\n\n\t// The VM lives until the host terminates the worker, so these handles are never disposed.\n\tconst api = vm.withScope((scope) =>\n\t\tscope.escape(\n\t\t\tvm.callFunction(\n\t\t\t\tvm.evalCode(PRELUDE_SOURCE, \"codemode-prelude.js\"),\n\t\t\t\tvm.undefined,\n\t\t\t\tbridge,\n\t\t\t\tvm.newString(JSON.stringify(data.tools)),\n\t\t\t\tvm.newString(JSON.stringify(data.globals)),\n\t\t\t\tvm.newString(JSON.stringify(data.store)),\n\t\t\t),\n\t\t),\n\t);\n\tconst settle = api.getProp(\"settle\");\n\tconst run = api.getProp(\"run\");\n\tconst stalled = api.getProp(\"stalled\");\n\t/** Run queued jobs, then fail a script that waits on nothing that can ever resume it. */\n\tconst drain = () => {\n\t\tvm.executePendingJobs();\n\t\tvm.callFunction(stalled, api).dispose();\n\t};\n\n\tparentPort?.on(\"message\", (message: unknown) => {\n\t\tif (!isHostToWorkerMessage(message)) return;\n\t\ttry {\n\t\t\tvm.withScope(() => {\n\t\t\t\tvm.callFunction(\n\t\t\t\t\tsettle,\n\t\t\t\t\tapi,\n\t\t\t\t\tvm.newNumber(message.id),\n\t\t\t\t\tmessage.ok ? vm.true : vm.false,\n\t\t\t\t\tmessage.payload === undefined ? vm.undefined : vm.newString(message.payload),\n\t\t\t\t);\n\t\t\t});\n\t\t\tdrain();\n\t\t} catch (error) {\n\t\t\tcrash(error);\n\t\t}\n\t});\n\n\t// The prefix shares the first line with the script so reported line numbers\n\t// match the script as written.\n\tlet fn: JSValueHandle;\n\ttry {\n\t\tfn = vm.evalCode(`(async (tools, console) => {${data.code}\\n})`, \"codemode.js\");\n\t} catch (error) {\n\t\tif (!(error instanceof JSException)) throw error;\n\t\tpost({ type: \"done\", ok: false, error: describeException(error) });\n\t\treturn;\n\t}\n\tvm.callFunction(run, api, fn).dispose();\n\tfn.dispose();\n\tdrain();\n}\n\nif (parentPort) {\n\tmain(workerData as WorkerData).catch(crash);\n}\n"]}
package/dist/types.d.ts CHANGED
@@ -40,11 +40,12 @@ export interface CodemodeTool {
40
40
  }
41
41
  /**
42
42
  * One item of the script's output, in the order the script produced it: `text()` and `console.*`
43
- * produce text items, `image()` image items. `data` is base64.
43
+ * produce text items, with `console: true` for `console.*`, and `image()` image items. `data` is base64.
44
44
  */
45
45
  export type CodemodeOutputItem = {
46
46
  type: "text";
47
47
  text: string;
48
+ console?: true;
48
49
  } | {
49
50
  type: "image";
50
51
  data: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,MAAM,EAAE,WAAW,CAAC;CACpB;AAED,qGAAqG;AACrG,MAAM,MAAM,kBAAkB,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC;AAEtE,MAAM,WAAW,YAAY;IAC5B;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6FAA6F;IAC7F,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,0FAA0F;IAC1F,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,gGAAgG;IAChG,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CACjF;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,IAAI,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,OAAO,GAAG,WAAW,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,iBAAiB;AAC5B,4FAA4F;AAC1F,QAAQ;AACV,+DAA+D;GAC7D,SAAS;AACX,sFAAsF;GACpF,SAAS;AACX,+GAA+G;GAC7G,SAAS,CAAC;AAEb,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wFAAwF;AACxF,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,kCAAkC;IAClC,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,iHAAiH;AACjH,MAAM,MAAM,cAAc,GACvB;IACA,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,WAAW,EAAE,mBAAmB,CAAC;CAChC,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAAC,KAAK,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC;AAE5F,MAAM,WAAW,sBAAsB;IACtC,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACxD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACtC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1C"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { CodemodeWasmModule } from \"./wasm.ts\";\n\nexport interface CodemodeToolContext {\n\t/**\n\t * Aborted when the script finishes (including unawaited calls), the\n\t * execution times out, the caller aborts, or the sandbox is closed.\n\t */\n\tsignal: AbortSignal;\n}\n\n/** A JSON Schema document. Only used to render declarations; values are not validated against it. */\nexport type CodemodeJsonSchema = { [key: string]: unknown } | boolean;\n\nexport interface CodemodeTool {\n\t/**\n\t * The script calls tools as `tools.<id>(args)`, where `<id>` is the name with characters that\n\t * are not valid in identifiers replaced by `_` (see `toCodemodeIdentifier`), and also as\n\t * `tools[\"<name>\"](args)`. Globals are called as `<name>(args)` and must be identifiers, or\n\t * `<namespace>.<member>`, which groups them into a frozen namespace object.\n\t */\n\tname: string;\n\t/** Shown as a doc comment in {@link renderDeclarations}, and listed in `ALL_TOOLS` for tools. */\n\tdescription?: string;\n\t/** Schema of the single argument. Rendered as the parameter type; `unknown` when omitted. */\n\tinputSchema?: CodemodeJsonSchema;\n\t/** Schema of the resolved value. Rendered as the promise type; `unknown` when omitted. */\n\toutputSchema?: CodemodeJsonSchema;\n\t/** Globals only: `execute` receives all call arguments as an array instead of the first one. */\n\tspread?: boolean;\n\t/**\n\t * Globals only: TypeScript parameter list and return type for {@link renderDeclarations}, for\n\t * example `(type: string, id?: string): Promise<Model[]>`. Replaces the rendering from the schemas.\n\t */\n\tsignature?: string;\n\t/**\n\t * `args` is whatever the script passed, after a JSON round trip. The return\n\t * value must be JSON-serializable; a thrown error surfaces in the script as\n\t * an `Error` with the same message.\n\t */\n\texecute(args: unknown, context: CodemodeToolContext): Promise<unknown> | unknown;\n}\n\n/**\n * One item of the script's output, in the order the script produced it: `text()` and `console.*`\n * produce text items, `image()` image items. `data` is base64.\n */\nexport type CodemodeOutputItem = { type: \"text\"; text: string } | { type: \"image\"; data: string; mimeType: string };\n\nexport type CodemodeCallStatus = \"ok\" | \"error\" | \"cancelled\";\n\nexport interface CodemodeCall {\n\tname: string;\n\tstatus: CodemodeCallStatus;\n\tdurationMs: number;\n}\n\nexport type CodemodeErrorKind =\n\t/** The script threw or failed to parse. `name` and `stack` come from the script's error. */\n\t| \"script\"\n\t/** The overall deadline expired. The worker was terminated. */\n\t| \"timeout\"\n\t/** The caller's signal fired or the sandbox was closed. The worker was terminated. */\n\t| \"aborted\"\n\t/** The worker or VM failed outside the script's control (for example a wasm trap or a missing worker file). */\n\t| \"sandbox\";\n\nexport interface CodemodeError {\n\tkind: CodemodeErrorKind;\n\tname?: string;\n\tmessage: string;\n\tstack?: string;\n}\n\n/** Keys the script changed with `store()`. Only successful executions report writes. */\nexport interface CodemodeStoreWrites {\n\tset: Record<string, unknown>;\n\t/** Keys stored as `undefined`. */\n\tdelete: string[];\n}\n\n/** `output` is kept for failed executions too, up to the failure. `exit()` completes with `value: undefined`. */\nexport type CodemodeResult =\n\t| {\n\t\t\tok: true;\n\t\t\tvalue: unknown;\n\t\t\toutput: CodemodeOutputItem[];\n\t\t\tcalls: CodemodeCall[];\n\t\t\tstoreWrites: CodemodeStoreWrites;\n\t }\n\t| { ok: false; error: CodemodeError; output: CodemodeOutputItem[]; calls: CodemodeCall[] };\n\nexport interface CodemodeSandboxOptions {\n\ttools?: CodemodeTool[];\n\t/**\n\t * Functions exposed as top-level identifiers instead of on `tools`, for host helpers such as\n\t * attaching an image to the result. They behave like tools (JSON round trip, promise result)\n\t * but are not recorded in `result.calls`. Names must be identifiers and may not shadow the\n\t * built-in globals (`tools`, `ALL_TOOLS`, `console`, `text`, `image`, `exit`, `store`, `load`).\n\t */\n\tglobals?: CodemodeTool[];\n\t/**\n\t * Overall deadline per execution, including time spent in tools. `Infinity` disables the\n\t * deadline; the execution then only ends when the script settles or is aborted.\n\t * Default: 300000.\n\t */\n\ttimeoutMs?: number;\n\t/**\n\t * Maximum memory the QuickJS VM may allocate. Allocations beyond it fail inside the script as\n\t * `InternalError: out of memory`. Default: no limit beyond wasm32's 4 GiB address space.\n\t */\n\tmemoryLimitBytes?: number;\n\t/**\n\t * Compiled `quickjs-wasi/quickjs.wasm`, usually from {@link loadQuickJSWasm}. Default:\n\t * `loadQuickJSWasm()`, the file in the installed `quickjs-wasi` package. Pass it when that file\n\t * is not on disk, for example in a Bun compiled executable.\n\t */\n\twasm?: CodemodeWasmModule | Promise<CodemodeWasmModule>;\n\t/**\n\t * Worker entry that imports `@earendil-works/pi-codemode/worker`. Default: this package's own\n\t * worker file. Pass it when this package is bundled, since the default is resolved relative to\n\t * the module that creates the sandbox. Bun compiled executables require the relative string\n\t * specifier of an embedded build entrypoint; other hosts usually use a URL.\n\t */\n\tworkerUrl?: string | URL;\n}\n\nexport interface CodemodeExecuteOptions {\n\tsignal?: AbortSignal;\n\t/** Overrides the sandbox default for this execution. */\n\ttimeoutMs?: number;\n\t/**\n\t * Values the script reads with `load(key)`. Must be JSON-serializable. The script's own\n\t * `store()` calls come back as `result.storeWrites`; persisting them is up to the caller.\n\t */\n\tstore?: Readonly<Record<string, unknown>>;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { CodemodeWasmModule } from \"./wasm.ts\";\n\nexport interface CodemodeToolContext {\n\t/**\n\t * Aborted when the script finishes (including unawaited calls), the\n\t * execution times out, the caller aborts, or the sandbox is closed.\n\t */\n\tsignal: AbortSignal;\n}\n\n/** A JSON Schema document. Only used to render declarations; values are not validated against it. */\nexport type CodemodeJsonSchema = { [key: string]: unknown } | boolean;\n\nexport interface CodemodeTool {\n\t/**\n\t * The script calls tools as `tools.<id>(args)`, where `<id>` is the name with characters that\n\t * are not valid in identifiers replaced by `_` (see `toCodemodeIdentifier`), and also as\n\t * `tools[\"<name>\"](args)`. Globals are called as `<name>(args)` and must be identifiers, or\n\t * `<namespace>.<member>`, which groups them into a frozen namespace object.\n\t */\n\tname: string;\n\t/** Shown as a doc comment in {@link renderDeclarations}, and listed in `ALL_TOOLS` for tools. */\n\tdescription?: string;\n\t/** Schema of the single argument. Rendered as the parameter type; `unknown` when omitted. */\n\tinputSchema?: CodemodeJsonSchema;\n\t/** Schema of the resolved value. Rendered as the promise type; `unknown` when omitted. */\n\toutputSchema?: CodemodeJsonSchema;\n\t/** Globals only: `execute` receives all call arguments as an array instead of the first one. */\n\tspread?: boolean;\n\t/**\n\t * Globals only: TypeScript parameter list and return type for {@link renderDeclarations}, for\n\t * example `(type: string, id?: string): Promise<Model[]>`. Replaces the rendering from the schemas.\n\t */\n\tsignature?: string;\n\t/**\n\t * `args` is whatever the script passed, after a JSON round trip. The return\n\t * value must be JSON-serializable; a thrown error surfaces in the script as\n\t * an `Error` with the same message.\n\t */\n\texecute(args: unknown, context: CodemodeToolContext): Promise<unknown> | unknown;\n}\n\n/**\n * One item of the script's output, in the order the script produced it: `text()` and `console.*`\n * produce text items, with `console: true` for `console.*`, and `image()` image items. `data` is base64.\n */\nexport type CodemodeOutputItem =\n\t| { type: \"text\"; text: string; console?: true }\n\t| { type: \"image\"; data: string; mimeType: string };\n\nexport type CodemodeCallStatus = \"ok\" | \"error\" | \"cancelled\";\n\nexport interface CodemodeCall {\n\tname: string;\n\tstatus: CodemodeCallStatus;\n\tdurationMs: number;\n}\n\nexport type CodemodeErrorKind =\n\t/** The script threw or failed to parse. `name` and `stack` come from the script's error. */\n\t| \"script\"\n\t/** The overall deadline expired. The worker was terminated. */\n\t| \"timeout\"\n\t/** The caller's signal fired or the sandbox was closed. The worker was terminated. */\n\t| \"aborted\"\n\t/** The worker or VM failed outside the script's control (for example a wasm trap or a missing worker file). */\n\t| \"sandbox\";\n\nexport interface CodemodeError {\n\tkind: CodemodeErrorKind;\n\tname?: string;\n\tmessage: string;\n\tstack?: string;\n}\n\n/** Keys the script changed with `store()`. Only successful executions report writes. */\nexport interface CodemodeStoreWrites {\n\tset: Record<string, unknown>;\n\t/** Keys stored as `undefined`. */\n\tdelete: string[];\n}\n\n/** `output` is kept for failed executions too, up to the failure. `exit()` completes with `value: undefined`. */\nexport type CodemodeResult =\n\t| {\n\t\t\tok: true;\n\t\t\tvalue: unknown;\n\t\t\toutput: CodemodeOutputItem[];\n\t\t\tcalls: CodemodeCall[];\n\t\t\tstoreWrites: CodemodeStoreWrites;\n\t }\n\t| { ok: false; error: CodemodeError; output: CodemodeOutputItem[]; calls: CodemodeCall[] };\n\nexport interface CodemodeSandboxOptions {\n\ttools?: CodemodeTool[];\n\t/**\n\t * Functions exposed as top-level identifiers instead of on `tools`, for host helpers such as\n\t * attaching an image to the result. They behave like tools (JSON round trip, promise result)\n\t * but are not recorded in `result.calls`. Names must be identifiers and may not shadow the\n\t * built-in globals (`tools`, `ALL_TOOLS`, `console`, `text`, `image`, `exit`, `store`, `load`).\n\t */\n\tglobals?: CodemodeTool[];\n\t/**\n\t * Overall deadline per execution, including time spent in tools. `Infinity` disables the\n\t * deadline; the execution then only ends when the script settles or is aborted.\n\t * Default: 300000.\n\t */\n\ttimeoutMs?: number;\n\t/**\n\t * Maximum memory the QuickJS VM may allocate. Allocations beyond it fail inside the script as\n\t * `InternalError: out of memory`. Default: no limit beyond wasm32's 4 GiB address space.\n\t */\n\tmemoryLimitBytes?: number;\n\t/**\n\t * Compiled `quickjs-wasi/quickjs.wasm`, usually from {@link loadQuickJSWasm}. Default:\n\t * `loadQuickJSWasm()`, the file in the installed `quickjs-wasi` package. Pass it when that file\n\t * is not on disk, for example in a Bun compiled executable.\n\t */\n\twasm?: CodemodeWasmModule | Promise<CodemodeWasmModule>;\n\t/**\n\t * Worker entry that imports `@earendil-works/pi-codemode/worker`. Default: this package's own\n\t * worker file. Pass it when this package is bundled, since the default is resolved relative to\n\t * the module that creates the sandbox. Bun compiled executables require the relative string\n\t * specifier of an embedded build entrypoint; other hosts usually use a URL.\n\t */\n\tworkerUrl?: string | URL;\n}\n\nexport interface CodemodeExecuteOptions {\n\tsignal?: AbortSignal;\n\t/** Overrides the sandbox default for this execution. */\n\ttimeoutMs?: number;\n\t/**\n\t * Values the script reads with `load(key)`. Must be JSON-serializable. The script's own\n\t * `store()` calls come back as `result.storeWrites`; persisting them is up to the caller.\n\t */\n\tstore?: Readonly<Record<string, unknown>>;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-codemode",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "Sandboxed JavaScript execution where the only capability is calling injected tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -58,7 +58,7 @@
58
58
  "quickjs-wasi": "3.6.2"
59
59
  },
60
60
  "devDependencies": {
61
- "shx": "0.4.0",
61
+ "shx": "0.3.4",
62
62
  "vitest": "4.1.11"
63
63
  }
64
64
  }