Skip to content

fix(cli): Bun Windows compatibility — shell:true child_process workaround and iii-exec config#917

Open
JackieJK wants to merge 5 commits into
rohitg00:mainfrom
JackieJK:fix/bun-windows-spawn
Open

fix(cli): Bun Windows compatibility — shell:true child_process workaround and iii-exec config#917
JackieJK wants to merge 5 commits into
rohitg00:mainfrom
JackieJK:fix/bun-windows-spawn

Conversation

@JackieJK

@JackieJK JackieJK commented Jun 12, 2026

Copy link
Copy Markdown

What

Fixes agentmemory CLI startup under Bun on Windows, where child_process cannot spawn native Rust-compiled executables (oven-sh/bun#32011).
Three changes, all gated behind an IS_BUN runtime detection:

  1. iiiBinVersion() — adds shell: true to execFileSync. Without it, the version probe hangs for 3s then times out, so the engine is never "found" even when iii.exe exists on disk.
  2. spawnEngineBackground() — adds shell: true to spawn. Without it, the engine process silently fails to start.
  3. writeBunCompatibleConfig() — generates a runtime config at ~/.agentmemory/iii-config.bun.yaml that replaces the iii-exec worker's node dist/index.mjs with bun run src/index.ts. Without it, the engine window prints 'node' is not recognized… on every startup.
    No impact on Node.js — all three changes are IS_WINDOWS && IS_BUN conditional.

Why

Bun's uv_spawn-based child_process implementation on Windows cannot spawn PE binaries with certain subsystem characteristics (iii.exe and other Rust-compiled executables). execFileSync and spawnSync both hang; spawn silently fails. The documented workaround is shell: true, which routes through cmd.exe.
Root cause is upstream in Bun (oven-sh/bun#32011). This PR is a defensive workaround so agentmemory works on Bun without waiting for the upstream fix.
How to verify

  • With Bun 1.3.14 on Windows: bun run src/cli.ts starts the engine, worker connects, and agentmemory is ready. No ETIMEDOUT, no node not found.
  • npm test — all existing tests pass (changes are Bun-conditional, Node path unchanged).

Summary by CodeRabbit

Summary

  • New Features

    • Added broader Bun runtime support, including automatic generation of a Bun-compatible engine configuration when needed.
    • Updated hook execution to launch consistently across runtimes.
  • Bug Fixes

    • Improved subprocess reliability for Windows + Bun.
    • Made private/local address blocking consistent by using runtime-appropriate DNS resolution.
    • Strengthened an in-process guard to prevent recursion collisions during concurrent SDK queries.
  • Chores

    • Updated runtime start/migration commands and engine requirements to better align with Bun.

…ound and iii-exec config

On Bun for Windows, child_process cannot spawn native Rust-compiled
executables (oven-sh/bun#32011). execFileSync and spawn hang, causing
iii version check and engine startup to fail silently.

- Add IS_BUN constant for runtime detection
- Use shell:true in execFileSync/spawn on Windows+Bun
- Generate Bun-compatible iii-config with \�un run src/index.ts\
  replacing \
ode dist/index.mjs\ in the iii-exec worker
@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

@JackieJK is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c752ebab-241b-40e8-a49a-06d0f696593b

📥 Commits

Reviewing files that changed from the base of the PR and between a2edefe and 12f36b1.

📒 Files selected for processing (4)
  • plugin/hooks/hooks.copilot.json
  • src/functions/mesh.ts
  • src/providers/agent-sdk.ts
  • src/providers/embedding/local.ts
💤 Files with no reviewable changes (1)
  • src/functions/mesh.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • plugin/hooks/hooks.copilot.json
  • src/providers/embedding/local.ts

📝 Walkthrough

Walkthrough

Adds comprehensive Bun runtime support via detection flags, iii config rewriting for Bun launcher commands, subprocess compatibility for Windows+Bun, hook execution through a cross-runtime runner, DNS/ONNX/dependency hints for service compatibility, and package config updates. Also refactors AgentSDKProvider's recursion guard from Node-only AsyncLocalStorage to a cross-runtime callId/Map approach.

Changes

Bun Runtime Support

Layer / File(s) Summary
Bun runtime detection
src/cli.ts, src/state/cjk-segmenter.ts
Introduces IS_BUN flag across modules to detect Bun via process.versions.bun or globalThis.Bun.
Bun-compatible config generation and engine startup
src/cli.ts
writeBunCompatibleConfig() rewrites iii config from node dist/index.mjs to bun run src/index.ts, writes ~/.agentmemory/iii-config.bun.yaml, and startEngine() uses this path when running under Bun.
Subprocess execution compatibility for Windows+Bun
src/cli.ts
iiiBinVersion() and spawnEngineBackground() add { shell: true } to subprocess options when spawning on Windows with Bun.
Hook execution refactoring through cross-runtime runner
scripts/hook-runner.mjs, plugin/hooks/hooks.json, plugin/hooks/hooks.copilot.json
New hook-runner.mjs detects runtime and spawns hook scripts via Bun or Node; both hook configs route all hook commands through the runner.
Cross-runtime service compatibility
src/functions/mesh.ts, src/providers/embedding/local.ts, src/state/cjk-segmenter.ts
Adds cross-runtime DNS lookup using Bun.dns.lookup() or node:dns/promises fallback, forces ONNX WASM backend under Bun, and adjusts jieba dependency hints.
Package scripts and engine configuration
package.json
Scripts use tsx for start/migrate/bench, and engines field adds Bun alongside Node.

SDK Provider Recursion Guard

Layer / File(s) Summary
AsyncLocalStorage to callId/Map recursion guard
src/providers/agent-sdk.ts
Replaces Node-only AsyncLocalStorage with module-level nextCallId counter and sdkActiveCalls Map, enabling per-call tracking that short-circuits re-entry without shared context interference.

Sequence Diagrams

sequenceDiagram
  participant User as User/CLI
  participant CLI as startEngine()
  participant Config as writeBunCompatibleConfig()
  participant FS as File System
  participant Engine as iii Engine
  User->>CLI: start engine
  CLI->>Config: IS_BUN detected
  Config->>FS: read original iii-config.yaml
  Config->>FS: rewrite node→bun, write to ~/.agentmemory/iii-config.bun.yaml
  Config-->>CLI: return Bun config path
  CLI->>Engine: spawn with Bun config path
  Engine-->>User: engine running
Loading
sequenceDiagram
  participant Plugin as Copilot/Claude Plugin
  participant HookConfig as hooks.json / hooks.copilot.json
  participant Runner as hook-runner.mjs
  participant Runtime as Bun/Node Runtime
  participant HookScript as Hook Script (e.g., session-start.mjs)
  Plugin->>HookConfig: event triggered
  HookConfig->>Runner: shell exec hook-runner.mjs [script-path]
  Runner->>Runtime: detect environment (IS_BUN)
  Runtime-->>Runner: runtime type
  Runner->>HookScript: spawn script via detected runtime
  HookScript->>Plugin: completion
Loading
stateDiagram-v2
  [*] --> Idle: AgentSDKProvider created
  Idle --> TopLevel: query() called (no parent)
  TopLevel --> AllocateCallId: nextCallId++ and add to sdkActiveCalls
  AllocateCallId --> ExecuteSDK: sdkContext.run(callId, ...)
  ExecuteSDK --> MayReenter: nested query() call
  MayReenter --> CheckCallId: sdkContext.getStore() == currentCallId?
  CheckCallId --> ShortCircuit: yes, already active
  CheckCallId --> AllocateNested: no, allocate new callId
  ShortCircuit --> ReturnEmpty: return ''
  AllocateNested --> ExecuteSDK: execute nested query
  ExecuteSDK --> CleanupInner: inner finally
  CleanupInner --> DecrementRefCount: sdkActiveCount--, restore AGENTMEMORY_SDK_CHILD
  DecrementRefCount --> CleanupOuter: outer finally
  CleanupOuter --> RemoveCallId: sdkActiveCalls.delete(callId)
  RemoveCallId --> [*]
  ReturnEmpty --> RemoveCallId
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • rohitg00/agentmemory#782: Modifies the same recursion-guard implementation in src/providers/agent-sdk.ts; both PRs update how SDK re-entrancy is tracked across the same guard checkpoint.

🐰 With Bun now hopping through every frame,
Hooks skip freely, DNS flows the same,
Guards track each call by its own unique name,
The system adapts without losing its game! 🥕⚡

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main change: adding Bun Windows compatibility via shell:true workaround and config generation, which aligns with the core objectives of fixing CLI startup under Bun on Windows.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cli.ts`:
- Around line 394-396: After reading and replacing the Bun config (the
readFileSync -> content and writeFileSync to bunPath using the regex /- node
dist\/index\.mjs/ -> `- ${runtimeCmd} src/index.ts`), verify that the
replacement actually changed the file by comparing the original read string
(from originalPath) to the new content; if they are equal (no match applied),
throw or exit with a clear error mentioning bunPath and the expected pattern so
the process fails fast instead of silently writing an unchanged config. Use the
existing symbols content, originalPath, bunPath, runtimeCmd and the
regex/pattern to perform the check before calling writeFileSync.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b91f9990-67f8-4f01-91ae-0a2c298bb86c

📥 Commits

Reviewing files that changed from the base of the PR and between f6f9e3c and b7b415e.

📒 Files selected for processing (1)
  • src/cli.ts

Comment thread src/cli.ts Outdated
JackieJK added 2 commits June 12, 2026 14:21
Address CodeRabbit review: verify the config replacement actually changed the file. If upstream iii-config.yaml drifts, throw instead of silently writing an unchanged config.
…ation

Replace three Node.js-only APIs with cross-runtime equivalents so the project runs under both Node.js >=20 and Bun >=1.1:

- AsyncLocalStorage → per-call Map recursion guard (agent-sdk.ts)
- node:dns/promises → Bun.dns.lookup() shim (mesh.ts)
- Force ONNX WASM backend under Bun (local.ts)
- Bun-aware CJK hint in cjk-segmenter.ts

Add cross-runtime hook launcher (scripts/hook-runner.mjs) that detects the current runtime and spawns hook scripts with the correct binary. Update all 22 hook commands in hooks.json + hooks.copilot.json to use it.

Switch package.json scripts from hardcoded node to tsx (already a dev dependency, works on both runtimes). Add bun >=1.1.0 to engines.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/functions/mesh.ts (1)

18-20: ⚡ Quick win

TypeScript guideline drift: WHAT-style explanatory comments were added in runtime helper blocks. Replace these comments with clearer identifier names and keep intent encoded in code structure.

  • src/functions/mesh.ts#L18-L20: remove the descriptive DNS helper comments and rely on the helper/function naming.
  • src/providers/embedding/local.ts#L3-L10: remove the Bun/ONNX explanatory comments and keep the runtime intent in naming and flow.

As per coding guidelines, for src/**/*.ts: “In TypeScript source code, avoid code comments explaining WHAT — use clear naming instead.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/functions/mesh.ts` around lines 18 - 20, The code contains WHAT-style
explanatory comments that violate the TypeScript coding guideline of using clear
naming instead of comments to convey intent. Fix this at two locations: (1) in
src/functions/mesh.ts lines 18-20, remove the comments describing the DNS lookup
behavior and cross-runtime handling, relying instead on the variable name IS_BUN
and function/method naming to convey the intent of the runtime detection logic;
(2) in src/providers/embedding/local.ts lines 3-10, remove the explanatory
comments about Bun and ONNX runtime handling and similarly encode the intent
through clear identifier names and code structure. Ensure the remaining code
(variable declarations, function names, and control flow) clearly communicates
what is being detected or handled without the descriptive comments.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugin/hooks/hooks.copilot.json`:
- Around line 7-68: The command entries in this hooks configuration file use
unquoted ${COPILOT_PLUGIN_ROOT} paths which will fail on systems where the
plugin root contains spaces. Fix this by adding double quotes around both the
hook-runner.mjs path and the individual script paths in all command values
throughout the file. Apply this consistently to all hooks including
userPromptSubmitted, preToolUse, postToolUse, postToolUseFailure, preCompact,
agentStop, sessionEnd, subagentStart, subagentStop, and notification hooks,
following the same quoting pattern already used in the plugin/hooks/hooks.json
file.

In `@src/providers/agent-sdk.ts`:
- Around line 25-26: The recursion guard is not working correctly because the
active call id is allocated fresh on every call (around line 68) and only
inserted into sdkActiveCalls after the recursion check (around line 69-81), so
re-entrant calls are never detected. Fix this by using async-local context or
storage (such as AsyncLocalStorage) to track the active call id per async
execution context. For root calls, allocate a new id and store it in both the
async context and sdkActiveCalls. For nested/re-entrant calls, first check if an
active call id already exists in the async context, and if so, verify it exists
in sdkActiveCalls to detect recursion before proceeding with the SDK query. This
ensures that when provider.summarize() is called recursively, the inner call
will detect the outer call's id in the active calls map and return an empty
string instead of making a new SDK query.

---

Nitpick comments:
In `@src/functions/mesh.ts`:
- Around line 18-20: The code contains WHAT-style explanatory comments that
violate the TypeScript coding guideline of using clear naming instead of
comments to convey intent. Fix this at two locations: (1) in
src/functions/mesh.ts lines 18-20, remove the comments describing the DNS lookup
behavior and cross-runtime handling, relying instead on the variable name IS_BUN
and function/method naming to convey the intent of the runtime detection logic;
(2) in src/providers/embedding/local.ts lines 3-10, remove the explanatory
comments about Bun and ONNX runtime handling and similarly encode the intent
through clear identifier names and code structure. Ensure the remaining code
(variable declarations, function names, and control flow) clearly communicates
what is being detected or handled without the descriptive comments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e4f75ab9-1be0-43dc-8971-15de0a4178c9

📥 Commits

Reviewing files that changed from the base of the PR and between 895765e and a2edefe.

📒 Files selected for processing (8)
  • package.json
  • plugin/hooks/hooks.copilot.json
  • plugin/hooks/hooks.json
  • scripts/hook-runner.mjs
  • src/functions/mesh.ts
  • src/providers/agent-sdk.ts
  • src/providers/embedding/local.ts
  • src/state/cjk-segmenter.ts
✅ Files skipped from review due to trivial changes (1)
  • src/state/cjk-segmenter.ts

Comment thread plugin/hooks/hooks.copilot.json Outdated
Comment thread src/providers/agent-sdk.ts
…ng, comment cleanup

- agent-sdk.ts: replace broken callId check with AsyncLocalStorage for
  per-async-context recursion detection (concurrent siblings get separate
  contexts, recursive re-entry is blocked)
- hooks.copilot.json: quote COPILOT_PLUGIN_ROOT paths to handle spaces,
  matching hooks.json pattern
- mesh.ts, local.ts: remove WHAT-style comments per coding guidelines
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.

1 participant