@bendyline/gezel-script-runtime

中文文档
1.0.13发布于 2026/11/05MITTypeScriptES Module构建来源已验证近 30 天下载 1805

Portable, capability-mediated script execution for Gezel.

原始使用文档
文档目录4 节
  1. Host integration
  2. Script profile (experimental)
  3. Stability
  4. Documentation

@bendyline/gezel-script-runtime

Portable, capability-mediated script execution for Gezel.

This package defines a platform-independent ScriptExecutor contract, a shared portable runner, and a QuickJS-WASM executor that runs Gezel scripts against the real Gezel SDK. Hosts that cannot use Node's sandbox — browsers and WebViews — run the same bundled standard scripts, SDK and checks inside a dedicated Web Worker. The Gezel service still selects its Node sandbox by default.

npm install @bendyline/gezel-script-runtime

Requires Node.js 24 or newer when used from Node.

ImportWhat it provides
@bendyline/gezel-script-runtimePortableScriptRunner and the ScriptExecutor contract
@bendyline/gezel-script-runtime/quickjsQuickJSScriptExecutor, for use inside a dedicated worker
@bendyline/gezel-script-runtime/web-workerWebWorkerScriptExecutor, the host side of a QuickJS Web Worker
@bendyline/gezel-script-runtime/worker-protocolMessage types and limits shared by host and worker
@bendyline/gezel-script-runtime/compilecompilePortableScript, the sandboxed TypeScript transpile step
@bendyline/gezel-script-runtime/sourceScript diagnostics, craftbook script validation, and scaffolding
@bendyline/gezel-script-runtime/metaparseScriptMeta, script metadata parsing

Host integration

The trusted host selects the executor. Scripts and model-generated metadata cannot change it. On desktop, the service exports an adapter that places each QuickJS guest in a dedicated worker:

import { QuickJSWorkerExecutor, ScriptRunner, Store } from '@bendyline/gezel-service';

const store = new Store({ home: '/path/to/gezel-home' });
await store.ensureLayout();

const runner = new ScriptRunner({
  store,
  executor: new QuickJSWorkerExecutor(),
  // Add chat, memory, tasks, … for the capabilities your scripts use.
});

Use the runner for product execution: it owns metadata/input validation, the AI activity setting, capability dispatch, output validation, run history, and secret redaction. The executor itself supplies none of those permissions. Returning a successful VM result does not establish that a script has valid product output. Construction above is intended for embedders and conformance testing; there is no UI preference, API parameter, or automatic fallback that selects it.

For another host, import QuickJSScriptExecutor from @bendyline/gezel-script-runtime/quickjs inside a dedicated worker. Supply the trusted SDK source as sdkModuleSource, a synchronous compile function, a now() clock, and callbacks to the host's capability dispatcher. The SDK source is the self-contained portable build that @bendyline/gezel-sdk ships; the Gezel service reads the same file, dist/portable.js. Bundle it at build time for a browser, or read it in Node:

import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';

const sdkModuleSource = await readFile(
  fileURLToPath(import.meta.resolve('@bendyline/gezel-sdk/portable')),
  'utf8',
);

To let scripts import @bendyline/gezel-sdk/checks too, read that module the same way and pass it as modules: { '@bendyline/gezel-sdk/checks': source }. If the computer can sleep during a run, make now() leave out the time it spent asleep, so a run is not timed out for time it could never use. The host must also enforce a deadline and terminate the worker independently. The portable executor uses standard host timers to pump promises; its guest receives no timer or platform APIs.

The executor uses the quickjs-emscripten WASM package, so a WebView host needs no native QuickJS bridge. A browser host can compile and validate the supported subset of the standard library at build time. Project and user TypeScript sources are compiled in a separate compiler worker that runs the TypeScript browser compiler with Node hosts disabled; it only parses and transpiles. Compiled programs execute in QuickJS, never in the compiler worker or the host's JavaScript realm. Compilation has a 256,000-character source bound and a host-enforced ten-second deadline. Only the bundled SDK and checks module can be imported.

Source saves preserve invalid edits and return the shared metadata, syntax, and runtime-compatibility diagnostics. Hash-based conflict detection is atomic. Project/user scope is explicit, and edited code can never acquire the immutable standard scope. Manual runs and task hooks/gates share the same capability, policy and audit checks. Task note operations remain confined to the current project and, for task-owned runs, the current task and active step.

Gates can hold advancement; approved transitions run ordinary exit hooks and compare the persisted task with the snapshot they checked. A gate/exit child retains its step trigger and records parentRunId, while inheriting the parent's cancellation, remaining budget, and live policy ceiling. Trusted host callbacks carry this authority; serialized SDK inputs cannot supply callbacks, bypass gates, or force completion. Task-control calls are refused from lifecycle/gate scripts to preserve their durable checkpoints. Creating a task from a script does not start background model work. Craftbook sources are snapshotted verbatim with the task, so later edits cannot change that run's recipe. Audits record scope, source SHA-256 and template identity; craftbook provenance never grants standard-library trust.

PortableScriptRunner takes a host resolver, dispatcher, configuration reader and atomic run-record writer. It shares the desktop input/output validators, method capabilities, metadata parser and execution-policy check. A host records admission before any effect and stores the completed run using the ordinary projects/<id>/scripts/runs/<date>/<runId>.json convention. Between the two, progress snapshots are coalesced to one per checkpointIntervalMs (default 1 s); a call's intent is written ahead of its effect when no snapshot is that recent. Invalid output and failed audit writes cannot report success, and neither can a gate that stamps no verdict. Any other script that declares outputs but never calls gezel.output() finishes ok with no output and a warning in its log. The runner stops a run that makes more than 250,000 host calls (DEFAULT_MAX_HOST_CALLS, set with limits.maxHostCalls); it is a backstop against runaway loops, sized for scripts that touch tens of thousands of records. Standard-scope and provenance-trusted scripts have no call limit by default (limits.maxTrustedHostCalls) and are bounded by their timeout. The QuickJS executor has a separate, much smaller budget of its own: 1,000 host calls and notifications per execution (its maxCalls option, and QUICKJS_MAX_CALLS in the Web Worker host). Both apply, so a QuickJS run stops at whichever it reaches first. Deadlines leave out time the computer spent asleep. Canceling a run from the host takes effect even before its deadline, and waits for host effects already under way and child audits to settle.

Script profile (experimental)

Scripts import gezel and defineScript from @bendyline/gezel-sdk as usual. The service adapter also bundles @bendyline/gezel-sdk/checks. Imports from the filesystem/network and other SDK subpaths are rejected. No Node globals, raw filesystem, raw networking, timers, subprocess APIs, or package resolver are installed in the guest. SDK operations cross a JSON boundary into the normal host dispatcher. console methods use the SDK's log notification.

Await all asynchronous work at module level, then write output. For example:

import { gezel } from '@bendyline/gezel-sdk';

const files = await gezel.artifacts.list();
gezel.output({ count: files.length });

The runtime rejects module completion with pending host calls and rejects output while host calls are pending. Catching an awaited capability denial is supported, including its typed code. Detached asynchronous functions and floating promises are unsupported: the QuickJS binding does not expose an unhandled-rejection tracker, so detached promise failures cannot reliably be reported. This is not full Node script compatibility.

QuickJS executor defaults are 32 MiB guest heap, 512 KiB guest stack, 1,000 host calls and notifications, 32 pending calls, one million UTF-16 code units per source or message, and four million aggregate units. The service worker also bounds JSON traffic and has its own V8 heap limits. These are separate bounds, not a total application memory limit. An interrupted worker ignores late replies and the runner freezes its audit record before redaction and persistence.

Termination stops guest execution and future calls. It cannot undo or cancel an already-started host write or network request; the run records pending operations as potentially still completing. Scripts must not treat a timeout as a transaction rollback. Cancellation revokes new calls and waits for already-dispatched file operations before releasing admission. A host that closes mid-run marks unfinished records interrupted on reopen and never replays them.

Stability

The exports above are public API under semver. The package is new: the Gezel service is its first host, and the executor contract may grow as other hosts adopt it.

Documentation

MIT © Bendyline

版本与发布记录

@bendyline/gezel-script-runtime 共发布 15 个版本,首次发布于 2026/09/27;过去 12 个月发布了 15 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.0.13latest2026/11/053 天前
1.0.122026/11/044 天前
1.0.112026/10/2811 天前
1.0.102026/10/2712 天前
1.0.92026/10/2712 天前
1.0.82026/10/2415 天前

关于 @bendyline/gezel-script-runtime 的常见问题

@bendyline/gezel-script-runtime 是什么?

Portable, capability-mediated script execution for Gezel.

如何安装 @bendyline/gezel-script-runtime?

在项目目录运行 npm install @bendyline/gezel-script-runtime,或使用 pnpm add / yarn add / bun add。

@bendyline/gezel-script-runtime 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@bendyline/gezel-script-runtime 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@bendyline/gezel-script-runtime 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@bendyline/gezel-script-runtime 可以商用吗?

@bendyline/gezel-script-runtime 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@bendyline/gezel-script-runtime 的下载量有多少?

根据 npm 官方下载统计,@bendyline/gezel-script-runtime 在 2026/10/08 – 2026/11/06 这 30 天内被下载 1,805 次,日均约 60 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bendyline/gezel-script-runtime 还在维护吗?

最新版本 1.0.13 发布于 2026/11/05(3 天前);至今共发布 15 个版本,其中过去 12 个月发布了 15 个;首次发布于 2026/09/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。