Skip to content

fix(windows): launch step under Bun with Node fallback to text CLI#79

Open
knqiufan wants to merge 10 commits into
stepfun-ai:mainfrom
knqiufan:fix/78-windows-opentui-bun-launcher
Open

fix(windows): launch step under Bun with Node fallback to text CLI#79
knqiufan wants to merge 10 commits into
stepfun-ai:mainfrom
knqiufan:fix/78-windows-opentui-bun-launcher

Conversation

@knqiufan

@knqiufan knqiufan commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

关联 Issue

Closes #78
Refs #29

变更类型

  • feat 新功能
  • fix bug 修复
  • docs 文档
  • refactor 重构(无行为变更)
  • test 仅测试
  • chore 构建 / 脚手架 / CI
  • perf 性能优化

影响范围

  • 改动了 packages/protocol/(跨边界协议,需要同步 SDK)
  • 改动了 packages/core/ 的公开 API
  • 改动了 src/gateway/(session authority 行为变更)
  • 改动了分层依赖(同步更新了 AGENTS.md.dependency-cruiser.cjs
  • 仅 src/commands + src/runtime + scripts/setup.ps1

变更说明(why,而非 what)

Windows 上的 setup.ps1 一直生成 Node-based step.cmd 启动器(来自 #12),但 @opentui/core 是 Bun-built 包:bundle 顶部有 11 个 .scm with { type: "file" } import、6 个 .wasm import、4 个 bun:ffi 顶层 import、以及 bun-webgpu 依赖。Node.js 的严格 ESM loader 拒绝 .scm(用户当前看到的 Unknown file extension ".scm"),即使 loader hook 假装掉 .scm/.wasmbun:ffi 也会立刻挂——FFI 调用无法伪造。

#29 跟踪了同类问题,但 mitigation 是"装 Linux-native Bun",对 Windows 不适用。

本 PR 同时做两件事:

  1. Part B(src 层兜底):在 src/runtime/open-tui-capability.ts 新增 isOpenTuiRuntimeSupported(),用 typeof process.versions.bun !== "undefined" 检测 Bun。root-command.tsresume-command.tsshouldUseTui 计算叠加这个检查——Node 上直接跳过 TUI 路径并打印一行警告,落到文本 CLI。voice-command.ts 在 Node 上抛清晰错误,指引装 Bun。
  2. Part C(installer 层)scripts/setup.ps1 新增 Install-Bun 函数(PATH → winget → 直接下载 zip 三级回退、bun --version 验证、finally 清理临时 zip、PATH 去重)、-SkipBun flag、把生成的 step.cmd 改成优先 Bun(STEP_BUN_BIN → PATH → Node 三级回退)。

两者合一构成完整的 Windows 故事:installer 尽量装 Bun 拿到全功能 TUI;万一 Bun 不可用,src 层兜底保证 step 文本 CLI 仍可用。step voice 在 Node 上明确不支持,错误信息指引装 Bun。

Test status

  • Full pnpm check: 1526 passed / 24 skipped; lint has 0 errors (5 existing warnings).
  • Windows manual verification:
    • Default Bun path: ran setup.ps1 with Bun 1.3.14 already installed (skipping only dependency installation); the installed launcher opened the STEP interactive TUI.
    • -SkipBun: with Bun removed from the child PATH, setup.ps1 -SkipInstall -SkipBuild -SkipBun completed and step used the Node text CLI with the one-time fallback warning; step voice returned the expected actionable Bun installation error.
    • STEP_BUN_BIN: with both bun and node absent from PATH, setting STEP_BUN_BIN to Bun started the installed launcher successfully (step --version returned 1.0.0).
    • Launcher cwd regression: launching step.cmd from a project directory now resolves installed runtime dependencies and starts successfully.
  • macOS/Linux regression: the re-run CI passed on macOS and Ubuntu (Windows passed too).

Commits

本 PR 包含 7 个原子 commit,按依赖顺序:

  1. feat(runtime): expose isOpenTuiRuntimeSupported for Bun detection
  2. fix(commands): skip TUI path on Node.js runtime in step root command
  3. fix(commands): skip TUI path on Node.js runtime in step resume
  4. fix(commands): fail step voice with actionable error on Node runtime
  5. fix(commands): make voice runtime error platform-aware
  6. feat(setup): install Bun on Windows and prefer it in step.cmd launcher
  7. fix(setup): harden Install-Bun against partial failures and stale PATH

已知限制 / 后续工作

  1. Windows ARM64Install-Bun 当前硬编码下载 bun-windows-x64.zip。ARM64 Windows 会装 x64 二进制走模拟(慢但能跑)。Bun 的 ARM64 Windows 构建稳定后可加分支。
  2. step voice 在 Node 上明确不支持:voice 是 TUI-driven 流程,没有合理的文本回退。错误信息明确指引装 Bun。
  3. README 更新延后:Bun 安装指引、Windows 升级流程的 README 更新按用户偏好不在本 PR 范围内,作为后续 PR 单独处理。

@github-actions github-actions Bot added area/build scripts, .github, build/config files area/cli src/cli, src/commands, src/runtime, src/bootstrap, src/*.ts labels Jun 21, 2026
@ZouR-Ma

ZouR-Ma commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

这个 PR 的架构判断我们完全认可:用 process.versions.bun运行时能力检测而不是平台判断、installer 改动全部圈在 setup.ps1/step.cmd 里、shouldUseTui 抽成纯函数配测试——这正是当初 #11 那种整体替换方案被关掉之后,我们希望看到的 Windows 支持形态。WinGet app-execution-alias 那个 Node spawn ENOENT 的坑识别得很准。我们还独立验证了核心前提:macOS + Node v24 下 import('@opentui/core') 同样报 bun: 协议错误——TUI 在纯 Node 下任何平台都起不来,所以这个门禁只会把崩溃变成干净降级,不会误伤任何现存路径。

合入前差两件事:

  1. (必须)rebase 到最新 main,让 CI 重新跑绿。 现在的三平台绿是 6 月 21 日在旧基线上跑的,此后 main 已合入 #75/#28/#69 等一批改动。顺带一个好消息:test(utils): align path and shell tests with TESTING.md on Windows #75 已经把 Windows 非开发者模式下那 10 个 symlink 测试失败修掉了——你 body 里 --no-verify 说明的根因没了,rebase 后本地 pnpm check 应该能全绿,那段说明可以删掉。
  2. (必须)把测试计划里 4 个没勾的手工验证跑掉。 installer 的 winget/直接下载/PATH 逻辑 CI 覆盖不到,而「默认装 Bun → TUI 可用」这条 happy path 目前还没人完整跑过。四条:默认安装、-SkipBunSTEP_BUN_BIN、macOS/Linux 回归。你跑或我们跑都行(你 body 里也是这么写的)——谁跑谁把记录贴到 PR 里。

两个不卡合入的小点:runtimeUnsupported 的警告现在不看 json/prompt/TTY 条件,step --json "q" 在 Node 下每次都会往 stderr 打一行 TUI 警告——建议收敛为「除 runtime 外其他 TUI 条件全满足时才警告」;这段警告逻辑在 root-command 和 resume-command 里重复了,可以抽个小辅助。

rebase + 验证记录齐了 @ 我们,这个我们想尽快合。

knqiufan and others added 9 commits July 18, 2026 01:25
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
winget installs Bun as a zero-byte reparse point at
%LOCALAPPDATA%\Microsoft\WinGet\Links\bun.exe. PowerShell and cmd.exe
resolve it via shell APIs, but Node's child_process.spawn uses
CreateProcess directly and gets ENOENT — breaking Invoke-StepCli which
spawns via node scripts/run-step.mjs.

When the resolved Bun path is a WinGet shim, leave STEP_BUN_BIN unset.
Node spawns then fall back to tsx (existing behavior), and the step.cmd
launcher resolves Bun via 'where bun' (cmd handles the alias correctly).

Windows CI was the first to hit this because it runs setup.ps1 without
-SkipBun; real Windows users would hit it too.
@knqiufan
knqiufan force-pushed the fix/78-windows-opentui-bun-launcher branch from 4ecfd8a to dcec217 Compare July 17, 2026 17:29
@knqiufan

knqiufan commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

@ZouR-Ma Thank you for the detailed review. All requested follow-ups are now complete:

  • Rebasing: rebased onto the latest main (including test(utils): align path and shell tests with TESTING.md on Windows #75) and force-pushed the refreshed branch.
  • Warning behavior: the Node fallback warning now appears only when the TUI would otherwise be selected, and the shared runtime helper removes the root/resume duplication.
  • Launcher robustness: manual validation exposed a cwd-dependent dependency-resolution issue when calling the installed step.cmd from another project. The launcher now switches to its install directory before startup, with a regression test.
  • Verification: pnpm check passes locally (1526 passed / 24 skipped); the re-run macOS, Ubuntu, and Windows CI checks are all green.
  • Windows manual validation: verified the Bun TUI path, -SkipBun Node text fallback (including the actionable step voice error), and STEP_BUN_BIN launch with both Bun and Node absent from PATH. I also updated the PR description and removed the obsolete --no-verify explanation.

One observation for transparency: Bun 1.3.14 rendered the TUI successfully, but crashed while closing it with Esc. This occurred after the validation target had started and appears to be a Bun runtime crash; it is separate from the Node/OpenTUI startup issue addressed here.

Regarding the exit diagnosis (for Windows) of Bun 1.3.14.

  • With Bun 1.3.14 on Windows, the installed launcher starts and renders the STEP OpenTUI interface successfully.
  • Pressing a single Esc then reproduces a Bun process segfault (exit code 1). The Bun crash report identifies opentui.dll in the failing native path.
  • Typing /exit requests the same application-level exit and returns exit code 0. This isolates the trigger to teardown after the raw Escape keyboard-event path, rather than startup, session state, or the general SDK close path.
  • Control experiments cleanly created and destroyed the minimal OpenTUI renderer, React root, keyboard handler, and textarea on the same Bun build. The failure requires the complete STEP TUI component/lifecycle composition.

The application currently uses @opentui/core / @opentui/react 0.1.90, whose native Zig core is loaded through Bun FFI. This makes the evidence consistent with a native OpenTUI lifecycle/FFI teardown defect exposed by Bun 1.3.14 on Windows, rather than a Node fallback or launcher defect. Bun has an open Windows 1.3.14 TUI segfault report in a separate OpenCode workload (oven-sh/bun#32691). Newer OpenTUI releases also contain closely related lifecycle and FFI ownership fixes, including guards for destroyed renderables and preserving borrowed pointer owners (OpenTUI v0.4.3); this is strong evidence for the next upgrade target, but not proof that an upgrade alone fixes this exact reproduction.

Current Windows workaround: exit with /exit rather than Esc, or use the Node text-CLI fallback. Follow-up work should upgrade and adapt OpenTUI, then add an interactive Windows Esc exit regression check before removing this limitation.

Self-check

Could you please take another look when convenient? Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/build scripts, .github, build/config files area/cli src/cli, src/commands, src/runtime, src/bootstrap, src/*.ts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Windows: step fails with "Unknown file extension .scm" — OpenTUI requires Bun runtime

2 participants