ai-project-manage-cli 6.0.77 → 6.0.80
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/README.md +22 -0
- package/dist/index.js +464 -54
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -33,6 +33,28 @@ apm update-skills
|
|
|
33
33
|
apm branch <sessionId>
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
## 常驻连接(后台守护)
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
apm connect --daemon # 长期在线(后台)
|
|
40
|
+
apm connect --daemon -f # 长期在线,并在当前终端实时看日志
|
|
41
|
+
apm connect --daemon --server https://your-server.com
|
|
42
|
+
|
|
43
|
+
# 运维
|
|
44
|
+
apm daemon status
|
|
45
|
+
apm daemon logs
|
|
46
|
+
apm daemon logs -f # 随时重新跟踪日志
|
|
47
|
+
apm daemon restart
|
|
48
|
+
apm daemon stop
|
|
49
|
+
apm daemon delete
|
|
50
|
+
|
|
51
|
+
# 备选启动
|
|
52
|
+
apm daemon start
|
|
53
|
+
apm daemon start -f
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
PM2 已内置;同一时刻仅允许一个 connect。启动时会自动检测 CLI 更新并刷新守护配置。
|
|
57
|
+
|
|
36
58
|
`apm pull` 会自动将平台登记的**仓库项目文档**同步到 `.apm/project/`(含 `manifest.json`)。Agent 修改 `.apm/project/` 下文件后,`apm connect` 处理完消息会自动推回平台。
|
|
37
59
|
|
|
38
60
|
详见仓库根目录 [docs/CLI.md](../../docs/CLI.md)。
|
package/dist/index.js
CHANGED
|
@@ -2126,7 +2126,6 @@ async function runUpdateMessageStatus(options) {
|
|
|
2126
2126
|
}
|
|
2127
2127
|
|
|
2128
2128
|
// src/commands/connect.ts
|
|
2129
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
2130
2129
|
import WebSocket from "ws";
|
|
2131
2130
|
|
|
2132
2131
|
// src/ws/protocol.ts
|
|
@@ -3232,6 +3231,337 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT) {
|
|
|
3232
3231
|
return { acquire, release };
|
|
3233
3232
|
}
|
|
3234
3233
|
|
|
3234
|
+
// src/commands/connect-lock.ts
|
|
3235
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync11, unlinkSync, writeFileSync as writeFileSync12 } from "fs";
|
|
3236
|
+
import { join as join14 } from "path";
|
|
3237
|
+
var CONNECT_LOCK_PATH = join14(APM_CONFIG_DIR, "connect.lock");
|
|
3238
|
+
function isProcessAlive(pid) {
|
|
3239
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
3240
|
+
try {
|
|
3241
|
+
process.kill(pid, 0);
|
|
3242
|
+
return true;
|
|
3243
|
+
} catch {
|
|
3244
|
+
return false;
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
function readConnectLock() {
|
|
3248
|
+
if (!existsSync13(CONNECT_LOCK_PATH)) return null;
|
|
3249
|
+
try {
|
|
3250
|
+
const raw = readFileSync11(CONNECT_LOCK_PATH, "utf8");
|
|
3251
|
+
const parsed = JSON.parse(raw);
|
|
3252
|
+
if (typeof parsed.pid !== "number" || parsed.mode !== "foreground" && parsed.mode !== "pm2" || typeof parsed.startedAt !== "string") {
|
|
3253
|
+
return null;
|
|
3254
|
+
}
|
|
3255
|
+
return parsed;
|
|
3256
|
+
} catch {
|
|
3257
|
+
return null;
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
function pruneStaleConnectLock() {
|
|
3261
|
+
const lock = readConnectLock();
|
|
3262
|
+
if (!lock) return;
|
|
3263
|
+
if (isProcessAlive(lock.pid)) return;
|
|
3264
|
+
try {
|
|
3265
|
+
unlinkSync(CONNECT_LOCK_PATH);
|
|
3266
|
+
} catch {
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
function acquireConnectLock(mode) {
|
|
3270
|
+
pruneStaleConnectLock();
|
|
3271
|
+
const existing = readConnectLock();
|
|
3272
|
+
if (existing && isProcessAlive(existing.pid)) {
|
|
3273
|
+
console.error(
|
|
3274
|
+
`[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${existing.pid}, mode=${existing.mode})`
|
|
3275
|
+
);
|
|
3276
|
+
process.exit(1);
|
|
3277
|
+
}
|
|
3278
|
+
mkdirSync6(APM_CONFIG_DIR, { recursive: true });
|
|
3279
|
+
const lock = {
|
|
3280
|
+
pid: process.pid,
|
|
3281
|
+
mode,
|
|
3282
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3283
|
+
};
|
|
3284
|
+
writeFileSync12(CONNECT_LOCK_PATH, JSON.stringify(lock, null, 2) + "\n", "utf8");
|
|
3285
|
+
}
|
|
3286
|
+
function releaseConnectLock() {
|
|
3287
|
+
const lock = readConnectLock();
|
|
3288
|
+
if (lock?.pid !== process.pid) return;
|
|
3289
|
+
try {
|
|
3290
|
+
unlinkSync(CONNECT_LOCK_PATH);
|
|
3291
|
+
} catch {
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
function forceReleaseConnectLock() {
|
|
3295
|
+
try {
|
|
3296
|
+
if (existsSync13(CONNECT_LOCK_PATH)) {
|
|
3297
|
+
unlinkSync(CONNECT_LOCK_PATH);
|
|
3298
|
+
}
|
|
3299
|
+
} catch {
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3303
|
+
// src/commands/daemon.ts
|
|
3304
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
3305
|
+
import { createRequire } from "node:module";
|
|
3306
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync13 } from "fs";
|
|
3307
|
+
import { join as join15 } from "path";
|
|
3308
|
+
var PM2_APP_NAME = "apm-connect";
|
|
3309
|
+
var PM2_ECOSYSTEM_PATH = join15(APM_CONFIG_DIR, "connect.ecosystem.cjs");
|
|
3310
|
+
function resolveConnectArgs(server) {
|
|
3311
|
+
const args = ["connect"];
|
|
3312
|
+
const trimmed = server?.trim();
|
|
3313
|
+
if (trimmed) {
|
|
3314
|
+
args.push("--server", trimmed.replace(/\/+$/, ""));
|
|
3315
|
+
}
|
|
3316
|
+
return args;
|
|
3317
|
+
}
|
|
3318
|
+
function buildConnectPm2Ecosystem(options) {
|
|
3319
|
+
const env = {};
|
|
3320
|
+
const baseUrl = options.baseUrl?.trim().replace(/\/+$/, "");
|
|
3321
|
+
if (baseUrl) {
|
|
3322
|
+
env.AI_PM_SERVER = baseUrl;
|
|
3323
|
+
}
|
|
3324
|
+
return {
|
|
3325
|
+
apps: [
|
|
3326
|
+
{
|
|
3327
|
+
name: PM2_APP_NAME,
|
|
3328
|
+
script: options.apmScript,
|
|
3329
|
+
interpreter: options.nodePath,
|
|
3330
|
+
args: options.connectArgs,
|
|
3331
|
+
autorestart: true,
|
|
3332
|
+
min_uptime: "10s",
|
|
3333
|
+
max_restarts: 100,
|
|
3334
|
+
restart_delay: 3e3,
|
|
3335
|
+
exp_backoff_restart_delay: 1e3,
|
|
3336
|
+
max_memory_restart: "1G",
|
|
3337
|
+
env
|
|
3338
|
+
}
|
|
3339
|
+
]
|
|
3340
|
+
};
|
|
3341
|
+
}
|
|
3342
|
+
function formatConnectPm2EcosystemFile(ecosystem) {
|
|
3343
|
+
return `module.exports = ${JSON.stringify(ecosystem, null, 2)};
|
|
3344
|
+
`;
|
|
3345
|
+
}
|
|
3346
|
+
function resolvePm2Bin() {
|
|
3347
|
+
const require2 = createRequire(import.meta.url);
|
|
3348
|
+
return require2.resolve("pm2/bin/pm2");
|
|
3349
|
+
}
|
|
3350
|
+
var useNpmShell2 = process.platform === "win32";
|
|
3351
|
+
function resolveApmEntryPath(entryArg = process.argv[1]) {
|
|
3352
|
+
const fromArgv = entryArg?.trim();
|
|
3353
|
+
if (fromArgv && existsSync14(fromArgv)) {
|
|
3354
|
+
return fromArgv;
|
|
3355
|
+
}
|
|
3356
|
+
const npmResult = spawnSync2(useNpmShell2 ? "npm.cmd" : "npm", ["root", "-g"], {
|
|
3357
|
+
encoding: "utf8",
|
|
3358
|
+
shell: useNpmShell2,
|
|
3359
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3360
|
+
});
|
|
3361
|
+
if (npmResult.status === 0) {
|
|
3362
|
+
const globalRoot = npmResult.stdout?.toString().trim();
|
|
3363
|
+
if (globalRoot) {
|
|
3364
|
+
const candidate = join15(globalRoot, CLI_PACKAGE_NAME, "dist", "index.js");
|
|
3365
|
+
if (existsSync14(candidate)) {
|
|
3366
|
+
return candidate;
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
if (fromArgv) {
|
|
3371
|
+
return fromArgv;
|
|
3372
|
+
}
|
|
3373
|
+
console.error("[apm] \u65E0\u6CD5\u89E3\u6790 apm \u5165\u53E3\u8DEF\u5F84");
|
|
3374
|
+
process.exit(1);
|
|
3375
|
+
}
|
|
3376
|
+
function isRunningUnderPm2() {
|
|
3377
|
+
return process.env.name === PM2_APP_NAME && process.env.pm_id !== void 0;
|
|
3378
|
+
}
|
|
3379
|
+
function runPm2(args, options) {
|
|
3380
|
+
let pm2Bin;
|
|
3381
|
+
try {
|
|
3382
|
+
pm2Bin = resolvePm2Bin();
|
|
3383
|
+
} catch {
|
|
3384
|
+
console.error(
|
|
3385
|
+
"[apm] \u672A\u627E\u5230\u5185\u7F6E pm2\uFF0C\u8BF7\u91CD\u65B0\u5B89\u88C5 apm CLI\uFF1Anpm install -g ai-project-manage-cli@latest"
|
|
3386
|
+
);
|
|
3387
|
+
process.exit(1);
|
|
3388
|
+
}
|
|
3389
|
+
const spawnOptions = {
|
|
3390
|
+
encoding: "utf8",
|
|
3391
|
+
stdio: options?.inherit ? "inherit" : ["ignore", "pipe", "pipe"]
|
|
3392
|
+
};
|
|
3393
|
+
const result = spawnSync2(process.execPath, [pm2Bin, ...args], spawnOptions);
|
|
3394
|
+
if (result.error) {
|
|
3395
|
+
console.error("[apm] \u6267\u884C pm2 \u5931\u8D25:", result.error.message);
|
|
3396
|
+
process.exit(1);
|
|
3397
|
+
}
|
|
3398
|
+
if (result.status !== 0) {
|
|
3399
|
+
const stderr = result.stderr?.toString().trim();
|
|
3400
|
+
const stdout = result.stdout?.toString().trim();
|
|
3401
|
+
const detail = stderr || stdout || `exit code ${result.status}`;
|
|
3402
|
+
console.error(`[apm] pm2 ${args.join(" ")} \u5931\u8D25: ${detail}`);
|
|
3403
|
+
process.exit(result.status ?? 1);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
function runPm2Json(args) {
|
|
3407
|
+
let pm2Bin;
|
|
3408
|
+
try {
|
|
3409
|
+
pm2Bin = resolvePm2Bin();
|
|
3410
|
+
} catch {
|
|
3411
|
+
return "[]";
|
|
3412
|
+
}
|
|
3413
|
+
const result = spawnSync2(process.execPath, [pm2Bin, ...args], {
|
|
3414
|
+
encoding: "utf8",
|
|
3415
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3416
|
+
});
|
|
3417
|
+
if (result.status !== 0) return "[]";
|
|
3418
|
+
return result.stdout?.toString() ?? "[]";
|
|
3419
|
+
}
|
|
3420
|
+
function isPm2ConnectOnline() {
|
|
3421
|
+
try {
|
|
3422
|
+
const raw = runPm2Json(["jlist"]);
|
|
3423
|
+
const list = JSON.parse(raw);
|
|
3424
|
+
return list.some(
|
|
3425
|
+
(app) => app.name === PM2_APP_NAME && (app.pm2_env?.status === "online" || app.pm2_env?.status === "launching")
|
|
3426
|
+
);
|
|
3427
|
+
} catch {
|
|
3428
|
+
return false;
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
function assertConnectNotRunning() {
|
|
3432
|
+
pruneStaleConnectLock();
|
|
3433
|
+
const lock = readConnectLock();
|
|
3434
|
+
if (lock && isProcessAlive(lock.pid)) {
|
|
3435
|
+
console.error(
|
|
3436
|
+
`[apm] \u5DF2\u6709 apm connect \u5728\u8FD0\u884C (pid=${lock.pid}, mode=${lock.mode})\uFF0C\u8BF7\u5148\u505C\u6B62\u540E\u518D\u542F\u52A8`
|
|
3437
|
+
);
|
|
3438
|
+
process.exit(1);
|
|
3439
|
+
}
|
|
3440
|
+
if (isPm2ConnectOnline()) {
|
|
3441
|
+
console.error(
|
|
3442
|
+
"[apm] \u5DF2\u6709 apm connect \u5B88\u62A4\u8FDB\u7A0B\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u6267\u884C apm daemon stop"
|
|
3443
|
+
);
|
|
3444
|
+
process.exit(1);
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
function resolveRuntimePaths() {
|
|
3448
|
+
return {
|
|
3449
|
+
apmScript: resolveApmEntryPath(),
|
|
3450
|
+
nodePath: process.execPath
|
|
3451
|
+
};
|
|
3452
|
+
}
|
|
3453
|
+
function reexecConnectWithResolvedPath(options) {
|
|
3454
|
+
const apmScript = resolveApmEntryPath();
|
|
3455
|
+
const args = [apmScript, "connect"];
|
|
3456
|
+
const server = options.server?.trim();
|
|
3457
|
+
if (server) {
|
|
3458
|
+
args.push("--server", server);
|
|
3459
|
+
}
|
|
3460
|
+
const result = spawnSync2(process.execPath, args, { stdio: "inherit" });
|
|
3461
|
+
if (result.error) {
|
|
3462
|
+
console.error("[apm] \u91CD\u542F connect \u5931\u8D25:", result.error.message);
|
|
3463
|
+
process.exit(1);
|
|
3464
|
+
}
|
|
3465
|
+
process.exit(result.status ?? 0);
|
|
3466
|
+
}
|
|
3467
|
+
async function handleConnectAfterUpdate(options) {
|
|
3468
|
+
console.log("[apm] \u66F4\u65B0\u5B8C\u6210\uFF0C\u6B63\u5728\u4EE5\u65B0\u7248\u672C\u91CD\u65B0\u8FDE\u63A5\u2026");
|
|
3469
|
+
await prepareEcosystem(options.server);
|
|
3470
|
+
if (isRunningUnderPm2()) {
|
|
3471
|
+
runPm2(["startOrRestart", PM2_ECOSYSTEM_PATH, "--update-env"], {
|
|
3472
|
+
inherit: true
|
|
3473
|
+
});
|
|
3474
|
+
console.log("[apm] \u5DF2\u901A\u77E5 PM2 \u4F7F\u7528\u65B0\u7248\u672C\u91CD\u542F connect");
|
|
3475
|
+
process.exit(0);
|
|
3476
|
+
}
|
|
3477
|
+
reexecConnectWithResolvedPath(options);
|
|
3478
|
+
}
|
|
3479
|
+
async function resolveBaseUrl(server) {
|
|
3480
|
+
if (server?.trim()) {
|
|
3481
|
+
return server.trim().replace(/\/+$/, "");
|
|
3482
|
+
}
|
|
3483
|
+
const cfg = await tryReadApmConfig();
|
|
3484
|
+
return cfg?.baseUrl;
|
|
3485
|
+
}
|
|
3486
|
+
function writeEcosystemFile(options) {
|
|
3487
|
+
mkdirSync7(APM_CONFIG_DIR, { recursive: true });
|
|
3488
|
+
const ecosystem = buildConnectPm2Ecosystem(options);
|
|
3489
|
+
writeFileSync13(
|
|
3490
|
+
PM2_ECOSYSTEM_PATH,
|
|
3491
|
+
formatConnectPm2EcosystemFile(ecosystem),
|
|
3492
|
+
"utf8"
|
|
3493
|
+
);
|
|
3494
|
+
}
|
|
3495
|
+
async function prepareEcosystem(server) {
|
|
3496
|
+
await ensureLoggedConfig();
|
|
3497
|
+
const cfg = await ensureApmConfig();
|
|
3498
|
+
const { apmScript, nodePath } = resolveRuntimePaths();
|
|
3499
|
+
const connectArgs = resolveConnectArgs(server);
|
|
3500
|
+
const baseUrl = await resolveBaseUrl(server);
|
|
3501
|
+
writeEcosystemFile({
|
|
3502
|
+
apmScript,
|
|
3503
|
+
nodePath,
|
|
3504
|
+
connectArgs,
|
|
3505
|
+
baseUrl
|
|
3506
|
+
});
|
|
3507
|
+
return cfg;
|
|
3508
|
+
}
|
|
3509
|
+
async function runDaemonStart(options) {
|
|
3510
|
+
assertConnectNotRunning();
|
|
3511
|
+
await runUpdate();
|
|
3512
|
+
const cfg = await prepareEcosystem(options.server);
|
|
3513
|
+
runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
|
|
3514
|
+
console.log(
|
|
3515
|
+
`[apm] ${PM2_APP_NAME} \u5DF2\u7531 PM2 \u542F\u52A8\uFF08server=${options.server?.trim() || cfg.baseUrl}\uFF09`
|
|
3516
|
+
);
|
|
3517
|
+
if (options.follow) {
|
|
3518
|
+
console.log(
|
|
3519
|
+
"[apm] \u6B63\u5728\u8DDF\u8E2A\u65E5\u5FD7\uFF08Ctrl+C \u4EC5\u9000\u51FA\u65E5\u5FD7\u67E5\u770B\uFF0C\u5B88\u62A4\u8FDB\u7A0B\u7EE7\u7EED\u8FD0\u884C\uFF09"
|
|
3520
|
+
);
|
|
3521
|
+
runDaemonLogs({ follow: true });
|
|
3522
|
+
return;
|
|
3523
|
+
}
|
|
3524
|
+
console.log("[apm] \u67E5\u770B\u72B6\u6001: apm daemon status");
|
|
3525
|
+
console.log("[apm] \u67E5\u770B\u65E5\u5FD7: apm daemon logs -f");
|
|
3526
|
+
console.log("[apm] \u505C\u6B62: apm daemon stop");
|
|
3527
|
+
}
|
|
3528
|
+
async function runDaemonStop() {
|
|
3529
|
+
runPm2(["stop", PM2_APP_NAME], { inherit: true });
|
|
3530
|
+
forceReleaseConnectLock();
|
|
3531
|
+
console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u505C\u6B62`);
|
|
3532
|
+
}
|
|
3533
|
+
async function runDaemonRestart(options) {
|
|
3534
|
+
pruneStaleConnectLock();
|
|
3535
|
+
const lock = readConnectLock();
|
|
3536
|
+
if (lock && isProcessAlive(lock.pid) && !isPm2ConnectOnline()) {
|
|
3537
|
+
console.error(
|
|
3538
|
+
`[apm] \u5DF2\u6709\u524D\u53F0 apm connect \u5728\u8FD0\u884C (pid=${lock.pid})\uFF0C\u8BF7\u5148\u505C\u6B62\u540E\u518D\u542F\u52A8\u5B88\u62A4\u8FDB\u7A0B`
|
|
3539
|
+
);
|
|
3540
|
+
process.exit(1);
|
|
3541
|
+
}
|
|
3542
|
+
await runUpdate();
|
|
3543
|
+
await prepareEcosystem(options.server);
|
|
3544
|
+
runPm2(["startOrRestart", PM2_ECOSYSTEM_PATH, "--update-env"], {
|
|
3545
|
+
inherit: true
|
|
3546
|
+
});
|
|
3547
|
+
console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u91CD\u542F`);
|
|
3548
|
+
}
|
|
3549
|
+
async function runDaemonDelete() {
|
|
3550
|
+
runPm2(["delete", PM2_APP_NAME], { inherit: true });
|
|
3551
|
+
forceReleaseConnectLock();
|
|
3552
|
+
console.log(`[apm] ${PM2_APP_NAME} \u5DF2\u4ECE PM2 \u79FB\u9664`);
|
|
3553
|
+
}
|
|
3554
|
+
async function runDaemonStatus() {
|
|
3555
|
+
runPm2(["describe", PM2_APP_NAME], { inherit: true });
|
|
3556
|
+
}
|
|
3557
|
+
async function runDaemonLogs(options) {
|
|
3558
|
+
const args = ["logs", PM2_APP_NAME, "--lines", String(options.lines ?? 100)];
|
|
3559
|
+
if (!options.follow) {
|
|
3560
|
+
args.push("--nostream");
|
|
3561
|
+
}
|
|
3562
|
+
runPm2(args, { inherit: true });
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3235
3565
|
// src/commands/connect.ts
|
|
3236
3566
|
var HEARTBEAT_MS = 3e4;
|
|
3237
3567
|
async function updateMessageStatus(cfg, messageId, status) {
|
|
@@ -3401,23 +3731,10 @@ function startHeartbeat(ws, clientMachineId) {
|
|
|
3401
3731
|
const timer = setInterval(send, HEARTBEAT_MS);
|
|
3402
3732
|
return () => clearInterval(timer);
|
|
3403
3733
|
}
|
|
3404
|
-
function reexecConnect(options) {
|
|
3405
|
-
const args = [process.argv[1], "connect"];
|
|
3406
|
-
const server = options.server?.trim();
|
|
3407
|
-
if (server) {
|
|
3408
|
-
args.push("--server", server);
|
|
3409
|
-
}
|
|
3410
|
-
const result = spawnSync2(process.execPath, args, { stdio: "inherit" });
|
|
3411
|
-
if (result.error) {
|
|
3412
|
-
console.error("[apm] \u91CD\u542F connect \u5931\u8D25:", result.error.message);
|
|
3413
|
-
process.exit(1);
|
|
3414
|
-
}
|
|
3415
|
-
process.exit(result.status ?? 0);
|
|
3416
|
-
}
|
|
3417
3734
|
async function runConnect(options) {
|
|
3418
3735
|
const { didUpdate } = await runUpdate();
|
|
3419
3736
|
if (didUpdate) {
|
|
3420
|
-
|
|
3737
|
+
await handleConnectAfterUpdate(options);
|
|
3421
3738
|
}
|
|
3422
3739
|
const cfg = await ensureLoggedConfig();
|
|
3423
3740
|
if (options.server?.trim()) {
|
|
@@ -3428,6 +3745,9 @@ async function runConnect(options) {
|
|
|
3428
3745
|
console.error("[apm] config \u7F3A\u5C11 clientMachineId\uFF0C\u8BF7\u91CD\u65B0 apm login");
|
|
3429
3746
|
process.exit(1);
|
|
3430
3747
|
}
|
|
3748
|
+
assertConnectNotRunning();
|
|
3749
|
+
acquireConnectLock("foreground");
|
|
3750
|
+
process.on("exit", releaseConnectLock);
|
|
3431
3751
|
const url = buildAgentWsUrl(cfg.baseUrl, resolveApiKey(cfg));
|
|
3432
3752
|
console.log(`[apm] \u8FDE\u63A5 ${cfg.baseUrl} \u2026`);
|
|
3433
3753
|
await new Promise((resolve5, reject) => {
|
|
@@ -3459,6 +3779,7 @@ async function runConnect(options) {
|
|
|
3459
3779
|
]);
|
|
3460
3780
|
} catch {
|
|
3461
3781
|
}
|
|
3782
|
+
releaseConnectLock();
|
|
3462
3783
|
resolve5();
|
|
3463
3784
|
process.exit(code);
|
|
3464
3785
|
};
|
|
@@ -3615,20 +3936,20 @@ async function runCreatePr(options) {
|
|
|
3615
3936
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
3616
3937
|
|
|
3617
3938
|
// src/commands/deploy/internal/apm-config.ts
|
|
3618
|
-
import { existsSync as
|
|
3939
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "node:fs";
|
|
3619
3940
|
import { homedir as homedir2 } from "node:os";
|
|
3620
|
-
import { join as
|
|
3941
|
+
import { join as join16, resolve as resolve4 } from "node:path";
|
|
3621
3942
|
function loadApmConfig(options) {
|
|
3622
3943
|
const p = resolve4(
|
|
3623
3944
|
process.cwd(),
|
|
3624
3945
|
options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
|
|
3625
3946
|
);
|
|
3626
|
-
if (!
|
|
3947
|
+
if (!existsSync15(p)) {
|
|
3627
3948
|
console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
|
|
3628
3949
|
process.exit(1);
|
|
3629
3950
|
}
|
|
3630
3951
|
try {
|
|
3631
|
-
const raw =
|
|
3952
|
+
const raw = readFileSync12(p, "utf8");
|
|
3632
3953
|
return JSON.parse(raw);
|
|
3633
3954
|
} catch (e) {
|
|
3634
3955
|
console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
|
|
@@ -3812,12 +4133,12 @@ function readMavenLocalRepoFromEnv(env = process.env) {
|
|
|
3812
4133
|
return null;
|
|
3813
4134
|
}
|
|
3814
4135
|
function readMavenLocalRepoFromSettings() {
|
|
3815
|
-
const settingsPath =
|
|
3816
|
-
if (!
|
|
4136
|
+
const settingsPath = join16(homedir2(), ".m2", "settings.xml");
|
|
4137
|
+
if (!existsSync15(settingsPath)) {
|
|
3817
4138
|
return null;
|
|
3818
4139
|
}
|
|
3819
4140
|
try {
|
|
3820
|
-
const xml =
|
|
4141
|
+
const xml = readFileSync12(settingsPath, "utf8");
|
|
3821
4142
|
const match = xml.match(
|
|
3822
4143
|
/<localRepository>\s*([^<]+?)\s*<\/localRepository>/
|
|
3823
4144
|
);
|
|
@@ -3848,11 +4169,24 @@ function resolveMavenLocalRepoWithSource() {
|
|
|
3848
4169
|
};
|
|
3849
4170
|
}
|
|
3850
4171
|
return {
|
|
3851
|
-
path:
|
|
4172
|
+
path: join16(homedir2(), ".m2", "repository"),
|
|
3852
4173
|
source: "default",
|
|
3853
4174
|
sourceDetail: "~/.m2/repository"
|
|
3854
4175
|
};
|
|
3855
4176
|
}
|
|
4177
|
+
function resolveWisdomDeployMode(raw) {
|
|
4178
|
+
if (raw === void 0 || raw === null || raw === "") {
|
|
4179
|
+
return "default";
|
|
4180
|
+
}
|
|
4181
|
+
const mode = String(raw).trim().toLowerCase();
|
|
4182
|
+
if (mode === "default" || mode === "full") {
|
|
4183
|
+
return mode;
|
|
4184
|
+
}
|
|
4185
|
+
console.error(
|
|
4186
|
+
`apm.config.json \u4E2D wisdomDeploy.mode \u53EA\u80FD\u4E3A default \u6216 full\uFF0C\u5F53\u524D\u503C: ${raw}`
|
|
4187
|
+
);
|
|
4188
|
+
process.exit(1);
|
|
4189
|
+
}
|
|
3856
4190
|
function resolveWisdomBackendDeployFromApmConfig(cfg) {
|
|
3857
4191
|
const projectName = reqTopLevelName(cfg);
|
|
3858
4192
|
const w = cfg.wisdomDeploy ?? {};
|
|
@@ -3886,7 +4220,8 @@ function resolveWisdomBackendDeployFromApmConfig(cfg) {
|
|
|
3886
4220
|
mavenLocalRepoSourceDetail: mavenLocalRepo.sourceDetail,
|
|
3887
4221
|
healthCheckPort: healthPort,
|
|
3888
4222
|
healthCheckContext: reqHc(h.context, "context").trim(),
|
|
3889
|
-
healthCheckTimeout: healthTimeout
|
|
4223
|
+
healthCheckTimeout: healthTimeout,
|
|
4224
|
+
mode: resolveWisdomDeployMode(w.mode)
|
|
3890
4225
|
};
|
|
3891
4226
|
}
|
|
3892
4227
|
function posixDirname(p) {
|
|
@@ -3904,18 +4239,18 @@ function posixBasename(p) {
|
|
|
3904
4239
|
}
|
|
3905
4240
|
|
|
3906
4241
|
// src/commands/deploy/internal/wisdom-auto-deploy.ts
|
|
3907
|
-
import { existsSync as
|
|
4242
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
|
|
3908
4243
|
import path3 from "node:path";
|
|
3909
4244
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
3910
4245
|
|
|
3911
4246
|
// src/commands/deploy/internal/wisdom-backend-deploy.ts
|
|
3912
4247
|
import {
|
|
3913
|
-
existsSync as
|
|
3914
|
-
mkdirSync as
|
|
4248
|
+
existsSync as existsSync16,
|
|
4249
|
+
mkdirSync as mkdirSync8,
|
|
3915
4250
|
readdirSync as readdirSync5,
|
|
3916
|
-
readFileSync as
|
|
4251
|
+
readFileSync as readFileSync13,
|
|
3917
4252
|
statSync as statSync5,
|
|
3918
|
-
writeFileSync as
|
|
4253
|
+
writeFileSync as writeFileSync14
|
|
3919
4254
|
} from "node:fs";
|
|
3920
4255
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
3921
4256
|
import path2 from "node:path";
|
|
@@ -4122,15 +4457,15 @@ function fileSignature(filePath) {
|
|
|
4122
4457
|
}
|
|
4123
4458
|
function loadManifest4() {
|
|
4124
4459
|
const manifestPath2 = manifestFilePath();
|
|
4125
|
-
if (!
|
|
4460
|
+
if (!existsSync16(manifestPath2)) {
|
|
4126
4461
|
return {};
|
|
4127
4462
|
}
|
|
4128
|
-
return JSON.parse(
|
|
4463
|
+
return JSON.parse(readFileSync13(manifestPath2, "utf8"));
|
|
4129
4464
|
}
|
|
4130
4465
|
function saveManifest4(manifest) {
|
|
4131
4466
|
const dir = deployCacheDir();
|
|
4132
|
-
|
|
4133
|
-
|
|
4467
|
+
mkdirSync8(dir, { recursive: true });
|
|
4468
|
+
writeFileSync14(manifestFilePath(), JSON.stringify(manifest, null, 2), "utf8");
|
|
4134
4469
|
}
|
|
4135
4470
|
function isProjectLibJar(jarName) {
|
|
4136
4471
|
return jarName.startsWith("jeecg-");
|
|
@@ -4186,12 +4521,12 @@ function updateManifestEntries(manifest, entries, projectRoot) {
|
|
|
4186
4521
|
}
|
|
4187
4522
|
async function createUpdatePackage(entries, packageName) {
|
|
4188
4523
|
const dir = deployCacheDir();
|
|
4189
|
-
|
|
4524
|
+
mkdirSync8(dir, { recursive: true });
|
|
4190
4525
|
const zipPath = path2.join(dir, packageName);
|
|
4191
4526
|
log(`\u521B\u5EFA\u66F4\u65B0\u5305: ${path2.basename(zipPath)}\uFF08${entries.length} \u4E2A\u6587\u4EF6\uFF09`);
|
|
4192
4527
|
const zip = new JSZip2();
|
|
4193
4528
|
for (const entry of entries) {
|
|
4194
|
-
const content =
|
|
4529
|
+
const content = readFileSync13(entry.path);
|
|
4195
4530
|
zip.file(entry.arcname, content);
|
|
4196
4531
|
log(` \u6253\u5305: ${entry.arcname} (${entry.reason})`);
|
|
4197
4532
|
}
|
|
@@ -4200,7 +4535,7 @@ async function createUpdatePackage(entries, packageName) {
|
|
|
4200
4535
|
compression: "DEFLATE",
|
|
4201
4536
|
compressionOptions: { level: 6 }
|
|
4202
4537
|
});
|
|
4203
|
-
|
|
4538
|
+
writeFileSync14(zipPath, buffer);
|
|
4204
4539
|
return zipPath;
|
|
4205
4540
|
}
|
|
4206
4541
|
function getMvnExecutable() {
|
|
@@ -4249,11 +4584,11 @@ function runMavenBuild(projectRoot, mavenLocalRepo, repoSource) {
|
|
|
4249
4584
|
}
|
|
4250
4585
|
function locateLibDir(projectRoot) {
|
|
4251
4586
|
const targetDir = getTargetDir(projectRoot);
|
|
4252
|
-
if (!
|
|
4587
|
+
if (!existsSync16(targetDir)) {
|
|
4253
4588
|
fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
|
|
4254
4589
|
}
|
|
4255
4590
|
const libDir = path2.join(targetDir, "lib");
|
|
4256
|
-
if (!
|
|
4591
|
+
if (!existsSync16(libDir) || !statSync5(libDir).isDirectory()) {
|
|
4257
4592
|
fail(`lib \u76EE\u5F55\u4E0D\u5B58\u5728: ${libDir}`);
|
|
4258
4593
|
}
|
|
4259
4594
|
const libJars = readdirSync5(libDir).filter((name) => name.endsWith(".jar"));
|
|
@@ -4263,6 +4598,19 @@ function locateLibDir(projectRoot) {
|
|
|
4263
4598
|
log(`\u5B9A\u4F4D lib \u4EA7\u7269: ${libJars.length} \u4E2A`);
|
|
4264
4599
|
return libDir;
|
|
4265
4600
|
}
|
|
4601
|
+
function locateMainJar(projectRoot) {
|
|
4602
|
+
const targetDir = getTargetDir(projectRoot);
|
|
4603
|
+
if (!existsSync16(targetDir)) {
|
|
4604
|
+
fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
|
|
4605
|
+
}
|
|
4606
|
+
const jarFiles = readdirSync5(targetDir).filter((name) => name.endsWith(".jar") && !name.endsWith(".jar.original")).map((name) => path2.join(targetDir, name)).sort((a, b) => statSync5(b).mtimeMs - statSync5(a).mtimeMs);
|
|
4607
|
+
if (jarFiles.length === 0) {
|
|
4608
|
+
fail(`target \u76EE\u5F55\u4E0B\u6CA1\u6709\u4E3B JAR: ${targetDir}`);
|
|
4609
|
+
}
|
|
4610
|
+
const mainJar = jarFiles[0];
|
|
4611
|
+
log(`\u5B9A\u4F4D\u4E3B JAR \u4EA7\u7269: ${path2.basename(mainJar)}`);
|
|
4612
|
+
return mainJar;
|
|
4613
|
+
}
|
|
4266
4614
|
async function connectSsh(config) {
|
|
4267
4615
|
const client = new Client();
|
|
4268
4616
|
log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
|
|
@@ -4319,6 +4667,18 @@ async function uploadUpdatePackage(sftp, zipPath, config) {
|
|
|
4319
4667
|
}
|
|
4320
4668
|
return remotePath;
|
|
4321
4669
|
}
|
|
4670
|
+
async function uploadFullJar(sftp, localJarPath, config) {
|
|
4671
|
+
const remoteDir = config.remoteAppDir.replace(/\/$/, "");
|
|
4672
|
+
const remotePath = `${remoteDir}/${config.startupJar}`;
|
|
4673
|
+
log(`\u4E0A\u4F20\u5168\u91CF JAR (${path2.basename(localJarPath)}) -> ${remotePath}`);
|
|
4674
|
+
try {
|
|
4675
|
+
await sftp.mkdir(remoteDir, true);
|
|
4676
|
+
await sftp.fastPut(localJarPath, remotePath);
|
|
4677
|
+
log("\u5168\u91CF JAR \u4E0A\u4F20\u6210\u529F");
|
|
4678
|
+
} catch (err) {
|
|
4679
|
+
fail(`\u5168\u91CF JAR \u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
|
|
4680
|
+
}
|
|
4681
|
+
}
|
|
4322
4682
|
async function runRemoteCommand(client, command, options) {
|
|
4323
4683
|
const check = options?.check ?? true;
|
|
4324
4684
|
const stream = options?.stream ?? false;
|
|
@@ -4574,14 +4934,26 @@ async function runWisdomBackendDeploy(options) {
|
|
|
4574
4934
|
log(`=== \u81EA\u52A8\u90E8\u7F72: ${config.projectName} ===`);
|
|
4575
4935
|
log(`\u914D\u7F6E\u6587\u4EF6: ${path2.join(workspaceApmDir(), "apm.config.json")}`);
|
|
4576
4936
|
log(`\u9879\u76EE\u6839\u76EE\u5F55: ${projectRoot}`);
|
|
4937
|
+
log(
|
|
4938
|
+
`\u90E8\u7F72\u6A21\u5F0F: ${config.mode}${config.mode === "full" ? "\uFF08\u5168\u91CF JAR\uFF0C\u8DF3\u8FC7 lib \u68C0\u67E5\uFF09" : "\uFF08\u589E\u91CF lib \u66F4\u65B0\uFF09"}`
|
|
4939
|
+
);
|
|
4577
4940
|
runMavenBuild(projectRoot, config.mavenLocalRepo, {
|
|
4578
4941
|
source: config.mavenLocalRepoSource,
|
|
4579
4942
|
sourceDetail: config.mavenLocalRepoSourceDetail
|
|
4580
4943
|
});
|
|
4581
|
-
const libDir = locateLibDir(projectRoot);
|
|
4582
|
-
let manifest = loadManifest4();
|
|
4583
4944
|
const conn = await connectSsh(config);
|
|
4584
4945
|
try {
|
|
4946
|
+
if (config.mode === "full") {
|
|
4947
|
+
const mainJar = locateMainJar(projectRoot);
|
|
4948
|
+
await uploadFullJar(conn.sftp, mainJar, config);
|
|
4949
|
+
log("\u91CD\u542F\u670D\u52A1...");
|
|
4950
|
+
await restartRemoteService(conn.client, config);
|
|
4951
|
+
await healthCheckService(conn.client, config);
|
|
4952
|
+
log("\u90E8\u7F72\u5B8C\u6210");
|
|
4953
|
+
return;
|
|
4954
|
+
}
|
|
4955
|
+
const libDir = locateLibDir(projectRoot);
|
|
4956
|
+
let manifest = loadManifest4();
|
|
4585
4957
|
const remoteLibStats = await getRemoteFileStats(
|
|
4586
4958
|
conn.sftp,
|
|
4587
4959
|
config.remoteLibDir
|
|
@@ -4647,15 +5019,15 @@ function isWisdomLegacyDeploy(cfg) {
|
|
|
4647
5019
|
return !hasNewFrontend && !hasNewBackend;
|
|
4648
5020
|
}
|
|
4649
5021
|
function detectWisdomProjectType(cwd) {
|
|
4650
|
-
return
|
|
5022
|
+
return existsSync17(path3.join(cwd, "package.json")) ? "frontend" : "backend";
|
|
4651
5023
|
}
|
|
4652
5024
|
function readPackageScripts(cwd) {
|
|
4653
5025
|
const pkgPath = path3.join(cwd, "package.json");
|
|
4654
|
-
if (!
|
|
5026
|
+
if (!existsSync17(pkgPath)) {
|
|
4655
5027
|
return {};
|
|
4656
5028
|
}
|
|
4657
5029
|
try {
|
|
4658
|
-
const raw =
|
|
5030
|
+
const raw = readFileSync14(pkgPath, "utf8");
|
|
4659
5031
|
const parsed = JSON.parse(raw);
|
|
4660
5032
|
return parsed.scripts ?? {};
|
|
4661
5033
|
} catch {
|
|
@@ -4765,7 +5137,7 @@ import path7 from "node:path";
|
|
|
4765
5137
|
import Docker from "dockerode";
|
|
4766
5138
|
|
|
4767
5139
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
|
|
4768
|
-
import { existsSync as
|
|
5140
|
+
import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
|
|
4769
5141
|
import path4 from "node:path";
|
|
4770
5142
|
function asOptionalTlsBuffer(value) {
|
|
4771
5143
|
if (typeof value !== "string") {
|
|
@@ -4777,8 +5149,8 @@ function asOptionalTlsBuffer(value) {
|
|
|
4777
5149
|
if (normalized === "") {
|
|
4778
5150
|
return void 0;
|
|
4779
5151
|
}
|
|
4780
|
-
if (
|
|
4781
|
-
return
|
|
5152
|
+
if (existsSync18(normalized)) {
|
|
5153
|
+
return readFileSync15(normalized);
|
|
4782
5154
|
}
|
|
4783
5155
|
const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
|
|
4784
5156
|
if (looksLikePath) {
|
|
@@ -4988,7 +5360,7 @@ var DockerodeClient = class {
|
|
|
4988
5360
|
var createDockerodeClient = (config) => new DockerodeClient(config);
|
|
4989
5361
|
|
|
4990
5362
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
|
|
4991
|
-
import { existsSync as
|
|
5363
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
|
|
4992
5364
|
import path5 from "node:path";
|
|
4993
5365
|
function stripSurroundingQuotes(value) {
|
|
4994
5366
|
const t = value.trim();
|
|
@@ -5005,10 +5377,10 @@ function loadEnvFromFile(envFilePath) {
|
|
|
5005
5377
|
return {};
|
|
5006
5378
|
}
|
|
5007
5379
|
const targetPath = path5.resolve(envFilePath);
|
|
5008
|
-
if (!
|
|
5380
|
+
if (!existsSync19(targetPath) || !statSync6(targetPath).isFile()) {
|
|
5009
5381
|
return {};
|
|
5010
5382
|
}
|
|
5011
|
-
const raw =
|
|
5383
|
+
const raw = readFileSync16(targetPath, "utf-8");
|
|
5012
5384
|
const result = {};
|
|
5013
5385
|
for (const line of raw.split(/\r?\n/)) {
|
|
5014
5386
|
const normalized = line.trim();
|
|
@@ -5179,12 +5551,12 @@ function dockerPushImage(params, cwd) {
|
|
|
5179
5551
|
}
|
|
5180
5552
|
|
|
5181
5553
|
// src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
|
|
5182
|
-
import { existsSync as
|
|
5554
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
5183
5555
|
import path6 from "node:path";
|
|
5184
5556
|
function resolveDockerBuildPaths(cwd) {
|
|
5185
5557
|
const dockerfilePath = path6.join(cwd, "Dockerfile");
|
|
5186
5558
|
Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
|
|
5187
|
-
if (!
|
|
5559
|
+
if (!existsSync20(dockerfilePath)) {
|
|
5188
5560
|
throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
|
|
5189
5561
|
}
|
|
5190
5562
|
Logger.info("\u2713 Dockerfile \u5B58\u5728");
|
|
@@ -5648,7 +6020,7 @@ function registerDeploySftpCommands(program) {
|
|
|
5648
6020
|
// src/commands/deploy/wisdom-backend.ts
|
|
5649
6021
|
function registerDeployWisdomBackendCommands(program) {
|
|
5650
6022
|
program.command("deploy-wisdom-backend").description(
|
|
5651
|
-
"Maven \u6784\u5EFA\u540E\
|
|
6023
|
+
"Maven \u6784\u5EFA\u540E\u90E8\u7F72 Spring Boot \u670D\u52A1\uFF08\u914D\u7F6E\u89C1 apm.config.json \u7684 wisdomDeploy \u4E0E healthCheck\uFF1Bmode=default \u589E\u91CF\u66F4\u65B0 lib\uFF0Cmode=full \u53D1\u5E03\u5168\u91CF JAR\uFF09"
|
|
5652
6024
|
).option(
|
|
5653
6025
|
"--config <path>",
|
|
5654
6026
|
"apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
|
|
@@ -5734,8 +6106,46 @@ function buildProgram() {
|
|
|
5734
6106
|
});
|
|
5735
6107
|
program.command("connect").description(
|
|
5736
6108
|
"\u8FDE\u63A5\u5E73\u53F0 WebSocket\uFF08/ws/agent\uFF09\uFF0C\u7EF4\u6301\u5FC3\u8DF3\u5E76\u5904\u7406\u4E0B\u884C message\uFF08TYPING \u2192 Cursor \u2192 SUCCESS/FAILED\uFF09\uFF1B\u542F\u52A8\u524D\u81EA\u52A8 apm update \u5230\u5F53\u524D\u5927\u7248\u672C\u6700\u65B0\u7248"
|
|
5737
|
-
).option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u8986\u76D6 config \u4E2D\u7684 baseUrl").
|
|
5738
|
-
|
|
6109
|
+
).option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u8986\u76D6 config \u4E2D\u7684 baseUrl").option(
|
|
6110
|
+
"--daemon",
|
|
6111
|
+
"\u540E\u53F0\u5B88\u62A4\u8FD0\u884C\uFF08\u5185\u7F6E PM2\uFF0C\u65AD\u7EBF\u6216\u9000\u51FA\u540E\u81EA\u52A8\u91CD\u542F\uFF1B\u63A8\u8350\u7528\u4E8E\u957F\u671F\u5728\u7EBF\uFF09"
|
|
6112
|
+
).option("-f, --follow", "\u4E0E --daemon \u5408\u7528\uFF1A\u542F\u52A8\u540E\u5728\u5F53\u524D\u7EC8\u7AEF\u5B9E\u65F6\u8DDF\u8E2A\u65E5\u5FD7").action(
|
|
6113
|
+
async (opts) => {
|
|
6114
|
+
if (opts.follow && !opts.daemon) {
|
|
6115
|
+
console.error("[apm] --follow \u4EC5\u53EF\u4E0E --daemon \u540C\u65F6\u4F7F\u7528");
|
|
6116
|
+
process.exit(1);
|
|
6117
|
+
}
|
|
6118
|
+
if (opts.daemon === true) {
|
|
6119
|
+
await runDaemonStart({ server: opts.server, follow: opts.follow });
|
|
6120
|
+
return;
|
|
6121
|
+
}
|
|
6122
|
+
await runConnect({ server: opts.server });
|
|
6123
|
+
}
|
|
6124
|
+
);
|
|
6125
|
+
const daemon = program.command("daemon").description(
|
|
6126
|
+
"\u540E\u53F0 connect \u8FD0\u7EF4\u547D\u4EE4\uFF08\u542F\u52A8\u8BF7\u4F18\u5148\u4F7F\u7528 apm connect --daemon\uFF1B\u6B64\u5904\u4F9B status/logs/stop \u7B49\uFF09"
|
|
6127
|
+
);
|
|
6128
|
+
daemon.command("start").description("\u542F\u52A8\u540E\u53F0 connect\uFF08\u7B49\u6548 apm connect --daemon\uFF09").option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u8986\u76D6 config \u4E2D\u7684 baseUrl").option("-f, --follow", "\u542F\u52A8\u540E\u5728\u5F53\u524D\u7EC8\u7AEF\u5B9E\u65F6\u8DDF\u8E2A\u65E5\u5FD7").action(async (opts) => {
|
|
6129
|
+
await runDaemonStart({ server: opts.server, follow: opts.follow });
|
|
6130
|
+
});
|
|
6131
|
+
daemon.command("stop").description("\u505C\u6B62 PM2 \u5B88\u62A4\u7684 apm connect").action(async () => {
|
|
6132
|
+
await runDaemonStop();
|
|
6133
|
+
});
|
|
6134
|
+
daemon.command("restart").description("\u91CD\u542F PM2 \u5B88\u62A4\u7684 apm connect\uFF08\u672A\u542F\u52A8\u65F6\u4F1A\u76F4\u63A5\u542F\u52A8\uFF09").option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u8986\u76D6 config \u4E2D\u7684 baseUrl").action(async (opts) => {
|
|
6135
|
+
await runDaemonRestart(opts);
|
|
6136
|
+
});
|
|
6137
|
+
daemon.command("delete").description("\u4ECE PM2 \u4E2D\u79FB\u9664 apm connect \u8FDB\u7A0B").action(async () => {
|
|
6138
|
+
await runDaemonDelete();
|
|
6139
|
+
});
|
|
6140
|
+
daemon.command("status").description("\u67E5\u770B PM2 \u5B88\u62A4\u7684 apm connect \u72B6\u6001").action(async () => {
|
|
6141
|
+
await runDaemonStatus();
|
|
6142
|
+
});
|
|
6143
|
+
daemon.command("logs").description("\u67E5\u770B PM2 \u5B88\u62A4\u7684 apm connect \u65E5\u5FD7").option("-f, --follow", "\u6301\u7EED\u8DDF\u8E2A\u65E5\u5FD7").option("-n, --lines <n>", "\u663E\u793A\u884C\u6570", "100").action(async (opts) => {
|
|
6144
|
+
const lines = Number.parseInt(opts.lines ?? "100", 10);
|
|
6145
|
+
await runDaemonLogs({
|
|
6146
|
+
follow: opts.follow === true,
|
|
6147
|
+
lines: Number.isFinite(lines) && lines > 0 ? lines : 100
|
|
6148
|
+
});
|
|
5739
6149
|
});
|
|
5740
6150
|
program.command("branch").description("\u5207\u6362\u6216\u521B\u5EFA\u4F1A\u8BDD\u5206\u652F feat/session-<sessionId>").argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").option(
|
|
5741
6151
|
"-m, --message <text>",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-project-manage-cli",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.80",
|
|
4
4
|
"description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"dockerode": "~5.0.0",
|
|
45
45
|
"ssh2": "~1.16.0",
|
|
46
46
|
"ssh2-sftp-client": "~12.0.1",
|
|
47
|
-
"jszip": "~3.10.1"
|
|
47
|
+
"jszip": "~3.10.1",
|
|
48
|
+
"pm2": "~5.4.3"
|
|
48
49
|
}
|
|
49
50
|
}
|