@foxden-app/foxclaw 0.3.11 → 0.3.12
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/.env.example +4 -1
- package/dist/main.js +90 -7
- package/dist/systemd.d.ts +5 -0
- package/dist/systemd.js +58 -0
- package/docs/troubleshooting.md +16 -0
- package/docs/user-manual.md +1 -1
- package/docs/zh/troubleshooting.md +16 -0
- package/docs/zh/user-manual.md +1 -1
- package/package.json +1 -1
- package/skills/foxclaw/SKILL.md +1 -0
package/.env.example
CHANGED
|
@@ -29,12 +29,15 @@ TELEGRAM_PREVIEW_THROTTLE_MS=800
|
|
|
29
29
|
THREAD_LIST_LIMIT=10
|
|
30
30
|
CODEX_CLI_BIN=/absolute/path/to/codex
|
|
31
31
|
|
|
32
|
-
# Optional: proxy for ChatGPT/Codex backend requests
|
|
32
|
+
# Optional: standard HTTP(S) proxy for Telegram and ChatGPT/Codex backend requests.
|
|
33
33
|
# Put these in the same env file that `foxclaw start` installs into systemd/launchd.
|
|
34
|
+
# FoxClaw passes them to the service and enables Node's env proxy support.
|
|
34
35
|
# HTTP_PROXY=http://127.0.0.1:7890
|
|
35
36
|
# HTTPS_PROXY=http://127.0.0.1:7890
|
|
36
37
|
# ALL_PROXY=socks5://127.0.0.1:7891
|
|
37
38
|
# NO_PROXY=127.0.0.1,localhost
|
|
39
|
+
# Optional Linux-only fallback when a service must run through proxychains4.
|
|
40
|
+
# FOXCLAW_PROXYCHAINS_CONF=/absolute/path/to/proxychains.conf
|
|
38
41
|
|
|
39
42
|
# Weixin (iLink): run `foxclaw weixin-login` once, then enable:
|
|
40
43
|
# WX_ENABLED=true
|
package/dist/main.js
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
8
8
|
import { APP_HOME, DEFAULT_ENV_PATH, DEFAULT_LOG_PATH, DEFAULT_STATUS_PATH, getLoadedEnvPath, loadConfig, loadEnv, } from './config.js';
|
|
9
9
|
import { acquireProcessLock, LockHeldError } from './lock.js';
|
|
10
10
|
import { readRuntimeStatus, writeRuntimeStatus } from './runtime.js';
|
|
11
|
-
import { refreshFoxclawExecStartDropIns } from './systemd.js';
|
|
11
|
+
import { refreshFoxclawExecStartDropIns, removeFoxclawExecStartDropIns } from './systemd.js';
|
|
12
12
|
const rawCommand = process.argv[2];
|
|
13
13
|
const command = rawCommand || 'serve';
|
|
14
14
|
loadEnv();
|
|
@@ -24,6 +24,7 @@ const PROXY_ENV_KEYS = [
|
|
|
24
24
|
'all_proxy',
|
|
25
25
|
'no_proxy',
|
|
26
26
|
];
|
|
27
|
+
const STANDARD_NODE_PROXY_ENV_KEYS = ['HTTP_PROXY', 'HTTPS_PROXY', 'http_proxy', 'https_proxy'];
|
|
27
28
|
async function main() {
|
|
28
29
|
if (isVersionCommand(command)) {
|
|
29
30
|
console.log(readPackageVersion());
|
|
@@ -493,9 +494,38 @@ function runDoctorChecks() {
|
|
|
493
494
|
passed = false;
|
|
494
495
|
}
|
|
495
496
|
warnIfProxyEnvMissingFromLoadedEnv();
|
|
497
|
+
warnIfProxyConfigNeedsAttention();
|
|
496
498
|
warnIfInstalledServiceNodeLooksWrong();
|
|
497
499
|
return passed;
|
|
498
500
|
}
|
|
501
|
+
function warnIfProxyConfigNeedsAttention() {
|
|
502
|
+
const proxychainsConf = process.env.FOXCLAW_PROXYCHAINS_CONF?.trim() || '';
|
|
503
|
+
if (proxychainsConf) {
|
|
504
|
+
if (process.platform !== 'linux') {
|
|
505
|
+
console.log('[WARN] FOXCLAW_PROXYCHAINS_CONF is only used by systemd on Linux.');
|
|
506
|
+
}
|
|
507
|
+
else if (!fs.existsSync(proxychainsConf)) {
|
|
508
|
+
console.log(`[WARN] FOXCLAW_PROXYCHAINS_CONF does not exist: ${proxychainsConf}`);
|
|
509
|
+
}
|
|
510
|
+
else if (!hasCommand('proxychains4')) {
|
|
511
|
+
console.log('[WARN] proxychains4 is not available, but FOXCLAW_PROXYCHAINS_CONF is set.');
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
console.log(`[OK] proxychains config exists: ${proxychainsConf}`);
|
|
515
|
+
}
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const proxyKeys = PROXY_ENV_KEYS.filter((key) => proxyEnvValue(key));
|
|
519
|
+
if (proxyKeys.length === 0) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
if (hasStandardNodeProxyEnv()) {
|
|
523
|
+
console.log(`[OK] service proxy env configured: ${proxyKeys.join(', ')}`);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
console.log('[WARN] Only ALL_PROXY/all_proxy is configured. Node service proxying works best with HTTP_PROXY/HTTPS_PROXY.');
|
|
527
|
+
console.log('[WARN] For SOCKS-only hosts, set FOXCLAW_PROXYCHAINS_CONF=/absolute/path/to/proxychains.conf and run foxclaw restart.');
|
|
528
|
+
}
|
|
499
529
|
function warnIfProxyEnvMissingFromLoadedEnv() {
|
|
500
530
|
const envPath = serviceEnvPath();
|
|
501
531
|
const proxyUpdates = detectMissingProxyEnv(envPath);
|
|
@@ -519,7 +549,7 @@ function warnIfInstalledServiceNodeLooksWrong() {
|
|
|
519
549
|
return;
|
|
520
550
|
}
|
|
521
551
|
const execStart = text.match(/^ExecStart=(.+)$/m)?.[1]?.trim();
|
|
522
|
-
const nodePath = execStart ?
|
|
552
|
+
const nodePath = execStart ? extractNodePathFromExecStart(execStart) : '';
|
|
523
553
|
if (!nodePath) {
|
|
524
554
|
return;
|
|
525
555
|
}
|
|
@@ -538,6 +568,14 @@ function warnIfInstalledServiceNodeLooksWrong() {
|
|
|
538
568
|
console.log(`[WARN] installed service node is older than 24: ${nodePath}${version ? ` (${version})` : ''}`);
|
|
539
569
|
console.log('[WARN] Run foxclaw start from a Node 24 shell to refresh the service unit.');
|
|
540
570
|
}
|
|
571
|
+
function extractNodePathFromExecStart(execStart) {
|
|
572
|
+
const tokens = execStart.split(/\s+/).map(systemdUnescape).filter(Boolean);
|
|
573
|
+
const directNode = tokens[0] || '';
|
|
574
|
+
if (path.basename(directNode) === 'node') {
|
|
575
|
+
return directNode;
|
|
576
|
+
}
|
|
577
|
+
return tokens.find((token) => path.basename(token) === 'node') || directNode;
|
|
578
|
+
}
|
|
541
579
|
function installSystemd() {
|
|
542
580
|
if (!hasCommand('systemctl')) {
|
|
543
581
|
console.error('systemctl not found (need systemd)');
|
|
@@ -551,6 +589,12 @@ function installSystemd() {
|
|
|
551
589
|
const nodeBin = process.execPath;
|
|
552
590
|
const nodeDir = path.dirname(nodeBin);
|
|
553
591
|
const pathValue = buildServicePath(nodeDir);
|
|
592
|
+
const proxychainsConf = process.env.FOXCLAW_PROXYCHAINS_CONF?.trim() || '';
|
|
593
|
+
const proxychainsBin = proxychainsConf ? resolveCommand('proxychains4') || '/usr/bin/proxychains4' : '';
|
|
594
|
+
const nodeProxyArgs = !proxychainsConf && hasStandardNodeProxyEnv() ? ' --use-env-proxy' : '';
|
|
595
|
+
const execStart = proxychainsConf
|
|
596
|
+
? `${systemdEscape(proxychainsBin)} -f ${systemdEscape(proxychainsConf)} ${systemdEscape(nodeBin)} ${systemdEscape(entryPoint)} serve`
|
|
597
|
+
: `${systemdEscape(nodeBin)}${nodeProxyArgs} ${systemdEscape(entryPoint)} serve`;
|
|
554
598
|
fs.mkdirSync(userSystemdDir, { recursive: true });
|
|
555
599
|
fs.mkdirSync(configDir, { recursive: true });
|
|
556
600
|
fs.mkdirSync(path.join(APP_HOME, 'logs'), { recursive: true });
|
|
@@ -566,12 +610,13 @@ StartLimitBurst=5
|
|
|
566
610
|
[Service]
|
|
567
611
|
Type=simple
|
|
568
612
|
WorkingDirectory=${systemdEscape(configDir)}
|
|
613
|
+
EnvironmentFile=-${systemdEscape(envPath)}
|
|
569
614
|
Environment=HOME=${systemdEscape(process.env.HOME || '')}
|
|
570
615
|
Environment=USER=${systemdEscape(process.env.USER || '')}
|
|
571
616
|
Environment=LOGNAME=${systemdEscape(process.env.LOGNAME || process.env.USER || '')}
|
|
572
617
|
Environment=PATH=${systemdEscape(pathValue)}
|
|
573
618
|
Environment=FOXCLAW_ENV=${systemdEscape(envPath)}
|
|
574
|
-
ExecStart=${
|
|
619
|
+
ExecStart=${execStart}
|
|
575
620
|
Restart=always
|
|
576
621
|
RestartSec=10
|
|
577
622
|
TimeoutStopSec=45
|
|
@@ -580,9 +625,23 @@ KillMode=process
|
|
|
580
625
|
[Install]
|
|
581
626
|
WantedBy=default.target
|
|
582
627
|
`);
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
628
|
+
if (proxychainsConf) {
|
|
629
|
+
console.log(`[OK] systemd proxychains enabled: ${proxychainsConf}`);
|
|
630
|
+
}
|
|
631
|
+
else if (nodeProxyArgs) {
|
|
632
|
+
console.log('[OK] systemd Node env proxy enabled');
|
|
633
|
+
}
|
|
634
|
+
if (proxychainsConf) {
|
|
635
|
+
const dropInUpdates = removeFoxclawExecStartDropIns(userSystemdDir, unitName);
|
|
636
|
+
for (const update of dropInUpdates) {
|
|
637
|
+
console.log(`[OK] removed stale FoxClaw ExecStart override: ${update.path}`);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
const dropInUpdates = refreshFoxclawExecStartDropIns(userSystemdDir, unitName, escapedEntryPoint);
|
|
642
|
+
for (const update of dropInUpdates) {
|
|
643
|
+
console.log(`[OK] updated FoxClaw ExecStart override: ${update.path}`);
|
|
644
|
+
}
|
|
586
645
|
}
|
|
587
646
|
spawnChecked('systemctl', ['--user', 'daemon-reload']);
|
|
588
647
|
spawnChecked('systemctl', ['--user', 'enable', unitName]);
|
|
@@ -625,6 +684,9 @@ function installLaunchd() {
|
|
|
625
684
|
const plist = path.join(home, 'Library', 'LaunchAgents', 'app.foxden.foxclaw.plist');
|
|
626
685
|
const envPath = serviceEnvPath();
|
|
627
686
|
const configDir = path.dirname(envPath);
|
|
687
|
+
const nodeProxyArgs = hasStandardNodeProxyEnv() ? ['--use-env-proxy'] : [];
|
|
688
|
+
const nodeProxyArgXml = nodeProxyArgs.map((arg) => ` <string>${xmlEscape(arg)}</string>`).join('\n');
|
|
689
|
+
const proxyEnvXml = buildLaunchdProxyEnvironmentXml();
|
|
628
690
|
fs.mkdirSync(path.dirname(plist), { recursive: true });
|
|
629
691
|
fs.mkdirSync(configDir, { recursive: true });
|
|
630
692
|
fs.mkdirSync(path.join(APP_HOME, 'logs'), { recursive: true });
|
|
@@ -637,7 +699,7 @@ function installLaunchd() {
|
|
|
637
699
|
<key>ProgramArguments</key>
|
|
638
700
|
<array>
|
|
639
701
|
<string>${xmlEscape(process.execPath)}</string>
|
|
640
|
-
<string>${xmlEscape(entryPoint)}</string>
|
|
702
|
+
${nodeProxyArgXml ? `${nodeProxyArgXml}\n` : ''} <string>${xmlEscape(entryPoint)}</string>
|
|
641
703
|
<string>serve</string>
|
|
642
704
|
</array>
|
|
643
705
|
<key>WorkingDirectory</key>
|
|
@@ -654,6 +716,7 @@ function installLaunchd() {
|
|
|
654
716
|
<string>${xmlEscape(process.env.LOGNAME || process.env.USER || '')}</string>
|
|
655
717
|
<key>FOXCLAW_ENV</key>
|
|
656
718
|
<string>${xmlEscape(envPath)}</string>
|
|
719
|
+
${proxyEnvXml}
|
|
657
720
|
</dict>
|
|
658
721
|
<key>RunAtLoad</key>
|
|
659
722
|
<true/>
|
|
@@ -669,6 +732,9 @@ function installLaunchd() {
|
|
|
669
732
|
spawnSync('launchctl', ['unload', plist], { stdio: 'ignore' });
|
|
670
733
|
spawnChecked('launchctl', ['load', plist]);
|
|
671
734
|
console.log(`Installed ${plist}`);
|
|
735
|
+
if (nodeProxyArgs.length > 0) {
|
|
736
|
+
console.log('[OK] launchd Node env proxy enabled');
|
|
737
|
+
}
|
|
672
738
|
}
|
|
673
739
|
function stopLaunchd() {
|
|
674
740
|
if (process.platform !== 'darwin') {
|
|
@@ -699,6 +765,23 @@ function buildServicePath(nodeDir) {
|
|
|
699
765
|
function serviceEnvPath() {
|
|
700
766
|
return path.resolve(process.env.FOXCLAW_ENV?.trim() || getLoadedEnvPath() || DEFAULT_ENV_PATH);
|
|
701
767
|
}
|
|
768
|
+
function hasStandardNodeProxyEnv() {
|
|
769
|
+
return STANDARD_NODE_PROXY_ENV_KEYS.some((key) => Boolean(proxyEnvValue(key)));
|
|
770
|
+
}
|
|
771
|
+
function proxyEnvValue(key) {
|
|
772
|
+
return process.env[key]?.trim() || '';
|
|
773
|
+
}
|
|
774
|
+
function buildLaunchdProxyEnvironmentXml() {
|
|
775
|
+
const entries = [];
|
|
776
|
+
for (const key of PROXY_ENV_KEYS) {
|
|
777
|
+
const value = proxyEnvValue(key);
|
|
778
|
+
if (!value)
|
|
779
|
+
continue;
|
|
780
|
+
entries.push(` <key>${xmlEscape(key)}</key>`);
|
|
781
|
+
entries.push(` <string>${xmlEscape(value)}</string>`);
|
|
782
|
+
}
|
|
783
|
+
return entries.length > 0 ? `${entries.join('\n')}\n` : '';
|
|
784
|
+
}
|
|
702
785
|
function spawnChecked(commandName, args) {
|
|
703
786
|
const result = spawnSync(commandName, args, { stdio: 'inherit' });
|
|
704
787
|
if (result.status !== 0) {
|
package/dist/systemd.d.ts
CHANGED
|
@@ -3,7 +3,12 @@ export interface SystemdDropInUpdate {
|
|
|
3
3
|
replacements: number;
|
|
4
4
|
}
|
|
5
5
|
export declare function refreshFoxclawExecStartDropIns(userSystemdDir: string, unitName: string, escapedEntryPoint: string): SystemdDropInUpdate[];
|
|
6
|
+
export declare function removeFoxclawExecStartDropIns(userSystemdDir: string, unitName: string): SystemdDropInUpdate[];
|
|
6
7
|
export declare function refreshFoxclawExecStartText(text: string, escapedEntryPoint: string): {
|
|
7
8
|
text: string;
|
|
8
9
|
replacements: number;
|
|
9
10
|
};
|
|
11
|
+
export declare function removeFoxclawExecStartText(text: string): {
|
|
12
|
+
text: string;
|
|
13
|
+
replacements: number;
|
|
14
|
+
};
|
package/dist/systemd.js
CHANGED
|
@@ -29,6 +29,39 @@ export function refreshFoxclawExecStartDropIns(userSystemdDir, unitName, escaped
|
|
|
29
29
|
}
|
|
30
30
|
return updates;
|
|
31
31
|
}
|
|
32
|
+
export function removeFoxclawExecStartDropIns(userSystemdDir, unitName) {
|
|
33
|
+
const dropInDir = path.join(userSystemdDir, `${unitName}.d`);
|
|
34
|
+
let names;
|
|
35
|
+
try {
|
|
36
|
+
names = fs.readdirSync(dropInDir).filter((name) => name.endsWith('.conf')).sort();
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const updates = [];
|
|
42
|
+
for (const name of names) {
|
|
43
|
+
const filePath = path.join(dropInDir, name);
|
|
44
|
+
let before = '';
|
|
45
|
+
try {
|
|
46
|
+
before = fs.readFileSync(filePath, 'utf8');
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const { text, replacements } = removeFoxclawExecStartText(before);
|
|
52
|
+
if (replacements === 0 || text === before) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (isEmptyServiceDropIn(text)) {
|
|
56
|
+
fs.rmSync(filePath, { force: true });
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
fs.writeFileSync(filePath, text, 'utf8');
|
|
60
|
+
}
|
|
61
|
+
updates.push({ path: filePath, replacements });
|
|
62
|
+
}
|
|
63
|
+
return updates;
|
|
64
|
+
}
|
|
32
65
|
export function refreshFoxclawExecStartText(text, escapedEntryPoint) {
|
|
33
66
|
let replacements = 0;
|
|
34
67
|
const lines = text.split(/(\r?\n)/);
|
|
@@ -43,3 +76,28 @@ export function refreshFoxclawExecStartText(text, escapedEntryPoint) {
|
|
|
43
76
|
});
|
|
44
77
|
return { text: refreshed.join(''), replacements };
|
|
45
78
|
}
|
|
79
|
+
export function removeFoxclawExecStartText(text) {
|
|
80
|
+
const hasFoxclawExecStart = text
|
|
81
|
+
.split(/\r?\n/)
|
|
82
|
+
.some((line) => line.startsWith('ExecStart=') && FOXCLAW_MAIN_PATH_RE.test(line));
|
|
83
|
+
if (!hasFoxclawExecStart) {
|
|
84
|
+
return { text, replacements: 0 };
|
|
85
|
+
}
|
|
86
|
+
let replacements = 0;
|
|
87
|
+
const lines = text.split(/(\r?\n)/);
|
|
88
|
+
const cleaned = lines.map((part) => {
|
|
89
|
+
if (!part.startsWith('ExecStart=')) {
|
|
90
|
+
return part;
|
|
91
|
+
}
|
|
92
|
+
replacements += 1;
|
|
93
|
+
return '';
|
|
94
|
+
});
|
|
95
|
+
return { text: cleaned.join(''), replacements };
|
|
96
|
+
}
|
|
97
|
+
function isEmptyServiceDropIn(text) {
|
|
98
|
+
const meaningfulLines = text
|
|
99
|
+
.split(/\r?\n/)
|
|
100
|
+
.map((line) => line.trim())
|
|
101
|
+
.filter(Boolean);
|
|
102
|
+
return meaningfulLines.length === 0 || (meaningfulLines.length === 1 && meaningfulLines[0] === '[Service]');
|
|
103
|
+
}
|
package/docs/troubleshooting.md
CHANGED
|
@@ -203,12 +203,28 @@ ALL_PROXY=socks5://127.0.0.1:20170
|
|
|
203
203
|
NO_PROXY=127.0.0.1,localhost
|
|
204
204
|
```
|
|
205
205
|
|
|
206
|
+
When `HTTP_PROXY` or `HTTPS_PROXY` is configured, FoxClaw passes those variables to systemd/launchd explicitly and starts Node with `--use-env-proxy`. Do not rely on proxy variables from the current shell; service processes do not inherit them automatically.
|
|
207
|
+
|
|
206
208
|
Restart FoxClaw after editing. The restart also restarts the managed Codex app-server so the new proxy environment takes effect:
|
|
207
209
|
|
|
208
210
|
```bash
|
|
209
211
|
foxclaw restart
|
|
210
212
|
```
|
|
211
213
|
|
|
214
|
+
If a Linux host must use `proxychains4` to reach Telegram or ChatGPT, do not hand-write a systemd drop-in that overrides `ExecStart`. Add this to the FoxClaw env file instead:
|
|
215
|
+
|
|
216
|
+
```dotenv
|
|
217
|
+
FOXCLAW_PROXYCHAINS_CONF=/home/wuya/.proxychains-rt.conf
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Then run:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
foxclaw restart
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
FoxClaw writes proxychains into the main service and removes stale FoxClaw `ExecStart` overrides, so later upgrades still only need the normal `pnpm install -g` and `foxclaw restart`.
|
|
227
|
+
|
|
212
228
|
## Service Starts With The Wrong Node Version
|
|
213
229
|
|
|
214
230
|
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.
|
package/docs/user-manual.md
CHANGED
|
@@ -100,7 +100,7 @@ Both install the same published npm package. Use one global package manager cons
|
|
|
100
100
|
|
|
101
101
|
### 1.6 Fill In The Config
|
|
102
102
|
|
|
103
|
-
`foxclaw init` creates the default config file at `~/.foxclaw/.env` and prompts for the Telegram bot token, your numeric Telegram user id, and the default workspace. If the current shell has proxy variables such as `HTTP_PROXY`, `HTTPS_PROXY`, or `ALL_PROXY`, it also asks whether to save them into the FoxClaw config
|
|
103
|
+
`foxclaw init` creates the default config file at `~/.foxclaw/.env` and prompts for the Telegram bot token, your numeric Telegram user id, and the default workspace. If the current shell has proxy variables such as `HTTP_PROXY`, `HTTPS_PROXY`, or `ALL_PROXY`, it also asks whether to save them into the FoxClaw config. When `HTTP_PROXY` or `HTTPS_PROXY` is configured, FoxClaw passes it to systemd/launchd explicitly and enables Node's env proxy support. Press Enter on any field to skip it, then edit manually if needed:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
106
|
$EDITOR ~/.foxclaw/.env
|
|
@@ -204,12 +204,28 @@ ALL_PROXY=socks5://127.0.0.1:20170
|
|
|
204
204
|
NO_PROXY=127.0.0.1,localhost
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
+
只要配置了 `HTTP_PROXY` 或 `HTTPS_PROXY`,FoxClaw 安装 systemd/launchd 时会把这些变量显式传给服务,并给 Node 加上 `--use-env-proxy`。不要依赖“当前 shell 里有代理变量”,服务进程不会自动继承它们。
|
|
208
|
+
|
|
207
209
|
改完后重启 FoxClaw。重启会同时重启托管的 Codex app-server,让新代理生效:
|
|
208
210
|
|
|
209
211
|
```bash
|
|
210
212
|
foxclaw restart
|
|
211
213
|
```
|
|
212
214
|
|
|
215
|
+
如果这台 Linux 机器必须用 `proxychains4` 才能访问 Telegram 或 ChatGPT,不要手写 systemd drop-in 覆盖 `ExecStart`。在 FoxClaw env 文件里写:
|
|
216
|
+
|
|
217
|
+
```dotenv
|
|
218
|
+
FOXCLAW_PROXYCHAINS_CONF=/home/wuya/.proxychains-rt.conf
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
然后运行:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
foxclaw restart
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
FoxClaw 会把 proxychains 写进主 service,并清理旧的 FoxClaw `ExecStart` 覆盖,后续升级仍然只需要正常 `pnpm install -g` 和 `foxclaw restart`。
|
|
228
|
+
|
|
213
229
|
## 服务用了错误的 Node 版本
|
|
214
230
|
|
|
215
231
|
systemd 安装脚本会记录当时正在运行的 Node 绝对路径,不依赖 systemd 去加载 `nvm.sh` 或其它 shell 初始化脚本。无论你用 nvm、fnm、asdf、mise、Volta、Homebrew 还是系统 Node,原则都是:从 Node 24+ 的 shell 里执行 `foxclaw start`,服务之后就固定使用这个 Node 24+ 路径。
|
package/docs/zh/user-manual.md
CHANGED
|
@@ -100,7 +100,7 @@ foxclaw init
|
|
|
100
100
|
|
|
101
101
|
### 1.6 填写配置
|
|
102
102
|
|
|
103
|
-
`foxclaw init` 会创建默认配置文件 `~/.foxclaw/.env`,并提示填写 Telegram bot token、Telegram 数字用户 ID 和默认工作目录。如果当前 shell 里有 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 等代理变量,它也会询问是否写入 FoxClaw
|
|
103
|
+
`foxclaw init` 会创建默认配置文件 `~/.foxclaw/.env`,并提示填写 Telegram bot token、Telegram 数字用户 ID 和默认工作目录。如果当前 shell 里有 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 等代理变量,它也会询问是否写入 FoxClaw 配置。配置了 `HTTP_PROXY` 或 `HTTPS_PROXY` 后,FoxClaw 会在安装服务时显式传给 systemd/launchd,并启用 Node 的 env proxy。任何一项都可以直接回车跳过,之后再手动编辑:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
106
|
$EDITOR ~/.foxclaw/.env
|
package/package.json
CHANGED
package/skills/foxclaw/SKILL.md
CHANGED
|
@@ -184,6 +184,7 @@ Use this checklist when the user asks for standard closing actions, release wrap
|
|
|
184
184
|
- If the user has a pnpm global FoxClaw install, prefer `pnpm add -g <repo-path>` so the global `foxclaw` points at the local repo.
|
|
185
185
|
- Rebuild before restarting because local linked installs run `dist/main.js`.
|
|
186
186
|
- Refresh systemd with the existing service env path, for example `FOXCLAW_ENV=<existing-env> <node24> dist/main.js install-systemd`. Do not run `install-systemd` from the repo without `FOXCLAW_ENV`, because it may rewrite the service to use the repo `.env`.
|
|
187
|
+
- Do not create systemd drop-ins that override FoxClaw `ExecStart`. For Linux hosts that require proxychains, set `FOXCLAW_PROXYCHAINS_CONF=/absolute/path/to/proxychains.conf` in the FoxClaw env file and rerun `foxclaw restart`.
|
|
187
188
|
- For macOS launchd, use the launchd install/start path from this skill and verify with `node dist/main.js status`.
|
|
188
189
|
- Verify the running service reports the expected FoxClaw version in `status`.
|
|
189
190
|
- If `doctor` fails only because `DEFAULT_CWD` is missing, report that separately; do not treat it as evidence that the service update failed.
|