chore: replace all node/npm/tsx references with bun across codebase

- Source: setup/service.ts, runners.ts, agent-runner.ts error messages
- Scripts: restart-stack.sh, run-migrations.ts → bun
- Bootstrap: setup.sh check_node→check_bun, npm install→bun install
- Docs: CLAUDE.md, README.md, all SKILL.md files
- Tests: service.test.ts, restart-stack.test.ts expectations updated
This commit is contained in:
Eyejoker
2026-03-31 00:10:23 +09:00
parent 0112f5a2d6
commit 35ba7cb5ba
23 changed files with 102 additions and 135 deletions

View File

@@ -31,10 +31,10 @@ description: Verify or port the existing /compact session command in current EJC
## 검증
```bash
npm run typecheck
npm test
npm run build:runners
npm run build
bun run typecheck
bun test
bun run build:runners
bun run build
```
그 다음 디스코드에서 확인합니다.

View File

@@ -13,7 +13,7 @@ description: Finish Discord bot setup and registration for EJClaw.
- `src/channels/discord.ts`가 존재하는지
- `package.json``discord.js`가 있는지
- `npm run typecheck`가 통과하는지
- `bun run typecheck`가 통과하는지
## 2. 봇 토큰 준비
@@ -47,7 +47,7 @@ DISCORD_CODEX_BOT_TOKEN=<second-token>
메인 채널:
```bash
npm run setup -- --step register -- \
bun run setup -- --step register -- \
--jid dc:<channel-id> \
--name "<server-name> #<channel-name>" \
--folder discord_main \
@@ -59,7 +59,7 @@ npm run setup -- --step register -- \
보조 채널:
```bash
npm run setup -- --step register -- \
bun run setup -- --step register -- \
--jid dc:<channel-id> \
--name "<server-name> #<channel-name>" \
--folder discord_<channel-name> \
@@ -69,10 +69,10 @@ npm run setup -- --step register -- \
## 5. 빌드와 검증
```bash
npm run build
npm run build:runners
npm run setup -- --step service
npm run setup -- --step verify
bun run build
bun run build:runners
bun run setup -- --step service
bun run setup -- --step verify
```
필요하면 로그 확인:

View File

@@ -61,9 +61,9 @@ ollama pull llama3.2
## 4. 빌드와 검증
```bash
npm run build:runners
npm run build
npm run setup -- --step service
bun run build:runners
bun run build
bun run setup -- --step service
```
디스코드에서 테스트:

View File

@@ -48,9 +48,9 @@ PARALLEL_API_KEY=...
## 5. 빌드와 검증
```bash
npm run build:runners
npm run build
npm run setup -- --step service
bun run build:runners
bun run build
bun run setup -- --step service
```
디스코드 테스트 예시:

View File

@@ -23,8 +23,8 @@ Groq를 쓰면 `whisper-large-v3-turbo`, OpenAI를 쓰면 `whisper-1` 경로를
## 2. 재시작
```bash
npm run build
npm run setup -- --step service
bun run build
bun run setup -- --step service
```
이미 서비스가 떠 있다면 플랫폼에 맞게 재시작만 해도 됩니다.
@@ -57,4 +57,4 @@ tail -f logs/ejclaw.log | grep -iE 'transcri|audio'
**채널에서는 보이는데 에이전트가 못 읽음**
- 채널 등록과 서비스 상태를 먼저 확인합니다.
- `npm run setup -- --step verify` 결과에서 `REGISTERED_GROUPS``SERVICE`를 같이 봅니다.
- `bun run setup -- --step verify` 결과에서 `REGISTERED_GROUPS``SERVICE`를 같이 봅니다.

View File

@@ -58,13 +58,13 @@ description: Customize Discord-only EJClaw behavior, routing, integrations, prom
작게 바꿨으면 최소 이 정도는 확인합니다.
```bash
npm run typecheck
npm test
bun run typecheck
bun test
```
러너나 실행 경로를 건드렸으면 추가로 확인합니다.
```bash
npm run build:runners
npm run setup -- --step verify
bun run build:runners
bun run setup -- --step verify
```

View File

@@ -11,12 +11,12 @@ description: Debug EJClaw runtime issues on the current Discord-only, host-proce
1. 타입과 테스트부터 확인
```bash
npm run typecheck
npm test
bun run typecheck
bun test
```
2. 서비스 상태 확인
```bash
npm run setup -- --step verify
bun run setup -- --step verify
```
3. 런타임 로그 확인
```bash
@@ -26,7 +26,7 @@ description: Debug EJClaw runtime issues on the current Discord-only, host-proce
```
4. 러너 빌드 확인
```bash
npm run build:runners
bun run build:runners
```
## 핵심 파일
@@ -46,7 +46,7 @@ description: Debug EJClaw runtime issues on the current Discord-only, host-proce
```bash
grep -n '^DISCORD_BOT_TOKEN=' .env
npm run setup -- --step verify
bun run setup -- --step verify
```
- `DISCORD_BOT_TOKEN`이 없으면 채널이 안 붙습니다.

View File

@@ -5,7 +5,7 @@ description: Run initial EJClaw setup for the dual-service Discord architecture.
# EJClaw Setup
설치는 `bash setup.sh`로 부트스트랩하고, 나머지는 `npm run setup -- --step <name>`으로 진행합니다. 현재 기준 채널은 디스코드만 지원합니다.
설치는 `bash setup.sh`로 부트스트랩하고, 나머지는 `bun run setup -- --step <name>`으로 진행합니다. 현재 기준 채널은 디스코드만 지원합니다.
EJClaw는 두 개의 서비스로 구성됩니다:
- **ejclaw** — Claude Code 봇 (`@claude`)
@@ -23,7 +23,7 @@ bash setup.sh
## 2. 현재 상태 확인
```bash
npm run setup -- --step environment
bun run setup -- --step environment
```
여기서 확인할 것:
@@ -83,7 +83,7 @@ SESSION_COMMAND_ALLOWED_SENDERS=... # 세션 명령 허용 유저 ID (쉼표
## 4. 러너 빌드
```bash
npm run setup -- --step runners
bun run setup -- --step runners
```
이 단계는 아래 두 러너를 빌드합니다.
@@ -91,7 +91,7 @@ npm run setup -- --step runners
- `runners/agent-runner` (Claude Code)
- `runners/codex-runner` (Codex)
실패하면 보통 `npm run build:runners` 출력과 각 러너의 `package.json` 의존성을 같이 보면 됩니다.
실패하면 보통 `bun run build:runners` 출력과 각 러너의 `package.json` 의존성을 같이 보면 됩니다.
## 5. 디스코드 채널 등록
@@ -102,7 +102,7 @@ npm run setup -- --step runners
Claude 봇 채널 등록:
```bash
npm run setup -- --step register -- \
bun run setup -- --step register -- \
--jid dc:123456789012345678 \
--name "My Server #general" \
--folder discord_main \
@@ -114,7 +114,7 @@ npm run setup -- --step register -- \
Codex 봇도 같은 채널을 쓴다면 별도로 등록합니다:
```bash
ASSISTANT_NAME=codex npm run setup -- --step register -- \
ASSISTANT_NAME=codex bun run setup -- --step register -- \
--jid dc:123456789012345678 \
--name "My Server #general" \
--folder discord_main \
@@ -126,7 +126,7 @@ ASSISTANT_NAME=codex npm run setup -- --step register -- \
보조 채널 예시:
```bash
npm run setup -- --step register -- \
bun run setup -- --step register -- \
--jid dc:123456789012345678 \
--name "My Server #ops" \
--folder discord_ops \
@@ -136,7 +136,7 @@ npm run setup -- --step register -- \
## 6. 서비스 시작
```bash
npm run setup -- --step service
bun run setup -- --step service
```
이 명령은:
@@ -163,7 +163,7 @@ journalctl --user -u ejclaw-codex -f
## 7. 최종 검증
```bash
npm run setup -- --step verify
bun run setup -- --step verify
```
성공 기준:
@@ -176,7 +176,7 @@ npm run setup -- --step verify
## 빠른 문제 해결
- 빌드 문제: `npm run typecheck`, `npm test`, `npm run build:runners`
- 빌드 문제: `bun run typecheck`, `bun test`, `bun run build:runners`
- Claude 서비스 문제: `logs/ejclaw.error.log` 또는 `journalctl --user -u ejclaw -f`
- Codex 서비스 문제: `logs/ejclaw-codex.error.log` 또는 `journalctl --user -u ejclaw-codex -f`
- 디스코드 연결 문제: `.env``DISCORD_BOT_TOKEN`과 등록된 `dc:*` JID 확인

View File

@@ -110,8 +110,8 @@ If a merge fails badly (e.g., cannot resolve conflicts):
# Step 4: Validation
After all selected skills are merged:
- `npm run build`
- `npm test` (do not fail the flow if tests are not configured)
- `bun run build`
- `bun test` (do not fail the flow if tests are not configured)
If build fails:
- Show the error.

View File

@@ -38,9 +38,9 @@ Single unified service (`ejclaw`) manages three Discord bots (Claude, Codex-main
Run commands directly—don't tell the user to run them.
```bash
npm run build # Build main project
npm run build:runners # Install + build both runners
npm run dev # Dev mode with hot reload
bun run build # Build main project
bun run build:runners # Install + build both runners
bun run dev # Dev mode with hot reload
```
Service management (Linux):
@@ -52,7 +52,7 @@ journalctl --user -u ejclaw -f # Follow logs
Deploy to server (build on server, not locally):
```bash
ssh clone-ej@100.64.185.108 'cd ~/EJClaw && git pull && npm run build && npm run build:runners && systemctl --user restart ejclaw'
ssh clone-ej@100.64.185.108 'cd ~/EJClaw && git pull && bun run build && bun run build:runners && systemctl --user restart ejclaw'
```
## Service Stack Architecture

View File

@@ -100,9 +100,9 @@ Reviewer (persistent Docker container):
```bash
git clone https://github.com/phj1081/EJClaw.git
cd EJClaw
npm install
npm run build:runners
npm run build
bun install
bun run build:runners
bun run build
```
### Environment
@@ -152,16 +152,16 @@ journalctl --user -u ejclaw -f # Follow logs
Build on server, not locally:
```bash
ssh clone-ej@100.64.185.108 'cd ~/EJClaw && git pull && npm run build && npm run build:runners && systemctl --user restart ejclaw'
ssh clone-ej@100.64.185.108 'cd ~/EJClaw && git pull && bun run build && bun run build:runners && systemctl --user restart ejclaw'
```
## Development
```bash
npm run build # Build main project
npm run build:runners # Install + build both runners
npm run dev # Dev mode with hot reload
npm test # Run tests
bun run build # Build main project
bun run build:runners # Install + build both runners
bun run dev # Dev mode with hot reload
bun test # Run tests
```
## License

View File

@@ -5,4 +5,4 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
cd "${PROJECT_ROOT}"
npx tsx setup/restart-stack.ts "$@"
bun setup/restart-stack.ts "$@"

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env tsx
#!/usr/bin/env bun
import { execFileSync, execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
@@ -13,20 +13,16 @@ function compareSemver(a: string, b: string): number {
return 0;
}
// Resolve tsx binary once to avoid npx race conditions across migrations
function resolveTsx(): string {
// Check local node_modules first
const local = path.resolve('node_modules/.bin/tsx');
if (fs.existsSync(local)) return local;
// Fall back to whichever tsx is in PATH
// Resolve bun binary once
function resolveBun(): string {
try {
return execSync('which tsx', { encoding: 'utf-8' }).trim();
return execSync('which bun', { encoding: 'utf-8' }).trim();
} catch {
return 'npx'; // last resort
return 'bun'; // last resort
}
}
const tsxBin = resolveTsx();
const bunBin = resolveBun();
const fromVersion = process.argv[2];
const toVersion = process.argv[3];
@@ -34,7 +30,7 @@ const newCorePath = process.argv[4];
if (!fromVersion || !toVersion || !newCorePath) {
console.error(
'Usage: tsx scripts/run-migrations.ts <from-version> <to-version> <new-core-path>',
'Usage: bun scripts/run-migrations.ts <from-version> <to-version> <new-core-path>',
);
process.exit(1);
}
@@ -80,10 +76,7 @@ for (const version of migrationVersions) {
}
try {
const tsxArgs = tsxBin.endsWith('npx')
? ['tsx', migrationIndex, projectRoot]
: [migrationIndex, projectRoot];
execFileSync(tsxBin, tsxArgs, {
execFileSync(bunBin, [migrationIndex, projectRoot], {
stdio: 'pipe',
cwd: projectRoot,
timeout: 120_000,

View File

@@ -2,7 +2,7 @@
set -euo pipefail
# setup.sh — Bootstrap script for EJClaw
# Handles Node.js/npm setup, then hands off to the Node.js setup modules.
# Handles Bun runtime setup, then hands off to the setup modules.
# This is the only bash script in the setup flow.
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -38,64 +38,43 @@ detect_platform() {
log "Platform: $PLATFORM, WSL: $IS_WSL, Root: $IS_ROOT"
}
# --- Node.js check ---
# --- Bun check ---
check_node() {
NODE_OK="false"
NODE_VERSION="not_found"
NODE_PATH_FOUND=""
check_bun() {
BUN_OK="false"
BUN_VERSION="not_found"
BUN_PATH_FOUND=""
if command -v node >/dev/null 2>&1; then
NODE_VERSION=$(node --version 2>/dev/null | sed 's/^v//')
NODE_PATH_FOUND=$(command -v node)
local major
major=$(echo "$NODE_VERSION" | cut -d. -f1)
if [ "$major" -ge 20 ] 2>/dev/null; then
NODE_OK="true"
fi
log "Node $NODE_VERSION at $NODE_PATH_FOUND (major=$major, ok=$NODE_OK)"
if command -v bun >/dev/null 2>&1; then
BUN_VERSION=$(bun --version 2>/dev/null)
BUN_PATH_FOUND=$(command -v bun)
BUN_OK="true"
log "Bun $BUN_VERSION at $BUN_PATH_FOUND (ok=$BUN_OK)"
else
log "Node not found"
log "Bun not found"
fi
}
# --- npm install ---
# --- bun install ---
install_deps() {
DEPS_OK="false"
NATIVE_OK="false"
if [ "$NODE_OK" = "false" ]; then
log "Skipping npm install — Node not available"
if [ "$BUN_OK" = "false" ]; then
log "Skipping bun install — Bun not available"
return
fi
cd "$PROJECT_ROOT"
# npm install with --unsafe-perm if root (needed for native modules)
local npm_flags=""
if [ "$IS_ROOT" = "true" ]; then
npm_flags="--unsafe-perm"
log "Running as root, using --unsafe-perm"
fi
log "Running npm install $npm_flags"
if npm install $npm_flags >> "$LOG_FILE" 2>&1; then
log "Running bun install"
if bun install >> "$LOG_FILE" 2>&1; then
DEPS_OK="true"
log "npm install succeeded"
log "bun install succeeded"
else
log "npm install failed"
log "bun install failed"
return
fi
# Verify native module (better-sqlite3)
log "Verifying native modules"
if node -e "require('better-sqlite3')" >> "$LOG_FILE" 2>&1; then
NATIVE_OK="true"
log "better-sqlite3 loads OK"
else
log "better-sqlite3 failed to load"
fi
}
# --- Build tools check ---
@@ -121,18 +100,16 @@ check_build_tools() {
log "=== Bootstrap started ==="
detect_platform
check_node
check_bun
install_deps
check_build_tools
# Emit status block
STATUS="success"
if [ "$NODE_OK" = "false" ]; then
STATUS="node_missing"
if [ "$BUN_OK" = "false" ]; then
STATUS="bun_missing"
elif [ "$DEPS_OK" = "false" ]; then
STATUS="deps_failed"
elif [ "$NATIVE_OK" = "false" ]; then
STATUS="native_failed"
fi
cat <<EOF
@@ -140,11 +117,10 @@ cat <<EOF
PLATFORM: $PLATFORM
IS_WSL: $IS_WSL
IS_ROOT: $IS_ROOT
NODE_VERSION: $NODE_VERSION
NODE_OK: $NODE_OK
NODE_PATH: ${NODE_PATH_FOUND:-not_found}
BUN_VERSION: $BUN_VERSION
BUN_OK: $BUN_OK
BUN_PATH: ${BUN_PATH_FOUND:-not_found}
DEPS_OK: $DEPS_OK
NATIVE_OK: $NATIVE_OK
HAS_BUILD_TOOLS: $HAS_BUILD_TOOLS
STATUS: $STATUS
LOG: logs/setup.log
@@ -153,9 +129,9 @@ EOF
log "=== Bootstrap completed: $STATUS ==="
if [ "$NODE_OK" = "false" ]; then
if [ "$BUN_OK" = "false" ]; then
exit 2
fi
if [ "$DEPS_OK" = "false" ] || [ "$NATIVE_OK" = "false" ]; then
if [ "$DEPS_OK" = "false" ]; then
exit 1
fi

View File

@@ -1,6 +1,6 @@
/**
* Setup CLI entry point.
* Usage: npx tsx setup/index.ts --step <name> [args...]
* Usage: bun setup/index.ts --step <name> [args...]
*/
import { logger } from '../src/logger.js';
import { emitStatus } from './status.js';
@@ -23,7 +23,7 @@ async function main(): Promise<void> {
if (stepIdx === -1 || !args[stepIdx + 1]) {
console.error(
`Usage: npx tsx setup/index.ts --step <${Object.keys(STEPS).join('|')}> [args...]`,
`Usage: bun setup/index.ts --step <${Object.keys(STEPS).join('|')}> [args...]`,
);
process.exit(1);
}

View File

@@ -155,7 +155,7 @@ describe('restartStackServices', () => {
serviceManager: 'systemd',
serviceId: 'codex-main',
}),
).toThrow('Run `npm run setup -- --step service`');
).toThrow('Run `bun run setup -- --step service`');
});
it('does not hide a general start failure behind direct fallback', () => {

View File

@@ -9,7 +9,7 @@ export const STACK_RESTART_UNIT_NAME = 'ejclaw-stack-restart.service';
const UNIT_NOT_FOUND_PATTERN =
/(Unit .* not found|Could not find the requested service|not-found)/i;
const MANAGED_SERVICE_CALLER_FALLBACK_MESSAGE =
'Stack restart unit is not installed yet. Run `npm run setup -- --step service` from an external shell before retrying from a managed EJClaw service.';
'Stack restart unit is not installed yet. Run `bun run setup -- --step service` from an external shell before retrying from a managed EJClaw service.';
interface RestartStackDeps {
execFileSyncImpl?: typeof execFileSync;

View File

@@ -15,7 +15,7 @@ export async function run(_args: string[]): Promise<void> {
let buildOk = false;
logger.info('Building agent runners');
try {
execSync('npm run build:runners', {
execSync('bun run build:runners', {
cwd: projectRoot,
stdio: ['ignore', 'pipe', 'pipe'],
});

View File

@@ -149,13 +149,13 @@ describe('systemd unit generation', () => {
it('sets correct ExecStart', () => {
const unit = generateSystemdUnit(
'/usr/bin/node',
'/usr/bin/bun',
'/srv/ejclaw',
'/home/user',
false,
);
expect(unit).toContain(
'ExecStart=/usr/bin/node /srv/ejclaw/dist/index.js',
'ExecStart=/usr/bin/bun /srv/ejclaw/dist/index.js',
);
});
});
@@ -207,7 +207,7 @@ describe('service definitions', () => {
it('generates a oneshot stack restart unit', () => {
const unit = buildStackRestartSystemdUnit(
'/srv/ejclaw',
'/usr/bin/node',
'/usr/bin/bun',
'/home/user',
);

View File

@@ -38,7 +38,7 @@ export async function run(_args: string[]): Promise<void> {
// Build first
logger.info('Building TypeScript');
try {
execSync('npm run build', {
execSync('bun run build', {
cwd: projectRoot,
stdio: ['ignore', 'pipe', 'pipe'],
});

View File

@@ -152,12 +152,12 @@ export async function runAgentProcess(
if (!fs.existsSync(distEntry)) {
logger.error(
{ runnerDir, chatJid: input.chatJid, runId: input.runId },
'Runner not built. Run: cd runners/agent-runner && npm install && npm run build',
'Runner not built. Run: cd runners/agent-runner && bun install && bun run build',
);
return {
status: 'error',
result: null,
error: `Runner not built at ${distEntry}. Run npm run build:runners first.`,
error: `Runner not built at ${distEntry}. Run bun run build:runners first.`,
};
}

View File

@@ -2271,9 +2271,7 @@ export function claimServiceHandoff(id: number): boolean {
WHERE id = ?
AND status = 'pending'`,
).run(id);
return (
(db.prepare('SELECT changes() as c').get() as { c: number }).c > 0
);
return (db.prepare('SELECT changes() as c').get() as { c: number }).c > 0;
}
export function completeServiceHandoff(id: number): void {

View File

@@ -5,7 +5,7 @@ function printUsageAndExit(): never {
console.error(
[
'Usage:',
' tsx src/restart-context-cli.ts write --chat-jid <jid> --summary <text> [--verify <text> ...] [--service-id <id> ...]',
' bun src/restart-context-cli.ts write --chat-jid <jid> --summary <text> [--verify <text> ...] [--service-id <id> ...]',
].join('\n'),
);
process.exit(1);