diff --git a/.claude/skills/update-nanoclaw/SKILL.md b/.claude/skills/update-ejclaw/SKILL.md similarity index 81% rename from .claude/skills/update-nanoclaw/SKILL.md rename to .claude/skills/update-ejclaw/SKILL.md index e7e36cf..9c6903c 100644 --- a/.claude/skills/update-nanoclaw/SKILL.md +++ b/.claude/skills/update-ejclaw/SKILL.md @@ -1,11 +1,11 @@ --- -name: update-nanoclaw -description: Safely merge upstream NanoClaw changes into a customized install with minimal drift. +name: update-ejclaw +description: Safely merge upstream EJClaw changes into a customized install with minimal drift. --- -# Update NanoClaw +# Update EJClaw -커스텀된 NanoClaw에 upstream 변경을 가져올 때 쓰는 절차입니다. 현재 기준 중요 경로는 `src/`, `runners/`, `setup/`, `.claude/skills/`, `groups/`, `README.md` 입니다. +커스텀된 EJClaw에 upstream 변경을 가져올 때 쓰는 절차입니다. 현재 기준 중요 경로는 `src/`, `runners/`, `setup/`, `.claude/skills/`, `groups/`, `README.md` 입니다. ## 원칙 @@ -76,16 +76,16 @@ git cherry-pick ## 6. 검증 ```bash -npm run typecheck -npm test -npm run build:runners -npm run build +pnpm typecheck +pnpm test +pnpm build:runners +pnpm build ``` 런타임 경로가 바뀌었으면 추가로 확인합니다. ```bash -npm run setup -- --step verify +pnpm setup -- --step verify ``` ## 7. 요약 diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb6496..974a034 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -All notable changes to NanoClaw will be documented in this file. +All notable changes to EJClaw will be documented in this file. -## [1.2.0](https://github.com/qwibitai/nanoclaw/compare/v1.1.6...v1.2.0) +## [1.2.0](https://github.com/phj1081/EJClaw/compare/v1.1.6...v1.2.0) [BREAKING] WhatsApp removed from core, now a skill. Run `/add-whatsapp` to re-add (existing auth/groups preserved). - **fix:** Prevent scheduled tasks from executing twice when container runtime exceeds poll interval (#138, #669) diff --git a/CLAUDE.md b/CLAUDE.md index a872827..46e8202 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,10 +1,10 @@ -# NanoClaw +# EJClaw -Dual-agent AI assistant (Claude Code + Codex) over Discord. Based on [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw). +Dual-agent AI assistant (Claude Code + Codex) over Discord. Originally derived from [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw). ## Quick Context -Two systemd services (`nanoclaw`, `nanoclaw-codex`) share the same codebase but run with separate stores, data, and groups (will be unified — DB supports shared access via WAL mode + service partitioning). Agents run as direct host processes (no containers). Claude Code uses the Agent SDK; Codex uses the Codex SDK (`codex exec`). Auth via `CLAUDE_CODE_OAUTH_TOKEN` in `.env` (1-year token from `claude setup-token`). +Two systemd services (`ejclaw`, `ejclaw-codex`) share the same codebase but run with separate stores, data, and groups (will be unified — DB supports shared access via WAL mode + service partitioning). Agents run as direct host processes (no containers). Claude Code uses the Agent SDK; Codex uses the Codex SDK (`codex exec`). Auth via `CLAUDE_CODE_OAUTH_TOKEN` in `.env` (1-year token from `claude setup-token`). ## Key Files @@ -29,7 +29,7 @@ Two systemd services (`nanoclaw`, `nanoclaw-codex`) share the same codebase but | `/setup` | First-time installation, authentication, service configuration | | `/customize` | Adding channels, integrations, changing behavior | | `/debug` | Agent issues, logs, troubleshooting | -| `/update-nanoclaw` | Bring upstream NanoClaw updates into a customized install | +| `/update-ejclaw` | Bring upstream EJClaw updates into a customized install | | `/qodo-pr-resolver` | Fetch and fix Qodo PR review issues interactively or in batch | | `/get-qodo-rules` | Load org- and repo-level coding rules from Qodo before code tasks | @@ -45,17 +45,17 @@ npm run dev # Dev mode with hot reload Service management (Linux): ```bash -systemctl --user restart nanoclaw nanoclaw-codex # Restart both -systemctl --user status nanoclaw # Check status -journalctl --user -u nanoclaw -f # Follow logs +systemctl --user restart ejclaw ejclaw-codex # Restart both +systemctl --user status ejclaw # Check status +journalctl --user -u ejclaw -f # Follow logs ``` -Deploy to server: `scp dist/*.js clone-ej@100.64.185.108:~/nanoclaw/dist/` +Deploy to server: `scp dist/*.js clone-ej@100.64.185.108:~/EJClaw/dist/` ## Dual-Service Architecture -- `nanoclaw.service` — Claude Code bot (`@claude`), `SERVICE_ID=claude`, `SERVICE_AGENT_TYPE=claude-code` -- `nanoclaw-codex.service` — Codex bot (`@codex`), `SERVICE_ID=codex`, `SERVICE_AGENT_TYPE=codex` +- `ejclaw.service` — Claude Code bot (`@claude`), `SERVICE_ID=claude`, `SERVICE_AGENT_TYPE=claude-code` +- `ejclaw-codex.service` — Codex bot (`@codex`), `SERVICE_ID=codex`, `SERVICE_AGENT_TYPE=codex` - Both share the same codebase (`dist/index.js`), differentiated by env vars - Unified dirs (`store/`, `groups/`, `data/` shared by both services): - `router_state`: keys prefixed with `{SERVICE_ID}:` (e.g., `claude:last_timestamp`) @@ -70,8 +70,8 @@ Unified DB + directories (both services share `store/`, `groups/`, `data/`): | 항목 | 경로 | |------|------| | **DB** | `store/messages.db` (공유, WAL 모드) | -| 서비스 로그 (Claude) | `journalctl --user -u nanoclaw -f` 또는 `logs/nanoclaw.log` | -| 서비스 로그 (Codex) | `journalctl --user -u nanoclaw-codex -f` 또는 `logs/nanoclaw-codex.log` | +| 서비스 로그 (Claude) | `journalctl --user -u ejclaw -f` 또는 `logs/ejclaw.log` | +| 서비스 로그 (Codex) | `journalctl --user -u ejclaw-codex -f` 또는 `logs/ejclaw-codex.log` | | 그룹별 로그 | `groups/{name}/logs/` (공유 채널은 양쪽 봇 로그가 같은 폴더) | | Claude 세션 | `data/sessions/{name}/.claude/` | | Codex 세션 | `data/sessions/{name}/.codex/` | diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1d4a5de..3ad7f3f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,6 +1,6 @@ # Contributors -Thanks to everyone who has contributed to NanoClaw! +Thanks to everyone who has contributed to EJClaw! - [Alakazam03](https://github.com/Alakazam03) — Vaibhav Aggarwal - [tydev-new](https://github.com/tydev-new) diff --git a/README.md b/README.md index bcccc27..61a6aa8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Dual-agent AI assistant (Claude Code + Codex) over Discord. -Forked from [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw), heavily customized for production use. +Originally derived from [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw), now maintained as EJClaw for personal production use. ## Overview @@ -77,12 +77,12 @@ GROQ_API_KEY= # Voice transcription (Groq Whisper) ### Systemd Services (Linux) ```bash -systemctl --user enable nanoclaw nanoclaw-codex -systemctl --user start nanoclaw nanoclaw-codex +systemctl --user enable ejclaw ejclaw-codex +systemctl --user start ejclaw ejclaw-codex # Logs -journalctl --user -u nanoclaw -f -journalctl --user -u nanoclaw-codex -f +journalctl --user -u ejclaw -f +journalctl --user -u ejclaw-codex -f ``` ## Development @@ -96,4 +96,4 @@ npm test # Run tests ## License -MIT — Based on [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw) +MIT — Originally derived from [qwibitai/nanoclaw](https://github.com/qwibitai/nanoclaw) diff --git a/README_zh.md b/README_zh.md deleted file mode 100644 index 273d6f9..0000000 --- a/README_zh.md +++ /dev/null @@ -1,200 +0,0 @@ -

- NanoClaw -

- -

- NanoClaw —— 您的专属 Claude 助手,在容器中安全运行。它轻巧易懂,并能根据您的个人需求灵活定制。 -

- -

- nanoclaw.dev  •   - English  •   - Discord  •   - 34.9k tokens, 17% of context window -

-通过 Claude Code,NanoClaw 可以动态重写自身代码,根据您的需求定制功能。 - -**新功能:** 首个支持 [Agent Swarms(智能体集群)](https://code.claude.com/docs/en/agent-teams) 的 AI 助手。可轻松组建智能体团队,在您的聊天中高效协作。 - -## 我为什么创建这个项目 - -[上游项目](https://github.com/openclaw/openclaw) 是一个令人印象深刻的项目,但我无法安心使用一个我不了解却能访问我个人隐私的软件。该上游项目有近 50 万行代码、53 个配置文件和 70+ 个依赖项。其安全性是应用级别的(通过白名单、配对码实现),而非操作系统级别的隔离。所有东西都在一个共享内存的 Node 进程中运行。 - -NanoClaw 用一个您能快速理解的代码库,为您提供了同样的核心功能。只有一个进程,少数几个文件。智能体(Agent)运行在具有文件系统隔离的真实 Linux 容器中,而不是依赖于权限检查。 - -## 快速开始 - -```bash -git clone https://github.com/qwibitai/nanoclaw.git -cd nanoclaw -claude -``` - -然后运行 `/setup`。Claude Code 会处理一切:依赖安装、身份验证、容器设置、服务配置。 - -> **注意:** 以 `/` 开头的命令(如 `/setup`、`/add-whatsapp`)是 [Claude Code 技能](https://code.claude.com/docs/en/skills)。请在 `claude` CLI 提示符中输入,而非在普通终端中。 - -## 设计哲学 - -**小巧易懂:** 单一进程,少量源文件。无微服务、无消息队列、无复杂抽象层。让 Claude Code 引导您轻松上手。 - -**通过隔离保障安全:** 智能体运行在 Linux 容器(在 macOS 上是 Apple Container,或 Docker)中。它们只能看到被明确挂载的内容。即便通过 Bash 访问也十分安全,因为所有命令都在容器内执行,不会直接操作您的宿主机。 - -**为单一用户打造:** 这不是一个框架,是一个完全符合您个人需求的、可工作的软件。您可以 Fork 本项目,然后让 Claude Code 根据您的精确需求进行修改和适配。 - -**定制即代码修改:** 没有繁杂的配置文件。想要不同的行为?直接修改代码。代码库足够小,这样做是安全的。 - -**AI 原生:** 无安装向导(由 Claude Code 指导安装)。无需监控仪表盘,直接询问 Claude 即可了解系统状况。无调试工具(描述问题,Claude 会修复它)。 - -**技能(Skills)优于功能(Features):** 贡献者不应该向代码库添加新功能(例如支持 Telegram)。相反,他们应该贡献像 `/add-telegram` 这样的 [Claude Code 技能](https://code.claude.com/docs/en/skills),这些技能可以改造您的 fork。最终,您得到的是只做您需要事情的整洁代码。 - -**最好的工具套件,最好的模型:** 本项目运行在 Claude Agent SDK 之上,这意味着您直接运行的就是 Claude Code。Claude Code 高度强大,其编码和问题解决能力使其能够修改和扩展 NanoClaw,为每个用户量身定制。 - -## 功能支持 - -- **多渠道消息** - 通过 WhatsApp、Telegram、Discord、Slack 或 Gmail 与您的助手对话。使用 `/add-whatsapp` 或 `/add-telegram` 等技能添加渠道,可同时运行一个或多个。 -- **隔离的群组上下文** - 每个群组都拥有独立的 `CLAUDE.md` 记忆和隔离的文件系统。它们在各自的容器沙箱中运行,且仅挂载所需的文件系统。 -- **主频道** - 您的私有频道(self-chat),用于管理控制;其他所有群组都完全隔离 -- **计划任务** - 运行 Claude 的周期性作业,并可以给您回发消息 -- **网络访问** - 搜索和抓取网页内容 -- **容器隔离** - 智能体在 Apple Container (macOS) 或 Docker (macOS/Linux) 的沙箱中运行 -- **智能体集群(Agent Swarms)** - 启动多个专业智能体团队,协作完成复杂任务(首个支持此功能的个人 AI 助手) -- **可选集成** - 通过技能添加 Gmail (`/add-gmail`) 等更多功能 - -## 使用方法 - -使用触发词(默认为 `@Andy`)与您的助手对话: - -``` -@Andy 每周一到周五早上9点,给我发一份销售渠道的概览(需要访问我的 Obsidian vault 文件夹) -@Andy 每周五回顾过去一周的 git 历史,如果与 README 有出入,就更新它 -@Andy 每周一早上8点,从 Hacker News 和 TechCrunch 收集关于 AI 发展的资讯,然后发给我一份简报 -``` - -在主频道(您的self-chat)中,可以管理群组和任务: -``` -@Andy 列出所有群组的计划任务 -@Andy 暂停周一简报任务 -@Andy 加入"家庭聊天"群组 -``` - -## 定制 - -没有需要学习的配置文件。直接告诉 Claude Code 您想要什么: - -- "把触发词改成 @Bob" -- "记住以后回答要更简短直接" -- "当我说早上好的时候,加一个自定义的问候" -- "每周存储一次对话摘要" - -或者运行 `/customize` 进行引导式修改。 - -代码库足够小,Claude 可以安全地修改它。 - -## 贡献 - -**不要添加功能,而是添加技能。** - -如果您想添加 Telegram 支持,不要创建一个 PR 同时添加 Telegram 和 WhatsApp。而是贡献一个技能文件 (`.claude/skills/add-telegram/SKILL.md`),教 Claude Code 如何改造一个 NanoClaw 安装以使用 Telegram。 - -然后用户在自己的 fork 上运行 `/add-telegram`,就能得到只做他们需要事情的整洁代码,而不是一个试图支持所有用例的臃肿系统。 - -### RFS (技能征集) - -我们希望看到的技能: - -**通信渠道** -- `/add-signal` - 添加 Signal 作为渠道 - -**会话管理** -- `/clear` - 添加一个 `/clear` 命令,用于压缩会话(在同一会话中总结上下文,同时保留关键信息)。这需要研究如何通过 Claude Agent SDK 以编程方式触发压缩。 - -## 系统要求 - -- macOS 或 Linux -- Node.js 20+ -- [Claude Code](https://claude.ai/download) -- [Apple Container](https://github.com/apple/container) (macOS) 或 [Docker](https://docker.com/products/docker-desktop) (macOS/Linux) - -## 架构 - -``` -渠道 --> SQLite --> 轮询循环 --> 容器 (Claude Agent SDK) --> 响应 -``` - -单一 Node.js 进程。渠道通过技能添加,启动时自注册 — 编排器连接具有凭据的渠道。智能体在具有文件系统隔离的 Linux 容器中执行。每个群组的消息队列带有并发控制。通过文件系统进行 IPC。 - -完整架构详情请见 [docs/SPEC.md](docs/SPEC.md)。 - -关键文件: -- `src/index.ts` - 编排器:状态管理、消息循环、智能体调用 -- `src/channels/registry.ts` - 渠道注册表(启动时自注册) -- `src/ipc.ts` - IPC 监听与任务处理 -- `src/router.ts` - 消息格式化与出站路由 -- `src/group-queue.ts` - 带全局并发限制的群组队列 -- `src/container-runner.ts` - 生成流式智能体容器 -- `src/task-scheduler.ts` - 运行计划任务 -- `src/db.ts` - SQLite 操作(消息、群组、会话、状态) -- `groups/*/CLAUDE.md` - 各群组的记忆 - -## FAQ - -**为什么是 Docker?** - -Docker 提供跨平台支持(macOS 和 Linux)和成熟的生态系统。在 macOS 上,您可以选择通过运行 `/convert-to-apple-container` 切换到 Apple Container,以获得更轻量级的原生运行时体验。 - -**我可以在 Linux 上运行吗?** - -可以。Docker 是默认的容器运行时,在 macOS 和 Linux 上都可以使用。只需运行 `/setup`。 - -**这个项目安全吗?** - -智能体在容器中运行,而不是在应用级别的权限检查之后。它们只能访问被明确挂载的目录。您仍然应该审查您运行的代码,但这个代码库小到您真的可以做到。完整的安全模型请见 [docs/SECURITY.md](docs/SECURITY.md)。 - -**为什么没有配置文件?** - -我们不希望配置泛滥。每个用户都应该定制它,让代码完全符合他们的需求,而不是去配置一个通用的系统。如果您喜欢用配置文件,告诉 Claude 让它加上。 - -**我可以使用第三方或开源模型吗?** - -可以。NanoClaw 支持任何 API 兼容的模型端点。在 `.env` 文件中设置以下环境变量: - -```bash -ANTHROPIC_BASE_URL=https://your-api-endpoint.com -ANTHROPIC_AUTH_TOKEN=your-token-here -``` - -这使您能够使用: -- 通过 [Ollama](https://ollama.ai) 配合 API 代理运行的本地模型 -- 托管在 [Together AI](https://together.ai)、[Fireworks](https://fireworks.ai) 等平台上的开源模型 -- 兼容 Anthropic API 格式的自定义模型部署 - -注意:为获得最佳兼容性,模型需支持 Anthropic API 格式。 - -**我该如何调试问题?** - -问 Claude Code。"为什么计划任务没有运行?" "最近的日志里有什么?" "为什么这条消息没有得到回应?" 这就是 AI 原生的方法。 - -**为什么我的安装不成功?** - -如果遇到问题,安装过程中 Claude 会尝试动态修复。如果问题仍然存在,运行 `claude`,然后运行 `/debug`。如果 Claude 发现一个可能影响其他用户的问题,请开一个 PR 来修改 setup SKILL.md。 - -**什么样的代码更改会被接受?** - -安全修复、bug 修复,以及对基础配置的明确改进。仅此而已。 - -其他一切(新功能、操作系统兼容性、硬件支持、增强功能)都应该作为技能来贡献。 - -这使得基础系统保持最小化,并让每个用户可以定制他们的安装,而无需继承他们不想要的功能。 - -## 社区 - -有任何疑问或建议?欢迎[加入 Discord 社区](https://discord.gg/VDdww8qS42)与我们交流。 - -## 更新日志 - -破坏性变更和迁移说明请见 [CHANGELOG.md](CHANGELOG.md)。 - -## 许可证 - -MIT diff --git a/assets/nanoclaw-favicon.png b/assets/ejclaw-favicon.png similarity index 100% rename from assets/nanoclaw-favicon.png rename to assets/ejclaw-favicon.png diff --git a/assets/nanoclaw-icon.png b/assets/ejclaw-icon.png similarity index 100% rename from assets/nanoclaw-icon.png rename to assets/ejclaw-icon.png diff --git a/assets/nanoclaw-logo-dark.png b/assets/ejclaw-logo-dark.png similarity index 100% rename from assets/nanoclaw-logo-dark.png rename to assets/ejclaw-logo-dark.png diff --git a/assets/nanoclaw-logo.png b/assets/ejclaw-logo.png similarity index 100% rename from assets/nanoclaw-logo.png rename to assets/ejclaw-logo.png diff --git a/assets/nanoclaw-profile.jpeg b/assets/ejclaw-profile.jpeg similarity index 100% rename from assets/nanoclaw-profile.jpeg rename to assets/ejclaw-profile.jpeg diff --git a/assets/nanoclaw-sales.png b/assets/ejclaw-sales.png similarity index 100% rename from assets/nanoclaw-sales.png rename to assets/ejclaw-sales.png diff --git a/launchd/com.ejclaw-codex.plist b/launchd/com.ejclaw-codex.plist index 855828e..844107f 100644 --- a/launchd/com.ejclaw-codex.plist +++ b/launchd/com.ejclaw-codex.plist @@ -23,11 +23,11 @@ {{HOME}} ASSISTANT_NAME Andy-Codex - NANOCLAW_STORE_DIR + EJCLAW_STORE_DIR {{PROJECT_ROOT}}/store-codex - NANOCLAW_GROUPS_DIR + EJCLAW_GROUPS_DIR {{PROJECT_ROOT}}/groups-codex - NANOCLAW_DATA_DIR + EJCLAW_DATA_DIR {{PROJECT_ROOT}}/data-codex StandardOutPath diff --git a/package.json b/package.json index 5f83655..04d47b7 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "nanoclaw", + "name": "ejclaw", "version": "1.2.12", "description": "Personal Claude assistant. Lightweight, secure, customizable.", "type": "module", diff --git a/repo-tokens/README.md b/repo-tokens/README.md index bd07f90..2977a71 100644 --- a/repo-tokens/README.md +++ b/repo-tokens/README.md @@ -12,7 +12,7 @@ A GitHub Action that calculates the size of your codebase in terms of tokens and ## Usage ```yaml -- uses: qwibitai/nanoclaw/repo-tokens@v1 +- uses: phj1081/EJClaw/repo-tokens@v1 with: include: 'src/**/*.ts' exclude: 'src/**/*.test.ts' @@ -34,7 +34,7 @@ Repos using repo-tokens: | Repo | Badge | |------|-------| -| [NanoClaw](https://github.com/qwibitai/NanoClaw) | ![tokens](https://raw.githubusercontent.com/qwibitai/NanoClaw/main/repo-tokens/badge.svg) | +| [EJClaw](https://github.com/phj1081/EJClaw) | ![tokens](https://raw.githubusercontent.com/phj1081/EJClaw/main/repo-tokens/badge.svg) | ### Full workflow example @@ -59,7 +59,7 @@ jobs: with: python-version: '3.12' - - uses: qwibitai/nanoclaw/repo-tokens@v1 + - uses: phj1081/EJClaw/repo-tokens@v1 id: tokens with: include: 'src/**/*.ts' diff --git a/repo-tokens/action.yml b/repo-tokens/action.yml index 5443e6e..7ead399 100644 --- a/repo-tokens/action.yml +++ b/repo-tokens/action.yml @@ -114,7 +114,7 @@ runs: with open(readme_path, "r", encoding="utf-8") as f: content = f.read() - repo_tokens_url = "https://github.com/qwibitai/nanoclaw/tree/main/repo-tokens" + repo_tokens_url = "https://github.com/phj1081/EJClaw/tree/main/repo-tokens" linked_badge = f'{badge}' new_content = marker_re.sub(rf"\1{linked_badge}\2", content) @@ -148,7 +148,7 @@ runs: lx = label_w // 2 vx = label_w + value_w // 2 - repo_tokens_url = "https://github.com/qwibitai/nanoclaw/tree/main/repo-tokens" + repo_tokens_url = "https://github.com/phj1081/EJClaw/tree/main/repo-tokens" svg = f''' {full_desc} diff --git a/repo-tokens/badge.svg b/repo-tokens/badge.svg index c3810cb..5b9cf89 100644 --- a/repo-tokens/badge.svg +++ b/repo-tokens/badge.svg @@ -7,7 +7,7 @@ - + @@ -20,4 +20,4 @@ - \ No newline at end of file + diff --git a/runners/agent-runner/package-lock.json b/runners/agent-runner/package-lock.json index 15fc530..1fd7e61 100644 --- a/runners/agent-runner/package-lock.json +++ b/runners/agent-runner/package-lock.json @@ -724,6 +724,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -928,6 +929,7 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.8.tgz", "integrity": "sha512-eVkB/CYCCei7K2WElZW9yYQFWssG0DhaDhVvr7wy5jJ22K+ck8fWW0EsLpB0sITUTvPnc97+rrbQqIr5iqiy9Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=16.9.0" } @@ -1507,6 +1509,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/runners/agent-runner/src/index.ts b/runners/agent-runner/src/index.ts index 71482e0..149977b 100644 --- a/runners/agent-runner/src/index.ts +++ b/runners/agent-runner/src/index.ts @@ -1,10 +1,10 @@ /** - * NanoClaw Agent Runner + * EJClaw Agent Runner * Runs as a child process, receives config via stdin, outputs result to stdout * * Input protocol: * Stdin: Full RunnerInput JSON (read until EOF, like before) - * IPC: Follow-up messages written as JSON files to $NANOCLAW_IPC_DIR/input/ + * IPC: Follow-up messages written as JSON files to $EJCLAW_IPC_DIR/input/ * Files: {type:"message", text:"..."}.json — polled and consumed * Sentinel: /workspace/ipc/input/_close — signals session end * @@ -60,10 +60,10 @@ interface SDKUserMessage { } // Paths configurable via env vars. -const GROUP_DIR = process.env.NANOCLAW_GROUP_DIR || '/workspace/group'; -const IPC_DIR = process.env.NANOCLAW_IPC_DIR || '/workspace/ipc'; +const GROUP_DIR = process.env.EJCLAW_GROUP_DIR || '/workspace/group'; +const IPC_DIR = process.env.EJCLAW_IPC_DIR || '/workspace/ipc'; // Optional: override cwd (agent works in this directory instead of GROUP_DIR) -const WORK_DIR = process.env.NANOCLAW_WORK_DIR || ''; +const WORK_DIR = process.env.EJCLAW_WORK_DIR || ''; const IPC_INPUT_DIR = path.join(IPC_DIR, 'input'); const IPC_INPUT_CLOSE_SENTINEL = path.join(IPC_INPUT_DIR, '_close'); @@ -161,8 +161,8 @@ async function readStdin(): Promise { }); } -const OUTPUT_START_MARKER = '---NANOCLAW_OUTPUT_START---'; -const OUTPUT_END_MARKER = '---NANOCLAW_OUTPUT_END---'; +const OUTPUT_START_MARKER = '---EJCLAW_OUTPUT_START---'; +const OUTPUT_END_MARKER = '---EJCLAW_OUTPUT_END---'; function writeOutput(output: ContainerOutput): void { console.log(OUTPUT_START_MARKER); @@ -469,22 +469,22 @@ async function runQuery( 'TeamCreate', 'TeamDelete', 'SendMessage', 'TodoWrite', 'ToolSearch', 'Skill', 'NotebookEdit', - 'mcp__nanoclaw__*' + 'mcp__ejclaw__*' ], env: sdkEnv, permissionMode: 'bypassPermissions', allowDangerouslySkipPermissions: true, settingSources: ['project', 'user'], mcpServers: { - nanoclaw: { + ejclaw: { command: 'node', args: [mcpServerPath], env: { - NANOCLAW_CHAT_JID: containerInput.chatJid, - NANOCLAW_GROUP_FOLDER: containerInput.groupFolder, - NANOCLAW_IS_MAIN: containerInput.isMain ? '1' : '0', - NANOCLAW_AGENT_TYPE: - process.env.NANOCLAW_AGENT_TYPE || 'claude-code', + EJCLAW_CHAT_JID: containerInput.chatJid, + EJCLAW_GROUP_FOLDER: containerInput.groupFolder, + EJCLAW_IS_MAIN: containerInput.isMain ? '1' : '0', + EJCLAW_AGENT_TYPE: + process.env.EJCLAW_AGENT_TYPE || 'claude-code', }, }, ...(process.env.MEMENTO_MCP_SSE_URL diff --git a/runners/agent-runner/src/ipc-mcp-stdio.ts b/runners/agent-runner/src/ipc-mcp-stdio.ts index 6da3493..2c6322e 100644 --- a/runners/agent-runner/src/ipc-mcp-stdio.ts +++ b/runners/agent-runner/src/ipc-mcp-stdio.ts @@ -1,5 +1,5 @@ /** - * Stdio MCP Server for NanoClaw + * Stdio MCP Server for EJClaw * Standalone process that agent teams subagents can inherit. * Reads context from environment variables, writes IPC files for the host. */ @@ -16,15 +16,15 @@ import { normalizeWatchCiIntervalSeconds, } from './watch-ci.js'; -const IPC_DIR = process.env.NANOCLAW_IPC_DIR || '/workspace/ipc'; +const IPC_DIR = process.env.EJCLAW_IPC_DIR || '/workspace/ipc'; const MESSAGES_DIR = path.join(IPC_DIR, 'messages'); const TASKS_DIR = path.join(IPC_DIR, 'tasks'); // Context from environment variables (set by the agent runner) -const chatJid = process.env.NANOCLAW_CHAT_JID!; -const groupFolder = process.env.NANOCLAW_GROUP_FOLDER!; -const isMain = process.env.NANOCLAW_IS_MAIN === '1'; -const agentType = process.env.NANOCLAW_AGENT_TYPE || 'claude-code'; +const chatJid = process.env.EJCLAW_CHAT_JID!; +const groupFolder = process.env.EJCLAW_GROUP_FOLDER!; +const isMain = process.env.EJCLAW_IS_MAIN === '1'; +const agentType = process.env.EJCLAW_AGENT_TYPE || 'claude-code'; const allowGenericScheduling = agentType !== 'codex'; function writeIpcFile(dir: string, data: object): string { @@ -42,7 +42,7 @@ function writeIpcFile(dir: string, data: object): string { } const server = new McpServer({ - name: 'nanoclaw', + name: 'ejclaw', version: '1.0.0', }); diff --git a/runners/codex-runner/package-lock.json b/runners/codex-runner/package-lock.json index 8dab381..c2a0740 100644 --- a/runners/codex-runner/package-lock.json +++ b/runners/codex-runner/package-lock.json @@ -1,11 +1,11 @@ { - "name": "nanoclaw-codex-runner", + "name": "ejclaw-codex-runner", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "nanoclaw-codex-runner", + "name": "ejclaw-codex-runner", "version": "1.0.0", "dependencies": { "@openai/codex": "^0.115.0" diff --git a/runners/codex-runner/package.json b/runners/codex-runner/package.json index 2fe0579..a5bd352 100644 --- a/runners/codex-runner/package.json +++ b/runners/codex-runner/package.json @@ -1,8 +1,8 @@ { - "name": "nanoclaw-codex-runner", + "name": "ejclaw-codex-runner", "version": "1.0.0", "type": "module", - "description": "Codex app-server runner for NanoClaw", + "description": "Codex app-server runner for EJClaw", "main": "dist/index.js", "scripts": { "build": "tsc", diff --git a/runners/codex-runner/src/app-server-client.ts b/runners/codex-runner/src/app-server-client.ts index a3d44da..798dc47 100644 --- a/runners/codex-runner/src/app-server-client.ts +++ b/runners/codex-runner/src/app-server-client.ts @@ -144,8 +144,8 @@ export class CodexAppServerClient { await this.request('initialize', { clientInfo: { - name: 'nanoclaw_codex_runner', - title: 'NanoClaw Codex Runner', + name: 'ejclaw_codex_runner', + title: 'EJClaw Codex Runner', version: '1.0.0', }, capabilities: { @@ -182,7 +182,7 @@ export class CodexAppServerClient { model: options.model, approvalPolicy: 'never', sandbox: 'danger-full-access', - serviceName: 'nanoclaw', + serviceName: 'ejclaw', }; const result = sessionId @@ -362,7 +362,7 @@ export class CodexAppServerClient { this.respondError( message.id, -32601, - `NanoClaw does not handle server request ${message.method}`, + `EJClaw does not handle server request ${message.method}`, ); } diff --git a/runners/codex-runner/src/index.ts b/runners/codex-runner/src/index.ts index 27da4cd..c717401 100644 --- a/runners/codex-runner/src/index.ts +++ b/runners/codex-runner/src/index.ts @@ -1,11 +1,11 @@ /** - * NanoClaw Codex Runner + * EJClaw Codex Runner * * App-server only runtime. * * Input protocol: * Stdin: Full ContainerInput JSON (read until EOF) - * IPC: Follow-up messages as JSON files in $NANOCLAW_IPC_DIR/input/ + * IPC: Follow-up messages as JSON files in $EJCLAW_IPC_DIR/input/ * Sentinel: _close — signals session end * * Stdout protocol: @@ -43,15 +43,15 @@ interface ContainerOutput { // ── Constants ────────────────────────────────────────────────────── -const GROUP_DIR = process.env.NANOCLAW_GROUP_DIR || '/workspace/group'; -const IPC_DIR = process.env.NANOCLAW_IPC_DIR || '/workspace/ipc'; -const WORK_DIR = process.env.NANOCLAW_WORK_DIR || ''; +const GROUP_DIR = process.env.EJCLAW_GROUP_DIR || '/workspace/group'; +const IPC_DIR = process.env.EJCLAW_IPC_DIR || '/workspace/ipc'; +const WORK_DIR = process.env.EJCLAW_WORK_DIR || ''; const IPC_INPUT_DIR = path.join(IPC_DIR, 'input'); const IPC_INPUT_CLOSE_SENTINEL = path.join(IPC_INPUT_DIR, '_close'); const IPC_POLL_MS = 500; -const OUTPUT_START_MARKER = '---NANOCLAW_OUTPUT_START---'; -const OUTPUT_END_MARKER = '---NANOCLAW_OUTPUT_END---'; +const OUTPUT_START_MARKER = '---EJCLAW_OUTPUT_START---'; +const OUTPUT_END_MARKER = '---EJCLAW_OUTPUT_END---'; const EFFECTIVE_CWD = WORK_DIR || GROUP_DIR; const CODEX_MODEL = process.env.CODEX_MODEL || ''; diff --git a/scripts/migrate-unify.cjs b/scripts/migrate-unify.cjs index 99420b0..2a6af0f 100644 --- a/scripts/migrate-unify.cjs +++ b/scripts/migrate-unify.cjs @@ -4,15 +4,15 @@ * * Run AFTER stopping both services. */ -const Database = require('/home/clone-ej/nanoclaw/node_modules/better-sqlite3'); +const Database = require('/home/clone-ej/EJClaw/node_modules/better-sqlite3'); const fs = require('fs'); const path = require('path'); -const BASE = '/home/clone-ej/nanoclaw'; +const BASE = '/home/clone-ej/EJClaw'; const CLAUDE_DB = path.join(BASE, 'store/messages.db'); const CODEX_DB = path.join(BASE, 'store-codex/messages.db'); -console.log('=== NanoClaw Data Unification ===\n'); +console.log('=== EJClaw Data Unification ===\n'); // 1. Open both DBs const primary = new Database(CLAUDE_DB); @@ -215,6 +215,6 @@ console.log(''); console.log('=== Migration complete ==='); console.log('Next steps:'); -console.log('1. Update .env.codex to remove NANOCLAW_STORE_DIR, NANOCLAW_DATA_DIR, NANOCLAW_GROUPS_DIR'); +console.log('1. Update .env.codex to remove EJCLAW_STORE_DIR, EJCLAW_DATA_DIR, EJCLAW_GROUPS_DIR'); console.log('2. Restart both services'); console.log('3. Verify, then rename old dirs to .bak'); diff --git a/setup.sh b/setup.sh index ef7d683..e5b2a6c 100755 --- a/setup.sh +++ b/setup.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -# setup.sh — Bootstrap script for NanoClaw +# setup.sh — Bootstrap script for EJClaw # Handles Node.js/npm setup, then hands off to the Node.js setup modules. # This is the only bash script in the setup flow. @@ -136,7 +136,7 @@ elif [ "$NATIVE_OK" = "false" ]; then fi cat <, ): void { - const lines = [`=== NANOCLAW SETUP: ${step} ===`]; + const lines = [`=== EJCLAW SETUP: ${step} ===`]; for (const [key, value] of Object.entries(fields)) { lines.push(`${key}: ${value}`); } diff --git a/setup/verify.ts b/setup/verify.ts index 5857b35..2b6b393 100644 --- a/setup/verify.ts +++ b/setup/verify.ts @@ -29,9 +29,9 @@ export async function run(_args: string[]): Promise { if (mgr === 'launchd') { try { const output = execSync('launchctl list', { encoding: 'utf-8' }); - if (output.includes('com.nanoclaw')) { + if (output.includes('com.ejclaw')) { // Check if it has a PID (actually running) - const line = output.split('\n').find((l) => l.includes('com.nanoclaw')); + const line = output.split('\n').find((l) => l.includes('com.ejclaw')); if (line) { const pidField = line.trim().split(/\s+/)[0]; service = pidField !== '-' && pidField ? 'running' : 'stopped'; @@ -43,14 +43,14 @@ export async function run(_args: string[]): Promise { } else if (mgr === 'systemd') { const prefix = isRoot() ? 'systemctl' : 'systemctl --user'; try { - execSync(`${prefix} is-active nanoclaw`, { stdio: 'ignore' }); + execSync(`${prefix} is-active ejclaw`, { stdio: 'ignore' }); service = 'running'; } catch { try { const output = execSync(`${prefix} list-unit-files`, { encoding: 'utf-8', }); - if (output.includes('nanoclaw')) { + if (output.includes('ejclaw')) { service = 'stopped'; } } catch { @@ -59,7 +59,7 @@ export async function run(_args: string[]): Promise { } } else { // Check for nohup PID file - const pidFile = path.join(projectRoot, 'nanoclaw.pid'); + const pidFile = path.join(projectRoot, 'ejclaw.pid'); if (fs.existsSync(pidFile)) { try { const raw = fs.readFileSync(pidFile, 'utf-8').trim(); diff --git a/src/agent-runner-environment.ts b/src/agent-runner-environment.ts index ae1c65a..34be1e7 100644 --- a/src/agent-runner-environment.ts +++ b/src/agent-runner-environment.ts @@ -87,14 +87,14 @@ function buildBaseRunnerEnv(args: { : currentPath, TZ: TIMEZONE, HOME: os.homedir(), - NANOCLAW_GROUP_DIR: args.groupDir, - NANOCLAW_IPC_DIR: args.groupIpcDir, - NANOCLAW_GLOBAL_DIR: args.globalDir, - ...(args.group.workDir ? { NANOCLAW_WORK_DIR: args.group.workDir } : {}), - NANOCLAW_CHAT_JID: args.chatJid, - NANOCLAW_GROUP_FOLDER: args.group.folder, - NANOCLAW_IS_MAIN: args.isMain ? '1' : '0', - NANOCLAW_AGENT_TYPE: args.agentType, + EJCLAW_GROUP_DIR: args.groupDir, + EJCLAW_IPC_DIR: args.groupIpcDir, + EJCLAW_GLOBAL_DIR: args.globalDir, + ...(args.group.workDir ? { EJCLAW_WORK_DIR: args.group.workDir } : {}), + EJCLAW_CHAT_JID: args.chatJid, + EJCLAW_GROUP_FOLDER: args.group.folder, + EJCLAW_IS_MAIN: args.isMain ? '1' : '0', + EJCLAW_AGENT_TYPE: args.agentType, CLAUDE_CONFIG_DIR: args.groupSessionsDir, }; } @@ -240,22 +240,22 @@ function prepareCodexSessionEnvironment(args: { let toml = fs.existsSync(sessionConfigPath) ? fs.readFileSync(sessionConfigPath, 'utf-8') : ''; - toml = toml.replace(/\n?\[mcp_servers\.nanoclaw\][\s\S]*?(?=\n\[|$)/, ''); + toml = toml.replace(/\n?\[mcp_servers\.ejclaw\][\s\S]*?(?=\n\[|$)/, ''); toml = toml.replace( /\n?\[mcp_servers\.memento-mcp\][\s\S]*?(?=\n\[|$)/, '', ); const mcpSection = ` -[mcp_servers.nanoclaw] +[mcp_servers.ejclaw] command = "node" args = [${JSON.stringify(mcpServerPath)}] -[mcp_servers.nanoclaw.env] -NANOCLAW_IPC_DIR = ${JSON.stringify(args.env.NANOCLAW_IPC_DIR)} -NANOCLAW_CHAT_JID = ${JSON.stringify(args.chatJid)} -NANOCLAW_GROUP_FOLDER = ${JSON.stringify(args.group.folder)} -NANOCLAW_IS_MAIN = ${JSON.stringify(args.isMain ? '1' : '0')} -NANOCLAW_AGENT_TYPE = ${JSON.stringify(args.env.NANOCLAW_AGENT_TYPE)} +[mcp_servers.ejclaw.env] +EJCLAW_IPC_DIR = ${JSON.stringify(args.env.EJCLAW_IPC_DIR)} +EJCLAW_CHAT_JID = ${JSON.stringify(args.chatJid)} +EJCLAW_GROUP_FOLDER = ${JSON.stringify(args.group.folder)} +EJCLAW_IS_MAIN = ${JSON.stringify(args.isMain ? '1' : '0')} +EJCLAW_AGENT_TYPE = ${JSON.stringify(args.env.EJCLAW_AGENT_TYPE)} `; const mementoSseUrl = args.envVars.MEMENTO_MCP_SSE_URL || process.env.MEMENTO_MCP_SSE_URL; diff --git a/src/agent-runner.test.ts b/src/agent-runner.test.ts index 95e189e..6352638 100644 --- a/src/agent-runner.test.ts +++ b/src/agent-runner.test.ts @@ -5,15 +5,15 @@ import fs from 'fs'; import { spawn } from 'child_process'; // Sentinel markers must match agent-runner.ts -const OUTPUT_START_MARKER = '---NANOCLAW_OUTPUT_START---'; -const OUTPUT_END_MARKER = '---NANOCLAW_OUTPUT_END---'; +const OUTPUT_START_MARKER = '---EJCLAW_OUTPUT_START---'; +const OUTPUT_END_MARKER = '---EJCLAW_OUTPUT_END---'; // Mock config vi.mock('./config.js', () => ({ AGENT_MAX_OUTPUT_SIZE: 10485760, AGENT_TIMEOUT: 1800000, // 30min - DATA_DIR: '/tmp/nanoclaw-test-data', - GROUPS_DIR: '/tmp/nanoclaw-test-groups', + DATA_DIR: '/tmp/ejclaw-test-data', + GROUPS_DIR: '/tmp/ejclaw-test-groups', IDLE_TIMEOUT: 1800000, // 30min TIMEZONE: 'America/Los_Angeles', })); @@ -287,7 +287,7 @@ describe('agent-runner timeout behavior', () => { const spawnEnv = vi.mocked(spawn).mock.calls[0]?.[2]?.env as | Record | undefined; - expect(spawnEnv?.NANOCLAW_CHAT_JID).toBe(testInput.chatJid); + expect(spawnEnv?.EJCLAW_CHAT_JID).toBe(testInput.chatJid); const tomlWrite = vi .mocked(fs.writeFileSync) @@ -295,7 +295,7 @@ describe('agent-runner timeout behavior', () => { String(call[0]).endsWith('/.codex/config.toml'), ); expect(String(tomlWrite?.[1])).toContain( - `NANOCLAW_CHAT_JID = ${JSON.stringify(testInput.chatJid)}`, + `EJCLAW_CHAT_JID = ${JSON.stringify(testInput.chatJid)}`, ); }); @@ -322,11 +322,11 @@ describe('agent-runner timeout behavior', () => { const spawnEnv = vi.mocked(spawn).mock.calls.at(-1)?.[2]?.env as | Record | undefined; - expect(spawnEnv?.NANOCLAW_IPC_DIR).toBe( - '/tmp/nanoclaw-test-data/ipc/test-group/tasks/task-123', + expect(spawnEnv?.EJCLAW_IPC_DIR).toBe( + '/tmp/ejclaw-test-data/ipc/test-group/tasks/task-123', ); expect(spawnEnv?.CLAUDE_CONFIG_DIR).toBe( - '/tmp/nanoclaw-test-data/sessions/test-group/tasks/task-123/.claude', + '/tmp/ejclaw-test-data/sessions/test-group/tasks/task-123/.claude', ); }); @@ -353,11 +353,11 @@ describe('agent-runner timeout behavior', () => { const spawnEnv = vi.mocked(spawn).mock.calls.at(-1)?.[2]?.env as | Record | undefined; - expect(spawnEnv?.NANOCLAW_IPC_DIR).toBe( - '/tmp/nanoclaw-test-data/ipc/test-group/tasks/task-watch-group', + expect(spawnEnv?.EJCLAW_IPC_DIR).toBe( + '/tmp/ejclaw-test-data/ipc/test-group/tasks/task-watch-group', ); expect(spawnEnv?.CLAUDE_CONFIG_DIR).toBe( - '/tmp/nanoclaw-test-data/sessions/test-group/.claude', + '/tmp/ejclaw-test-data/sessions/test-group/.claude', ); }); @@ -365,9 +365,9 @@ describe('agent-runner timeout behavior', () => { vi.useRealTimers(); fakeProc = createFakeProcess(); const overlayPath = - '/tmp/nanoclaw-test-groups/test-group/.codex/config.toml'; + '/tmp/ejclaw-test-groups/test-group/.codex/config.toml'; const sessionConfigPath = - '/tmp/nanoclaw-test-data/sessions/test-group/.codex/config.toml'; + '/tmp/ejclaw-test-data/sessions/test-group/.codex/config.toml'; let sessionToml = `model = "gpt-5.4"\n`; vi.mocked(fs.existsSync).mockImplementation((p: fs.PathLike) => { @@ -428,7 +428,7 @@ OUROBOROS_LLM_BACKEND = "codex" const toml = String(tomlWrite?.[1]); expect(toml).toContain('[mcp_servers.ouroboros]'); expect(toml).toContain('OUROBOROS_AGENT_RUNTIME = "codex"'); - expect(toml).toContain('[mcp_servers.nanoclaw]'); + expect(toml).toContain('[mcp_servers.ejclaw]'); }); it('waits for queued streamed output before resolving an error exit', async () => { diff --git a/src/agent-runner.ts b/src/agent-runner.ts index 12aa156..330f97a 100644 --- a/src/agent-runner.ts +++ b/src/agent-runner.ts @@ -1,5 +1,5 @@ /** - * Agent Process Runner for NanoClaw + * Agent Process Runner for EJClaw * Spawns agent execution as direct host processes and handles IPC */ import { ChildProcess, spawn } from 'child_process'; @@ -21,8 +21,8 @@ import { logger } from './logger.js'; import { AgentType, RegisteredGroup } from './types.js'; // Sentinel markers for robust output parsing (must match agent-runner) -const OUTPUT_START_MARKER = '---NANOCLAW_OUTPUT_START---'; -const OUTPUT_END_MARKER = '---NANOCLAW_OUTPUT_END---'; +const OUTPUT_START_MARKER = '---EJCLAW_OUTPUT_START---'; +const OUTPUT_END_MARKER = '---EJCLAW_OUTPUT_END---'; export interface AgentInput { prompt: string; @@ -75,12 +75,12 @@ export async function runAgentProcess( } } if (input.runId) { - env.NANOCLAW_RUN_ID = input.runId; + env.EJCLAW_RUN_ID = input.runId; } const safeName = group.folder.replace(/[^a-zA-Z0-9-]/g, '-'); const processSuffix = input.runId || `${Date.now()}`; - const processName = `nanoclaw-${safeName}-${processSuffix}`; + const processName = `ejclaw-${safeName}-${processSuffix}`; // Check if runner is built const distEntry = path.join(runnerDir, 'dist', 'index.js'); @@ -119,7 +119,7 @@ export async function runAgentProcess( env, }); - onProcess(proc, processName, env.NANOCLAW_IPC_DIR); + onProcess(proc, processName, env.EJCLAW_IPC_DIR); let stdout = ''; let stderr = ''; diff --git a/src/channels/discord.test.ts b/src/channels/discord.test.ts index 04b4a9a..e6c9a7f 100644 --- a/src/channels/discord.test.ts +++ b/src/channels/discord.test.ts @@ -12,8 +12,8 @@ vi.mock('../env.js', () => ({ readEnvFile: vi.fn(() => ({})) })); vi.mock('../config.js', () => ({ ASSISTANT_NAME: 'Andy', TRIGGER_PATTERN: /^@Andy\b/i, - DATA_DIR: '/tmp/nanoclaw-test-data', - CACHE_DIR: '/tmp/nanoclaw-test-cache', + DATA_DIR: '/tmp/ejclaw-test-data', + CACHE_DIR: '/tmp/ejclaw-test-cache', })); // Mock logger diff --git a/src/config.ts b/src/config.ts index 7f7bb57..67cdbd7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -40,17 +40,17 @@ const HOME_DIR = process.env.HOME || os.homedir(); export const SENDER_ALLOWLIST_PATH = path.join( HOME_DIR, '.config', - 'nanoclaw', + 'ejclaw', 'sender-allowlist.json', ); export const STORE_DIR = path.resolve( - process.env.NANOCLAW_STORE_DIR || path.join(PROJECT_ROOT, 'store'), + process.env.EJCLAW_STORE_DIR || path.join(PROJECT_ROOT, 'store'), ); export const GROUPS_DIR = path.resolve( - process.env.NANOCLAW_GROUPS_DIR || path.join(PROJECT_ROOT, 'groups'), + process.env.EJCLAW_GROUPS_DIR || path.join(PROJECT_ROOT, 'groups'), ); export const DATA_DIR = path.resolve( - process.env.NANOCLAW_DATA_DIR || path.join(PROJECT_ROOT, 'data'), + process.env.EJCLAW_DATA_DIR || path.join(PROJECT_ROOT, 'data'), ); // Shared cache directory (same across both services for dedup) export const CACHE_DIR = path.join(PROJECT_ROOT, 'cache'); diff --git a/src/index.ts b/src/index.ts index 0b36845..863443d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -474,7 +474,7 @@ const isDirectRun = if (isDirectRun) { main().catch((err) => { - logger.error({ err }, 'Failed to start NanoClaw'); + logger.error({ err }, 'Failed to start EJClaw'); process.exit(1); }); } diff --git a/src/message-runtime.test.ts b/src/message-runtime.test.ts index a60d808..dcfd96c 100644 --- a/src/message-runtime.test.ts +++ b/src/message-runtime.test.ts @@ -7,7 +7,7 @@ vi.mock('./agent-runner.js', () => ({ })); vi.mock('./config.js', () => ({ - DATA_DIR: '/tmp/nanoclaw-test-data', + DATA_DIR: '/tmp/ejclaw-test-data', isSessionCommandSenderAllowed: vi.fn(() => false), }));