ai-project-manage-cli 6.0.97 → 6.0.99

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 (2) hide show
  1. package/dist/index.js +171 -59
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3758,7 +3758,13 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT) {
3758
3758
  }
3759
3759
 
3760
3760
  // src/commands/connect-lock.ts
3761
- import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync12, unlinkSync, writeFileSync as writeFileSync12 } from "fs";
3761
+ import {
3762
+ existsSync as existsSync13,
3763
+ mkdirSync as mkdirSync6,
3764
+ readFileSync as readFileSync12,
3765
+ unlinkSync,
3766
+ writeFileSync as writeFileSync12
3767
+ } from "fs";
3762
3768
  import { join as join14 } from "path";
3763
3769
  var CONNECT_LOCK_PATH = join14(APM_CONFIG_DIR, "connect.lock");
3764
3770
  function isProcessAlive(pid) {
@@ -3770,6 +3776,22 @@ function isProcessAlive(pid) {
3770
3776
  return false;
3771
3777
  }
3772
3778
  }
3779
+ function sleepSync(ms) {
3780
+ const deadline = Date.now() + ms;
3781
+ while (Date.now() < deadline) {
3782
+ }
3783
+ }
3784
+ function waitForPm2LockHandoff(timeoutMs = 5e3) {
3785
+ const deadline = Date.now() + timeoutMs;
3786
+ while (Date.now() < deadline) {
3787
+ pruneStaleConnectLock();
3788
+ const lock = readConnectLock();
3789
+ if (!lock || lock.mode !== "pm2" || lock.pid === process.pid || !isProcessAlive(lock.pid)) {
3790
+ return;
3791
+ }
3792
+ sleepSync(100);
3793
+ }
3794
+ }
3773
3795
  function readConnectLock() {
3774
3796
  if (!existsSync13(CONNECT_LOCK_PATH)) return null;
3775
3797
  try {
@@ -3796,10 +3818,17 @@ function acquireConnectLock(mode) {
3796
3818
  pruneStaleConnectLock();
3797
3819
  const existing = readConnectLock();
3798
3820
  if (existing && isProcessAlive(existing.pid)) {
3799
- console.error(
3800
- `[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${existing.pid}, mode=${existing.mode})`
3801
- );
3802
- process.exit(1);
3821
+ if (existing.pid === process.pid) {
3822
+ return;
3823
+ }
3824
+ if (mode === "pm2" && existing.mode === "pm2") {
3825
+ forceReleaseConnectLock();
3826
+ } else {
3827
+ console.error(
3828
+ `[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${existing.pid}, mode=${existing.mode})`
3829
+ );
3830
+ process.exit(1);
3831
+ }
3803
3832
  }
3804
3833
  mkdirSync6(APM_CONFIG_DIR, { recursive: true });
3805
3834
  const lock = {
@@ -3807,7 +3836,11 @@ function acquireConnectLock(mode) {
3807
3836
  mode,
3808
3837
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
3809
3838
  };
3810
- writeFileSync12(CONNECT_LOCK_PATH, JSON.stringify(lock, null, 2) + "\n", "utf8");
3839
+ writeFileSync12(
3840
+ CONNECT_LOCK_PATH,
3841
+ JSON.stringify(lock, null, 2) + "\n",
3842
+ "utf8"
3843
+ );
3811
3844
  }
3812
3845
  function releaseConnectLock() {
3813
3846
  const lock = readConnectLock();
@@ -3829,10 +3862,18 @@ function forceReleaseConnectLock() {
3829
3862
  // src/commands/daemon.ts
3830
3863
  import { spawnSync as spawnSync2 } from "child_process";
3831
3864
  import { setTimeout as delay } from "node:timers/promises";
3832
- import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync13 } from "fs";
3865
+ import { existsSync as existsSync14, mkdirSync as mkdirSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync13 } from "fs";
3833
3866
  import { join as join15 } from "path";
3834
3867
  var PM2_APP_NAME = "apm-connect";
3835
- var PM2_ECOSYSTEM_PATH = join15(APM_CONFIG_DIR, "connect.ecosystem.cjs");
3868
+ var PM2_ECOSYSTEM_PATH = join15(
3869
+ APM_CONFIG_DIR,
3870
+ "connect.ecosystem.config.cjs"
3871
+ );
3872
+ var LEGACY_PM2_ECOSYSTEM_PATH = join15(
3873
+ APM_CONFIG_DIR,
3874
+ "connect.ecosystem.cjs"
3875
+ );
3876
+ var LEGACY_PM2_APP_NAMES = ["connect.ecosystem"];
3836
3877
  function resolveConnectArgs(server) {
3837
3878
  const args = ["connect"];
3838
3879
  const trimmed = server?.trim();
@@ -3847,24 +3888,28 @@ function buildConnectPm2Ecosystem(options) {
3847
3888
  if (baseUrl) {
3848
3889
  env.AI_PM_SERVER = baseUrl;
3849
3890
  }
3891
+ const app = {
3892
+ name: PM2_APP_NAME,
3893
+ script: options.apmScript,
3894
+ interpreter: options.nodePath,
3895
+ args: options.connectArgs,
3896
+ autorestart: true,
3897
+ min_uptime: "10s",
3898
+ max_restarts: 10,
3899
+ restart_delay: 3e3,
3900
+ exp_backoff_restart_delay: 1e3,
3901
+ max_memory_restart: "1G",
3902
+ kill_timeout: 5e3,
3903
+ shutdown_with_message: true,
3904
+ instances: 1,
3905
+ exec_mode: "fork",
3906
+ env
3907
+ };
3908
+ if (process.platform === "win32") {
3909
+ app.windowsHide = true;
3910
+ }
3850
3911
  return {
3851
- apps: [
3852
- {
3853
- name: PM2_APP_NAME,
3854
- script: options.apmScript,
3855
- interpreter: options.nodePath,
3856
- args: options.connectArgs,
3857
- autorestart: true,
3858
- min_uptime: "10s",
3859
- max_restarts: 0,
3860
- restart_delay: 3e3,
3861
- exp_backoff_restart_delay: 1e3,
3862
- max_memory_restart: "1G",
3863
- kill_timeout: 5e3,
3864
- shutdown_with_message: true,
3865
- env
3866
- }
3867
- ]
3912
+ apps: [app]
3868
3913
  };
3869
3914
  }
3870
3915
  function formatConnectPm2EcosystemFile(ecosystem) {
@@ -4033,14 +4078,66 @@ function resolveApmEntryPath(entryArg = process.argv[1]) {
4033
4078
  process.exit(1);
4034
4079
  }
4035
4080
  function isRunningUnderPm2() {
4036
- return process.env.name === PM2_APP_NAME && process.env.pm_id !== void 0;
4081
+ if (process.env.pm_id === void 0) {
4082
+ return false;
4083
+ }
4084
+ const name = process.env.name;
4085
+ return name === PM2_APP_NAME || name !== void 0 && LEGACY_PM2_APP_NAMES.includes(name);
4086
+ }
4087
+ function isConnectPm2Process(app) {
4088
+ if (app.name === PM2_APP_NAME) {
4089
+ return true;
4090
+ }
4091
+ return app.name !== void 0 && LEGACY_PM2_APP_NAMES.includes(app.name);
4092
+ }
4093
+ function listPm2Processes() {
4094
+ try {
4095
+ const raw = runPm2Json(["jlist"]);
4096
+ return JSON.parse(raw);
4097
+ } catch {
4098
+ return [];
4099
+ }
4100
+ }
4101
+ function findPm2ConnectProcess() {
4102
+ return listPm2Processes().find(isConnectPm2Process) ?? null;
4103
+ }
4104
+ function resolvePm2ConnectName(app) {
4105
+ return app?.name ?? PM2_APP_NAME;
4106
+ }
4107
+ function deletePm2AppIfExists(name) {
4108
+ const pm2Bin = findGlobalPm2();
4109
+ if (!pm2Bin) {
4110
+ return;
4111
+ }
4112
+ ensurePm2DaemonUpdated(pm2Bin);
4113
+ spawnSync2(pm2Bin, ["delete", name], {
4114
+ encoding: "utf8",
4115
+ shell: useNpmShell2,
4116
+ stdio: "ignore",
4117
+ windowsHide: useNpmShell2
4118
+ });
4119
+ }
4120
+ function removePm2ConnectProcesses() {
4121
+ const seen = /* @__PURE__ */ new Set();
4122
+ for (const app of listPm2Processes()) {
4123
+ if (!isConnectPm2Process(app) || !app.name || seen.has(app.name)) {
4124
+ continue;
4125
+ }
4126
+ seen.add(app.name);
4127
+ deletePm2AppIfExists(app.name);
4128
+ }
4129
+ for (const legacyName of LEGACY_PM2_APP_NAMES) {
4130
+ deletePm2AppIfExists(legacyName);
4131
+ }
4132
+ deletePm2AppIfExists(PM2_APP_NAME);
4037
4133
  }
4038
4134
  function runPm2(args, options) {
4039
4135
  const pm2Bin = ensureGlobalPm2({ quiet: true });
4040
4136
  const spawnOptions = {
4041
4137
  encoding: "utf8",
4042
4138
  stdio: options?.inherit ? "inherit" : ["ignore", "pipe", "pipe"],
4043
- shell: useNpmShell2
4139
+ shell: useNpmShell2,
4140
+ windowsHide: useNpmShell2
4044
4141
  };
4045
4142
  const result = spawnSync2(pm2Bin, args, spawnOptions);
4046
4143
  if (result.error) {
@@ -4064,7 +4161,8 @@ function runPm2Json(args) {
4064
4161
  const result = spawnSync2(pm2Bin, args, {
4065
4162
  encoding: "utf8",
4066
4163
  stdio: ["ignore", "pipe", "pipe"],
4067
- shell: useNpmShell2
4164
+ shell: useNpmShell2,
4165
+ windowsHide: useNpmShell2
4068
4166
  });
4069
4167
  if (result.status !== 0) return "[]";
4070
4168
  return result.stdout?.toString() ?? "[]";
@@ -4075,15 +4173,6 @@ function isPm2ConnectOnline() {
4075
4173
  const status = app.pm2_env?.status;
4076
4174
  return status === "online" || status === "launching";
4077
4175
  }
4078
- function findPm2ConnectProcess() {
4079
- try {
4080
- const raw = runPm2Json(["jlist"]);
4081
- const list = JSON.parse(raw);
4082
- return list.find((app) => app.name === PM2_APP_NAME) ?? null;
4083
- } catch {
4084
- return null;
4085
- }
4086
- }
4087
4176
  function printConnectNotRunningHint() {
4088
4177
  console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728\u8FD0\u884C`);
4089
4178
  console.log("[apm] \u542F\u52A8\u5B88\u62A4: apm connect --daemon");
@@ -4091,13 +4180,13 @@ function printConnectNotRunningHint() {
4091
4180
  function assertConnectNotRunning() {
4092
4181
  pruneStaleConnectLock();
4093
4182
  const lock = readConnectLock();
4094
- if (lock && isProcessAlive(lock.pid)) {
4183
+ if (lock && isProcessAlive(lock.pid) && lock.pid !== process.pid) {
4095
4184
  console.error(
4096
4185
  `[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${lock.pid}, mode=${lock.mode})\uFF0C\u8BF7\u5148\u505C\u6B62\u540E\u518D\u542F\u52A8`
4097
4186
  );
4098
4187
  process.exit(1);
4099
4188
  }
4100
- if (isPm2ConnectOnline()) {
4189
+ if (!isRunningUnderPm2() && isPm2ConnectOnline()) {
4101
4190
  console.error(
4102
4191
  "[apm] \u5DF2\u6709 apm connect \u5B88\u62A4\u8FDB\u7A0B\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u6267\u884C apm daemon stop"
4103
4192
  );
@@ -4128,10 +4217,8 @@ async function handleConnectAfterUpdate(options) {
4128
4217
  console.log("[apm] \u66F4\u65B0\u5B8C\u6210\uFF0C\u6B63\u5728\u4EE5\u65B0\u7248\u672C\u91CD\u65B0\u8FDE\u63A5\u2026");
4129
4218
  await prepareEcosystem(options.server);
4130
4219
  if (isRunningUnderPm2()) {
4131
- runPm2(["startOrRestart", PM2_ECOSYSTEM_PATH, "--update-env"], {
4132
- inherit: true
4133
- });
4134
- console.log("[apm] \u5DF2\u901A\u77E5 PM2 \u4F7F\u7528\u65B0\u7248\u672C\u91CD\u542F connect");
4220
+ runPm2(["reload", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
4221
+ console.log("[apm] \u5DF2\u901A\u77E5 PM2 \u4F7F\u7528\u65B0\u7248\u672C\u91CD\u65B0\u52A0\u8F7D connect");
4135
4222
  process.exit(0);
4136
4223
  }
4137
4224
  reexecConnectWithResolvedPath(options);
@@ -4151,6 +4238,12 @@ function writeEcosystemFile(options) {
4151
4238
  formatConnectPm2EcosystemFile(ecosystem),
4152
4239
  "utf8"
4153
4240
  );
4241
+ if (existsSync14(LEGACY_PM2_ECOSYSTEM_PATH)) {
4242
+ try {
4243
+ unlinkSync2(LEGACY_PM2_ECOSYSTEM_PATH);
4244
+ } catch {
4245
+ }
4246
+ }
4154
4247
  }
4155
4248
  async function prepareEcosystem(server) {
4156
4249
  await ensureLoggedConfig();
@@ -4171,7 +4264,14 @@ async function runDaemonStart(options) {
4171
4264
  await runUpdate();
4172
4265
  ensureGlobalPm2();
4173
4266
  const cfg = await prepareEcosystem(options.server);
4267
+ removePm2ConnectProcesses();
4174
4268
  runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
4269
+ await delay(1e3);
4270
+ if (!isPm2ConnectOnline()) {
4271
+ console.error(
4272
+ `[apm] ${PM2_APP_NAME} \u542F\u52A8\u540E\u672A\u5904\u4E8E online \u72B6\u6001\uFF0C\u8BF7\u6267\u884C: apm daemon logs -n 200`
4273
+ );
4274
+ }
4175
4275
  console.log(
4176
4276
  `[apm] ${PM2_APP_NAME} \u5DF2\u7531 PM2 \u542F\u52A8\uFF08server=${options.server?.trim() || cfg.baseUrl}\uFF09`
4177
4277
  );
@@ -4194,14 +4294,18 @@ async function runDaemonStop() {
4194
4294
  console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728\u8FD0\u884C`);
4195
4295
  return;
4196
4296
  }
4197
- runPm2(["stop", PM2_APP_NAME], { inherit: true });
4297
+ runPm2(["stop", resolvePm2ConnectName(findPm2ConnectProcess())], {
4298
+ inherit: true
4299
+ });
4198
4300
  for (let i = 0; i < 10; i += 1) {
4199
4301
  if (!isPm2ConnectOnline()) break;
4200
4302
  await delay(500);
4201
4303
  }
4202
4304
  if (isPm2ConnectOnline()) {
4203
4305
  console.log(`[apm] \u4F18\u96C5\u505C\u6B62\u8D85\u65F6\uFF0C\u5F3A\u5236\u79FB\u9664 ${PM2_APP_NAME}\u2026`);
4204
- runPm2(["delete", PM2_APP_NAME], { inherit: true });
4306
+ runPm2(["delete", resolvePm2ConnectName(findPm2ConnectProcess())], {
4307
+ inherit: true
4308
+ });
4205
4309
  }
4206
4310
  killConnectLockProcessIfAlive();
4207
4311
  forceReleaseConnectLock();
@@ -4236,36 +4340,38 @@ async function runDaemonRestart(options) {
4236
4340
  }
4237
4341
  await runUpdate();
4238
4342
  await prepareEcosystem(options.server);
4239
- runPm2(["startOrRestart", PM2_ECOSYSTEM_PATH, "--update-env"], {
4240
- inherit: true
4241
- });
4343
+ removePm2ConnectProcesses();
4344
+ runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
4242
4345
  console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u91CD\u542F`);
4243
4346
  }
4244
4347
  async function runDaemonDelete() {
4245
4348
  ensureGlobalPm2();
4246
- if (!findPm2ConnectProcess()) {
4349
+ const app = findPm2ConnectProcess();
4350
+ if (!app?.name) {
4247
4351
  console.log(`[apm] ${PM2_APP_NAME} \u672A\u5728 PM2 \u4E2D\u6CE8\u518C`);
4248
4352
  return;
4249
4353
  }
4250
- runPm2(["delete", PM2_APP_NAME], { inherit: true });
4354
+ runPm2(["delete", app.name], { inherit: true });
4251
4355
  forceReleaseConnectLock();
4252
- console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u4ECE PM2 \u79FB\u9664`);
4356
+ console.log(`[apm] ${app.name} \u5DF2\u4ECE PM2 \u79FB\u9664`);
4253
4357
  }
4254
4358
  async function runDaemonStatus() {
4255
4359
  ensureGlobalPm2();
4256
- if (!findPm2ConnectProcess()) {
4360
+ const app = findPm2ConnectProcess();
4361
+ if (!app?.name) {
4257
4362
  printConnectNotRunningHint();
4258
4363
  return;
4259
4364
  }
4260
- runPm2(["describe", PM2_APP_NAME], { inherit: true });
4365
+ runPm2(["describe", app.name], { inherit: true });
4261
4366
  }
4262
4367
  async function runDaemonLogs(options) {
4263
4368
  ensureGlobalPm2();
4264
- if (!findPm2ConnectProcess()) {
4369
+ const app = findPm2ConnectProcess();
4370
+ if (!app?.name) {
4265
4371
  printConnectNotRunningHint();
4266
4372
  return;
4267
4373
  }
4268
- const args = ["logs", PM2_APP_NAME, "--lines", String(options.lines ?? 100)];
4374
+ const args = ["logs", app.name, "--lines", String(options.lines ?? 100)];
4269
4375
  if (!options.follow) {
4270
4376
  args.push("--nostream");
4271
4377
  }
@@ -4616,9 +4722,12 @@ function connectOnce(url, ctx, connectionAbort, onConnected) {
4616
4722
  });
4617
4723
  }
4618
4724
  async function runConnect(options) {
4619
- const { didUpdate } = await runUpdate();
4620
- if (didUpdate) {
4621
- await handleConnectAfterUpdate(options);
4725
+ const underPm2 = isRunningUnderPm2();
4726
+ if (!underPm2) {
4727
+ const { didUpdate } = await runUpdate();
4728
+ if (didUpdate) {
4729
+ await handleConnectAfterUpdate(options);
4730
+ }
4622
4731
  }
4623
4732
  const cfg = await ensureLoggedConfig();
4624
4733
  if (options.server?.trim()) {
@@ -4630,7 +4739,10 @@ async function runConnect(options) {
4630
4739
  process.exit(1);
4631
4740
  }
4632
4741
  assertConnectNotRunning();
4633
- const lockMode = isRunningUnderPm2() ? "pm2" : "foreground";
4742
+ if (underPm2) {
4743
+ waitForPm2LockHandoff();
4744
+ }
4745
+ const lockMode = underPm2 ? "pm2" : "foreground";
4634
4746
  acquireConnectLock(lockMode);
4635
4747
  process.on("exit", releaseConnectLock);
4636
4748
  let shuttingDown = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "6.0.97",
3
+ "version": "6.0.99",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,