Skip to content

fix(cli): avoid node util styleText dependency in setup wizard#12

Closed
freelanceagent1 wants to merge 2 commits intocortexkit:mainfrom
freelanceagent1:fix/cli-node19-prompts
Closed

fix(cli): avoid node util styleText dependency in setup wizard#12
freelanceagent1 wants to merge 2 commits intocortexkit:mainfrom
freelanceagent1:fix/cli-node19-prompts

Conversation

@freelanceagent1
Copy link
Copy Markdown
Contributor

Summary

Fixes the aft-opencode setup / doctor CLI crash on older Node runtimes where node:util.styleText is unavailable.

The failure reported was:

$ bunx @cortexkit/aft-opencode@latest setup
SyntaxError: The requested module 'node:util' does not provide an export named 'styleText'

Cause

The CLI prompt path depended on @clack/prompts, which pulled in a runtime path that expected newer Node node:util exports than are available on Node 19.9.0.

Fix

  • replace the CLI prompt wrapper with a small Node-native implementation
  • remove @clack/prompts from the plugin package dependencies
  • keep the existing setup / doctor CLI behavior intact

Validation

  • bun install
  • bun run build in packages/opencode-plugin
  • node packages/opencode-plugin/dist/cli.js

Additionally, the built dist/cli.js no longer contains:

  • styleText
  • stripVTControlCharacters
  • @clack/prompts
  • node:util

Compatibility note

  • validated on the current Windows host by rebuilding and running the bundled CLI
  • this change is intended to improve compatibility for older Node runtimes, including the reported macOS arm64 Node 19.9.0 case
  • I did not runtime-test on macOS in this branch from this machine

@freelanceagent1 freelanceagent1 force-pushed the fix/cli-node19-prompts branch from 7215f95 to 07cefc0 Compare April 16, 2026 16:11
@ualtinok
Copy link
Copy Markdown
Collaborator

Thanks for the PR and the careful diagnosis — you correctly identified the root cause.

We ended up fixing this a different way in v0.13.1: instead of removing `@clack/prompts`, we changed all documented commands to use `bunx --bun` instead of `bunx`. The `--bun` flag tells bun to execute the JavaScript directly with its own runtime, bypassing the `#!/usr/bin/env node` shebang that was routing to the user's older Node. This preserves the `@clack/prompts` UX (colors, prompts, spinners) while working on any Node version — or with no Node installed at all.

Closing this PR since the underlying issue (#10) is resolved, but genuinely appreciate the contribution and investigation. 🙏

@ualtinok ualtinok closed this Apr 18, 2026
ualtinok added a commit that referenced this pull request Apr 25, 2026
…llowups

Second full-codebase audit found 38 items; 32 confirmed real after triple-
verification, plus a third pass after Oracle review caught one introduced
SSRF bypass.

Security:
- aft-cli: createGitHubIssue uses spawnSync with argv to prevent shell
  injection through repo/title (#6).
- opencode + pi: restrict_to_project_root defaults to true for plugin
  contexts; the Rust CLI default stays false for direct/scripted use (#1).
- opencode: per-server random RPC token (32B hex) stored in JSON port file;
  every request requires the token; legacy integer port files still parsed
  for backward compatibility (#23).
- opencode: url-fetch SSRF guard with manual redirect handling (max 5 hops),
  full IPv6 expansion, and IPv4-mapped/compatible bypass detection
  (::ffff:127.0.0.1, ::127.0.0.1, [::]); allowPrivate escape hatch (#32 +
  Oracle followup).
- Rust: handle_git_conflicts now validates each conflicted file path
  through ctx.validate_path() (#20).

Cross-plugin parity:
- pi-plugin pool keys bridges by realpathSync canonicalization, mirroring
  opencode (#5).
- pi-plugin zoom multi-symbol fan-out routes through callBridge so each
  parallel request carries Pi's session_id (#16 — regression from v0.15.3).
- pi-plugin tool-surface ALL_ONLY constants align with opencode (#9).
- both bridges enforce 64MB MAX_STDOUT_BUFFER and treat overflow as crash
  (#10).
- pi-plugin aft_transform validates per-op required parameters (#17).
- both bridges' compareSemver implements semver pre-release ordering (#29).

Rust correctness:
- glob edit_match wraps multi-file writes in checkpoint snapshot with
  rollback on failure (#3).
- LSP client kills+waits child on shutdown timeout and via Drop impl (#4).
- type-checker working_dir uses config.project_root, not path.parent() (#7).
- ast_search/grep return invalid_pattern errors instead of empty matches
  on malformed regex/AST patterns (#11).
- zoom ambiguous suggestions output 1-based start-end line ranges (#12).
- zoom line-range response uses clamped end_line (#13).
- configure.validate_on_edit accepts booleans (#18).
- checkpoint restore creates parent directories (#19).
- lsp_hints paths_match uses canonical comparison + separator-bounded
  suffix matching (#22).
- format.resolve_tool --version probe has 2s timeout (#24).
- backup.canonicalize_key fallback logs at debug (#25).
- read.handle_directory caps at 1000 entries with truncation note (#34).
- read uses saturating_add/sub for end_line math (#36).
- lsp_rename + lsp_find_references use consistent 1-based character (#37).
- ast_search/replace comments now reference panic=unwind (#27).

Workflow + docs:
- release.yml has top-level concurrency control (#35).
- test job runs bun build before publish-crates (#8).
- release.yml uses sha256sum on Ubuntu (#29).
- version-sync.mjs comment reflects 9 packages (#28).

Verification: 726 Rust tests pass / 1 ignored (was 718, +8 new tests),
383 TS tests pass (was 362, +21 new tests covering RPC auth, SSRF guard,
pool canonicalization, semver pre-release, structure validation, edit_match
atomicity, IPv4-mapped IPv6 bypass detection). Typecheck + lint clean.
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.

2 participants