@foxden-app/foxclaw 0.3.0 → 0.3.2
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 +15 -22
- package/README_EN.md +16 -23
- package/dist/main.js +217 -13
- package/docs/agent-assisted-install.md +1 -24
- package/docs/install-for-beginners.md +5 -5
- package/docs/troubleshooting.md +5 -26
- package/docs/user-manual.md +2 -1
- package/docs/zh/agent-assisted-install.md +1 -24
- package/docs/zh/install-for-beginners.md +8 -17
- package/docs/zh/troubleshooting.md +5 -11
- package/docs/zh/user-manual.md +2 -1
- package/package.json +67 -65
package/README.md
CHANGED
|
@@ -51,7 +51,6 @@ FoxClaw(狸爪)的目标很直接:让你用手机控制本机的 Codex,
|
|
|
51
51
|
```bash
|
|
52
52
|
npm install -g @foxden-app/foxclaw
|
|
53
53
|
foxclaw init
|
|
54
|
-
$EDITOR ~/.foxclaw/.env
|
|
55
54
|
foxclaw doctor
|
|
56
55
|
foxclaw start
|
|
57
56
|
```
|
|
@@ -61,11 +60,12 @@ pnpm 用户:
|
|
|
61
60
|
```bash
|
|
62
61
|
pnpm add -g @foxden-app/foxclaw
|
|
63
62
|
foxclaw init
|
|
64
|
-
$EDITOR ~/.foxclaw/.env
|
|
65
63
|
foxclaw doctor
|
|
66
64
|
foxclaw start
|
|
67
65
|
```
|
|
68
66
|
|
|
67
|
+
`foxclaw init` 会创建 `~/.foxclaw/.env`,并在终端里提示填写 Telegram bot token、Telegram 数字用户 ID 和默认工作目录。任何一项都可以直接回车跳过,之后再用 `$EDITOR ~/.foxclaw/.env` 手动修改。
|
|
68
|
+
|
|
69
69
|
跑 `doctor` 或 `start` 之前先把 `.env` 填好。私聊模式最小配置:
|
|
70
70
|
|
|
71
71
|
```dotenv
|
|
@@ -139,6 +139,14 @@ systemctl --user status foxclaw.service
|
|
|
139
139
|
journalctl --user -u foxclaw.service -f
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
+
也可以直接用包装命令:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
foxclaw status
|
|
146
|
+
foxclaw restart
|
|
147
|
+
foxclaw stop
|
|
148
|
+
```
|
|
149
|
+
|
|
142
150
|
需要前台调试时:
|
|
143
151
|
|
|
144
152
|
```bash
|
|
@@ -157,26 +165,9 @@ foxclaw serve
|
|
|
157
165
|
|
|
158
166
|
可通过 `STORE_PATH`、`LOCK_PATH`、`CODEX_APP_SERVER_STATE_PATH`、`CODEX_APP_SERVER_LOG_PATH` 覆盖。
|
|
159
167
|
|
|
160
|
-
##
|
|
161
|
-
|
|
162
|
-
FoxClaw 最初 fork 自 `Gan-Xing/telegram-codex-app-bridge`,继续以 MIT License 分发。
|
|
163
|
-
|
|
164
|
-
升级已有安装:
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
systemctl --user disable --now telegram-codex-app-bridge.service 2>/dev/null || true
|
|
168
|
-
test -e ~/.foxclaw || cp -a ~/.telegram-codex-app-bridge ~/.foxclaw
|
|
169
|
-
foxclaw start
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
macOS launchd 用户先卸载旧 plist:
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
launchctl unload ~/Library/LaunchAgents/com.ganxing.telegram-codex-app-bridge.plist 2>/dev/null || true
|
|
176
|
-
foxclaw start
|
|
177
|
-
```
|
|
168
|
+
## 鸣谢
|
|
178
169
|
|
|
179
|
-
|
|
170
|
+
FoxClaw 最初基于 `Gan-Xing/telegram-codex-app-bridge` fork 演进而来,继续以 MIT License 分发。感谢原项目对 Telegram 与 Codex 本地桥接思路的探索。
|
|
180
171
|
|
|
181
172
|
## Telegram 设置
|
|
182
173
|
|
|
@@ -284,7 +275,7 @@ foxclaw weixin-login
|
|
|
284
275
|
|
|
285
276
|
## 故障排查
|
|
286
277
|
|
|
287
|
-
`doctor` 报错、Telegram
|
|
278
|
+
`doctor` 报错、Telegram 没回复、服务日志看不懂、重启行为异常——都看 [故障排查](./docs/zh/troubleshooting.md)。
|
|
288
279
|
|
|
289
280
|
## 运维命令
|
|
290
281
|
|
|
@@ -292,6 +283,8 @@ foxclaw weixin-login
|
|
|
292
283
|
foxclaw doctor
|
|
293
284
|
foxclaw status
|
|
294
285
|
foxclaw start
|
|
286
|
+
foxclaw restart
|
|
287
|
+
foxclaw stop
|
|
295
288
|
foxclaw uninstall-systemd
|
|
296
289
|
```
|
|
297
290
|
|
package/README_EN.md
CHANGED
|
@@ -51,7 +51,6 @@ The minimum install needs only a Telegram bot token, your numeric Telegram user
|
|
|
51
51
|
```bash
|
|
52
52
|
npm install -g @foxden-app/foxclaw
|
|
53
53
|
foxclaw init
|
|
54
|
-
$EDITOR ~/.foxclaw/.env
|
|
55
54
|
foxclaw doctor
|
|
56
55
|
foxclaw start
|
|
57
56
|
```
|
|
@@ -61,12 +60,13 @@ pnpm users:
|
|
|
61
60
|
```bash
|
|
62
61
|
pnpm add -g @foxden-app/foxclaw
|
|
63
62
|
foxclaw init
|
|
64
|
-
$EDITOR ~/.foxclaw/.env
|
|
65
63
|
foxclaw doctor
|
|
66
64
|
foxclaw start
|
|
67
65
|
```
|
|
68
66
|
|
|
69
|
-
|
|
67
|
+
`foxclaw init` creates `~/.foxclaw/.env` and prompts for the Telegram bot token, your numeric Telegram user id, and the default workspace. Press Enter on any field to skip it and edit later with `$EDITOR ~/.foxclaw/.env`.
|
|
68
|
+
|
|
69
|
+
Fill `.env` before running `doctor` or `start`. Minimum private-chat config:
|
|
70
70
|
|
|
71
71
|
```dotenv
|
|
72
72
|
TG_BOT_TOKEN=123456:telegram-token
|
|
@@ -139,6 +139,14 @@ systemctl --user status foxclaw.service
|
|
|
139
139
|
journalctl --user -u foxclaw.service -f
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
+
You can also use the wrapper commands:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
foxclaw status
|
|
146
|
+
foxclaw restart
|
|
147
|
+
foxclaw stop
|
|
148
|
+
```
|
|
149
|
+
|
|
142
150
|
For foreground debugging:
|
|
143
151
|
|
|
144
152
|
```bash
|
|
@@ -157,26 +165,9 @@ Default runtime files are stored under `~/.foxclaw`:
|
|
|
157
165
|
|
|
158
166
|
Override with `STORE_PATH`, `LOCK_PATH`, `CODEX_APP_SERVER_STATE_PATH`, and `CODEX_APP_SERVER_LOG_PATH`.
|
|
159
167
|
|
|
160
|
-
##
|
|
161
|
-
|
|
162
|
-
FoxClaw was originally forked from `Gan-Xing/telegram-codex-app-bridge` and remains distributed under the MIT License.
|
|
163
|
-
|
|
164
|
-
When upgrading an existing local install:
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
systemctl --user disable --now telegram-codex-app-bridge.service 2>/dev/null || true
|
|
168
|
-
test -e ~/.foxclaw || cp -a ~/.telegram-codex-app-bridge ~/.foxclaw
|
|
169
|
-
foxclaw start
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
For launchd installs, unload the old plist if present:
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
launchctl unload ~/Library/LaunchAgents/com.ganxing.telegram-codex-app-bridge.plist 2>/dev/null || true
|
|
176
|
-
foxclaw start
|
|
177
|
-
```
|
|
168
|
+
## Acknowledgements
|
|
178
169
|
|
|
179
|
-
|
|
170
|
+
FoxClaw originally evolved from a fork of `Gan-Xing/telegram-codex-app-bridge` and remains distributed under the MIT License. Thanks to that project for exploring the Telegram-to-local-Codex bridge pattern.
|
|
180
171
|
|
|
181
172
|
## Telegram Setup
|
|
182
173
|
|
|
@@ -284,7 +275,7 @@ This repo ships a Codex skill at [`skills/foxclaw`](./skills/foxclaw). Use it wh
|
|
|
284
275
|
|
|
285
276
|
## Troubleshooting
|
|
286
277
|
|
|
287
|
-
See [Troubleshooting](./docs/troubleshooting.md) for `doctor` failures, Telegram no-reply cases, service logs, reboot behavior
|
|
278
|
+
See [Troubleshooting](./docs/troubleshooting.md) for `doctor` failures, Telegram no-reply cases, service logs, and reboot behavior.
|
|
288
279
|
|
|
289
280
|
## Operations
|
|
290
281
|
|
|
@@ -292,6 +283,8 @@ See [Troubleshooting](./docs/troubleshooting.md) for `doctor` failures, Telegram
|
|
|
292
283
|
foxclaw doctor
|
|
293
284
|
foxclaw status
|
|
294
285
|
foxclaw start
|
|
286
|
+
foxclaw restart
|
|
287
|
+
foxclaw stop
|
|
295
288
|
foxclaw uninstall-systemd
|
|
296
289
|
```
|
|
297
290
|
|
package/dist/main.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import process from 'node:process';
|
|
5
|
+
import { createInterface } from 'node:readline/promises';
|
|
5
6
|
import { spawnSync } from 'node:child_process';
|
|
6
7
|
import { fileURLToPath } from 'node:url';
|
|
7
8
|
import { APP_HOME, DEFAULT_ENV_PATH, DEFAULT_LOG_PATH, DEFAULT_STATUS_PATH, loadConfig, loadEnv, } from './config.js';
|
|
@@ -13,7 +14,7 @@ const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
|
13
14
|
const entryPoint = fileURLToPath(import.meta.url);
|
|
14
15
|
async function main() {
|
|
15
16
|
if (command === 'init') {
|
|
16
|
-
initConfig();
|
|
17
|
+
await initConfig();
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
20
|
if (command === 'install-systemd') {
|
|
@@ -23,7 +24,16 @@ async function main() {
|
|
|
23
24
|
}
|
|
24
25
|
if (command === 'start') {
|
|
25
26
|
requireNode24(command);
|
|
26
|
-
startService();
|
|
27
|
+
startService('start');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (command === 'restart') {
|
|
31
|
+
requireNode24(command);
|
|
32
|
+
startService('restart');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (command === 'stop') {
|
|
36
|
+
stopService();
|
|
27
37
|
return;
|
|
28
38
|
}
|
|
29
39
|
if (command === 'uninstall-systemd') {
|
|
@@ -134,22 +144,182 @@ async function runServeCli() {
|
|
|
134
144
|
throw error;
|
|
135
145
|
}
|
|
136
146
|
}
|
|
137
|
-
function initConfig() {
|
|
147
|
+
async function initConfig() {
|
|
138
148
|
const envPath = process.env.FOXCLAW_ENV?.trim() || DEFAULT_ENV_PATH;
|
|
139
149
|
fs.mkdirSync(path.dirname(envPath), { recursive: true });
|
|
140
|
-
|
|
150
|
+
const existed = fs.existsSync(envPath);
|
|
151
|
+
if (existed) {
|
|
141
152
|
console.log(`Config already exists: ${envPath}`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
const examplePath = path.join(packageRoot, '.env.example');
|
|
156
|
+
fs.copyFileSync(examplePath, envPath);
|
|
157
|
+
console.log(`Created ${envPath}`);
|
|
158
|
+
}
|
|
159
|
+
if (!canPromptForInit()) {
|
|
160
|
+
console.log(`Edit it manually, then run: foxclaw doctor`);
|
|
142
161
|
return;
|
|
143
162
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
163
|
+
await configureEnvInteractively(envPath, existed);
|
|
164
|
+
}
|
|
165
|
+
function canPromptForInit() {
|
|
166
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.argv.includes('--no-input') && !process.argv.includes('--skip-prompts'));
|
|
167
|
+
}
|
|
168
|
+
async function configureEnvInteractively(envPath, existed) {
|
|
169
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
170
|
+
try {
|
|
171
|
+
if (existed) {
|
|
172
|
+
const updateExisting = (await rl.question('Update Telegram/workspace setup fields now? [y/N]: ')).trim().toLowerCase();
|
|
173
|
+
if (updateExisting !== 'y' && updateExisting !== 'yes') {
|
|
174
|
+
console.log(`Edit it manually, then run: foxclaw doctor`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
console.log('Interactive setup. Press Enter to skip any field and edit it later.');
|
|
180
|
+
}
|
|
181
|
+
const updates = {};
|
|
182
|
+
const skipped = [];
|
|
183
|
+
const warnings = [];
|
|
184
|
+
const token = sanitizeEnvInput(await rl.question('Telegram bot token (TG_BOT_TOKEN): '));
|
|
185
|
+
if (token) {
|
|
186
|
+
updates.TG_BOT_TOKEN = token;
|
|
187
|
+
if (!/^\d+:[A-Za-z0-9_-]+$/.test(token)) {
|
|
188
|
+
warnings.push('TG_BOT_TOKEN does not look like a standard Telegram bot token.');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
skipped.push('TG_BOT_TOKEN');
|
|
193
|
+
}
|
|
194
|
+
const userId = sanitizeEnvInput(await rl.question('Telegram numeric user ID (TG_ALLOWED_USER_ID): '));
|
|
195
|
+
if (userId) {
|
|
196
|
+
if (/^\d+$/.test(userId)) {
|
|
197
|
+
updates.TG_ALLOWED_USER_ID = userId;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
skipped.push('TG_ALLOWED_USER_ID');
|
|
201
|
+
warnings.push('TG_ALLOWED_USER_ID must be numeric; use the Id from @userinfobot, not @username.');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
skipped.push('TG_ALLOWED_USER_ID');
|
|
206
|
+
}
|
|
207
|
+
const cwdDefault = defaultInitCwd();
|
|
208
|
+
const cwdPrompt = cwdDefault
|
|
209
|
+
? `Default Codex workspace (DEFAULT_CWD) [${cwdDefault}]: `
|
|
210
|
+
: 'Default Codex workspace (DEFAULT_CWD): ';
|
|
211
|
+
const cwdAnswer = sanitizeEnvInput(await rl.question(cwdPrompt));
|
|
212
|
+
const cwd = cwdAnswer ? normalizeUserPath(cwdAnswer) : cwdDefault;
|
|
213
|
+
if (cwd) {
|
|
214
|
+
updates.DEFAULT_CWD = cwd;
|
|
215
|
+
warnings.push(...validateDefaultCwd(cwd));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
skipped.push('DEFAULT_CWD');
|
|
219
|
+
}
|
|
220
|
+
const codexBin = resolveCommand('codex');
|
|
221
|
+
if (codexBin) {
|
|
222
|
+
updates.CODEX_CLI_BIN = codexBin;
|
|
223
|
+
}
|
|
224
|
+
const updatedKeys = Object.keys(updates);
|
|
225
|
+
if (updatedKeys.length > 0) {
|
|
226
|
+
writeEnvUpdates(envPath, updates);
|
|
227
|
+
console.log(`Saved ${updatedKeys.join(', ')} to ${envPath}`);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
console.log('No setup fields changed.');
|
|
231
|
+
}
|
|
232
|
+
for (const warning of warnings) {
|
|
233
|
+
console.log(`[WARN] ${warning}`);
|
|
234
|
+
}
|
|
235
|
+
if (skipped.length > 0) {
|
|
236
|
+
console.log(`Skipped ${skipped.join(', ')}. Edit later: ${editorCommand(envPath)}`);
|
|
237
|
+
}
|
|
238
|
+
console.log('Next: foxclaw doctor');
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
rl.close();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function sanitizeEnvInput(value) {
|
|
245
|
+
return value.replace(/[\r\n]/g, '').trim();
|
|
246
|
+
}
|
|
247
|
+
function defaultInitCwd() {
|
|
248
|
+
const cwd = path.resolve(process.cwd());
|
|
249
|
+
if (isUnsafeDefaultCwd(cwd))
|
|
250
|
+
return null;
|
|
251
|
+
try {
|
|
252
|
+
if (fs.statSync(cwd).isDirectory())
|
|
253
|
+
return cwd;
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
function normalizeUserPath(value) {
|
|
261
|
+
const expanded = value === '~' || value.startsWith('~/')
|
|
262
|
+
? path.join(process.env.HOME || '', value.slice(2))
|
|
263
|
+
: value;
|
|
264
|
+
return path.resolve(expanded);
|
|
148
265
|
}
|
|
149
|
-
function
|
|
266
|
+
function validateDefaultCwd(cwd) {
|
|
267
|
+
const warnings = [];
|
|
268
|
+
if (!path.isAbsolute(cwd)) {
|
|
269
|
+
warnings.push('DEFAULT_CWD should be an absolute path.');
|
|
270
|
+
}
|
|
271
|
+
if (isUnsafeDefaultCwd(cwd)) {
|
|
272
|
+
warnings.push('DEFAULT_CWD points at a very broad directory; use a project/workspace folder for the first install.');
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
if (!fs.statSync(cwd).isDirectory()) {
|
|
276
|
+
warnings.push('DEFAULT_CWD exists but is not a directory.');
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
warnings.push('DEFAULT_CWD does not exist yet; create it or edit the path before starting.');
|
|
281
|
+
}
|
|
282
|
+
return warnings;
|
|
283
|
+
}
|
|
284
|
+
function isUnsafeDefaultCwd(cwd) {
|
|
285
|
+
const resolved = path.resolve(cwd);
|
|
286
|
+
const home = process.env.HOME ? path.resolve(process.env.HOME) : '';
|
|
287
|
+
return resolved === path.parse(resolved).root || resolved === home || resolved === '/home' || resolved === '/Users';
|
|
288
|
+
}
|
|
289
|
+
function writeEnvUpdates(envPath, updates) {
|
|
290
|
+
let text = fs.readFileSync(envPath, 'utf8');
|
|
291
|
+
const newline = text.includes('\r\n') ? '\r\n' : '\n';
|
|
292
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
293
|
+
const line = `${key}=${formatEnvValue(value)}`;
|
|
294
|
+
const pattern = new RegExp(`^${escapeRegExp(key)}=.*$`, 'm');
|
|
295
|
+
if (pattern.test(text)) {
|
|
296
|
+
text = text.replace(pattern, line);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
if (text && !text.endsWith('\n') && !text.endsWith('\r\n')) {
|
|
300
|
+
text += newline;
|
|
301
|
+
}
|
|
302
|
+
text += `${line}${newline}`;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
fs.writeFileSync(envPath, text);
|
|
306
|
+
}
|
|
307
|
+
function formatEnvValue(value) {
|
|
308
|
+
const cleaned = value.replace(/[\r\n]/g, '').trim();
|
|
309
|
+
if (!/[\s#"\\]/.test(cleaned))
|
|
310
|
+
return cleaned;
|
|
311
|
+
return `"${cleaned.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
312
|
+
}
|
|
313
|
+
function escapeRegExp(value) {
|
|
314
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
315
|
+
}
|
|
316
|
+
function editorCommand(envPath) {
|
|
317
|
+
return `${process.env.EDITOR?.trim() || '$EDITOR'} ${envPath}`;
|
|
318
|
+
}
|
|
319
|
+
function startService(action) {
|
|
150
320
|
if (!runDoctorChecks()) {
|
|
151
321
|
console.error('');
|
|
152
|
-
console.error(
|
|
322
|
+
console.error(`Fix the failed checks above, then run: foxclaw ${action}`);
|
|
153
323
|
process.exit(1);
|
|
154
324
|
}
|
|
155
325
|
if (process.platform === 'darwin') {
|
|
@@ -158,6 +328,13 @@ function startService() {
|
|
|
158
328
|
}
|
|
159
329
|
installSystemd();
|
|
160
330
|
}
|
|
331
|
+
function stopService() {
|
|
332
|
+
if (process.platform === 'darwin') {
|
|
333
|
+
stopLaunchd();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
stopSystemd();
|
|
337
|
+
}
|
|
161
338
|
function runDoctorChecks() {
|
|
162
339
|
const configuredCodexBin = process.env.CODEX_CLI_BIN;
|
|
163
340
|
const checks = [
|
|
@@ -263,6 +440,15 @@ function uninstallSystemd() {
|
|
|
263
440
|
spawnChecked('systemctl', ['--user', 'daemon-reload']);
|
|
264
441
|
console.log(`Removed ${unitPath}`);
|
|
265
442
|
}
|
|
443
|
+
function stopSystemd() {
|
|
444
|
+
if (!hasCommand('systemctl')) {
|
|
445
|
+
console.error('systemctl not found');
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
const unitName = 'foxclaw.service';
|
|
449
|
+
spawnChecked('systemctl', ['--user', 'stop', unitName]);
|
|
450
|
+
console.log(`Stopped ${unitName}`);
|
|
451
|
+
}
|
|
266
452
|
function installLaunchd() {
|
|
267
453
|
if (process.platform !== 'darwin') {
|
|
268
454
|
console.error('launchd install is only available on macOS');
|
|
@@ -320,6 +506,19 @@ ${foxclawEnvXml}
|
|
|
320
506
|
spawnChecked('launchctl', ['load', plist]);
|
|
321
507
|
console.log(`Installed ${plist}`);
|
|
322
508
|
}
|
|
509
|
+
function stopLaunchd() {
|
|
510
|
+
if (process.platform !== 'darwin') {
|
|
511
|
+
console.error('launchd stop is only available on macOS');
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
const plist = path.join(process.env.HOME || '', 'Library', 'LaunchAgents', 'app.foxden.foxclaw.plist');
|
|
515
|
+
if (!fs.existsSync(plist)) {
|
|
516
|
+
console.error(`launchd plist not found: ${plist}`);
|
|
517
|
+
process.exit(1);
|
|
518
|
+
}
|
|
519
|
+
spawnChecked('launchctl', ['unload', plist]);
|
|
520
|
+
console.log(`Stopped ${plist}`);
|
|
521
|
+
}
|
|
323
522
|
function buildServicePath(nodeDir) {
|
|
324
523
|
const parts = [
|
|
325
524
|
path.join(process.env.HOME || '', '.local', 'bin'),
|
|
@@ -425,13 +624,18 @@ void main().catch((error) => {
|
|
|
425
624
|
process.exit(1);
|
|
426
625
|
});
|
|
427
626
|
function hasCommand(commandName) {
|
|
627
|
+
return Boolean(resolveCommand(commandName));
|
|
628
|
+
}
|
|
629
|
+
function resolveCommand(commandName) {
|
|
428
630
|
try {
|
|
429
631
|
const which = process.platform === 'win32' ? 'where' : 'which';
|
|
430
|
-
const result = spawnSync(which, [commandName], {
|
|
431
|
-
|
|
632
|
+
const result = spawnSync(which, [commandName], { encoding: 'utf8' });
|
|
633
|
+
if (result.status !== 0)
|
|
634
|
+
return null;
|
|
635
|
+
return result.stdout.split(/\r?\n/).map(line => line.trim()).find(Boolean) ?? null;
|
|
432
636
|
}
|
|
433
637
|
catch {
|
|
434
|
-
return
|
|
638
|
+
return null;
|
|
435
639
|
}
|
|
436
640
|
}
|
|
437
641
|
function hasConfiguredCodexBin(binPath) {
|
|
@@ -38,7 +38,7 @@ TG_ALLOWED_USER_ID=<paste numeric Telegram user id here>
|
|
|
38
38
|
DEFAULT_CWD=<paste absolute working directory here>
|
|
39
39
|
|
|
40
40
|
Tasks:
|
|
41
|
-
1. Inspect the machine first. If a FoxClaw
|
|
41
|
+
1. Inspect the machine first. If a FoxClaw service already exists, report it before changing services.
|
|
42
42
|
2. Ensure Node.js 24+ is available. If not, install or activate Node 24 with nvm.
|
|
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.
|
|
@@ -48,33 +48,10 @@ Tasks:
|
|
|
48
48
|
8. Ask me to send /help and /status to the Telegram bot.
|
|
49
49
|
9. Verify the final state:
|
|
50
50
|
- foxclaw.service is active/enabled on Linux
|
|
51
|
-
- old telegram-codex-app-bridge.service is inactive/disabled if present
|
|
52
51
|
- foxclaw status works
|
|
53
52
|
10. Report the commands used, the final status, and the log command I should use if something stops working. Redact TG_BOT_TOKEN and never print the full token or full .env content.
|
|
54
53
|
```
|
|
55
54
|
|
|
56
|
-
## Migration Prompt For Old Installs
|
|
57
|
-
|
|
58
|
-
Use this when the target computer is still running `telegram-codex-app-bridge`:
|
|
59
|
-
|
|
60
|
-
```text
|
|
61
|
-
Migrate this machine from telegram-codex-app-bridge to FoxClaw.
|
|
62
|
-
|
|
63
|
-
New package:
|
|
64
|
-
@foxden-app/foxclaw
|
|
65
|
-
|
|
66
|
-
Please:
|
|
67
|
-
1. Inspect the current install method, service file, and runtime directory before changing anything.
|
|
68
|
-
2. Stop and disable telegram-codex-app-bridge.service if it exists.
|
|
69
|
-
3. If ~/.foxclaw does not exist and ~/.telegram-codex-app-bridge exists, copy ~/.telegram-codex-app-bridge to ~/.foxclaw.
|
|
70
|
-
4. Install or update FoxClaw with npm install -g @foxden-app/foxclaw@latest.
|
|
71
|
-
5. Run foxclaw init if ~/.foxclaw/.env does not exist, then verify ~/.foxclaw/.env.
|
|
72
|
-
6. Run foxclaw doctor.
|
|
73
|
-
7. Install or restart the FoxClaw service with foxclaw start.
|
|
74
|
-
8. Verify foxclaw.service is active and telegram-codex-app-bridge.service is inactive/disabled.
|
|
75
|
-
9. Report final status and any blockers. Redact TG_BOT_TOKEN and never print the full token or full .env content.
|
|
76
|
-
```
|
|
77
|
-
|
|
78
55
|
## Safety Notes
|
|
79
56
|
|
|
80
57
|
- Do not paste bot tokens into public issue trackers or public chat logs.
|
|
@@ -123,7 +123,7 @@ npm install -g @foxden-app/foxclaw
|
|
|
123
123
|
foxclaw init
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
-
This creates the config file at `~/.foxclaw/.env
|
|
126
|
+
This creates the config file at `~/.foxclaw/.env` and prompts for the Telegram bot token, your numeric Telegram user id, and the default workspace.
|
|
127
127
|
|
|
128
128
|
If you prefer pnpm:
|
|
129
129
|
|
|
@@ -134,7 +134,7 @@ foxclaw init
|
|
|
134
134
|
|
|
135
135
|
## 7. Fill In `.env`
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
If you filled the token, user id, and workspace during `foxclaw init`, go straight to the first check. If you skipped a field or want to change anything, open `.env` in a simple editor:
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
140
|
nano ~/.foxclaw/.env
|
|
@@ -259,13 +259,13 @@ foxclaw status
|
|
|
259
259
|
Restart Linux service after changing `.env`:
|
|
260
260
|
|
|
261
261
|
```bash
|
|
262
|
-
foxclaw
|
|
262
|
+
foxclaw restart
|
|
263
263
|
```
|
|
264
264
|
|
|
265
|
-
Stop
|
|
265
|
+
Stop the service:
|
|
266
266
|
|
|
267
267
|
```bash
|
|
268
|
-
|
|
268
|
+
foxclaw stop
|
|
269
269
|
```
|
|
270
270
|
|
|
271
271
|
Uninstall Linux service:
|
package/docs/troubleshooting.md
CHANGED
|
@@ -93,7 +93,7 @@ Check these in order:
|
|
|
93
93
|
5. Restart after changing `.env`:
|
|
94
94
|
|
|
95
95
|
```bash
|
|
96
|
-
foxclaw
|
|
96
|
+
foxclaw restart
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
If running foreground mode, stop with `Ctrl+C` and run `foxclaw serve` again.
|
|
@@ -129,23 +129,17 @@ If FoxClaw is still running, it may consume the update before you inspect it.
|
|
|
129
129
|
|
|
130
130
|
If Telegram reports conflicts or the same bot behaves strangely, two processes may be polling the same bot token.
|
|
131
131
|
|
|
132
|
-
Check
|
|
132
|
+
Check the service and any extra foreground processes:
|
|
133
133
|
|
|
134
134
|
```bash
|
|
135
135
|
systemctl --user is-active foxclaw.service
|
|
136
|
-
|
|
136
|
+
pgrep -af foxclaw
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
Stop the
|
|
139
|
+
Stop the extra process or service, then restart FoxClaw:
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
|
-
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
Then restart FoxClaw:
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
foxclaw start
|
|
142
|
+
foxclaw restart
|
|
149
143
|
```
|
|
150
144
|
|
|
151
145
|
## Codex Or App-Server Fails
|
|
@@ -219,18 +213,3 @@ macOS launchd starts FoxClaw when you log in after running:
|
|
|
219
213
|
```bash
|
|
220
214
|
foxclaw start
|
|
221
215
|
```
|
|
222
|
-
|
|
223
|
-
## Migrating From The Old Project Name
|
|
224
|
-
|
|
225
|
-
If this machine still runs `telegram-codex-app-bridge`, migrate once:
|
|
226
|
-
|
|
227
|
-
```bash
|
|
228
|
-
systemctl --user disable --now telegram-codex-app-bridge.service 2>/dev/null || true
|
|
229
|
-
test -e ~/.foxclaw || cp -a ~/.telegram-codex-app-bridge ~/.foxclaw
|
|
230
|
-
npm install -g @foxden-app/foxclaw@latest
|
|
231
|
-
foxclaw init
|
|
232
|
-
foxclaw doctor
|
|
233
|
-
foxclaw start
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
If `~/.foxclaw/.env` already exists, `foxclaw init` leaves it untouched.
|
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
|
-
|
|
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. Press Enter on any field to skip it, then edit manually if needed:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
106
|
$EDITOR ~/.foxclaw/.env
|
|
@@ -146,6 +146,7 @@ journalctl --user -u foxclaw.service -f
|
|
|
146
146
|
On macOS, `foxclaw start` manages launchd. For foreground debugging, stop the background service and run:
|
|
147
147
|
|
|
148
148
|
```bash
|
|
149
|
+
foxclaw stop
|
|
149
150
|
foxclaw serve
|
|
150
151
|
```
|
|
151
152
|
|
|
@@ -37,7 +37,7 @@ TG_ALLOWED_USER_ID=<把 Telegram 数字用户 ID 粘贴在这里>
|
|
|
37
37
|
DEFAULT_CWD=<把绝对工作目录粘贴在这里>
|
|
38
38
|
|
|
39
39
|
任务:
|
|
40
|
-
1. 先检查机器环境。如果已经存在 FoxClaw
|
|
40
|
+
1. 先检查机器环境。如果已经存在 FoxClaw 服务,先报告再改服务。
|
|
41
41
|
2. 确保 Node.js 24+ 可用;如果没有,请用 nvm 安装或切到 Node 24。
|
|
42
42
|
3. 确保 Codex CLI 存在并且已经登录。如果需要登录,停下来告诉我具体要执行什么。
|
|
43
43
|
4. 用 npm install -g @foxden-app/foxclaw@latest 安装或升级 FoxClaw。
|
|
@@ -47,33 +47,10 @@ DEFAULT_CWD=<把绝对工作目录粘贴在这里>
|
|
|
47
47
|
8. 让我在 Telegram bot 里发送 /help 和 /status。
|
|
48
48
|
9. 验证最终状态:
|
|
49
49
|
- Linux 上 foxclaw.service 处于 active/enabled
|
|
50
|
-
- 如果存在旧 telegram-codex-app-bridge.service,它应当 inactive/disabled
|
|
51
50
|
- foxclaw status 可以正常输出
|
|
52
51
|
10. 汇报执行过的命令、最终状态和后续看日志的命令。请隐藏 TG_BOT_TOKEN,不要打印完整 token 或完整 .env。
|
|
53
52
|
```
|
|
54
53
|
|
|
55
|
-
## 旧项目迁移提示词
|
|
56
|
-
|
|
57
|
-
如果目标机器还在跑 `telegram-codex-app-bridge`,用这段:
|
|
58
|
-
|
|
59
|
-
```text
|
|
60
|
-
请把这台机器从 telegram-codex-app-bridge 迁移到 FoxClaw。
|
|
61
|
-
|
|
62
|
-
新发布包:
|
|
63
|
-
@foxden-app/foxclaw
|
|
64
|
-
|
|
65
|
-
请执行:
|
|
66
|
-
1. 修改前先检查现有安装方式、服务文件和运行目录。
|
|
67
|
-
2. 如果存在 telegram-codex-app-bridge.service,停止并禁用它。
|
|
68
|
-
3. 如果 ~/.foxclaw 不存在而 ~/.telegram-codex-app-bridge 存在,把旧目录复制到 ~/.foxclaw。
|
|
69
|
-
4. 用 npm install -g @foxden-app/foxclaw@latest 安装或升级 FoxClaw。
|
|
70
|
-
5. 如果 ~/.foxclaw/.env 不存在,运行 foxclaw init;然后检查配置是否完整。
|
|
71
|
-
6. 运行 foxclaw doctor。
|
|
72
|
-
7. 用 foxclaw start 安装或重启 FoxClaw 服务。
|
|
73
|
-
8. 验证 foxclaw.service 正常运行,旧 telegram-codex-app-bridge.service 已停止或禁用。
|
|
74
|
-
9. 汇报最终状态和阻塞点。请隐藏 TG_BOT_TOKEN,不要打印完整 token 或完整 .env。
|
|
75
|
-
```
|
|
76
|
-
|
|
77
54
|
## 安全注意事项
|
|
78
55
|
|
|
79
56
|
- 不要把 bot token 粘贴到公开 issue、公开聊天或代码仓库。
|
|
@@ -121,7 +121,7 @@ npm install -g @foxden-app/foxclaw
|
|
|
121
121
|
foxclaw init
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
这会创建默认配置文件 `~/.foxclaw/.env
|
|
124
|
+
这会创建默认配置文件 `~/.foxclaw/.env`,并提示你填写 Telegram bot token、Telegram 数字用户 ID 和默认工作目录。
|
|
125
125
|
|
|
126
126
|
如果你用 pnpm:
|
|
127
127
|
|
|
@@ -132,7 +132,7 @@ foxclaw init
|
|
|
132
132
|
|
|
133
133
|
## 7. 填写 `.env`
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
如果刚才在 `foxclaw init` 里已经填好了 token、用户 ID 和工作目录,可以直接进入下一步检查。如果你选择了跳过,或者想改配置,用简单编辑器打开:
|
|
136
136
|
|
|
137
137
|
```bash
|
|
138
138
|
nano ~/.foxclaw/.env
|
|
@@ -257,13 +257,13 @@ foxclaw status
|
|
|
257
257
|
修改 `.env` 后重启:
|
|
258
258
|
|
|
259
259
|
```bash
|
|
260
|
-
foxclaw
|
|
260
|
+
foxclaw restart
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
-
|
|
263
|
+
停止服务:
|
|
264
264
|
|
|
265
265
|
```bash
|
|
266
|
-
|
|
266
|
+
foxclaw stop
|
|
267
267
|
```
|
|
268
268
|
|
|
269
269
|
卸载 Linux 服务:
|
|
@@ -279,20 +279,11 @@ npm install -g @foxden-app/foxclaw@latest
|
|
|
279
279
|
foxclaw start
|
|
280
280
|
```
|
|
281
281
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
如果这台机器仍在运行 `telegram-codex-app-bridge`,迁移一次即可:
|
|
282
|
+
如果 `~/.foxclaw/.env` 已经存在,`foxclaw init` 会先询问是否更新 Telegram 和工作目录相关字段,其它配置保持不变。
|
|
285
283
|
|
|
286
|
-
|
|
287
|
-
systemctl --user disable --now telegram-codex-app-bridge.service 2>/dev/null || true
|
|
288
|
-
test -e ~/.foxclaw || cp -a ~/.telegram-codex-app-bridge ~/.foxclaw
|
|
289
|
-
npm install -g @foxden-app/foxclaw@latest
|
|
290
|
-
foxclaw init
|
|
291
|
-
foxclaw doctor
|
|
292
|
-
foxclaw start
|
|
293
|
-
```
|
|
284
|
+
## 鸣谢
|
|
294
285
|
|
|
295
|
-
|
|
286
|
+
FoxClaw 最初基于 `Gan-Xing/telegram-codex-app-bridge` fork 演进而来。感谢原项目对 Telegram 与 Codex 本地桥接思路的探索。
|
|
296
287
|
|
|
297
288
|
## 下一步
|
|
298
289
|
|
|
@@ -94,7 +94,7 @@ CODEX_CLI_BIN=/absolute/path/to/codex
|
|
|
94
94
|
5. 修改 `.env` 后重启:
|
|
95
95
|
|
|
96
96
|
```bash
|
|
97
|
-
foxclaw
|
|
97
|
+
foxclaw restart
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
如果正在前台运行,先 `Ctrl+C` 停止,再重新运行 `foxclaw serve`。
|
|
@@ -130,23 +130,17 @@ CODEX_CLI_BIN=/absolute/path/to/codex
|
|
|
130
130
|
|
|
131
131
|
如果 Telegram 报 conflict,或者同一个 bot 行为异常,通常是两个进程在轮询同一个 bot token。
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
检查服务和额外的前台进程:
|
|
134
134
|
|
|
135
135
|
```bash
|
|
136
136
|
systemctl --user is-active foxclaw.service
|
|
137
|
-
|
|
137
|
+
pgrep -af foxclaw
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
停掉多余进程或服务后,重启 FoxClaw:
|
|
141
141
|
|
|
142
142
|
```bash
|
|
143
|
-
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
然后重启 FoxClaw:
|
|
147
|
-
|
|
148
|
-
```bash
|
|
149
|
-
foxclaw start
|
|
143
|
+
foxclaw restart
|
|
150
144
|
```
|
|
151
145
|
|
|
152
146
|
## Codex 或 app-server 异常
|
package/docs/zh/user-manual.md
CHANGED
|
@@ -100,7 +100,7 @@ foxclaw init
|
|
|
100
100
|
|
|
101
101
|
### 1.6 填写配置
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
`foxclaw init` 会创建默认配置文件 `~/.foxclaw/.env`,并提示填写 Telegram bot token、Telegram 数字用户 ID 和默认工作目录。任何一项都可以直接回车跳过,之后再手动编辑:
|
|
104
104
|
|
|
105
105
|
```bash
|
|
106
106
|
$EDITOR ~/.foxclaw/.env
|
|
@@ -146,6 +146,7 @@ journalctl --user -u foxclaw.service -f
|
|
|
146
146
|
macOS 上 `foxclaw start` 会管理 launchd。前台排障时,先停后台服务,再运行:
|
|
147
147
|
|
|
148
148
|
```bash
|
|
149
|
+
foxclaw stop
|
|
149
150
|
foxclaw serve
|
|
150
151
|
```
|
|
151
152
|
|
package/package.json
CHANGED
|
@@ -1,65 +1,67 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@foxden-app/foxclaw",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Foxden local execution claw for controlling Codex from trusted chat interfaces.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/main.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"foxclaw": "dist/main.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"docs",
|
|
13
|
-
"scripts",
|
|
14
|
-
"skills",
|
|
15
|
-
".env.example",
|
|
16
|
-
"README.md",
|
|
17
|
-
"README_EN.md",
|
|
18
|
-
"LICENSE"
|
|
19
|
-
],
|
|
20
|
-
"private": false,
|
|
21
|
-
"repository": {
|
|
22
|
-
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/foxden-app/foxclaw.git"
|
|
24
|
-
},
|
|
25
|
-
"homepage": "https://github.com/foxden-app/foxclaw#readme",
|
|
26
|
-
"bugs": {
|
|
27
|
-
"url": "https://github.com/foxden-app/foxclaw/issues"
|
|
28
|
-
},
|
|
29
|
-
"publishConfig": {
|
|
30
|
-
"access": "public"
|
|
31
|
-
},
|
|
32
|
-
"engines": {
|
|
33
|
-
"node": ">=24"
|
|
34
|
-
},
|
|
35
|
-
"scripts": {
|
|
36
|
-
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
37
|
-
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
38
|
-
"dev": "tsx src/main.ts serve",
|
|
39
|
-
"serve": "node dist/main.js serve",
|
|
40
|
-
"start-service": "node dist/main.js start",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"install-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"eslint": "^9.39.0",
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@foxden-app/foxclaw",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "Foxden local execution claw for controlling Codex from trusted chat interfaces.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/main.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"foxclaw": "dist/main.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"docs",
|
|
13
|
+
"scripts",
|
|
14
|
+
"skills",
|
|
15
|
+
".env.example",
|
|
16
|
+
"README.md",
|
|
17
|
+
"README_EN.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"private": false,
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/foxden-app/foxclaw.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://github.com/foxden-app/foxclaw#readme",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/foxden-app/foxclaw/issues"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=24"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
37
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
38
|
+
"dev": "tsx src/main.ts serve",
|
|
39
|
+
"serve": "node dist/main.js serve",
|
|
40
|
+
"start-service": "node dist/main.js start",
|
|
41
|
+
"stop-service": "node dist/main.js stop",
|
|
42
|
+
"restart-service": "node dist/main.js restart",
|
|
43
|
+
"weixin-login": "node dist/main.js weixin-login",
|
|
44
|
+
"status": "node dist/main.js status",
|
|
45
|
+
"doctor": "node dist/main.js doctor",
|
|
46
|
+
"init": "node dist/main.js init",
|
|
47
|
+
"install-systemd": "node dist/main.js install-systemd",
|
|
48
|
+
"uninstall-systemd": "node dist/main.js uninstall-systemd",
|
|
49
|
+
"install-launchd": "node dist/main.js install-launchd",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"lint": "eslint .",
|
|
52
|
+
"test": "node --test --import tsx \"src/**/*.test.ts\"",
|
|
53
|
+
"prepack": "npm run build"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"dotenv": "^16.6.1",
|
|
57
|
+
"qrcode-terminal": "^0.12.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@eslint/js": "^9.39.0",
|
|
61
|
+
"@types/node": "^24.12.0",
|
|
62
|
+
"eslint": "^9.39.0",
|
|
63
|
+
"tsx": "^4.19.3",
|
|
64
|
+
"typescript": "5.9.3",
|
|
65
|
+
"typescript-eslint": "^8.58.0"
|
|
66
|
+
}
|
|
67
|
+
}
|