Skip to content

fix(ecosystem): use 'node --import tsx' for cross-platform PM2 spawn (closes #234)#245

Merged
floodsung merged 19 commits into
mainfrom
fix/ecosystem-tsx-cross-platform
May 9, 2026
Merged

fix(ecosystem): use 'node --import tsx' for cross-platform PM2 spawn (closes #234)#245
floodsung merged 19 commits into
mainfrom
fix/ecosystem-tsx-cross-platform

Conversation

@floodsung

Copy link
Copy Markdown
Contributor

Summary

Replaces interpreter: node_modules/.bin/tsx with interpreter: node + interpreter_args: '--import tsx' so PM2 can launch MetaBot on Windows without EINVAL.

Why

The POSIX shell wrapper at node_modules/.bin/tsx cannot be exec'd directly by child_process.spawn on Windows (no .cmd shim is consulted without shell: true). The result was that pm2 start ecosystem.config.cjs reported the process as online while it actually died at exec time — pm2 info showed pid: N/A / mem: 0b, and pidusage spammed "PID invalid" errors.

node --import tsx is tsx 4.x's documented cross-platform entrypoint and works identically on Linux, macOS, and Windows. tsx is already a dependency (^4.21.0) and Node ≥ 20.6 is already a documented prerequisite, so no version bumps are needed.

Test plan

  • node --import tsx -e "..." resolves the loader locally
  • npm run build passes
  • npm test — 219/219 pass
  • npm run lint — no new errors
  • Manual on Windows: pm2 start ecosystem.config.cjs && pm2 list shows real pid + memory

Notes

PR #244 also rewrites ecosystem.config.cjs. If #244 lands first, the fix needs to be re-applied there (the diff still spawns tsx via the wrapper script).

Closes #234.

🤖 Generated with Claude Code

Flood Sung and others added 19 commits April 25, 2026 08:32
install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.
fix(codex): show model metadata in cards
fix(codex): mirror skills and avoid bwrap sandbox
fix(codex): tolerate AGENTS deployment failures
…back

fix(codex): install bundled skills when user cache is empty
Closes #234.

The previous interpreter pointed at node_modules/.bin/tsx, which is a
POSIX shell wrapper on Windows with no .cmd shim. PM2 spawns the
interpreter via child_process.spawn, which cannot exec a sh script
directly on Windows (EINVAL) — the process appeared to start but died
at exec time, leaving 'pm2 list' showing online with pid: N/A.

Switching to 'node --import tsx' is tsx 4.x's documented cross-platform
entrypoint and behaves identically on Linux, macOS, and Windows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@floodsung floodsung merged commit 2b0db02 into main May 9, 2026
3 checks passed
@floodsung floodsung deleted the fix/ecosystem-tsx-cross-platform branch May 9, 2026 03:46
Liyunlun added a commit to Liyunlun/metabot that referenced this pull request May 12, 2026
* fix(executor): switch to auto permission mode when running as root (xvirobotics#212)

Claude Code blocks --dangerously-skip-permissions under root/sudo
privileges (exit code 1). Detect root via process.getuid() and fall
back to permissionMode 'auto', which auto-approves all tool permissions
without that flag. Non-root behaviour is unchanged (bypassPermissions).

Also update docs/troubleshooting.md and CLAUDE.md to document this as
Cause B of the "process exited with code 1" error.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(feishu): propagate send/update failures so retry + fallback actually trigger (xvirobotics#213)

MessageSender's updateCard / sendImage / sendFile silently swallowed API
errors and returned void. Downstream:

- sendFinalCard's retry + text fallback in MessageBridge never ran — the
  try/catch was unreachable. When a long task produced many throttled card
  updates, the final "complete" update could be rate-limited by Feishu and
  silently lost, leaving the card stuck on an intermediate tool state
  (e.g. "⏳ bash") even after the task finished. (fixes xvirobotics#186)

- sendImageFile / sendLocalFile returned true even when the actual message
  send step failed after a successful upload. The text fallback in
  OutputHandler (triggered on false) never fired, so group chats whose
  file-send call failed got no file and no notification. (fixes xvirobotics#190)

Change updateCard / sendImage / sendFile to return Promise<boolean>, and
propagate the real success signal through sendImageFile / sendLocalFile
and sendFinalCard. Return-based signalling (not throw) keeps the many
fire-and-forget call sites inside rate-limiter schedule callbacks safe
from unhandled promise rejections.

Also updated the IMessageSender interface and the Telegram / WeChat /
Null sender implementations to match.

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* feat(feishu): surface Monitor / background task events on the live card (xvirobotics#217)

When Claude kicked off a background task (Monitor, long-running Task
tool, etc.) the Feishu card stopped updating — task_started /
task_progress / task_notification / task_updated system messages were
dropped in StreamProcessor, so the user saw "bot went silent" even
though the agent was receiving live events.

- Add `BackgroundEvent` to the shared CardState shape (taskId,
  description, status, lastEvent).
- StreamProcessor now tracks one BackgroundEvent per task_id and
  updates it on every SDK `type:'system'` with a task_* subtype.
  Also covers the Codex translator's `type:'task_notification'`
  shape. Ambient / `skip_transcript:true` tasks stay hidden.
- Card builder renders a "📡 Background" section with per-task
  status icon (⏳ running, ✅ completed, ❌ failed, ⏹️ stopped),
  short task id, description, and the latest event line.
- Tests: 9 new cases in stream-processor.test.ts covering started /
  progress / notification statuses / updated patch / skip_transcript /
  missing task_id / codex shape / result propagation; 2 new cases in
  card-builder.test.ts for the rendered section.

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* feat(installer): allow custom install directory via --dir / -Dir flag (xvirobotics#220)

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>

* fix(feishu): require explicit @mention match when botOpenId is known (xvirobotics#225)

* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(feishu): require explicit @mention match when botOpenId is known

The previous `!botOpenId || m.id?.open_id === botOpenId` short-circuit
treated *any* @mention in a group as if the bot were mentioned whenever
botOpenId was unset, and incidentally also matched any single mention
when it was set (because `.some()` returns true on the first iteration
where `!botOpenId` is true). Replace with a clearer branch: when
botOpenId is known, match strictly; otherwise fall back to "any mention
present" so bots without a resolved open_id still behave reasonably.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ecosystem): use 'node --import tsx' for cross-platform PM2 spawn (closes xvirobotics#234) (xvirobotics#245)

* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* fix(ecosystem): use 'node --import tsx' for cross-platform spawn

Closes xvirobotics#234.

The previous interpreter pointed at node_modules/.bin/tsx, which is a
POSIX shell wrapper on Windows with no .cmd shim. PM2 spawns the
interpreter via child_process.spawn, which cannot exec a sh script
directly on Windows (EINVAL) — the process appeared to start but died
at exec time, leaving 'pm2 list' showing online with pid: N/A.

Switching to 'node --import tsx' is tsx 4.x's documented cross-platform
entrypoint and behaves identically on Linux, macOS, and Windows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* feat(session): disable session TTL (sessions never expire) (xvirobotics#242)

Previously sessions auto-expired after 24h. This made resuming long-running
projects unreliable — users would return after a day and find their context
gone, even though Claude's session JSONL still exists on disk.

Set SESSION_TTL_MS = Infinity. Users can still manually /reset.

Also adds a comment about the sibling concern: when switching a bot's
defaultWorkingDirectory, sessions-*.json must be preserved so old projects
can be resumed.

Co-authored-by: uestney <uestney@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* fix(install): fail fast on git pull error and stale checkout (refs xvirobotics#224) (xvirobotics#246)

* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* fix(install): fail fast on git pull error and stale checkout

Closes xvirobotics#224.

Both install.sh and install.ps1 previously swallowed `git pull --ff-only`
failures with a warning and continued with stale code, causing later
phases (typically Phase 6 'skill not found') to error with a confusing
'cannot find path src/skills/metaskill/SKILL.md' even though that path
is in the repo — the user's local checkout had simply diverged.

- Phase 2: `git pull --ff-only` failure now exits with diagnostics and
  three concrete remediation commands (inspect / stash+retry / hard
  reset) instead of warn-and-continue.
- Phase 6: Adds a one-shot Test-Path / [[ -f ]] sentinel on the bundled
  metaskill SKILL.md so a stale checkout fails immediately with a clear
  message rather than midway through a Copy-Item / cp.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* fix(cli): auto-detect METABOT_HOME from script's own location (xvirobotics#247)

* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* fix(cli): auto-detect METABOT_HOME from script's own location

`mb` and `metabot` previously hard-coded `$HOME/metabot` as the fallback
install path. When MetaBot is installed elsewhere and METABOT_HOME isn't
exported (e.g. on a fresh shell, or after a non-default install where the
shell rc was never updated), the CLIs read no .env, fall back to
API_SECRET=changeme, and every API call returns 401 Unauthorized.

Resolve the script's own path via `readlink -f` and use its parent as
METABOT_HOME when METABOT_HOME is unset. This makes both `~/.local/bin/mb`
copies (default install) and symlinks (manual setup) discover the right
.env without requiring the user to export METABOT_HOME.

`mm` already had this fallback — port the same pattern to mb/metabot.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: zhangsanxueai <149186776+zhangsanxueai@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Flood Sung <floodsung@gmail.com>
Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: uestney <uestney@gmail.com>
Co-authored-by: uestney <uestney@users.noreply.github.com>
SimonYeyi pushed a commit to SimonYeyi/metabot that referenced this pull request May 26, 2026
…loses xvirobotics#234) (xvirobotics#245)

* feat(installer): allow custom install directory via --dir / -Dir flag

install.sh and install.ps1 previously hardcoded the install path to
$HOME/metabot. Add a CLI flag (and matching PowerShell parameter) plus
an interactive prompt so users can install MetaBot anywhere.

- Priority: --dir / -Dir > METABOT_HOME env var > prompt > default.
- Tilde expansion + absolute-path validation; refuses to clobber
  $HOME / system roots.
- Persists METABOT_HOME to ~/.bashrc / ~/.zshrc (Linux/macOS) or
  user-level env (Windows) when non-default, so the mm/mb/metabot
  CLIs can locate the install in new shells.

* fix(codex): show model metadata in cards

* fix(codex): mirror skills and avoid bwrap sandbox

* fix(codex): tolerate agents deployment failures

* fix(codex): install bundled skills when user cache is empty

* docs: explain Codex skill migration

* fix(ecosystem): use 'node --import tsx' for cross-platform spawn

Closes xvirobotics#234.

The previous interpreter pointed at node_modules/.bin/tsx, which is a
POSIX shell wrapper on Windows with no .cmd shim. PM2 spawns the
interpreter via child_process.spawn, which cannot exec a sh script
directly on Windows (EINVAL) — the process appeared to start but died
at exec time, leaving 'pm2 list' showing online with pid: N/A.

Switching to 'node --import tsx' is tsx 4.x's documented cross-platform
entrypoint and behaves identically on Linux, macOS, and Windows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Flood Sung <floodsung@xvirobotics.ai>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

Proposal: switch ecosystem.config.cjs interpreter to "node --import tsx" for cross-platform spawn correctness

1 participant