@keyou007/agent-bot 0.1.4 → 0.1.5

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/src/cli.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import fs from "node:fs";
2
3
  import { spawnSync } from "node:child_process";
3
4
  import { fileURLToPath } from "node:url";
4
5
  import qrcode from "qrcode-terminal";
@@ -19,6 +20,7 @@ import {
19
20
  type InitializationResult,
20
21
  type InitializationStatus,
21
22
  } from "./cli/Initializer.js";
23
+ import { parseInitCommandOptions, type InitCommandOptions } from "./cli/initOptions.js";
22
24
  import {
23
25
  registerFeishuApp,
24
26
  type FeishuAppCredentials,
@@ -47,6 +49,7 @@ import {
47
49
  prepareCrashReportDirectory,
48
50
  resolveSupervisorDiagnosticsPaths,
49
51
  } from "./supervision/SupervisorDiagnostics.js";
52
+ import { agentBotHome, defaultSqlitePath } from "./config/paths.js";
50
53
 
51
54
  const args = process.argv.slice(2);
52
55
 
@@ -69,7 +72,7 @@ async function main(input: string[]): Promise<void> {
69
72
  return;
70
73
  }
71
74
  if (command === "init") {
72
- await initCommand(rest, parsed.configPath);
75
+ await initCommand(rest, parsed.configPath, Boolean(parsed.profilePath));
73
76
  return;
74
77
  }
75
78
  if (command === "console") {
@@ -102,44 +105,43 @@ interface InitCommandResult extends InitializationResult {
102
105
  server: InitializationServerResult;
103
106
  }
104
107
 
105
- async function initCommand(input: string[], configPath?: string): Promise<void> {
106
- const supported = new Set(["--json", "--skip-feishu", "--reconfigure-feishu"]);
107
- const unsupported = input.filter((value) => !supported.has(value));
108
- if (unsupported.length > 0) throw new Error(`Unsupported init options: ${unsupported.join(" ")}`);
109
- const json = input.includes("--json");
110
- const skipFeishu = input.includes("--skip-feishu");
111
- const reconfigureFeishu = input.includes("--reconfigure-feishu");
112
- if (skipFeishu && reconfigureFeishu) {
113
- throw new Error("--skip-feishu and --reconfigure-feishu cannot be used together.");
114
- }
115
-
116
- const paths = initializeAgentBot({ configPath });
117
- if (!json) printInitializationPaths(paths);
118
- const initializationLock = acquireInitializationLock(paths.home.path);
119
-
108
+ async function initCommand(
109
+ input: string[],
110
+ configPath: string | undefined,
111
+ explicitProfile: boolean,
112
+ ): Promise<void> {
113
+ const options = parseInitCommandOptions(input, explicitProfile);
114
+ let initializationLock = options.reset
115
+ ? acquireInitializationLock(agentBotHome())
116
+ : undefined;
117
+ let paths: InitializationResult;
120
118
  let initialized: Omit<InitCommandResult, "server">;
121
119
  try {
120
+ if (options.reset) await assertResetProfileServerStopped(configPath);
121
+ paths = initializeAgentBot({ configPath, reset: options.reset });
122
+ if (!options.json) printInitializationPaths(paths);
123
+ initializationLock ??= acquireInitializationLock(paths.home.path);
122
124
  cleanupFeishuCredentialTemporaryFiles(paths.env.path);
123
125
  const feishu = await initializeFeishu(
124
126
  paths,
125
- { json, skipFeishu, reconfigureFeishu },
127
+ options,
126
128
  );
127
129
  initialized = { ...paths, feishu };
128
130
  } finally {
129
- initializationLock.release();
131
+ initializationLock?.release();
130
132
  }
131
133
 
132
- if (!json) printInitializationResult(initialized);
133
- if (!json && !skipFeishu) process.stdout.write("\nStarting Agent Bot server...\n");
134
- const server = await startInitializedServer({ skipFeishu, configPath });
134
+ if (!options.json) printInitializationResult(initialized);
135
+ if (!options.json && !options.skipFeishu) process.stdout.write("\nStarting Agent Bot server...\n");
136
+ const server = await startInitializedServer({ skipFeishu: options.skipFeishu, configPath });
135
137
  const result: InitCommandResult = { ...initialized, server };
136
- if (json) printJson(result);
138
+ if (options.json) printJson(result);
137
139
  else printInitializationServerResult(server);
138
140
  }
139
141
 
140
142
  async function initializeFeishu(
141
143
  paths: InitializationResult,
142
- options: { json: boolean; skipFeishu: boolean; reconfigureFeishu: boolean },
144
+ options: InitCommandOptions,
143
145
  ): Promise<InitCommandResult["feishu"]> {
144
146
  const existing = readFeishuCredentials(paths.env.path);
145
147
  if (options.skipFeishu) {
@@ -191,6 +193,25 @@ async function initializeFeishu(
191
193
  }
192
194
  }
193
195
 
196
+ async function assertResetProfileServerStopped(configPath?: string): Promise<void> {
197
+ const endpoints = new Set<string>([controlEndpoint(defaultSqlitePath())]);
198
+ const selectedConfigPath = configPath ?? process.env.AGENT_BOT_CONFIG;
199
+ if (selectedConfigPath && fs.existsSync(selectedConfigPath)) {
200
+ try {
201
+ endpoints.add(controlEndpoint(loadConfig(selectedConfigPath).storage.sqlitePath));
202
+ } catch {
203
+ // Reset must remain available when the existing configuration is invalid.
204
+ }
205
+ }
206
+ for (const endpoint of endpoints) {
207
+ if (await isServerReachable(endpoint)) {
208
+ throw new Error(
209
+ "Cannot reset a running profile. Stop it with agent-bot --profile <directory> server stop, then try again.",
210
+ );
211
+ }
212
+ }
213
+ }
214
+
194
215
  function skillsCommand(input: string[]): void {
195
216
  const [action = "status", ...rest] = input;
196
217
  const sourcePath = fileURLToPath(new URL("../skills/agent-bot/", import.meta.url));
@@ -462,6 +483,9 @@ function printSkillStatus(status: SkillRegistrationStatus): void {
462
483
 
463
484
  function printInitializationPaths(result: InitializationResult): void {
464
485
  process.stdout.write("Preparing the Agent Bot user environment...\n");
486
+ if (result.reset) {
487
+ process.stdout.write(`Reset backup: ${result.reset.backupPath}\n`);
488
+ }
465
489
  process.stdout.write(`Home directory: ${result.home.path} (${initializationStatusLabel(result.home.status)})\n`);
466
490
  process.stdout.write(`Config file: ${result.config.path} (${initializationStatusLabel(result.config.status)})\n`);
467
491
  process.stdout.write(`Environment file: ${result.env.path} (${initializationStatusLabel(result.env.status)})\n`);
@@ -603,6 +627,7 @@ function optionalFeishuFeatureWarnings(missing: FeishuConfigurationChallenge["mi
603
627
 
604
628
  function initializationStatusLabel(status: InitializationStatus): string {
605
629
  if (status === "created") return "created";
630
+ if (status === "reset") return "reset from template";
606
631
  return "already exists; unchanged";
607
632
  }
608
633
 
@@ -16,6 +16,7 @@ import { localCardImage } from "./LocalCardImage.js";
16
16
  export interface StartupStatusView {
17
17
  startedAt: Date;
18
18
  restartReason: string;
19
+ agentBotVersion: string;
19
20
  defaultAgentName: string;
20
21
  defaultAgentTitle: string;
21
22
  cwd: string;
@@ -340,6 +341,7 @@ export class CardRenderer {
340
341
  `**默认 Agent**:${view.defaultAgentTitle} (${inlineCode(view.defaultAgentName)})`,
341
342
  ];
342
343
  lines.push(
344
+ `**Agent Bot 版本**:${inlineCode(view.agentBotVersion)}`,
343
345
  `**服务状态 / 启动时间**:🟢 在线 / ${formatStartupTime(view.startedAt)}`,
344
346
  `**重启原因**:${inlineCode(view.restartReason)}`,
345
347
  "> 发送消息即可开始对话;发送 `/new` 创建新任务;发送 `/help` 查看帮助。",
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ import { CodexProcessManager } from "./codex/CodexProcessManager.js";
7
7
  import { CodexRuntime } from "./codex/CodexRuntime.js";
8
8
  import { LocalControlServer } from "./cli/LocalControlServer.js";
9
9
  import { controlEndpoint, type ControlRequest, type ControlResponse } from "./cli/controlProtocol.js";
10
+ import { readPackageVersion } from "./cli/packageVersion.js";
10
11
  import { loadConfig } from "./config/loadConfig.js";
11
12
  import { ConsoleConnector } from "./console/ConsoleConnector.js";
12
13
  import { ConsoleTurnPresenter } from "./console/ConsoleTurnPresenter.js";
@@ -36,6 +37,7 @@ import {
36
37
  } from "./supervision/SupervisorDiagnostics.js";
37
38
 
38
39
  const processStartedAt = new Date();
40
+ const agentBotVersion = readPackageVersion();
39
41
  const supervised = process.env.AGENT_BOT_SUPERVISED === "1";
40
42
  const startupReason = process.env.AGENT_BOT_RESTART_REASON?.trim()
41
43
  || (supervised ? "Supervisor 启动" : "直接启动");
@@ -79,6 +81,7 @@ if (feishuOutbound) {
79
81
  const defaultAgent = config.agents[defaultAgentName];
80
82
  const metadataHydrator = new SessionMetadataHydrator(store, runtimes);
81
83
  startupNotifier = new StartupNotifier(store, feishuOutbound, renderer, logger, {
84
+ agentBotVersion,
82
85
  defaultAgentName,
83
86
  defaultAgentTitle: defaultAgent?.title ?? defaultAgentName,
84
87
  cwd: path.resolve(config.defaults.cwd),
@@ -5,6 +5,7 @@ import type { FeishuOutbound } from "../feishu/types.js";
5
5
  import type { SessionRecord, StateStore, UserContextRecord } from "../state/StateStore.js";
6
6
 
7
7
  export interface StartupNotificationOptions {
8
+ agentBotVersion: string;
8
9
  defaultAgentName: string;
9
10
  defaultAgentTitle: string;
10
11
  cwd: string;
@@ -74,6 +75,7 @@ export class StartupNotifier {
74
75
  const card = this.renderer.renderStartupStatus({
75
76
  startedAt,
76
77
  restartReason,
78
+ agentBotVersion: this.options.agentBotVersion,
77
79
  defaultAgentName: this.options.defaultAgentName,
78
80
  defaultAgentTitle: this.options.defaultAgentTitle,
79
81
  cwd,