pi-courier 0.1.0

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.
Files changed (86) hide show
  1. package/README.md +363 -0
  2. package/README.zh-CN.md +362 -0
  3. package/deploy/pi-msg-bridge.service +26 -0
  4. package/deploy/pi-msg-bridge.user.service +37 -0
  5. package/dist/auth/challenge-auth.d.ts +76 -0
  6. package/dist/auth/challenge-auth.d.ts.map +1 -0
  7. package/dist/auth/challenge-auth.js +337 -0
  8. package/dist/auth/challenge-auth.js.map +1 -0
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +265 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/config.d.ts +10 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +49 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/formatting.d.ts +22 -0
  18. package/dist/formatting.d.ts.map +1 -0
  19. package/dist/formatting.js +74 -0
  20. package/dist/formatting.js.map +1 -0
  21. package/dist/lock.d.ts +3 -0
  22. package/dist/lock.d.ts.map +1 -0
  23. package/dist/lock.js +75 -0
  24. package/dist/lock.js.map +1 -0
  25. package/dist/rpc/command-map.d.ts +19 -0
  26. package/dist/rpc/command-map.d.ts.map +1 -0
  27. package/dist/rpc/command-map.js +191 -0
  28. package/dist/rpc/command-map.js.map +1 -0
  29. package/dist/rpc/message-router.d.ts +30 -0
  30. package/dist/rpc/message-router.d.ts.map +1 -0
  31. package/dist/rpc/message-router.js +110 -0
  32. package/dist/rpc/message-router.js.map +1 -0
  33. package/dist/rpc/pi-rpc.d.ts +79 -0
  34. package/dist/rpc/pi-rpc.d.ts.map +1 -0
  35. package/dist/rpc/pi-rpc.js +199 -0
  36. package/dist/rpc/pi-rpc.js.map +1 -0
  37. package/dist/setup.d.ts +10 -0
  38. package/dist/setup.d.ts.map +1 -0
  39. package/dist/setup.js +159 -0
  40. package/dist/setup.js.map +1 -0
  41. package/dist/standalone.d.ts +13 -0
  42. package/dist/standalone.d.ts.map +1 -0
  43. package/dist/standalone.js +184 -0
  44. package/dist/standalone.js.map +1 -0
  45. package/dist/transports/discord.d.ts +33 -0
  46. package/dist/transports/discord.d.ts.map +1 -0
  47. package/dist/transports/discord.js +216 -0
  48. package/dist/transports/discord.js.map +1 -0
  49. package/dist/transports/interface.d.ts +42 -0
  50. package/dist/transports/interface.d.ts.map +1 -0
  51. package/dist/transports/interface.js +2 -0
  52. package/dist/transports/interface.js.map +1 -0
  53. package/dist/transports/manager.d.ts +54 -0
  54. package/dist/transports/manager.d.ts.map +1 -0
  55. package/dist/transports/manager.js +98 -0
  56. package/dist/transports/manager.js.map +1 -0
  57. package/dist/transports/matrix-utils.d.ts +31 -0
  58. package/dist/transports/matrix-utils.d.ts.map +1 -0
  59. package/dist/transports/matrix-utils.js +99 -0
  60. package/dist/transports/matrix-utils.js.map +1 -0
  61. package/dist/transports/matrix-utils.test.d.ts +2 -0
  62. package/dist/transports/matrix-utils.test.d.ts.map +1 -0
  63. package/dist/transports/matrix-utils.test.js +246 -0
  64. package/dist/transports/matrix-utils.test.js.map +1 -0
  65. package/dist/transports/matrix.d.ts +34 -0
  66. package/dist/transports/matrix.d.ts.map +1 -0
  67. package/dist/transports/matrix.js +240 -0
  68. package/dist/transports/matrix.js.map +1 -0
  69. package/dist/transports/slack.d.ts +31 -0
  70. package/dist/transports/slack.d.ts.map +1 -0
  71. package/dist/transports/slack.js +203 -0
  72. package/dist/transports/slack.js.map +1 -0
  73. package/dist/transports/telegram.d.ts +38 -0
  74. package/dist/transports/telegram.d.ts.map +1 -0
  75. package/dist/transports/telegram.js +167 -0
  76. package/dist/transports/telegram.js.map +1 -0
  77. package/dist/transports/whatsapp.d.ts +31 -0
  78. package/dist/transports/whatsapp.d.ts.map +1 -0
  79. package/dist/transports/whatsapp.js +235 -0
  80. package/dist/transports/whatsapp.js.map +1 -0
  81. package/dist/types.d.ts +69 -0
  82. package/dist/types.d.ts.map +1 -0
  83. package/dist/types.js +2 -0
  84. package/dist/types.js.map +1 -0
  85. package/extensions/index.ts +42 -0
  86. package/package.json +71 -0
@@ -0,0 +1,337 @@
1
+ /**
2
+ * Challenge-based authentication for remote messengers
3
+ * Ported from vscode-chonky-remote-pilot
4
+ */
5
+ import { loadConfig, saveConfig } from "../config.js";
6
+ /**
7
+ * Manages authentication via 6-digit challenge codes and trusted users
8
+ */
9
+ export class ChallengeAuth {
10
+ onShowCode;
11
+ onNotify;
12
+ onSendMessage;
13
+ onSaveAuth;
14
+ challenges = new Map();
15
+ trustedUsers = new Set();
16
+ channelAuth = new Map();
17
+ blockedUsers = new Map(); // userId -> unblock timestamp
18
+ adminUserId;
19
+ constructor(onShowCode, onNotify, onSendMessage, onSaveAuth) {
20
+ this.onShowCode = onShowCode;
21
+ this.onNotify = onNotify;
22
+ this.onSendMessage = onSendMessage;
23
+ this.onSaveAuth = onSaveAuth;
24
+ }
25
+ /**
26
+ * Initialize auth state from config
27
+ */
28
+ loadFromConfig(config) {
29
+ if (config.trustedUsers) {
30
+ this.trustedUsers = new Set(config.trustedUsers);
31
+ }
32
+ if (config.adminUserId) {
33
+ this.adminUserId = config.adminUserId;
34
+ }
35
+ if (config.channels) {
36
+ this.channelAuth = new Map(Object.entries(config.channels));
37
+ }
38
+ }
39
+ /**
40
+ * Export auth state for config persistence
41
+ */
42
+ exportConfig() {
43
+ return {
44
+ trustedUsers: Array.from(this.trustedUsers),
45
+ adminUserId: this.adminUserId,
46
+ channels: Object.fromEntries(this.channelAuth),
47
+ };
48
+ }
49
+ /**
50
+ * Check if a user is authorized to send messages
51
+ * Handles challenge creation, validation, and channel authorization
52
+ */
53
+ async checkAuthorization(userId, chatId, username, isGroupChat, wasMentioned, sendMessage, transport) {
54
+ // Create namespaced user ID (transport:userId)
55
+ const namespacedUserId = transport ? `${transport}:${userId}` : userId;
56
+ // Check if user is blocked
57
+ const blockedUntil = this.blockedUsers.get(namespacedUserId);
58
+ if (blockedUntil && Date.now() < blockedUntil) {
59
+ return false;
60
+ }
61
+ if (blockedUntil && Date.now() >= blockedUntil) {
62
+ this.blockedUsers.delete(namespacedUserId);
63
+ }
64
+ // DM: check trusted or initiate challenge
65
+ if (!isGroupChat) {
66
+ if (this.trustedUsers.has(namespacedUserId)) {
67
+ // Set as admin if first trusted user
68
+ if (!this.adminUserId) {
69
+ this.adminUserId = namespacedUserId;
70
+ this.onNotify(`🔐 ${username} is now the admin`, "info");
71
+ }
72
+ return true;
73
+ }
74
+ // Temporarily override onSendMessage for this challenge if provided
75
+ if (sendMessage) {
76
+ const originalSender = this.onSendMessage;
77
+ this.onSendMessage = sendMessage;
78
+ const result = await this.initiateChallenge(namespacedUserId, chatId, username);
79
+ this.onSendMessage = originalSender;
80
+ return result;
81
+ }
82
+ return await this.initiateChallenge(namespacedUserId, chatId, username);
83
+ }
84
+ // Group chat: check channel authorization
85
+ const channelAuthData = this.channelAuth.get(chatId);
86
+ // Channel not enabled
87
+ if (!channelAuthData?.enabled) {
88
+ return false;
89
+ }
90
+ // Check mode
91
+ switch (channelAuthData.mode) {
92
+ case "all":
93
+ return true;
94
+ case "mentions":
95
+ return wasMentioned || false;
96
+ case "trusted-only":
97
+ return this.trustedUsers.has(namespacedUserId);
98
+ default:
99
+ return false;
100
+ }
101
+ }
102
+ /**
103
+ * Initiate or validate a challenge
104
+ */
105
+ async initiateChallenge(userId, chatId, username) {
106
+ const existingChallenge = this.challenges.get(userId);
107
+ // Check if there's an active challenge
108
+ if (existingChallenge) {
109
+ // Expired?
110
+ if (Date.now() > existingChallenge.expiresAt) {
111
+ this.challenges.delete(userId);
112
+ return await this.initiateChallenge(userId, chatId, username);
113
+ }
114
+ // Challenge still active, return false (user needs to enter code)
115
+ return false;
116
+ }
117
+ // Create new challenge
118
+ const code = this.generateCode();
119
+ const expiresAt = Date.now() + 2 * 60 * 1000; // 2 minutes
120
+ this.challenges.set(userId, {
121
+ code,
122
+ userId,
123
+ chatId,
124
+ username,
125
+ expiresAt,
126
+ attempts: 0,
127
+ });
128
+ // Show code in terminal FIRST
129
+ this.onShowCode(code, username);
130
+ // Then send message to user asking for the code
131
+ if (this.onSendMessage) {
132
+ try {
133
+ await this.onSendMessage(chatId, "🔐 Please enter the 6-digit code provided by the bot admin.\n⏱️ Expires in 2 minutes.");
134
+ }
135
+ catch (_err) {
136
+ // Ignore send errors
137
+ }
138
+ }
139
+ return false;
140
+ }
141
+ /**
142
+ * Handle admin commands in DM
143
+ * Returns true if command was handled
144
+ */
145
+ async handleAdminCommand(text, _chatId, userId, sendMessage, transport) {
146
+ // Create namespaced user ID
147
+ const namespacedUserId = transport ? `${transport}:${userId}` : userId;
148
+ // Non-admin users: check for challenge code entry
149
+ if (!this.trustedUsers.has(namespacedUserId)) {
150
+ const challenge = this.challenges.get(namespacedUserId);
151
+ if (challenge && text.match(/^\d{6}$/)) {
152
+ return await this.validateChallenge(namespacedUserId, text, sendMessage);
153
+ }
154
+ return false;
155
+ }
156
+ // Admin commands
157
+ const parts = text.split(/\s+/);
158
+ const cmd = parts[0].toLowerCase();
159
+ switch (cmd) {
160
+ case "/help":
161
+ await sendMessage(this.getHelpText());
162
+ return true;
163
+ case "/enable":
164
+ if (parts.length < 3) {
165
+ await sendMessage("Usage: /enable <chatId> <all|mentions|trusted-only>");
166
+ return true;
167
+ }
168
+ this.channelAuth.set(parts[1], {
169
+ enabled: true,
170
+ mode: parts[2],
171
+ });
172
+ if (this.onSaveAuth)
173
+ this.onSaveAuth();
174
+ await sendMessage(`✅ Channel ${parts[1]} enabled (mode: ${parts[2]})`);
175
+ this.onNotify(`Channel ${parts[1]} enabled (${parts[2]})`, "info");
176
+ return true;
177
+ case "/disable":
178
+ if (parts.length < 2) {
179
+ await sendMessage("Usage: /disable <chatId>");
180
+ return true;
181
+ }
182
+ this.channelAuth.delete(parts[1]);
183
+ if (this.onSaveAuth)
184
+ this.onSaveAuth();
185
+ await sendMessage(`❌ Channel ${parts[1]} disabled`);
186
+ this.onNotify(`Channel ${parts[1]} disabled`, "info");
187
+ return true;
188
+ case "/channels": {
189
+ const channels = Array.from(this.channelAuth.entries())
190
+ .map(([id, auth]) => `• ${id}: ${auth.enabled ? "✅" : "❌"} (${auth.mode})`)
191
+ .join("\n");
192
+ await sendMessage(channels || "No channels configured");
193
+ return true;
194
+ }
195
+ case "/trusted": {
196
+ const trusted = Array.from(this.trustedUsers)
197
+ .map(id => {
198
+ const [transport, uid] = id.split(':');
199
+ return uid ? `${uid} (${transport})` : id;
200
+ })
201
+ .join(", ");
202
+ await sendMessage(`Trusted users (${this.trustedUsers.size}):\n${trusted || "None"}`);
203
+ return true;
204
+ }
205
+ case "/toggletools": {
206
+ const cfg = loadConfig();
207
+ cfg.hideToolCalls = !cfg.hideToolCalls;
208
+ saveConfig(cfg);
209
+ const state = cfg.hideToolCalls ? "hidden" : "shown";
210
+ await sendMessage(`🔧 Tool calls ${state} in remote messages`);
211
+ return true;
212
+ }
213
+ case "/revoke": {
214
+ if (parts.length < 2) {
215
+ await sendMessage("Usage: /revoke <userId> or /revoke <transport:userId>");
216
+ return true;
217
+ }
218
+ const revokeId = parts[1];
219
+ // Support both "telegram:123" and "123" (searches for any match)
220
+ let revoked = false;
221
+ if (revokeId.includes(':')) {
222
+ // Full namespaced ID
223
+ if (this.trustedUsers.has(revokeId)) {
224
+ this.trustedUsers.delete(revokeId);
225
+ revoked = true;
226
+ }
227
+ }
228
+ else {
229
+ // Plain ID - search across all transports
230
+ for (const id of this.trustedUsers) {
231
+ if (id.endsWith(`:${revokeId}`)) {
232
+ this.trustedUsers.delete(id);
233
+ revoked = true;
234
+ break;
235
+ }
236
+ }
237
+ }
238
+ if (revoked) {
239
+ if (this.onSaveAuth)
240
+ this.onSaveAuth();
241
+ await sendMessage(`🔓 Revoked trust for ${revokeId}`);
242
+ this.onNotify(`Revoked: ${revokeId}`, "warning");
243
+ }
244
+ else {
245
+ await sendMessage(`❌ User ${revokeId} not found in trusted users`);
246
+ }
247
+ return true;
248
+ }
249
+ default:
250
+ return false;
251
+ }
252
+ }
253
+ /**
254
+ * Validate a challenge code entered by the user
255
+ */
256
+ async validateChallenge(userId, code, sendMessage) {
257
+ const challenge = this.challenges.get(userId);
258
+ if (!challenge)
259
+ return false;
260
+ // Expired?
261
+ if (Date.now() > challenge.expiresAt) {
262
+ this.challenges.delete(userId);
263
+ await sendMessage("⏱️ Challenge expired. Send any message to get a new code.");
264
+ return true;
265
+ }
266
+ // Correct code?
267
+ if (code === challenge.code) {
268
+ this.trustedUsers.add(userId);
269
+ this.challenges.delete(userId);
270
+ if (this.onSaveAuth)
271
+ this.onSaveAuth();
272
+ await sendMessage("✅ Authenticated! You can now chat with the agent.");
273
+ this.onNotify(`✅ ${challenge.username} authenticated`, "info");
274
+ return true;
275
+ }
276
+ // Wrong code
277
+ challenge.attempts++;
278
+ if (challenge.attempts >= 3) {
279
+ this.challenges.delete(userId);
280
+ this.blockedUsers.set(userId, Date.now() + 5 * 60 * 1000); // 5 min block
281
+ await sendMessage("🚫 Too many failed attempts. Blocked for 5 minutes.");
282
+ this.onNotify(`🚫 ${challenge.username} blocked (3 failed attempts)`, "warning");
283
+ return true;
284
+ }
285
+ await sendMessage(`❌ Wrong code. ${3 - challenge.attempts} attempts remaining.`);
286
+ return true;
287
+ }
288
+ /**
289
+ * Generate a random 6-digit code
290
+ */
291
+ generateCode() {
292
+ return Math.floor(100000 + Math.random() * 900000).toString();
293
+ }
294
+ /**
295
+ * Get help text for admin commands
296
+ */
297
+ getHelpText() {
298
+ return `**Admin Commands**
299
+
300
+ *DM Only:*
301
+ • \`/help\` — Show this help
302
+ • \`/trusted\` — List trusted users
303
+ • \`/revoke <userId>\` — Revoke trust for a user
304
+ • \`/channels\` — List enabled channels
305
+ • \`/enable <chatId> <mode>\` — Enable a channel
306
+ Modes: \`all\`, \`mentions\`, \`trusted-only\`
307
+ • \`/disable <chatId>\` — Disable a channel
308
+ • \`/toggletools\` — Toggle tool call visibility in replies
309
+
310
+ *Authentication:*
311
+ • First DM to bot → 6-digit code shown in terminal
312
+ • Enter code in chat → become trusted
313
+ • First trusted user = admin`;
314
+ }
315
+ /**
316
+ * Get current stats with detailed user info
317
+ */
318
+ getStats() {
319
+ // Group users by transport
320
+ const usersByTransport = {};
321
+ for (const namespacedId of this.trustedUsers) {
322
+ const [transport, userId] = namespacedId.split(':');
323
+ if (transport && userId) {
324
+ if (!usersByTransport[transport]) {
325
+ usersByTransport[transport] = [];
326
+ }
327
+ usersByTransport[transport].push(userId);
328
+ }
329
+ }
330
+ return {
331
+ trustedUsers: this.trustedUsers.size,
332
+ channels: Array.from(this.channelAuth.values()).filter((a) => a.enabled).length,
333
+ usersByTransport,
334
+ };
335
+ }
336
+ }
337
+ //# sourceMappingURL=challenge-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenge-auth.js","sourceRoot":"","sources":["../../src/auth/challenge-auth.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * pi-courier CLI — one command for everything.
4
+ *
5
+ * pi-courier setup first-run configuration wizard (Matrix account,
6
+ * trusted user, workdir; writes ~/.pi/msg-bridge.json)
7
+ * pi-courier run run in the foreground (workdir from config, --workdir overrides)
8
+ * pi-courier enable install a user-level systemd service (auto-start) and start it
9
+ * pi-courier start start the systemd service
10
+ * pi-courier stop stop the systemd service
11
+ * pi-courier status show service status + recent logs
12
+ * pi-courier logs tail the service logs
13
+ * pi-courier update update this project (git pull + npm install + build)
14
+ *
15
+ * pi itself is managed independently on the system (npm i -g ...); this
16
+ * project only ever updates itself.
17
+ */
18
+ import { spawnSync } from "node:child_process";
19
+ import * as fs from "node:fs";
20
+ import * as os from "node:os";
21
+ import * as path from "node:path";
22
+ import { fileURLToPath } from "node:url";
23
+ import { loadConfig } from "./config.js";
24
+ // Suppress the known `util._extend` deprecation warning emitted by some
25
+ // transport dependencies at load time — it pollutes interactive output.
26
+ function suppressDeprecationWarnings() {
27
+ const orig = process.emitWarning;
28
+ process.emitWarning = ((warning, ...rest) => {
29
+ const msg = typeof warning === "string" ? warning : warning?.message ?? "";
30
+ if (msg.includes("util._extend"))
31
+ return;
32
+ orig.call(process, warning, ...rest);
33
+ });
34
+ }
35
+ suppressDeprecationWarnings();
36
+ const SERVICE_NAME = "pi-msg-bridge";
37
+ const SERVICE_UNIT = `${SERVICE_NAME}.service`;
38
+ /** Project root (parent of the dist/ directory this file is compiled into). */
39
+ function projectDir() {
40
+ return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
41
+ }
42
+ function usage() {
43
+ console.log(`pi-courier — run the pi coding agent from your messenger
44
+
45
+ 用法:
46
+ pi-courier setup 首次运行配置向导(Matrix 账号、信任用户、工作目录)
47
+ pi-courier run 前台运行(--workdir 可覆盖配置里的工作目录)
48
+ pi-courier enable 安装用户级 systemd 服务并开机自启、立即启动
49
+ pi-courier start 启动服务
50
+ pi-courier stop 停止服务
51
+ pi-courier restart 重启服务
52
+ pi-courier status 查看服务状态与最近日志
53
+ pi-courier logs 跟踪服务日志(Ctrl+C 退出)
54
+ pi-courier disable 卸载服务(停止 + 取消自启 + 删除 unit 文件)
55
+ pi-courier update 更新本项目(git pull + 安装依赖 + 重新构建)
56
+
57
+ 说明:pi 由系统独立安装与升级(npm i -g @earendil-works/pi-coding-agent),
58
+ 本项目只更新自身。`);
59
+ }
60
+ // ===========================================================================
61
+ // setup
62
+ // ===========================================================================
63
+ async function cmdSetup() {
64
+ const { runSetup } = await import("./setup.js");
65
+ await runSetup();
66
+ }
67
+ // ===========================================================================
68
+ // run
69
+ // ===========================================================================
70
+ async function cmdRun(args) {
71
+ const config = loadConfig();
72
+ // Only --workdir is supported as a positional override.
73
+ let workdir;
74
+ for (let i = 0; i < args.length; i++) {
75
+ if (args[i] === "--workdir") {
76
+ workdir = args[++i];
77
+ }
78
+ else {
79
+ console.warn(`⚠️ 忽略未知参数: ${args[i]}(旧参数已废弃,请用配置或子命令)`);
80
+ }
81
+ }
82
+ const finalWorkdir = workdir ?? config.workdir;
83
+ if (!finalWorkdir) {
84
+ console.error("❌ 未配置工作目录。先运行 `pi-courier setup`,或用 `pi-courier run --workdir <目录>` 指定。");
85
+ process.exit(1);
86
+ }
87
+ const { main } = await import("./standalone.js");
88
+ await main(["--workdir", finalWorkdir]);
89
+ }
90
+ // ===========================================================================
91
+ // enable / start / stop / status / logs
92
+ // ===========================================================================
93
+ function userUnitPath() {
94
+ return path.join(os.homedir(), ".config", "systemd", "user", SERVICE_UNIT);
95
+ }
96
+ function buildUnit(projDir, workdir) {
97
+ const nodeBin = process.execPath;
98
+ // The pi child process is spawned via PATH ("node" lookup), so the nvm bin
99
+ // dir must come first — otherwise systemd's default PATH finds a system
100
+ // node (e.g. v20) that pi's undici is incompatible with.
101
+ const nodeDir = path.dirname(nodeBin);
102
+ return `[Unit]
103
+ Description=pi-courier (messengers -> pi RPC)
104
+ After=default.target
105
+
106
+ [Service]
107
+ Type=simple
108
+ WorkingDirectory=${projDir}
109
+ Environment=PATH=${nodeDir}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
110
+ EnvironmentFile=-%h/.config/pi-bridge.env
111
+ ExecStart=${nodeBin} ${projDir}/dist/standalone.js --workdir ${workdir}
112
+ Restart=on-failure
113
+ RestartSec=5
114
+ NoNewPrivileges=true
115
+ PrivateTmp=true
116
+
117
+ [Install]
118
+ WantedBy=default.target
119
+ `;
120
+ }
121
+ function cmdEnable() {
122
+ const major = Number(process.versions.node.split(".")[0]);
123
+ if (major < 21) {
124
+ console.warn(`⚠️ 当前 Node 版本为 v${process.versions.node},pi 的 undici 需要 Node >= 21。建议用 nvm 安装 v24 后重新执行本命令。`);
125
+ }
126
+ const config = loadConfig();
127
+ const projDir = projectDir();
128
+ const workdir = config.workdir ?? process.cwd();
129
+ const unit = buildUnit(projDir, workdir);
130
+ const unitPath = userUnitPath();
131
+ fs.mkdirSync(path.dirname(unitPath), { recursive: true });
132
+ fs.writeFileSync(unitPath, unit);
133
+ console.log(`📝 已写入 ${unitPath}`);
134
+ runSystemctl(["daemon-reload"]);
135
+ runSystemctl(["enable", "--now", SERVICE_NAME]);
136
+ console.log("✅ 服务已启用并启动(开机自启)。");
137
+ console.log(` 日志: journalctl --user -u ${SERVICE_NAME} -f`);
138
+ }
139
+ function runSystemctl(args) {
140
+ const res = spawnSync("systemctl", ["--user", ...args], { stdio: "inherit" });
141
+ if (res.status !== 0) {
142
+ console.error(`❌ systemctl ${args.join(" ")} 失败(退出码 ${res.status})`);
143
+ process.exit(res.status ?? 1);
144
+ }
145
+ }
146
+ function cmdService(action) {
147
+ const unitPath = userUnitPath();
148
+ if (!fs.existsSync(unitPath)) {
149
+ console.error(`❌ 服务未安装。先运行 \`pi-courier enable\` 安装。`);
150
+ process.exit(1);
151
+ }
152
+ const cmd = action === "logs"
153
+ ? ["journalctl", "--user", "-u", SERVICE_NAME, "-f"]
154
+ : ["systemctl", "--user", action, SERVICE_NAME];
155
+ const res = spawnSync(cmd[0], cmd.slice(1), { stdio: "inherit" });
156
+ if (res.status !== 0 && action !== "logs") {
157
+ process.exit(res.status ?? 1);
158
+ }
159
+ if (action === "status") {
160
+ // Append recent logs for convenience
161
+ const logs = spawnSync("journalctl", ["--user", "-u", SERVICE_NAME, "-n", "15", "--no-pager"], {
162
+ encoding: "utf-8",
163
+ });
164
+ if (logs.stdout)
165
+ console.log(logs.stdout);
166
+ }
167
+ }
168
+ function cmdDisable() {
169
+ const unitPath = userUnitPath();
170
+ if (!fs.existsSync(unitPath)) {
171
+ console.error("❌ 服务未安装(unit 文件不存在)。");
172
+ process.exit(1);
173
+ }
174
+ // Stop + remove from autostart, then delete the unit file (full uninstall).
175
+ runSystemctl(["disable", "--now", SERVICE_NAME]);
176
+ fs.rmSync(unitPath, { force: true });
177
+ runSystemctl(["daemon-reload"]);
178
+ console.log("✅ 服务已停止并卸载。以后要恢复:`pi-courier enable`(配置不受影响)。");
179
+ }
180
+ // ===========================================================================
181
+ // update
182
+ // ===========================================================================
183
+ function cmdUpdate() {
184
+ const projDir = projectDir();
185
+ const installedViaNpm = !fs.existsSync(path.join(projDir, ".git"));
186
+ if (installedViaNpm) {
187
+ // Installed with `npm install -g pi-courier` → upgrade via npm.
188
+ console.log("🔄 通过 npm 升级 pi-courier …");
189
+ const res = spawnSync("npm", ["install", "-g", "pi-courier@latest"], {
190
+ stdio: "inherit",
191
+ });
192
+ if (res.status !== 0) {
193
+ console.error(`❌ npm 升级失败(退出码 ${res.status})`);
194
+ process.exit(res.status ?? 1);
195
+ }
196
+ }
197
+ else {
198
+ // Installed from a git clone → pull + install + build.
199
+ console.log("🔄 更新 pi-courier(git)…");
200
+ for (const [cmd, args] of [
201
+ ["git", ["pull"]],
202
+ ["npm", ["install"]],
203
+ ["npm", ["run", "build"]],
204
+ ]) {
205
+ console.log(`\n$ ${cmd} ${args.join(" ")}`);
206
+ const res = spawnSync(cmd, args, { cwd: projDir, stdio: "inherit" });
207
+ if (res.status !== 0) {
208
+ console.error(`❌ ${cmd} 失败(退出码 ${res.status})`);
209
+ process.exit(res.status ?? 1);
210
+ }
211
+ }
212
+ }
213
+ // Restart the service if it's running, so the update takes effect.
214
+ const active = spawnSync("systemctl", ["--user", "is-active", SERVICE_NAME], { encoding: "utf-8" });
215
+ if (active.stdout?.trim() === "active") {
216
+ console.log("\n🔄 服务运行中,自动重启…");
217
+ runSystemctl(["restart", SERVICE_NAME]);
218
+ }
219
+ console.log("\n✅ 更新完成。");
220
+ }
221
+ // ===========================================================================
222
+ // main
223
+ // ===========================================================================
224
+ async function main() {
225
+ const [cmd, ...rest] = process.argv.slice(2);
226
+ switch (cmd) {
227
+ case "setup":
228
+ await cmdSetup();
229
+ break;
230
+ case "run":
231
+ await cmdRun(rest);
232
+ break;
233
+ case "enable":
234
+ cmdEnable();
235
+ break;
236
+ case "start":
237
+ case "stop":
238
+ case "restart":
239
+ case "status":
240
+ case "logs":
241
+ cmdService(cmd);
242
+ break;
243
+ case "disable":
244
+ cmdDisable();
245
+ break;
246
+ case "update":
247
+ cmdUpdate();
248
+ break;
249
+ case "help":
250
+ case "--help":
251
+ case "-h":
252
+ usage();
253
+ break;
254
+ default:
255
+ usage();
256
+ if (cmd)
257
+ console.error(`\n❌ 未知命令: ${cmd}`);
258
+ process.exitCode = 1;
259
+ }
260
+ }
261
+ main().catch((err) => {
262
+ console.error("[pi-courier] fatal:", err.message);
263
+ process.exit(1);
264
+ });
265
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { MsgBridgeConfig } from "./types.js";
2
+ /**
3
+ * Load config from file and env vars (env vars override file).
4
+ */
5
+ export declare function loadConfig(): MsgBridgeConfig;
6
+ /**
7
+ * Save config to file with secure permissions.
8
+ */
9
+ export declare function saveConfig(config: MsgBridgeConfig): void;
10
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD;;GAEG;AACH,wBAAgB,UAAU,IAAI,eAAe,CA2B5C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAUxD"}