aws-runtime-bridge 1.9.77 → 1.9.78

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.
@@ -1,4 +1,5 @@
1
1
  import type { StartupConfigWizardResult } from "./startup-config-wizard.js";
2
+ import { type WindowsServiceManager } from "./windows-service-manager.js";
2
3
  export interface CliCommandResult {
3
4
  handled: boolean;
4
5
  exitCode: number;
@@ -19,8 +20,10 @@ export interface CliCommandOptions {
19
20
  platform?: NodeJS.Platform;
20
21
  serviceUnitPath?: string;
21
22
  executablePath?: string;
22
- /** Windows 服务日志文件路径(默认 ProgramData 下的 awsb-service.log),供 install 重定向与 log 读取。 */
23
+ /** Windows 服务日志文件路径(默认 ProgramData 下的 awsb.out.log),供 install 重定向与 log 读取。 */
23
24
  windowsServiceLogPath?: string;
25
+ /** Windows 服务管理器(基于 node-windows),用于 install 操作;测试时可注入 mock。 */
26
+ windowsServiceManager?: WindowsServiceManager;
24
27
  /** 检测正在运行的 bridge 进程 PID 列表(默认按平台用 pgrep / powershell)。 */
25
28
  findRunningBridgeProcesses?: (platform: NodeJS.Platform) => number[];
26
29
  /** 关闭指定 PID 的进程(默认按平台用 kill -9 / taskkill)。 */
@@ -1 +1 @@
1
- {"version":3,"file":"cli-commands.d.ts","sourceRoot":"","sources":["../../src/services/cli-commands.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAqB5E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,gBAAgB,CAAC;IACnE,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACrD,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,0BAA0B,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;IACrE,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC;IACrE,oCAAoC;IACpC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAChD;AAYD,wBAAgB,kBAAkB,CAAC,WAAW,SAA0B,GAAG,MAAM,CAMhF;AAgCD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAsBvE;AAkuBD,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CA8C3B"}
1
+ {"version":3,"file":"cli-commands.d.ts","sourceRoot":"","sources":["../../src/services/cli-commands.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAK5E,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,8BAA8B,CAAC;AAkBtC,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,gBAAgB,CAAC;IACnE,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACrD,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,gEAAgE;IAChE,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,2DAA2D;IAC3D,0BAA0B,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;IACrE,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC;IACrE,oCAAoC;IACpC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAChD;AAYD,wBAAgB,kBAAkB,CAAC,WAAW,SAA0B,GAAG,MAAM,CAMhF;AAgCD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAsBvE;AA8sBD,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CA8C3B"}
@@ -4,13 +4,15 @@ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { configureStartupConfig, printConfigExampleCommand, } from "./startup-config-wizard.js";
7
+ import { createWindowsServiceManager, isNodeWindowsAvailable, } from "./windows-service-manager.js";
7
8
  const SYSTEMD_SERVICE_NAME = "awsb.service";
8
9
  const DEFAULT_SYSTEMD_UNIT_PATH = `/etc/systemd/system/${SYSTEMD_SERVICE_NAME}`;
9
10
  const WINDOWS_SERVICE_NAME = "awsb";
10
- // Windows 服务日志:install 时用 nssm AppStdout/AppStderr 把 node 输出重定向到此文件,
11
- // `awsb log` 再读取它。路径放在 ProgramData 下,保证安装用户与服务运行账户(LocalSystem)都能访问。
11
+ // Windows 服务日志:node-windows (WinSW)logpath 配置项将日志输出到此目录,
12
+ // 生成 awsb.out.log(stdout)和 awsb.err.log(stderr)。
13
+ // 路径放在 ProgramData 下,保证安装用户与服务运行账户(LocalSystem)都能访问。
12
14
  const WINDOWS_SERVICE_LOG_DIR = path.join(process.env.ProgramData || "C:\\ProgramData", "aws-runtime-bridge", "logs");
13
- const WINDOWS_SERVICE_LOG_PATH = path.join(WINDOWS_SERVICE_LOG_DIR, "awsb-service.log");
15
+ const WINDOWS_SERVICE_LOG_PATH = path.join(WINDOWS_SERVICE_LOG_DIR, "awsb.out.log");
14
16
  function getDefaultPackageRoot() {
15
17
  const currentFile = fileURLToPath(import.meta.url);
16
18
  return path.resolve(path.dirname(currentFile), "..", "..");
@@ -273,100 +275,98 @@ function stopSystemdService(options) {
273
275
  options.stdout("[runtime-bridge] awsb systemd 服务已停止。");
274
276
  return { handled: true, exitCode: 0 };
275
277
  }
276
- function findNssmCommand(options) {
277
- const probe = options.runCommand("nssm", ["version"]);
278
- return commandSucceeded(probe) ? "nssm" : null;
279
- }
280
- function nssmMissingError(options) {
281
- options.stderr("[runtime-bridge] 未检测到 nssm(Windows 服务包装器)。在 Windows 上把 node 程序" +
282
- "注册为真正的服务必须借助 nssm 实现 SCM 协议,否则会像之前一样“启动失败”。请先安装 nssm:\n" +
283
- " winget install nssm\n" +
284
- " 或 choco install nssm\n" +
285
- " 或访问 https://nssm.cc 下载 nssm.exe 并放入 PATH,然后重试。");
278
+ /**
279
+ * Windows 服务通过 node-windows(内置 WinSW 包装器)实现 SCM 协议适配。
280
+ * 用户 `npm install -g aws-runtime-bridge` 时自动获得 node-windows,无需额外安装 nssm。
281
+ *
282
+ * - install: 用 node-windows 注册服务(WinSW 包装器处理 SCM 协议);
283
+ * - uninstall/start/stop/restart: 用 sc.exe(Windows 原生命令)直接操作 SCM。
284
+ */
285
+ function nodeWindowsMissingError(stderr) {
286
+ stderr("[runtime-bridge] 未检测到 node-windows 模块。请重新安装 aws-runtime-bridge:\n" +
287
+ " npm install -g aws-runtime-bridge");
286
288
  return { handled: true, exitCode: 1 };
287
289
  }
288
290
  /**
289
- * 用 nssm 安装并启动 Windows 服务。
290
- * - nssm install `node <executablePath>` 注册为真正的 Windows 服务(SCM 协议由 nssm 实现);
291
- * - 安装前先 remove 一次,清理可能由旧 `New-Service` 方式残留的坏服务;
292
- * - AppStdout/AppStderr 把输出写入 ProgramData 下的日志文件,供 `awsb log` 读取。
293
- * 日志目录创建失败不阻断安装(nssm 启动时按需创建)。
291
+ * 用 node-windows 安装并启动 Windows 服务。
292
+ * - node-windows script 所在目录下创建 daemon/ 子目录(含 WinSW 包装器和 XML 配置);
293
+ * - logpath 配置项将日志输出到 ProgramData 下的指定目录,供 `awsb log` 读取;
294
+ * - 安装后用 sc.exe start 启动服务。
294
295
  */
295
- function installWindowsService(options) {
296
- const nssm = findNssmCommand(options);
297
- if (!nssm) {
298
- return nssmMissingError(options);
296
+ async function installWindowsService(options) {
297
+ // 测试时可注入 mock manager;生产环境用 node-windows 默认实现
298
+ const manager = options.windowsServiceManager;
299
+ if (!manager && !isNodeWindowsAvailable()) {
300
+ return nodeWindowsMissingError(options.stderr);
299
301
  }
300
302
  const logPath = options.windowsServiceLogPath || WINDOWS_SERVICE_LOG_PATH;
301
303
  const execDir = path.dirname(options.executablePath);
302
304
  try {
303
- mkdirSync(WINDOWS_SERVICE_LOG_DIR, { recursive: true });
305
+ const actualManager = manager || createWindowsServiceManager();
306
+ await actualManager.install({
307
+ name: WINDOWS_SERVICE_NAME,
308
+ description: "awsb runtime bridge",
309
+ script: options.executablePath,
310
+ workingDirectory: execDir,
311
+ env: [{ name: "AWS_BRIDGE_SKIP_SETUP", value: "true" }],
312
+ logpath: WINDOWS_SERVICE_LOG_DIR,
313
+ });
304
314
  }
305
- catch {
306
- // 日志目录创建失败不阻断安装
307
- }
308
- const run = (args) => options.runCommand(nssm, args);
309
- // 清理可能残留的旧服务(含非 nssm 创建的),忽略失败
310
- run(["remove", WINDOWS_SERVICE_NAME, "confirm"]);
311
- run(["install", WINDOWS_SERVICE_NAME, process.execPath, options.executablePath]);
312
- run(["set", WINDOWS_SERVICE_NAME, "AppDirectory", execDir]);
313
- run(["set", WINDOWS_SERVICE_NAME, "DisplayName", "awsb runtime bridge"]);
314
- run(["set", WINDOWS_SERVICE_NAME, "Start", "SERVICE_AUTO_START"]);
315
- run(["set", WINDOWS_SERVICE_NAME, "AppStdout", logPath]);
316
- run(["set", WINDOWS_SERVICE_NAME, "AppStderr", logPath]);
317
- run(["set", WINDOWS_SERVICE_NAME, "AppRotateFiles", "1"]);
318
- run(["set", WINDOWS_SERVICE_NAME, "AppRotateBytes", "1048576"]);
319
- const startResult = run(["start", WINDOWS_SERVICE_NAME]);
315
+ catch (error) {
316
+ const err = error instanceof Error ? error : new Error(String(error));
317
+ options.stderr(`[runtime-bridge] 安装 Windows 服务失败: ${err.message}`);
318
+ return { handled: true, exitCode: 1 };
319
+ }
320
+ // 安装成功后启动服务
321
+ const startResult = options.runCommand("sc.exe", [
322
+ "start",
323
+ WINDOWS_SERVICE_NAME,
324
+ ]);
320
325
  if (!commandSucceeded(startResult)) {
321
- options.stderr(`[runtime-bridge] 安装/启动 Windows 服务失败: ${startResult.error?.message ?? `退出码 ${startResult.status ?? "unknown"}`}`);
326
+ options.stderr(`[runtime-bridge] 启动 Windows 服务失败: ${startResult.error?.message ?? `退出码 ${startResult.status ?? "unknown"}`}`);
322
327
  return { handled: true, exitCode: startResult.status ?? 1 };
323
328
  }
324
329
  options.stdout(`[runtime-bridge] awsb Windows 服务已安装并已启动(日志: ${logPath})。`);
325
330
  return { handled: true, exitCode: 0 };
326
331
  }
327
332
  /**
328
- * 卸载 Windows 服务(nssm stop + nssm remove)。
333
+ * 卸载 Windows 服务(sc.exe stop + sc.exe delete)。
329
334
  */
330
335
  function uninstallWindowsService(options) {
331
- const nssm = findNssmCommand(options);
332
- if (!nssm) {
333
- return nssmMissingError(options);
334
- }
335
- const run = (args) => options.runCommand(nssm, args);
336
- run(["stop", WINDOWS_SERVICE_NAME]); // 未运行则忽略
337
- const removeResult = run(["remove", WINDOWS_SERVICE_NAME, "confirm"]);
338
- if (!commandSucceeded(removeResult)) {
339
- options.stderr(`[runtime-bridge] 卸载 Windows 服务失败: ${removeResult.error?.message ?? `退出码 ${removeResult.status ?? "unknown"}`}`);
340
- return { handled: true, exitCode: removeResult.status ?? 1 };
336
+ const run = (args) => options.runCommand("sc.exe", args);
337
+ // 先尝试停止(服务可能未运行,忽略失败)
338
+ run(["stop", WINDOWS_SERVICE_NAME]);
339
+ const deleteResult = run(["delete", WINDOWS_SERVICE_NAME]);
340
+ if (!commandSucceeded(deleteResult)) {
341
+ options.stderr(`[runtime-bridge] 卸载 Windows 服务失败: ${deleteResult.error?.message ?? `退出码 ${deleteResult.status ?? "unknown"}`}`);
342
+ return { handled: true, exitCode: deleteResult.status ?? 1 };
341
343
  }
342
344
  options.stdout("[runtime-bridge] awsb Windows 服务已卸载。");
343
345
  return { handled: true, exitCode: 0 };
344
346
  }
345
347
  /**
346
- * 重启 Windows 服务(nssm restart,未运行会被启动)。
348
+ * 重启 Windows 服务(sc.exe stop + sc.exe start,未运行会被启动)。
347
349
  */
348
350
  function restartWindowsService(options) {
349
- const nssm = findNssmCommand(options);
350
- if (!nssm) {
351
- return nssmMissingError(options);
352
- }
353
- const result = options.runCommand(nssm, ["restart", WINDOWS_SERVICE_NAME]);
354
- if (!commandSucceeded(result)) {
355
- options.stderr(`[runtime-bridge] 重启 Windows 服务失败: ${result.error?.message ?? `退出码 ${result.status ?? "unknown"}`}`);
356
- return { handled: true, exitCode: result.status ?? 1 };
351
+ const run = (args) => options.runCommand("sc.exe", args);
352
+ // 先停止(可能未运行,忽略失败)
353
+ run(["stop", WINDOWS_SERVICE_NAME]);
354
+ const startResult = run(["start", WINDOWS_SERVICE_NAME]);
355
+ if (!commandSucceeded(startResult)) {
356
+ options.stderr(`[runtime-bridge] 重启 Windows 服务失败: ${startResult.error?.message ?? `退出码 ${startResult.status ?? "unknown"}`}`);
357
+ return { handled: true, exitCode: startResult.status ?? 1 };
357
358
  }
358
359
  options.stdout("[runtime-bridge] awsb Windows 服务已重启。");
359
360
  return { handled: true, exitCode: 0 };
360
361
  }
361
362
  /**
362
- * 启动 Windows 服务(nssm start)。
363
+ * 启动 Windows 服务(sc.exe start)。
363
364
  */
364
365
  function startWindowsService(options) {
365
- const nssm = findNssmCommand(options);
366
- if (!nssm) {
367
- return nssmMissingError(options);
368
- }
369
- const result = options.runCommand(nssm, ["start", WINDOWS_SERVICE_NAME]);
366
+ const result = options.runCommand("sc.exe", [
367
+ "start",
368
+ WINDOWS_SERVICE_NAME,
369
+ ]);
370
370
  if (!commandSucceeded(result)) {
371
371
  options.stderr(`[runtime-bridge] 启动 Windows 服务失败: ${result.error?.message ?? `退出码 ${result.status ?? "unknown"}`}`);
372
372
  return { handled: true, exitCode: result.status ?? 1 };
@@ -375,14 +375,13 @@ function startWindowsService(options) {
375
375
  return { handled: true, exitCode: 0 };
376
376
  }
377
377
  /**
378
- * 停止 Windows 服务(nssm stop)。
378
+ * 停止 Windows 服务(sc.exe stop)。
379
379
  */
380
380
  function stopWindowsService(options) {
381
- const nssm = findNssmCommand(options);
382
- if (!nssm) {
383
- return nssmMissingError(options);
384
- }
385
- const result = options.runCommand(nssm, ["stop", WINDOWS_SERVICE_NAME]);
381
+ const result = options.runCommand("sc.exe", [
382
+ "stop",
383
+ WINDOWS_SERVICE_NAME,
384
+ ]);
386
385
  if (!commandSucceeded(result)) {
387
386
  options.stderr(`[runtime-bridge] 停止 Windows 服务失败: ${result.error?.message ?? `退出码 ${result.status ?? "unknown"}`}`);
388
387
  return { handled: true, exitCode: result.status ?? 1 };
@@ -390,7 +389,7 @@ function stopWindowsService(options) {
390
389
  options.stdout("[runtime-bridge] awsb Windows 服务已停止。");
391
390
  return { handled: true, exitCode: 0 };
392
391
  }
393
- function handleServiceCommand(argv, options, stdout, stderr) {
392
+ async function handleServiceCommand(argv, options, stdout, stderr) {
394
393
  const subcommand = argv[1];
395
394
  if (!subcommand ||
396
395
  subcommand === "-h" ||
@@ -406,6 +405,7 @@ function handleServiceCommand(argv, options, stdout, stderr) {
406
405
  platform: options.platform || process.platform,
407
406
  serviceUnitPath: options.serviceUnitPath || DEFAULT_SYSTEMD_UNIT_PATH,
408
407
  executablePath: options.executablePath || getDefaultExecutablePath(),
408
+ windowsServiceManager: options.windowsServiceManager,
409
409
  };
410
410
  // 仅 Linux systemd 与 Windows 服务支持 install/uninstall/restart
411
411
  if (serviceOptions.platform !== "linux" &&
@@ -415,7 +415,7 @@ function handleServiceCommand(argv, options, stdout, stderr) {
415
415
  }
416
416
  if (subcommand === "install") {
417
417
  return serviceOptions.platform === "win32"
418
- ? installWindowsService(serviceOptions)
418
+ ? await installWindowsService(serviceOptions)
419
419
  : installSystemdService(serviceOptions);
420
420
  }
421
421
  if (subcommand === "uninstall") {
@@ -636,7 +636,7 @@ export async function handleCliCommand(options = {}) {
636
636
  };
637
637
  }
638
638
  if (command === "service") {
639
- return handleServiceCommand(argv, options, stdout, stderr);
639
+ return await handleServiceCommand(argv, options, stdout, stderr);
640
640
  }
641
641
  if (command === "log") {
642
642
  return handleLogCommand(options, stdout, stderr);
@@ -0,0 +1,28 @@
1
+ /**
2
+ * node-windows 封装模块。
3
+ *
4
+ * node-windows 内部使用 WinSW(.NET 服务包装器)实现 SCM 协议适配,
5
+ * 用户 `npm install -g aws-runtime-bridge` 时自动获得,无需额外安装 nssm。
6
+ *
7
+ * 关键行为:
8
+ * - install 时在 `path.dirname(script)/daemon/` 下创建 winsw.exe + XML 配置;
9
+ * - `logpath` 配置项控制日志输出目录(WinSW 生成 `<id>.out.log` / `<id>.err.log`);
10
+ * - `id` = `name.replace(/[^\w]/gi,'').toLowerCase()`,对 "awsb" → "awsb"。
11
+ */
12
+ export interface WindowsServiceConfig {
13
+ name: string;
14
+ description: string;
15
+ script: string;
16
+ workingDirectory?: string;
17
+ env?: {
18
+ name: string;
19
+ value: string;
20
+ }[];
21
+ logpath?: string;
22
+ }
23
+ export interface WindowsServiceManager {
24
+ install(config: WindowsServiceConfig): Promise<void>;
25
+ }
26
+ export declare function isNodeWindowsAvailable(): boolean;
27
+ export declare function createWindowsServiceManager(): WindowsServiceManager;
28
+ //# sourceMappingURL=windows-service-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-service-manager.d.ts","sourceRoot":"","sources":["../../src/services/windows-service-manager.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD;AAiBD,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,wBAAgB,2BAA2B,IAAI,qBAAqB,CAkCnE"}
@@ -0,0 +1,54 @@
1
+ import { createRequire } from "node:module";
2
+ import { mkdirSync } from "node:fs";
3
+ // node-windows 是 CommonJS 包,在 ESM 中通过 createRequire 懒加载。
4
+ // 非Windows 平台或包未安装时返回 null。
5
+ let cachedServiceCtor;
6
+ function getNodeWindowsServiceCtor() {
7
+ if (cachedServiceCtor !== undefined)
8
+ return cachedServiceCtor;
9
+ try {
10
+ const require = createRequire(import.meta.url);
11
+ cachedServiceCtor = require("node-windows").Service;
12
+ }
13
+ catch {
14
+ cachedServiceCtor = null;
15
+ }
16
+ return cachedServiceCtor;
17
+ }
18
+ export function isNodeWindowsAvailable() {
19
+ return getNodeWindowsServiceCtor() !== null;
20
+ }
21
+ export function createWindowsServiceManager() {
22
+ return {
23
+ async install(config) {
24
+ const ServiceCtor = getNodeWindowsServiceCtor();
25
+ if (!ServiceCtor) {
26
+ throw new Error("node-windows 未安装。请重新安装 aws-runtime-bridge:npm install -g aws-runtime-bridge");
27
+ }
28
+ // 确保日志目录存在
29
+ if (config.logpath) {
30
+ try {
31
+ mkdirSync(config.logpath, { recursive: true });
32
+ }
33
+ catch {
34
+ // 日志目录创建失败不阻断安装
35
+ }
36
+ }
37
+ const svc = new ServiceCtor({
38
+ name: config.name,
39
+ description: config.description,
40
+ script: config.script,
41
+ workingDirectory: config.workingDirectory,
42
+ env: config.env,
43
+ logpath: config.logpath,
44
+ logmode: "rotate",
45
+ });
46
+ await new Promise((resolve, reject) => {
47
+ svc.on("install", () => resolve());
48
+ svc.on("alreadyinstalled", () => resolve());
49
+ svc.on("error", (err) => reject(err));
50
+ svc.install();
51
+ });
52
+ },
53
+ };
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws-runtime-bridge",
3
- "version": "1.9.77",
3
+ "version": "1.9.78",
4
4
  "description": "AgentsWorkStudio runtime bridge service for machine-level agent runtime integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,6 +25,9 @@
25
25
  "bundleDependencies": [
26
26
  "@cc-switch/sdk"
27
27
  ],
28
+ "optionalDependencies": {
29
+ "node-windows": "^1.0.0-beta.8"
30
+ },
28
31
  "engines": {
29
32
  "node": ">=20.0.0 <25"
30
33
  },