@foxden-app/foxclaw 0.3.6 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README_EN.md +1 -1
- package/dist/controller/controller.d.ts +2 -0
- package/dist/controller/controller.js +53 -10
- package/dist/i18n.d.ts +8 -8
- package/dist/i18n.js +8 -8
- package/docs/agent-assisted-install.md +1 -1
- package/docs/install-for-beginners.md +5 -5
- package/docs/troubleshooting.md +8 -8
- package/docs/user-manual.md +3 -3
- package/docs/zh/agent-assisted-install.md +1 -1
- package/docs/zh/foxclaw-skill.md +1 -1
- package/docs/zh/install-for-beginners.md +5 -5
- package/docs/zh/troubleshooting.md +8 -8
- package/docs/zh/user-manual.md +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ FoxClaw(狸爪)的目标很直接:让你用手机控制本机的 Codex,
|
|
|
40
40
|
- Git、Node、`.env` 都玩得转?直接往下看快速设置。
|
|
41
41
|
- 卡住了?看 [故障排查](./docs/zh/troubleshooting.md)。
|
|
42
42
|
|
|
43
|
-
最低要求:一个 Telegram bot token、你的 Telegram 数字用户 ID、Node.js 24
|
|
43
|
+
最低要求:一个 Telegram bot token、你的 Telegram 数字用户 ID、Node.js 24+、一份已登录的 `codex` CLI。首次安装大约 10–20 分钟。
|
|
44
44
|
|
|
45
45
|
**30 秒体验**:启动 FoxClaw 后,给你的 Telegram 机器人发一句 `List files in DEFAULT_CWD`。Codex 会在本地检查那个目录,然后把结果发回 Telegram。
|
|
46
46
|
|
package/README_EN.md
CHANGED
|
@@ -40,7 +40,7 @@ FoxClaw is more than message forwarding. It provides Telegram panels for Codex w
|
|
|
40
40
|
- Already comfortable with Git, Node, and `.env` files? Use the quick setup below.
|
|
41
41
|
- Something failed? Check [Troubleshooting](./docs/troubleshooting.md).
|
|
42
42
|
|
|
43
|
-
The minimum install needs only a Telegram bot token, your numeric Telegram user id, Node.js 24
|
|
43
|
+
The minimum install needs only a Telegram bot token, your numeric Telegram user id, Node.js 24+, and a logged-in `codex` CLI. A first install usually takes 10–20 minutes.
|
|
44
44
|
|
|
45
45
|
**30-second demo**: after FoxClaw is running, send `List files in DEFAULT_CWD` to your Telegram bot. FoxClaw asks local Codex to inspect that folder on your computer and sends the answer back to Telegram.
|
|
46
46
|
|
|
@@ -249,6 +249,8 @@ export declare class BridgeSessionCore {
|
|
|
249
249
|
private retryTurnAfterAuthRotation;
|
|
250
250
|
private selectNextCodexAuthCandidate;
|
|
251
251
|
private listCodexAuthState;
|
|
252
|
+
private readCodexAuthSwitchLabels;
|
|
253
|
+
private codexAuthSwitchParams;
|
|
252
254
|
private switchCodexAuthAndRestart;
|
|
253
255
|
private buildNativeCollaborationMode;
|
|
254
256
|
private buildCodexUsageStatusLines;
|
|
@@ -3693,7 +3693,8 @@ export class BridgeSessionCore {
|
|
|
3693
3693
|
await this.sendMessage(scopeId, renderAuthListMessage(locale, state, parseWeixinBridgeScope(scopeId) !== null));
|
|
3694
3694
|
return;
|
|
3695
3695
|
}
|
|
3696
|
-
await this.
|
|
3696
|
+
const switchLabels = await this.readCodexAuthSwitchLabels(candidate);
|
|
3697
|
+
await this.sendMessage(scopeId, t(locale, 'auth_switching', this.codexAuthSwitchParams(locale, switchLabels.fromLabel, switchLabels.toLabel)));
|
|
3697
3698
|
await this.switchCodexAuthAndRestart(scopeId, locale, candidate, false);
|
|
3698
3699
|
}
|
|
3699
3700
|
async handleAuthToggleCommand(scopeId, locale, args, disabled) {
|
|
@@ -4190,8 +4191,10 @@ export class BridgeSessionCore {
|
|
|
4190
4191
|
}
|
|
4191
4192
|
await this.messaging.answerCallback(event.callbackQueryId, t(locale, 'auth_choice_recorded'));
|
|
4192
4193
|
this.pendingAuthChoiceLists.delete(localId);
|
|
4194
|
+
const switchLabels = await this.readCodexAuthSwitchLabels(candidate);
|
|
4195
|
+
const switchingMessage = t(locale, 'auth_switching', this.codexAuthSwitchParams(locale, switchLabels.fromLabel, switchLabels.toLabel));
|
|
4193
4196
|
if (record.messageId !== null) {
|
|
4194
|
-
await this.editMessage(event.scopeId, record.messageId,
|
|
4197
|
+
await this.editMessage(event.scopeId, record.messageId, switchingMessage, []);
|
|
4195
4198
|
}
|
|
4196
4199
|
await this.switchCodexAuthAndRestart(event.scopeId, locale, candidate, false);
|
|
4197
4200
|
}
|
|
@@ -4207,16 +4210,17 @@ export class BridgeSessionCore {
|
|
|
4207
4210
|
this.authRotationInProgress = true;
|
|
4208
4211
|
try {
|
|
4209
4212
|
const failedTargets = rotation.retry?.failedAuthTargets ?? this.authRotationFailedTargets;
|
|
4210
|
-
const
|
|
4213
|
+
const selection = await this.selectNextCodexAuthCandidate(failedTargets);
|
|
4211
4214
|
const locale = this.localeForChat(rotation.scopeId);
|
|
4212
|
-
if (!
|
|
4215
|
+
if (!selection) {
|
|
4213
4216
|
await this.sendMessage(rotation.scopeId, t(locale, 'auth_auto_no_candidate', {
|
|
4214
4217
|
error: formatShortStatusError(rotation.reason),
|
|
4215
4218
|
}));
|
|
4216
4219
|
return false;
|
|
4217
4220
|
}
|
|
4221
|
+
const { candidate, fromLabel, toLabel } = selection;
|
|
4218
4222
|
await this.sendMessage(rotation.scopeId, t(locale, 'auth_auto_switching', {
|
|
4219
|
-
|
|
4223
|
+
...this.codexAuthSwitchParams(locale, fromLabel, toLabel),
|
|
4220
4224
|
error: formatShortStatusError(rotation.reason),
|
|
4221
4225
|
}));
|
|
4222
4226
|
await this.switchCodexAuthAndRestart(rotation.scopeId, locale, candidate, true);
|
|
@@ -4290,21 +4294,35 @@ export class BridgeSessionCore {
|
|
|
4290
4294
|
for (let offset = 1; offset <= state.candidates.length; offset += 1) {
|
|
4291
4295
|
const candidate = state.candidates[(currentIndex + offset + state.candidates.length) % state.candidates.length];
|
|
4292
4296
|
if (candidate && !candidate.disabled && !failedTargets.has(candidate.path)) {
|
|
4293
|
-
return candidate;
|
|
4297
|
+
return { candidate, fromLabel: state.currentLabel, toLabel: await authPathDisplayLabel(candidate.path) };
|
|
4294
4298
|
}
|
|
4295
4299
|
}
|
|
4296
|
-
|
|
4300
|
+
const candidate = candidates[0] ?? null;
|
|
4301
|
+
return candidate ? { candidate, fromLabel: state.currentLabel, toLabel: await authPathDisplayLabel(candidate.path) } : null;
|
|
4297
4302
|
}
|
|
4298
4303
|
async listCodexAuthState() {
|
|
4299
4304
|
return listCodexAuthState(this.store.listDisabledCodexAuthCandidateNames());
|
|
4300
4305
|
}
|
|
4306
|
+
async readCodexAuthSwitchLabels(candidate) {
|
|
4307
|
+
const state = await this.listCodexAuthState();
|
|
4308
|
+
return {
|
|
4309
|
+
fromLabel: state.currentLabel,
|
|
4310
|
+
toLabel: await authPathDisplayLabel(candidate.path),
|
|
4311
|
+
};
|
|
4312
|
+
}
|
|
4313
|
+
codexAuthSwitchParams(locale, fromLabel, toLabel) {
|
|
4314
|
+
return {
|
|
4315
|
+
from: fromLabel ?? t(locale, 'none'),
|
|
4316
|
+
to: toLabel,
|
|
4317
|
+
};
|
|
4318
|
+
}
|
|
4301
4319
|
async switchCodexAuthAndRestart(scopeId, locale, candidate, automatic) {
|
|
4302
|
-
await switchCodexAuth(candidate.path);
|
|
4320
|
+
const result = await switchCodexAuth(candidate.path);
|
|
4303
4321
|
this.authRotationFailedTargets.delete(candidate.path);
|
|
4304
4322
|
this.pendingTurnErrors.clear();
|
|
4305
4323
|
this.attachedThreads.clear();
|
|
4306
4324
|
await this.app.restart();
|
|
4307
|
-
const lines = [t(locale, automatic ? 'auth_auto_done' : 'auth_switch_done',
|
|
4325
|
+
const lines = [t(locale, automatic ? 'auth_auto_done' : 'auth_switch_done', this.codexAuthSwitchParams(locale, result.fromLabel, result.toLabel))];
|
|
4308
4326
|
lines.push(...await this.buildCodexUsageStatusLines(locale));
|
|
4309
4327
|
await this.sendMessage(scopeId, lines.join('\n'));
|
|
4310
4328
|
}
|
|
@@ -6913,7 +6931,7 @@ async function listCodexAuthState(disabledNames = new Set()) {
|
|
|
6913
6931
|
authDir,
|
|
6914
6932
|
authPath,
|
|
6915
6933
|
currentTargetPath,
|
|
6916
|
-
currentLabel: currentTargetPath ?
|
|
6934
|
+
currentLabel: currentTargetPath ? await authPathDisplayLabel(currentTargetPath) : null,
|
|
6917
6935
|
candidates,
|
|
6918
6936
|
};
|
|
6919
6937
|
}
|
|
@@ -6946,6 +6964,27 @@ async function resolveCurrentAuthTarget(authDir, authPath) {
|
|
|
6946
6964
|
}
|
|
6947
6965
|
return authPath;
|
|
6948
6966
|
}
|
|
6967
|
+
async function resolveAuthFinalTargetPath(startPath) {
|
|
6968
|
+
let currentPath = startPath;
|
|
6969
|
+
const seen = new Set();
|
|
6970
|
+
for (let depth = 0; depth < 20; depth += 1) {
|
|
6971
|
+
const absolutePath = path.resolve(currentPath);
|
|
6972
|
+
if (seen.has(absolutePath)) {
|
|
6973
|
+
return currentPath;
|
|
6974
|
+
}
|
|
6975
|
+
seen.add(absolutePath);
|
|
6976
|
+
const stat = await fs.lstat(currentPath).catch(() => null);
|
|
6977
|
+
if (!stat?.isSymbolicLink()) {
|
|
6978
|
+
return currentPath;
|
|
6979
|
+
}
|
|
6980
|
+
const target = await fs.readlink(currentPath);
|
|
6981
|
+
currentPath = path.resolve(path.dirname(currentPath), target);
|
|
6982
|
+
}
|
|
6983
|
+
return currentPath;
|
|
6984
|
+
}
|
|
6985
|
+
async function authPathDisplayLabel(authPath) {
|
|
6986
|
+
return path.basename(await resolveAuthFinalTargetPath(authPath));
|
|
6987
|
+
}
|
|
6949
6988
|
async function pointCodexAuthAtTarget(authDir, authPath, targetPath) {
|
|
6950
6989
|
await fs.mkdir(authDir, { recursive: true });
|
|
6951
6990
|
const tempLink = path.join(authDir, `.auth.json.${process.pid}.${Date.now()}.tmp`);
|
|
@@ -6965,6 +7004,10 @@ async function switchCodexAuth(targetPath) {
|
|
|
6965
7004
|
throw new Error(`Auth candidate is no longer available: ${path.basename(targetPath)}`);
|
|
6966
7005
|
}
|
|
6967
7006
|
await pointCodexAuthAtTarget(state.authDir, state.authPath, candidate.path);
|
|
7007
|
+
return {
|
|
7008
|
+
fromLabel: state.currentLabel,
|
|
7009
|
+
toLabel: await authPathDisplayLabel(candidate.path),
|
|
7010
|
+
};
|
|
6968
7011
|
}
|
|
6969
7012
|
function renderAuthListMessage(locale, state, includeWeixinCopyPaste = false) {
|
|
6970
7013
|
const lines = [
|
package/dist/i18n.d.ts
CHANGED
|
@@ -133,10 +133,10 @@ declare const MESSAGES: {
|
|
|
133
133
|
readonly auth_choice_expired: "This auth list is no longer active";
|
|
134
134
|
readonly auth_choice_mismatch: "Auth choice does not match this message";
|
|
135
135
|
readonly auth_choice_recorded: "Auth selected";
|
|
136
|
-
readonly auth_switching: "Switching Codex auth
|
|
137
|
-
readonly auth_switch_done: "Codex auth switched
|
|
138
|
-
readonly auth_auto_switching: "Codex auth problem detected ({error}). Switching
|
|
139
|
-
readonly auth_auto_done: "Auto-switched Codex auth
|
|
136
|
+
readonly auth_switching: "Switching Codex auth: {from} -> {to}...";
|
|
137
|
+
readonly auth_switch_done: "Codex auth switched: {from} -> {to}.";
|
|
138
|
+
readonly auth_auto_switching: "Codex auth problem detected ({error}). Switching: {from} -> {to}...";
|
|
139
|
+
readonly auth_auto_done: "Auto-switched Codex auth: {from} -> {to}.";
|
|
140
140
|
readonly auth_auto_retrying: "Retrying the same request with the new auth...";
|
|
141
141
|
readonly auth_auto_retry_thread_missing: "Auth was switched, but the original thread is no longer available ({threadId}). Retry was stopped to avoid creating duplicate sessions.";
|
|
142
142
|
readonly auth_auto_no_candidate: "Codex auth problem detected ({error}), but no unused auth candidate is available.";
|
|
@@ -683,10 +683,10 @@ declare const MESSAGES: {
|
|
|
683
683
|
readonly auth_choice_expired: "这个 auth 列表已经不再有效";
|
|
684
684
|
readonly auth_choice_mismatch: "这个 auth 选择按钮不属于当前消息";
|
|
685
685
|
readonly auth_choice_recorded: "已选择 auth";
|
|
686
|
-
readonly auth_switching: "正在切换 Codex auth
|
|
687
|
-
readonly auth_switch_done: "Codex auth
|
|
688
|
-
readonly auth_auto_switching: "检测到 Codex auth 问题({error}
|
|
689
|
-
readonly auth_auto_done: "已自动切换 Codex auth
|
|
686
|
+
readonly auth_switching: "正在切换 Codex auth:{from} -> {to}...";
|
|
687
|
+
readonly auth_switch_done: "Codex auth 已切换:{from} -> {to}。";
|
|
688
|
+
readonly auth_auto_switching: "检测到 Codex auth 问题({error}),正在切换:{from} -> {to}...";
|
|
689
|
+
readonly auth_auto_done: "已自动切换 Codex auth:{from} -> {to}。";
|
|
690
690
|
readonly auth_auto_retrying: "正在用新的 auth 重试同一条请求...";
|
|
691
691
|
readonly auth_auto_retry_thread_missing: "Auth 已切换,但原线程已经不可用({threadId})。已停止重试,避免创建重复 session。";
|
|
692
692
|
readonly auth_auto_no_candidate: "检测到 Codex auth 问题({error}),但没有可用的未失败候选 auth。";
|
package/dist/i18n.js
CHANGED
|
@@ -131,10 +131,10 @@ const MESSAGES = {
|
|
|
131
131
|
auth_choice_expired: 'This auth list is no longer active',
|
|
132
132
|
auth_choice_mismatch: 'Auth choice does not match this message',
|
|
133
133
|
auth_choice_recorded: 'Auth selected',
|
|
134
|
-
auth_switching: 'Switching Codex auth
|
|
135
|
-
auth_switch_done: 'Codex auth switched
|
|
136
|
-
auth_auto_switching: 'Codex auth problem detected ({error}). Switching
|
|
137
|
-
auth_auto_done: 'Auto-switched Codex auth
|
|
134
|
+
auth_switching: 'Switching Codex auth: {from} -> {to}...',
|
|
135
|
+
auth_switch_done: 'Codex auth switched: {from} -> {to}.',
|
|
136
|
+
auth_auto_switching: 'Codex auth problem detected ({error}). Switching: {from} -> {to}...',
|
|
137
|
+
auth_auto_done: 'Auto-switched Codex auth: {from} -> {to}.',
|
|
138
138
|
auth_auto_retrying: 'Retrying the same request with the new auth...',
|
|
139
139
|
auth_auto_retry_thread_missing: 'Auth was switched, but the original thread is no longer available ({threadId}). Retry was stopped to avoid creating duplicate sessions.',
|
|
140
140
|
auth_auto_no_candidate: 'Codex auth problem detected ({error}), but no unused auth candidate is available.',
|
|
@@ -681,10 +681,10 @@ const MESSAGES = {
|
|
|
681
681
|
auth_choice_expired: '这个 auth 列表已经不再有效',
|
|
682
682
|
auth_choice_mismatch: '这个 auth 选择按钮不属于当前消息',
|
|
683
683
|
auth_choice_recorded: '已选择 auth',
|
|
684
|
-
auth_switching: '正在切换 Codex auth
|
|
685
|
-
auth_switch_done: 'Codex auth
|
|
686
|
-
auth_auto_switching: '检测到 Codex auth 问题({error}
|
|
687
|
-
auth_auto_done: '已自动切换 Codex auth
|
|
684
|
+
auth_switching: '正在切换 Codex auth:{from} -> {to}...',
|
|
685
|
+
auth_switch_done: 'Codex auth 已切换:{from} -> {to}。',
|
|
686
|
+
auth_auto_switching: '检测到 Codex auth 问题({error}),正在切换:{from} -> {to}...',
|
|
687
|
+
auth_auto_done: '已自动切换 Codex auth:{from} -> {to}。',
|
|
688
688
|
auth_auto_retrying: '正在用新的 auth 重试同一条请求...',
|
|
689
689
|
auth_auto_retry_thread_missing: 'Auth 已切换,但原线程已经不可用({threadId})。已停止重试,避免创建重复 session。',
|
|
690
690
|
auth_auto_no_candidate: '检测到 Codex auth 问题({error}),但没有可用的未失败候选 auth。',
|
|
@@ -39,7 +39,7 @@ DEFAULT_CWD=<paste absolute working directory here>
|
|
|
39
39
|
|
|
40
40
|
Tasks:
|
|
41
41
|
1. Inspect the machine first. If a FoxClaw service already exists, report it before changing services.
|
|
42
|
-
2. Ensure Node.js 24+ is available. If not, install or activate Node 24
|
|
42
|
+
2. Ensure Node.js 24+ is available. If not, install or activate Node 24+ by any suitable method; nvm is only one common option.
|
|
43
43
|
3. Ensure the Codex CLI exists and is logged in. If login is required, stop and tell me exactly what I need to do.
|
|
44
44
|
4. Install or update FoxClaw with npm install -g @foxden-app/foxclaw@latest.
|
|
45
45
|
5. Run foxclaw init, then write ~/.foxclaw/.env. Never print or commit the bot token.
|
|
@@ -25,17 +25,17 @@ You need:
|
|
|
25
25
|
|
|
26
26
|
Use private chat first. Group and topic setup can wait until the bot replies reliably.
|
|
27
27
|
|
|
28
|
-
## 2. Install Node.js 24
|
|
28
|
+
## 2. Install Node.js 24+
|
|
29
29
|
|
|
30
|
-
FoxClaw needs Node.js 24 because it uses the built-in SQLite runtime.
|
|
30
|
+
FoxClaw needs Node.js 24+ because it uses the built-in SQLite runtime. It does not require nvm; you can use nvm, fnm, asdf, mise, Volta, Homebrew, or your system package manager.
|
|
31
31
|
|
|
32
|
-
If you already have Node 24
|
|
32
|
+
If you already have Node 24+, this should print `v24...` or newer:
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
node -v
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
If not,
|
|
38
|
+
If not, nvm is a good default for first-time users. Example:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
|
@@ -47,7 +47,7 @@ node -v
|
|
|
47
47
|
npm -v
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
If `node -v` still shows an old version, close the terminal, open a new one, and run:
|
|
50
|
+
If you use nvm and `node -v` still shows an old version, close the terminal, open a new one, and run:
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
53
|
nvm use 24
|
package/docs/troubleshooting.md
CHANGED
|
@@ -18,7 +18,7 @@ journalctl --user -u foxclaw.service -f
|
|
|
18
18
|
|
|
19
19
|
| Symptom | Meaning | Fix |
|
|
20
20
|
| --- | --- | --- |
|
|
21
|
-
| `[FAIL] node >= 24` | Your current shell is using an older Node.js. |
|
|
21
|
+
| `[FAIL] node >= 24` | Your current shell is using an older Node.js. | Install or activate Node.js 24+ by any method, then rerun `foxclaw doctor`. If the service uses old Node, reinstall it from a Node 24+ shell with `foxclaw start`. |
|
|
22
22
|
| `[FAIL] codex cli available` | The `codex` command is not in PATH. | Install Codex CLI or fix PATH, then confirm `codex --version` works. |
|
|
23
23
|
| `[FAIL] telegram bot token configured` | `TG_BOT_TOKEN` is missing from `.env`. | Copy the token from `@BotFather` into `.env`. |
|
|
24
24
|
| `[FAIL] telegram allowed user configured` | `TG_ALLOWED_USER_ID` is missing from `.env`. | Get your numeric id from `@userinfobot` and add it to `.env`. |
|
|
@@ -26,7 +26,7 @@ journalctl --user -u foxclaw.service -f
|
|
|
26
26
|
|
|
27
27
|
## Node Or npm Is Missing
|
|
28
28
|
|
|
29
|
-
If you see `node: command not found` or `npm: command not found`, install Node.js 24
|
|
29
|
+
If you see `node: command not found` or `npm: command not found`, install Node.js 24+ using your preferred tool, such as nvm, fnm, asdf, mise, Volta, Homebrew, or your system package manager. This is an nvm example:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
|
@@ -38,7 +38,7 @@ node -v
|
|
|
38
38
|
npm -v
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
If it still fails, close the terminal, open a new one, and run:
|
|
41
|
+
If you use nvm and it still fails, close the terminal, open a new one, and run:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
nvm use 24
|
|
@@ -48,7 +48,7 @@ nvm use 24
|
|
|
48
48
|
|
|
49
49
|
If `npm install -g @openai/codex` fails with `EACCES`, `EPERM`, or `permission denied`, your global npm directory is not writable by your user.
|
|
50
50
|
|
|
51
|
-
Recommended fix: use Node
|
|
51
|
+
Recommended fix: use a user-level Node.js 24+ install, then install again. This is an nvm example:
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
nvm install 24
|
|
@@ -56,7 +56,7 @@ nvm use 24
|
|
|
56
56
|
npm install -g @openai/codex
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
Avoid `sudo npm install -g ...` unless you already understand how your Node installation is managed. Mixing `sudo`, system Node, and
|
|
59
|
+
Avoid `sudo npm install -g ...` unless you already understand how your Node installation is managed. Mixing `sudo`, system Node, and user-level Node managers is a common source of broken PATHs.
|
|
60
60
|
|
|
61
61
|
If `codex` installs but FoxClaw still cannot find it, locate the binary:
|
|
62
62
|
|
|
@@ -211,9 +211,9 @@ foxclaw restart
|
|
|
211
211
|
|
|
212
212
|
## Service Starts With The Wrong Node Version
|
|
213
213
|
|
|
214
|
-
The systemd installer records the absolute path of the Node process that is currently running FoxClaw. It does not rely on systemd loading `nvm.sh
|
|
214
|
+
The systemd installer records the absolute path of the Node process that is currently running FoxClaw. It does not rely on systemd loading `nvm.sh` or any other shell init script. Whether you use nvm, fnm, asdf, mise, Volta, Homebrew, or system Node, run `foxclaw start` from a Node 24+ shell and the service will keep using that Node 24+ path.
|
|
215
215
|
|
|
216
|
-
If you installed the service from a shell using Node 22 or older, reinstall it from a Node 24 shell:
|
|
216
|
+
If you installed the service from a shell using Node 22 or older, reinstall it from a Node 24+ shell. Example for nvm users:
|
|
217
217
|
|
|
218
218
|
```bash
|
|
219
219
|
nvm use 24
|
|
@@ -221,7 +221,7 @@ foxclaw start
|
|
|
221
221
|
systemctl --user status foxclaw.service
|
|
222
222
|
```
|
|
223
223
|
|
|
224
|
-
The status output should show a Node 24 path in `ExecStart`. `foxclaw doctor` also checks the installed service Node path and warns if it is missing or older than 24.
|
|
224
|
+
The status output should show a Node 24+ path in `ExecStart`. `foxclaw doctor` also checks the installed service Node path and warns if it is missing or older than 24.
|
|
225
225
|
|
|
226
226
|
## Does It Run After Reboot?
|
|
227
227
|
|
package/docs/user-manual.md
CHANGED
|
@@ -16,15 +16,15 @@ Your code, shell access, Codex auth, and runtime state stay on the host machine.
|
|
|
16
16
|
|
|
17
17
|
## 1. Full Setup
|
|
18
18
|
|
|
19
|
-
### 1.1 Install Node.js 24
|
|
19
|
+
### 1.1 Install Node.js 24+
|
|
20
20
|
|
|
21
|
-
FoxClaw requires Node.js 24. Check first:
|
|
21
|
+
FoxClaw requires Node.js 24+ and does not require nvm. Check first:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
node -v
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
If this is not `v24
|
|
27
|
+
If this is not `v24...` or newer, install Node 24+ with nvm, fnm, asdf, mise, Volta, Homebrew, or your system package manager. This is an nvm example:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
|
@@ -38,7 +38,7 @@ DEFAULT_CWD=<把绝对工作目录粘贴在这里>
|
|
|
38
38
|
|
|
39
39
|
任务:
|
|
40
40
|
1. 先检查机器环境。如果已经存在 FoxClaw 服务,先报告再改服务。
|
|
41
|
-
2. 确保 Node.js 24+
|
|
41
|
+
2. 确保 Node.js 24+ 可用;如果没有,请用任意合适方式安装或切到 Node 24+,nvm 只是常见选择。
|
|
42
42
|
3. 确保 Codex CLI 存在并且已经登录。如果需要登录,停下来告诉我具体要执行什么。
|
|
43
43
|
4. 用 npm install -g @foxden-app/foxclaw@latest 安装或升级 FoxClaw。
|
|
44
44
|
5. 运行 foxclaw init,然后写入 ~/.foxclaw/.env。不要打印或提交 bot token。
|
package/docs/zh/foxclaw-skill.md
CHANGED
|
@@ -23,17 +23,17 @@ FoxClaw 跑在你的电脑上。手机发消息给 Telegram bot,bot 把消息
|
|
|
23
23
|
- 一个 Codex 可以工作的目录,例如 `~/Projects` 或 `~/Desktop`
|
|
24
24
|
- 第一次安装大约 10-20 分钟
|
|
25
25
|
|
|
26
|
-
## 2. 安装 Node.js 24
|
|
26
|
+
## 2. 安装 Node.js 24+
|
|
27
27
|
|
|
28
|
-
FoxClaw 需要 Node.js 24
|
|
28
|
+
FoxClaw 需要 Node.js 24+,因为它使用 Node 内置 SQLite 运行时。不强依赖 nvm;你可以用 nvm、fnm、asdf、mise、Volta、Homebrew 或系统包管理器安装。
|
|
29
29
|
|
|
30
|
-
如果已经安装 Node 24
|
|
30
|
+
如果已经安装 Node 24+,这条命令会输出 `v24...` 或更高版本:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
node -v
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
如果不是 Node 24
|
|
36
|
+
如果不是 Node 24+,推荐普通用户用 `nvm` 安装,示例:
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
39
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
|
@@ -45,7 +45,7 @@ node -v
|
|
|
45
45
|
npm -v
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
如果使用 nvm 后 `node -v` 仍然显示旧版本,关闭终端,重新打开后运行:
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
51
|
nvm use 24
|
|
@@ -18,7 +18,7 @@ journalctl --user -u foxclaw.service -f
|
|
|
18
18
|
|
|
19
19
|
| 现象 | 含义 | 处理方式 |
|
|
20
20
|
| --- | --- | --- |
|
|
21
|
-
| `[FAIL] node >= 24` | 当前 shell 使用的是旧版 Node.js。 |
|
|
21
|
+
| `[FAIL] node >= 24` | 当前 shell 使用的是旧版 Node.js。 | 先用任意方式安装或切换到 Node.js 24+,再重新执行 `foxclaw doctor`。如果服务仍用旧 Node,从 Node 24+ 的 shell 里重新执行 `foxclaw start`。 |
|
|
22
22
|
| `[FAIL] codex cli available` | `codex` 命令不在 PATH 里。 | 安装 Codex CLI 或修正 PATH,再确认 `codex --version` 可用。 |
|
|
23
23
|
| `[FAIL] telegram bot token configured` | `.env` 里缺少 `TG_BOT_TOKEN`。 | 从 `@BotFather` 复制 token,填入 `.env`。 |
|
|
24
24
|
| `[FAIL] telegram allowed user configured` | `.env` 里缺少 `TG_ALLOWED_USER_ID`。 | 从 `@userinfobot` 获取数字 ID,填入 `.env`。 |
|
|
@@ -26,7 +26,7 @@ journalctl --user -u foxclaw.service -f
|
|
|
26
26
|
|
|
27
27
|
## Node 或 npm 不存在
|
|
28
28
|
|
|
29
|
-
如果看到 `node: command not found` 或 `npm: command not found
|
|
29
|
+
如果看到 `node: command not found` 或 `npm: command not found`,先用你习惯的方式安装 Node.js 24+,例如 nvm、fnm、asdf、mise、Volta、Homebrew 或系统包管理器。下面是 nvm 示例:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
|
@@ -38,7 +38,7 @@ node -v
|
|
|
38
38
|
npm -v
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
如果使用 nvm 后仍然失败,关闭终端,重新打开后运行:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
nvm use 24
|
|
@@ -48,7 +48,7 @@ nvm use 24
|
|
|
48
48
|
|
|
49
49
|
如果 `npm install -g @openai/codex` 或 `npm install -g @foxden-app/foxclaw` 报 `EACCES`、`EPERM`、`permission denied`,说明当前全局 npm 目录不可写。
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
推荐处理方式是使用一个用户级 Node.js 24+,然后重新安装。下面是 nvm 示例:
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
nvm install 24
|
|
@@ -57,7 +57,7 @@ npm install -g @openai/codex
|
|
|
57
57
|
npm install -g @foxden-app/foxclaw
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
除非你很清楚本机 Node 的安装方式,否则不要直接混用 `sudo npm install -g ...`。`sudo`、系统 Node
|
|
60
|
+
除非你很清楚本机 Node 的安装方式,否则不要直接混用 `sudo npm install -g ...`。`sudo`、系统 Node 和用户级 Node 管理器混在一起,常见结果是 PATH 断掉或服务启动时找不到命令。
|
|
61
61
|
|
|
62
62
|
如果 `codex` 已安装但 FoxClaw 找不到它,先定位二进制:
|
|
63
63
|
|
|
@@ -212,9 +212,9 @@ foxclaw restart
|
|
|
212
212
|
|
|
213
213
|
## 服务用了错误的 Node 版本
|
|
214
214
|
|
|
215
|
-
systemd 安装脚本会记录当时正在运行的 Node 绝对路径,不依赖 systemd 去加载 `nvm.sh
|
|
215
|
+
systemd 安装脚本会记录当时正在运行的 Node 绝对路径,不依赖 systemd 去加载 `nvm.sh` 或其它 shell 初始化脚本。无论你用 nvm、fnm、asdf、mise、Volta、Homebrew 还是系统 Node,原则都是:从 Node 24+ 的 shell 里执行 `foxclaw start`,服务之后就固定使用这个 Node 24+ 路径。
|
|
216
216
|
|
|
217
|
-
如果你从 Node 22 或更旧版本的 shell 里安装过服务,请从 Node 24 的 shell
|
|
217
|
+
如果你从 Node 22 或更旧版本的 shell 里安装过服务,请从 Node 24+ 的 shell 重新安装。nvm 用户示例:
|
|
218
218
|
|
|
219
219
|
```bash
|
|
220
220
|
nvm use 24
|
|
@@ -222,7 +222,7 @@ foxclaw start
|
|
|
222
222
|
systemctl --user status foxclaw.service
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
状态输出里应该能看到 Node 24 的路径。`foxclaw doctor` 也会检查已安装服务里的 Node 路径,如果发现路径不存在或版本低于 24,会提示重新运行 `foxclaw start`。
|
|
225
|
+
状态输出里应该能看到 Node 24+ 的路径。`foxclaw doctor` 也会检查已安装服务里的 Node 路径,如果发现路径不存在或版本低于 24,会提示重新运行 `foxclaw start`。
|
|
226
226
|
|
|
227
227
|
## 重启后是否会自动运行
|
|
228
228
|
|
package/docs/zh/user-manual.md
CHANGED
|
@@ -16,15 +16,15 @@ FoxClaw 把本机 Codex 包成一个可从手机控制的服务。Telegram 或
|
|
|
16
16
|
|
|
17
17
|
## 1. 完整安装流程
|
|
18
18
|
|
|
19
|
-
### 1.1 安装 Node.js 24
|
|
19
|
+
### 1.1 安装 Node.js 24+
|
|
20
20
|
|
|
21
|
-
FoxClaw 需要 Node.js 24。先检查:
|
|
21
|
+
FoxClaw 需要 Node.js 24+,不强依赖 nvm。先检查:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
node -v
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
如果不是 `v24
|
|
27
|
+
如果不是 `v24...` 或更高版本,可以用 nvm、fnm、asdf、mise、Volta、Homebrew 或系统包管理器安装 Node 24+。下面是 nvm 示例:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|