@messenger-agent/client 0.24.0-alpha.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/dist/args.d.ts ADDED
@@ -0,0 +1,66 @@
1
+ import { type ReleaseChannel } from "./runtime.js";
2
+ export type InstallArgs = {
3
+ command: "install";
4
+ tunnelId?: string;
5
+ token?: string;
6
+ workspace?: string;
7
+ serverUrl?: string;
8
+ configPath: string;
9
+ dataDir: string;
10
+ workspaceId?: string;
11
+ workspaceName?: string;
12
+ channel?: ReleaseChannel;
13
+ };
14
+ export type UpgradeArgs = {
15
+ command: "upgrade";
16
+ version: string;
17
+ configPath: string;
18
+ delaySeconds?: number;
19
+ allowWaiting: boolean;
20
+ channel?: ReleaseChannel;
21
+ };
22
+ export type VersionArgs = {
23
+ command: "version";
24
+ };
25
+ export type SessionsArgs = {
26
+ command: "sessions";
27
+ json: boolean;
28
+ configPath: string;
29
+ };
30
+ export type MaintenanceArgs = {
31
+ command: "maintenance";
32
+ action: "status" | "cancel";
33
+ json: boolean;
34
+ configPath: string;
35
+ };
36
+ export type RunServiceArgs = {
37
+ command: "run-service";
38
+ configPath?: string;
39
+ };
40
+ export type StatusArgs = {
41
+ command: "status";
42
+ };
43
+ export type StartArgs = {
44
+ command: "start";
45
+ };
46
+ export type RestartArgs = {
47
+ command: "restart";
48
+ agent?: "codex" | "claude";
49
+ delaySeconds?: number;
50
+ allowWaiting: boolean;
51
+ };
52
+ export type StopArgs = {
53
+ command: "stop";
54
+ delaySeconds?: number;
55
+ allowWaiting: boolean;
56
+ };
57
+ export type UninstallArgs = {
58
+ command: "uninstall";
59
+ delaySeconds?: number;
60
+ allowWaiting: boolean;
61
+ };
62
+ export type CliArgs = InstallArgs | UpgradeArgs | VersionArgs | SessionsArgs | MaintenanceArgs | RunServiceArgs | StatusArgs | StartArgs | RestartArgs | StopArgs | UninstallArgs;
63
+ export declare class UsageError extends Error {
64
+ }
65
+ export declare function parseCliArgs(argv: string[], env?: NodeJS.ProcessEnv): CliArgs;
66
+ export declare function usage(): string;
package/dist/args.js ADDED
@@ -0,0 +1,303 @@
1
+ import cac from "cac";
2
+ import { defaultConfigPath, defaultDataDir, resolvePath } from "./paths.js";
3
+ import { normalizeReleaseChannel } from "./runtime.js";
4
+ const serverUrlEnvName = "CODING_AGENT_TUNNEL_SERVER_URL";
5
+ const publicCommands = [
6
+ "install",
7
+ "upgrade",
8
+ "sessions",
9
+ "maintenance",
10
+ "status",
11
+ "start",
12
+ "restart",
13
+ "stop",
14
+ "uninstall",
15
+ ];
16
+ const allCommands = [...publicCommands, "run-service"];
17
+ export class UsageError extends Error {
18
+ }
19
+ export function parseCliArgs(argv, env = process.env) {
20
+ if (argv[0] === "--version" || argv[0] === "-v") {
21
+ if (argv.length > 1)
22
+ throw new UsageError(`Unknown option for version: ${argv[1]}`);
23
+ return { command: "version" };
24
+ }
25
+ const command = argv[0];
26
+ if (!command || command === "--help" || command === "-h") {
27
+ throw new UsageError(usage());
28
+ }
29
+ if (argv.includes("--")) {
30
+ throw new UsageError(`Unknown option for ${command}: --`);
31
+ }
32
+ assertKnownOptions(argv);
33
+ let parsedArgs;
34
+ const cli = createCli({
35
+ env,
36
+ includeInternalCommands: true,
37
+ onParsed(args) {
38
+ parsedArgs = args;
39
+ },
40
+ });
41
+ try {
42
+ cli.parse(["node", "coding-agent", ...argv]);
43
+ }
44
+ catch (err) {
45
+ const message = err instanceof Error ? err.message : String(err);
46
+ throw new UsageError(normalizeCacError(message, argv));
47
+ }
48
+ if (!parsedArgs) {
49
+ throw new UsageError(`Unknown command: ${command}`);
50
+ }
51
+ return parsedArgs;
52
+ }
53
+ export function usage() {
54
+ const cli = createCli({ includeInternalCommands: false });
55
+ cli.help();
56
+ return `${captureConsoleInfo(() => cli.outputHelp())}\n\nGlobal Options:\n -v, --version Show the installed client version`;
57
+ }
58
+ function createCli(options) {
59
+ const cli = cac("coding-agent");
60
+ const env = options.env ?? process.env;
61
+ const onParsed = options.onParsed ?? (() => undefined);
62
+ cli
63
+ .command("install", "Install and configure the local coding-agent service")
64
+ .option("--tunnel-id <id>", "Tunnel id")
65
+ .option("--token <token>", "Tunnel token")
66
+ .option("--workspace <path>", "Workspace path (default: ~/messenger-workspace)")
67
+ .option("--server-url <wss-url>", "Tunnel server URL")
68
+ .option("--config <path>", "Config file path", { default: defaultConfigPath })
69
+ .option("--data-dir <path>", "Data directory", { default: defaultDataDir })
70
+ .option("--workspace-id <id>", "Workspace id")
71
+ .option("--workspace-name <name>", "Workspace display name")
72
+ .option("--channel <channel>", "Auto-upgrade release channel: latest, beta, or alpha")
73
+ .action((commandOptions) => {
74
+ const tunnelId = optionalString(commandOptions.tunnelId);
75
+ const token = optionalString(commandOptions.token);
76
+ const workspace = optionalString(commandOptions.workspace);
77
+ onParsed({
78
+ command: "install",
79
+ tunnelId,
80
+ token,
81
+ workspace: workspace ? resolvePath(workspace) : undefined,
82
+ serverUrl: optionalString(commandOptions.serverUrl) ?? env[serverUrlEnvName],
83
+ configPath: resolvePath(requiredString(commandOptions.config, "--config")),
84
+ dataDir: resolvePath(requiredString(commandOptions.dataDir, "--data-dir")),
85
+ workspaceId: optionalString(commandOptions.workspaceId),
86
+ workspaceName: optionalString(commandOptions.workspaceName),
87
+ channel: parseChannelOption(commandOptions.channel),
88
+ });
89
+ });
90
+ cli
91
+ .command("upgrade", "Upgrade the local coding-agent runtime")
92
+ .option("--version <version>", "Runtime version or release channel", { default: "latest" })
93
+ .option("--channel <channel>", "Auto-upgrade release channel: latest, beta, or alpha")
94
+ .option("--config <path>", "Config file path", { default: defaultConfigPath })
95
+ .option("--delay <seconds>", "Schedule the upgrade after a delay")
96
+ .option("--allow-waiting", "Allow upgrade while sessions wait for user input")
97
+ .action((commandOptions) => {
98
+ const delaySeconds = optionalDelay(commandOptions.delay);
99
+ const allowWaiting = commandOptions.allowWaiting === true;
100
+ assertAllowWaitingHasDelay(allowWaiting, delaySeconds);
101
+ onParsed({
102
+ command: "upgrade",
103
+ version: requiredString(commandOptions.version, "--version"),
104
+ configPath: resolvePath(requiredString(commandOptions.config, "--config")),
105
+ delaySeconds,
106
+ allowWaiting,
107
+ channel: parseChannelOption(commandOptions.channel),
108
+ });
109
+ });
110
+ cli
111
+ .command("sessions", "Show active and waiting client sessions")
112
+ .option("--json", "Print machine-readable JSON")
113
+ .option("--config <path>", "Config file path", { default: defaultConfigPath })
114
+ .action((commandOptions) => {
115
+ onParsed({
116
+ command: "sessions",
117
+ json: commandOptions.json === true,
118
+ configPath: resolvePath(requiredString(commandOptions.config, "--config")),
119
+ });
120
+ });
121
+ cli
122
+ .command("maintenance <action>", "Inspect or cancel scheduled maintenance")
123
+ .option("--json", "Print machine-readable JSON")
124
+ .option("--config <path>", "Config file path", { default: defaultConfigPath })
125
+ .action((action, commandOptions) => {
126
+ if (action !== "status" && action !== "cancel") {
127
+ throw new UsageError(`Unknown maintenance action: ${action}`);
128
+ }
129
+ onParsed({
130
+ command: "maintenance",
131
+ action,
132
+ json: commandOptions.json === true,
133
+ configPath: resolvePath(requiredString(commandOptions.config, "--config")),
134
+ });
135
+ });
136
+ for (const command of ["status", "start"]) {
137
+ cli.command(command, `${capitalize(command)} the local coding-agent service`).action(() => {
138
+ onParsed({ command });
139
+ });
140
+ }
141
+ cli
142
+ .command("restart [agent]", "Restart the local service or a specific agent")
143
+ .option("--delay <seconds>", "Schedule the restart after a delay")
144
+ .option("--allow-waiting", "Allow restart while sessions wait for user input")
145
+ .action((agent, commandOptions) => {
146
+ if (agent !== undefined && agent !== "codex" && agent !== "claude") {
147
+ throw new UsageError(`Unknown agent for restart: ${agent}`);
148
+ }
149
+ const delaySeconds = optionalDelay(commandOptions.delay);
150
+ const allowWaiting = commandOptions.allowWaiting === true;
151
+ assertAllowWaitingHasDelay(allowWaiting, delaySeconds);
152
+ onParsed({ command: "restart", agent, delaySeconds, allowWaiting });
153
+ });
154
+ for (const command of ["stop", "uninstall"]) {
155
+ cli
156
+ .command(command, `${capitalize(command)} the local coding-agent service`)
157
+ .option("--delay <seconds>", `Schedule the ${command} after a delay`)
158
+ .option("--allow-waiting", `Allow ${command} while sessions wait for user input`)
159
+ .action((commandOptions) => {
160
+ const delaySeconds = optionalDelay(commandOptions.delay);
161
+ const allowWaiting = commandOptions.allowWaiting === true;
162
+ assertAllowWaitingHasDelay(allowWaiting, delaySeconds);
163
+ onParsed({ command, delaySeconds, allowWaiting });
164
+ });
165
+ }
166
+ if (options.includeInternalCommands) {
167
+ cli
168
+ .command("run-service", "Run the managed service supervisor")
169
+ .option("--config <path>", "Config file path")
170
+ .action((commandOptions) => {
171
+ const configPath = optionalString(commandOptions.config);
172
+ onParsed({ command: "run-service", configPath: configPath ? resolvePath(configPath) : undefined });
173
+ });
174
+ }
175
+ return cli;
176
+ }
177
+ function requiredString(value, name) {
178
+ const text = optionalString(value);
179
+ if (!text)
180
+ throw new UsageError(`Missing value for ${name}`);
181
+ return text;
182
+ }
183
+ function optionalString(value) {
184
+ return typeof value === "string" ? value : undefined;
185
+ }
186
+ function parseChannelOption(value) {
187
+ const text = optionalString(value);
188
+ if (text === undefined)
189
+ return undefined;
190
+ try {
191
+ return normalizeReleaseChannel(text);
192
+ }
193
+ catch {
194
+ throw new UsageError(`Unknown release channel for --channel: ${text} (expected latest, beta, or alpha)`);
195
+ }
196
+ }
197
+ function optionalDelay(value) {
198
+ if (value === undefined)
199
+ return undefined;
200
+ const text = typeof value === "number" ? String(value) : requiredString(value, "--delay");
201
+ if (!/^\d+$/.test(text))
202
+ throw new UsageError("--delay must be an integer between 1 and 86400 seconds");
203
+ const delay = Number.parseInt(text, 10);
204
+ if (delay < 1 || delay > 86_400) {
205
+ throw new UsageError("--delay must be an integer between 1 and 86400 seconds");
206
+ }
207
+ return delay;
208
+ }
209
+ function assertAllowWaitingHasDelay(allowWaiting, delaySeconds) {
210
+ if (allowWaiting && delaySeconds === undefined) {
211
+ throw new UsageError("--allow-waiting requires --delay");
212
+ }
213
+ }
214
+ function normalizeCacError(message, argv) {
215
+ if (message.startsWith("Unknown option `")) {
216
+ const rawOption = findFirstUnknownOption(argv);
217
+ if (rawOption)
218
+ return `Unknown option for ${argv[0]}: ${rawOption}`;
219
+ }
220
+ if (message.startsWith("option `")) {
221
+ const match = /^option `([^` ]+)/.exec(message);
222
+ if (match)
223
+ return `Missing value for ${match[1]}`;
224
+ }
225
+ if (message.startsWith("Unused args:")) {
226
+ const firstUnusedArg = argv.slice(1).find((arg) => !arg.startsWith("-"));
227
+ if (firstUnusedArg)
228
+ return `Unknown option for ${argv[0]}: ${firstUnusedArg}`;
229
+ }
230
+ return message;
231
+ }
232
+ function findFirstUnknownOption(argv) {
233
+ const command = argv[0];
234
+ if (!command || !isKnownCommand(command))
235
+ return argv.find((arg) => arg.startsWith("-"));
236
+ const knownOptions = knownOptionsForCommand(command);
237
+ for (const arg of argv.slice(1)) {
238
+ if (!arg.startsWith("-"))
239
+ continue;
240
+ const optionName = arg.includes("=") ? arg.slice(0, arg.indexOf("=")) : arg;
241
+ if (!knownOptions.has(optionName))
242
+ return optionName;
243
+ }
244
+ return undefined;
245
+ }
246
+ function assertKnownOptions(argv) {
247
+ const command = argv[0];
248
+ if (!command || !isKnownCommand(command))
249
+ return;
250
+ const unknownOption = findFirstUnknownOption(argv);
251
+ if (unknownOption) {
252
+ throw new UsageError(`Unknown option for ${command}: ${unknownOption}`);
253
+ }
254
+ }
255
+ function knownOptionsForCommand(command) {
256
+ switch (command) {
257
+ case "install":
258
+ return new Set([
259
+ "--tunnel-id",
260
+ "--token",
261
+ "--workspace",
262
+ "--server-url",
263
+ "--config",
264
+ "--data-dir",
265
+ "--workspace-id",
266
+ "--workspace-name",
267
+ "--channel",
268
+ ]);
269
+ case "upgrade":
270
+ return new Set(["--version", "--channel", "--config", "--delay", "--allow-waiting"]);
271
+ case "sessions":
272
+ case "maintenance":
273
+ return new Set(["--json", "--config"]);
274
+ case "restart":
275
+ case "stop":
276
+ case "uninstall":
277
+ return new Set(["--delay", "--allow-waiting"]);
278
+ case "run-service":
279
+ return new Set(["--config"]);
280
+ default:
281
+ return new Set();
282
+ }
283
+ }
284
+ function isKnownCommand(command) {
285
+ return allCommands.includes(command);
286
+ }
287
+ function captureConsoleInfo(callback) {
288
+ const originalInfo = console.info;
289
+ const output = [];
290
+ console.info = (...args) => {
291
+ output.push(args.map(String).join(" "));
292
+ };
293
+ try {
294
+ callback();
295
+ }
296
+ finally {
297
+ console.info = originalInfo;
298
+ }
299
+ return output.join("\n");
300
+ }
301
+ function capitalize(value) {
302
+ return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
303
+ }
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: manage-coding-agent-client
3
+ description: 管理本机 coding-agent client,包括查询版本和会话状态、升级、启动、停止、重启 Codex/Claude、查看日志和卸载。用户要求检查、升级、重启、停止、排查或卸载 coding-agent client 时使用。
4
+ ---
5
+
6
+ # 管理 Coding Agent Client
7
+
8
+ 始终使用安装后生成的稳定命令:
9
+
10
+ ```bash
11
+ ~/.coding-agent/bin/coding-agent
12
+ ```
13
+
14
+ ## 检查状态
15
+
16
+ 查询版本和服务状态:
17
+
18
+ ```bash
19
+ ~/.coding-agent/bin/coding-agent --version
20
+ ~/.coding-agent/bin/coding-agent status
21
+ ```
22
+
23
+ 执行任何会中断 Agent 的操作前,先查询会话:
24
+
25
+ ```bash
26
+ ~/.coding-agent/bin/coding-agent sessions --json
27
+ ```
28
+
29
+ 按以下规则处理结果:
30
+
31
+ - 当前管理请求也计入 `active`。`active` 为 0 或 1 时,没有其他活动会话。
32
+ - `active` 大于 1 时,说明还有 `active - 1` 个其他活动会话。告知用户,并确认是否安排为全部空闲后执行。
33
+ - 任一 Agent 为 `unavailable` 时,不要安排操作;说明无法可靠判断会话状态。
34
+ - `waiting` 大于 0 时,说明升级或重启可能使等待回答或批准的交互失效。必须获得用户明确确认,确认后在调度命令中加入 `--allow-waiting`。
35
+
36
+ ## 延后执行
37
+
38
+ 升级、重启、停止和卸载必须交给 client supervisor 延后执行。不要使用 `sleep`、`nohup`、后台 shell,也不要在当前会话中立即执行这些操作。
39
+
40
+ 默认延后 10 秒:
41
+
42
+ ```bash
43
+ ~/.coding-agent/bin/coding-agent upgrade --delay 10
44
+ ~/.coding-agent/bin/coding-agent upgrade --version <version> --delay 10
45
+ ~/.coding-agent/bin/coding-agent restart --delay 10
46
+ ~/.coding-agent/bin/coding-agent restart codex --delay 10
47
+ ~/.coding-agent/bin/coding-agent restart claude --delay 10
48
+ ~/.coding-agent/bin/coding-agent stop --delay 10
49
+ ~/.coding-agent/bin/coding-agent uninstall --delay 10
50
+ ```
51
+
52
+ 存在 waiting 会话且用户已经确认时,追加:
53
+
54
+ ```bash
55
+ --allow-waiting
56
+ ```
57
+
58
+ 调度命令必须是本轮的最后一个工具动作。确认命令返回 maintenance task id 后,立即回复用户,不再运行其他命令。升级时回复:
59
+
60
+ > 客户端 Agent 已安排在最早 10 秒后升级并重启;如果届时仍有会话正在运行,将等待空闲后执行。
61
+
62
+ 重启、停止或卸载时,将“升级并重启”替换为对应操作。
63
+
64
+ ## 管理延后任务
65
+
66
+ 查询或取消任务:
67
+
68
+ ```bash
69
+ ~/.coding-agent/bin/coding-agent maintenance status
70
+ ~/.coding-agent/bin/coding-agent maintenance cancel
71
+ ```
72
+
73
+ 同一时间只能有一个延后任务。新会话中可使用 `maintenance status`、`--version` 和 `status` 验证升级结果。
74
+
75
+ ## 操作影响
76
+
77
+ - `upgrade` 安装目标 runtime,并重启整个 client 服务。
78
+ - `restart codex` 或 `restart claude` 只重启对应 Agent。
79
+ - 不带 Agent 的 `restart` 重启整个 client 服务。
80
+ - `stop` 停止服务,必须先获得用户确认。
81
+
82
+ ## 发布通道
83
+
84
+ client 的自动升级默认跟踪稳定版本(`latest` 通道)。用户要求使用预发布版本或回到稳定版时,切换发布通道:
85
+
86
+ ```bash
87
+ ~/.coding-agent/bin/coding-agent upgrade --channel beta --delay 10
88
+ ~/.coding-agent/bin/coding-agent upgrade --channel alpha --delay 10
89
+ ~/.coding-agent/bin/coding-agent upgrade --channel latest --delay 10
90
+ ```
91
+
92
+ 切换通道会更新自动升级跟踪的 npm dist-tag,并把 runtime 升级到该通道的最新版本。之后自动升级会持续跟踪同一通道,直到用户再次切换。
93
+
94
+ - `uninstall` 停止并移除用户服务,但保留配置、数据、工作空间和已下载的 runtime。执行前说明保留项并获得确认。
95
+ - 不要使用全局 npm 安装代替内置升级命令。
96
+
97
+ ## 日志排查
98
+
99
+ 先判断系统类型,再读取最近 100 行,避免默认持续跟随日志。
100
+
101
+ Linux:
102
+
103
+ ```bash
104
+ journalctl --user -u coding-agent-client.service -n 100 --no-pager
105
+ ```
106
+
107
+ macOS:
108
+
109
+ ```bash
110
+ tail -n 100 ~/.coding-agent/data/logs/client-service.out.log
111
+ tail -n 100 ~/.coding-agent/data/logs/client-service.err.log
112
+ ```
113
+
114
+ 提醒用户在分享日志前检查并隐藏 token、服务地址和敏感路径。
@@ -0,0 +1,43 @@
1
+ import type { MaintenanceScheduler } from "./maintenance.js";
2
+ import { type ReleaseChannel } from "./runtime.js";
3
+ export type AutoUpgradeState = {
4
+ status: "up-to-date" | "pending" | "scheduled" | "failed";
5
+ currentVersion: string;
6
+ channel: ReleaseChannel;
7
+ latestVersion?: string;
8
+ lastCheckedAt?: string;
9
+ updatedAt: string;
10
+ message?: string;
11
+ };
12
+ type AutoUpgradeOptions = {
13
+ statePath: string;
14
+ maintenance: MaintenanceScheduler;
15
+ getChannel?: () => Promise<ReleaseChannel>;
16
+ checkIntervalMs?: number;
17
+ pendingRetryMs?: number;
18
+ now?: () => number;
19
+ getCurrentVersion?: () => Promise<string>;
20
+ getLatestVersion?: (channel: ReleaseChannel) => Promise<string>;
21
+ };
22
+ export declare class AutoUpgradeScheduler {
23
+ private readonly options;
24
+ private state;
25
+ private timer;
26
+ private readonly checkIntervalMs;
27
+ private readonly pendingRetryMs;
28
+ private readonly now;
29
+ private readonly getCurrentVersion;
30
+ private readonly getLatestVersion;
31
+ private readonly getChannel;
32
+ constructor(options: AutoUpgradeOptions);
33
+ start(): Promise<void>;
34
+ stop(): void;
35
+ getState(): AutoUpgradeState | undefined;
36
+ checkNow(): Promise<void>;
37
+ private arm;
38
+ private tick;
39
+ private updateState;
40
+ private readState;
41
+ private isoNow;
42
+ }
43
+ export {};