Skip to content

fix: run workflows on the shipped binary through a QuickJS sandbox - #187

Merged
ZouR-Ma merged 1 commit into
mainfrom
fix/ultracode_registration
Sep 24, 2026
Merged

ZouR-Ma merged 1 commit into
mainfrom
fix/ultracode_registration

Conversation

@TPLin22

@TPLin22 TPLin22 commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

workflow(ultracode)收敛为单一 QuickJS-WASM 执行器

背景

#178 已将 workflow 沙箱从 isolated-vm 换成 QuickJS-WASM,解决了正式版二进制上 workflow 与 ultracode 完全不可用的问题。但作为过渡形态,遗留三件事:

  1. 双执行器并存:runtime.ts 按宿主能否加载原生扩展在 isolated-vm 与 QuickJS 间选择,导致开发机与正式版跑两套引擎,语义差异只在发布版暴露——正是 fix: restore workflow and ultracode on the released binary #178 所修 bug 的成因类型。同时 --ignore-scripts 装不上原生扩展、CI node-gyp 编译、Node 版本 ABI 匹配等问题仍在。
  2. QuickJS 路径两个活跃 teardown 缺陷:
    • 中断器豁免在飞宿主调用(vm-quickjs.ts:104),而该豁免唯一生效场景恰是必须终止的场景;循环运行在 WebAssembly 调用内堵死宿主事件循环,外层兜底定时器也无法执行,实测进程挂死。
    • 未结清 deferred 无人释放。脚本不 await 宿主调用就返回时,残留 deferred 会让 QuickJS 在 JS_FreeRuntime 处 abort 整个 WASM 实例,随后对已释放 context 结清抛出 use-after-free 杀进程;模块按进程缓存还会毒化后续所有运行。
  3. 文档仍把原生扩展写成必需条件。

修改(16 文件,+710 / −1152)

收敛为单一执行器

  • vm-quickjs.ts 合并进 vm.ts 并删除;vm.ts 成为唯一沙箱,兼持契约类型与引擎无关纯函数
  • runtime.ts:vmExecutor 默认 runInQuickJs,移除按宿主选择的 defaultWorkflowVmExecutor;显式注入仍优先
  • index.ts:导出面收敛为 runInQuickJs + WORKFLOW_MAX_SCRIPT_BYTES

移除 isolated-vm

  • package.json optionalDependencies、pnpm-lock.yaml、bundle 脚本 externals 白名单

门禁简化

  • registration-gate.ts:决策收敛为 enabled / not-enabled / disabled-by-env;移除 vm-unavailable、vm-unsupported-runtime 与 WORKFLOW_VM_UNAVAILABLE_WARNING
  • step-workflow.ts:删掉发出该告警的 session_start 分支;执行器类型改为 typeof runInQuickJs

缺陷 1 修复

  • 中断器不再豁免在飞宿主调用,改为从「最近一次宿主活动」起算并在每次调用结清时刷新。若仅在最后一个结清时刷新,首个 agent 耗时超 timeoutMs 的扇出会在过期 deadline 上恢复续体并被中断,parallel() 会把该分支报成裸 null 而非错误,即误判超时变成静默错误结果。宿主侧定时器保留 pending 豁免。

缺陷 2 修复

  • HostCallTracker 增加未结清 deferred 集合与 closed 标志:teardown 时先置位 closed、释放全部残留 deferred,再释放 context 与 runtime;此后到达的结清直接返回,不再触碰 VM。

测试

  • workflow-vm.test.ts 重写为单执行器契约套件(26 例),吸收原 conformance 全部用例,新增覆盖上述两缺陷及「较窄中断器修法会打破」的扇出场景
  • 删除 workflow-vm-conformance.test.ts(已并入)
  • workflow-extension.test.ts、workflow-ultraloop-opt-in.test.ts 去掉 skipIf(!isIsolatedVmAvailable()) 门控
  • workflow-registration.test.ts 按新门禁重写

文档

  • development.md、orchestration-lifecycle.md:更正原生扩展必需的错误描述,记录两条编辑约束(必须用 singlefile 变体;handle 与 context/runtime 释放顺序)

行为变化与边界

  • 单次不间断 CPU 突发超 timeoutMs 会被终止(与原 isolated-vm 按墙钟一致);交错短突发不受影响,每次宿主调用结清都会重新计时;等待宿主调用的时间不计入超时。
  • QuickJS 不提供 Intl、structuredClone、Array.fromAsync;其余 ES 特性(含 ES2023 toSorted/with、ES2024 Object.groupBy)可用。
  • 副作用:无原生依赖,CI 无需 node-gyp、无 Node 版本 ABI 问题;pnpm install --ignore-scripts 开箱即得可用 workflow,README 无需修改。

验证

  • 两缺陷定向验证均在按官方入口与 target 编译的 bun 二进制内、于无 node_modules 空目录运行。
  • 运行时一致性:同一探针在 Node 与 bun 编译产物下输出逐字节相同。

测试与门禁

  • 契约套件 26 例通过,含全部回归
  • coding-agent 全量 3484 passed / 273 files,0 失败(rebase 到最新 main 后重跑)
  • tsgo --noEmit 通过
  • biome check --error-on-warnings .(全仓)通过
  • 仓库守卫全部 PASS:check:pinned-deps / ts-imports / layer-direction / ui-layer / workspace-registry / coding-agent-entry-freeze / public-boundary / no-secret-leak
  • bun 二进制与 pnpm 源码路径均冒烟通过(--version、--list-models)
  • 构建产物中已无 isolated-vm 残留

Copilot AI lite review requested due to automatic review settings September 24, 2026 07:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

QuickJS deferred promises are not disposed after normal host-call settlement, causing a critical handle leak.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity

Open (1)
What changed in this PR

Migrates workflow execution from isolated-vm to a bundled QuickJS WebAssembly sandbox for consistent runtime support.

Changes:

  • Consolidates sandbox execution and lifecycle management.
  • Removes native runtime dependencies and gating.
  • Updates tests, build metadata, and documentation.
File Summary
scripts/​build-coding-agent-bundle.mjs Removes native VM externalization.
pnpm-lock.yaml Updates dependency lock data.
packages/​coding-agent/​test/​workflow-vm.test.ts Adds QuickJS sandbox coverage.
packages/​coding-agent/​test/​workflow-vm-conformance.test.ts Removes obsolete dual-runtime tests.
packages/​coding-agent/​test/​workflow-ultraloop-opt-in.test.ts Updates opt-in coverage.
packages/​coding-agent/​test/​workflow-registration.test.ts Updates registration tests.
packages/​coding-agent/​test/​workflow-extension.test.ts Enables workflow tests across runtimes.
packages/​coding-agent/​src/​features/​workflow/​vm.ts Implements the QuickJS sandbox.
packages/​coding-agent/​src/​features/​workflow/​vm-quickjs.ts Removes the duplicate executor.
packages/​coding-agent/​src/​features/​workflow/​step-workflow.ts Updates workflow executor wiring.
packages/​coding-agent/​src/​features/​workflow/​runtime.ts Uses QuickJS by default.
packages/​coding-agent/​src/​features/​workflow/​registration-gate.ts Removes runtime-dependent gating.
packages/​coding-agent/​src/​features/​workflow/​index.ts Updates workflow exports.
packages/​coding-agent/​package.json Replaces the native dependency.
packages/​coding-agent/​docs/​development.md Documents QuickJS constraints.
docs/​orchestration-lifecycle.md Updates workflow runtime documentation.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +317 to +321
hostCalls.live.delete(deferred);
hostCalls.pending = Math.max(0, hostCalls.pending - 1);
if (hostCalls.closed) return;
hostCalls.refreshDeadline?.();
hostCalls.onSettled?.();
@ZouR-Ma
ZouR-Ma merged commit 8297eb5 into main Sep 24, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants