ai-project-manage-cli 6.0.65 → 6.0.66

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/index.js CHANGED
@@ -110,8 +110,8 @@ function toFsPath(inputPath) {
110
110
  }
111
111
  return `\\\\?\\${normalized}`;
112
112
  }
113
- function normalizeWorkdirPath(path10) {
114
- let normalized = path10.trim().replace(/\\/g, "/").normalize("NFC");
113
+ function normalizeWorkdirPath(path12) {
114
+ let normalized = path12.trim().replace(/\\/g, "/").normalize("NFC");
115
115
  if (normalized.startsWith("//?/")) {
116
116
  normalized = normalized.slice(4);
117
117
  }
@@ -326,9 +326,9 @@ function assertTemplateCopiedToApm(apmDir, workdir) {
326
326
  "sessions"
327
327
  ];
328
328
  for (const item of required) {
329
- const path10 = join2(apmDir, item);
330
- if (!existsSync(toFsPath(path10))) {
331
- throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path10}`);
329
+ const path12 = join2(apmDir, item);
330
+ if (!existsSync(toFsPath(path12))) {
331
+ throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path12}`);
332
332
  }
333
333
  }
334
334
  const leakedRules = join2(workdir, "rules");
@@ -613,14 +613,14 @@ function projectDocumentLocalPath(apmRoot, documentPath) {
613
613
  const normalized = normalizeLocalDocumentPath(documentPath);
614
614
  return join4(projectDocumentsDir(apmRoot), ...normalized.split("/"));
615
615
  }
616
- function normalizeLocalDocumentPath(path10) {
617
- const trimmed = path10.trim().replace(/\\/g, "/");
616
+ function normalizeLocalDocumentPath(path12) {
617
+ const trimmed = path12.trim().replace(/\\/g, "/");
618
618
  if (!trimmed || trimmed.startsWith("/") || /^[a-zA-Z]:/.test(trimmed)) {
619
- throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path10}`);
619
+ throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path12}`);
620
620
  }
621
621
  const segments = trimmed.split("/").filter(Boolean);
622
622
  if (segments.some((segment) => segment === ".." || segment === ".")) {
623
- throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path10}`);
623
+ throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path12}`);
624
624
  }
625
625
  return segments.join("/");
626
626
  }
@@ -671,15 +671,15 @@ function diffManifestPaths(remote, local) {
671
671
  (local?.documents ?? []).map((doc) => [doc.path, doc.contentHash])
672
672
  );
673
673
  const download = [];
674
- for (const [path10, hash] of remoteMap) {
675
- if (localMap.get(path10) !== hash) {
676
- download.push(path10);
674
+ for (const [path12, hash] of remoteMap) {
675
+ if (localMap.get(path12) !== hash) {
676
+ download.push(path12);
677
677
  }
678
678
  }
679
679
  const deleteLocal = [];
680
- for (const path10 of localMap.keys()) {
681
- if (!remoteMap.has(path10)) {
682
- deleteLocal.push(path10);
680
+ for (const path12 of localMap.keys()) {
681
+ if (!remoteMap.has(path12)) {
682
+ deleteLocal.push(path12);
683
683
  }
684
684
  }
685
685
  return { download, deleteLocal };
@@ -739,8 +739,8 @@ ${diagnostic ?? ""}`
739
739
  }
740
740
  }
741
741
  let deleted = 0;
742
- for (const path10 of deleteLocal) {
743
- const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path10));
742
+ for (const path12 of deleteLocal) {
743
+ const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path12));
744
744
  if (existsSync2(absPath)) {
745
745
  rmSync(absPath, { force: true });
746
746
  deleted += 1;
@@ -785,21 +785,21 @@ async function syncRepositoryProjectDocumentsPush(cfg, workdirPath, apmRoot) {
785
785
  ])
786
786
  );
787
787
  let synced = 0;
788
- for (const path10 of localPaths) {
789
- const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path10));
788
+ for (const path12 of localPaths) {
789
+ const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path12));
790
790
  const content = readFileSync3(absPath, "utf8");
791
791
  const contentHash = hashLocalFileContent(content);
792
- if (remoteHashByPath.get(path10) === contentHash) {
792
+ if (remoteHashByPath.get(path12) === contentHash) {
793
793
  continue;
794
794
  }
795
795
  await api.cli.upsertRepositoryProjectDocument({
796
796
  repositoryId,
797
- path: path10,
797
+ path: path12,
798
798
  content,
799
- description: remoteDescriptionByPath.get(path10) ?? void 0
799
+ description: remoteDescriptionByPath.get(path12) ?? void 0
800
800
  });
801
801
  synced += 1;
802
- console.log(`[apm] \u5DF2\u540C\u6B65\u4ED3\u5E93\u9879\u76EE\u6587\u6863: ${path10}`);
802
+ console.log(`[apm] \u5DF2\u540C\u6B65\u4ED3\u5E93\u9879\u76EE\u6587\u6863: ${path12}`);
803
803
  }
804
804
  if (synced === 0) {
805
805
  console.log("[apm] \u4ED3\u5E93\u9879\u76EE\u6587\u6863\u65E0\u53D8\u5316\uFF0C\u8DF3\u8FC7\u63A8\u9001");
@@ -1395,13 +1395,13 @@ async function downloadAttachment(cfg, attachmentId) {
1395
1395
  return Buffer.from(await res.arrayBuffer());
1396
1396
  }
1397
1397
  function loadManifest(dir) {
1398
- const path10 = join6(dir, MANIFEST_FILE2);
1399
- if (!existsSync4(path10)) {
1398
+ const path12 = join6(dir, MANIFEST_FILE2);
1399
+ if (!existsSync4(path12)) {
1400
1400
  return { version: 1, attachments: {} };
1401
1401
  }
1402
1402
  try {
1403
1403
  const parsed = JSON.parse(
1404
- readFileSync5(path10, "utf8")
1404
+ readFileSync5(path12, "utf8")
1405
1405
  );
1406
1406
  if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
1407
1407
  return parsed;
@@ -1482,8 +1482,8 @@ function sanitizeSkillDirName(name) {
1482
1482
  function listBaseSkillDirNames() {
1483
1483
  if (!existsSync5(BASE_SKILLS_TEMPLATE_DIR)) return [];
1484
1484
  return readdirSync3(BASE_SKILLS_TEMPLATE_DIR).filter((name) => {
1485
- const path10 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
1486
- return statSync2(path10).isDirectory();
1485
+ const path12 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
1486
+ return statSync2(path12).isDirectory();
1487
1487
  });
1488
1488
  }
1489
1489
  function syncAgentsGuide(apmDir) {
@@ -1495,8 +1495,8 @@ function syncAgentsGuide(apmDir) {
1495
1495
  function listBaseRuleFileNames() {
1496
1496
  if (!existsSync5(BASE_RULES_TEMPLATE_DIR)) return [];
1497
1497
  return readdirSync3(BASE_RULES_TEMPLATE_DIR).filter((name) => {
1498
- const path10 = join7(BASE_RULES_TEMPLATE_DIR, name);
1499
- return statSync2(path10).isFile();
1498
+ const path12 = join7(BASE_RULES_TEMPLATE_DIR, name);
1499
+ return statSync2(path12).isFile();
1500
1500
  });
1501
1501
  }
1502
1502
  function syncBaseRules(rulesDir) {
@@ -1559,13 +1559,13 @@ function ruleLocalFileName(ruleName) {
1559
1559
  return `${sanitized}.md`;
1560
1560
  }
1561
1561
  function loadManifest2(rulesDir) {
1562
- const path10 = join8(rulesDir, MANIFEST_FILE3);
1563
- if (!existsSync6(toFsPath(path10))) {
1562
+ const path12 = join8(rulesDir, MANIFEST_FILE3);
1563
+ if (!existsSync6(toFsPath(path12))) {
1564
1564
  return { version: 1, rules: {} };
1565
1565
  }
1566
1566
  try {
1567
1567
  const parsed = JSON.parse(
1568
- readFileSync6(toFsPath(path10), "utf8")
1568
+ readFileSync6(toFsPath(path12), "utf8")
1569
1569
  );
1570
1570
  if (parsed?.version === 1 && parsed.rules && typeof parsed.rules === "object") {
1571
1571
  return parsed;
@@ -2102,7 +2102,7 @@ async function runUpdateMessageStatus(options) {
2102
2102
  }
2103
2103
 
2104
2104
  // src/commands/connect.ts
2105
- import { spawnSync as spawnSync2 } from "child_process";
2105
+ import { spawnSync as spawnSync4 } from "child_process";
2106
2106
  import WebSocket from "ws";
2107
2107
 
2108
2108
  // src/ws/protocol.ts
@@ -2226,19 +2226,915 @@ function validateAgentWsMessage(value, kind) {
2226
2226
 
2227
2227
  // src/commands/connect/deploy-run.ts
2228
2228
  import { spawn } from "node:child_process";
2229
- import { readFileSync as readFileSync9 } from "node:fs";
2229
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
2230
2230
  import { join as join13 } from "node:path";
2231
+
2232
+ // src/commands/deploy/internal/wisdom-auto-deploy.ts
2233
+ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
2234
+ import path3 from "node:path";
2235
+ import { spawnSync as spawnSync3 } from "node:child_process";
2236
+
2237
+ // src/commands/deploy/internal/apm-config.ts
2238
+ import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
2239
+ import { resolve as resolve3 } from "node:path";
2240
+ function loadApmConfig(options) {
2241
+ const p = resolve3(
2242
+ process.cwd(),
2243
+ options?.configPath ?? resolve3(workspaceApmDir(), "apm.config.json")
2244
+ );
2245
+ if (!existsSync11(p)) {
2246
+ console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
2247
+ process.exit(1);
2248
+ }
2249
+ try {
2250
+ const raw = readFileSync9(p, "utf8");
2251
+ return JSON.parse(raw);
2252
+ } catch (e) {
2253
+ console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
2254
+ process.exit(1);
2255
+ }
2256
+ }
2257
+ function req(v, field) {
2258
+ if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2259
+ console.error(`apm.config.json \u4E2D backendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2260
+ process.exit(1);
2261
+ }
2262
+ return v;
2263
+ }
2264
+ function reqTopLevelName(cfg) {
2265
+ const n = (cfg.name ?? "").trim();
2266
+ if (!n) {
2267
+ console.error(
2268
+ "\u8BF7\u5728 apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4E0E\u524D\u7AEF\u5236\u54C1\u524D\u7F00\u3001\u540E\u7AEF\u955C\u50CF\u540D\u5171\u7528\uFF09"
2269
+ );
2270
+ process.exit(1);
2271
+ }
2272
+ return n;
2273
+ }
2274
+ function reqBackendPositiveInt(v, field) {
2275
+ const n = Number(v);
2276
+ if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
2277
+ console.error(`apm.config.json \u4E2D backendDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
2278
+ process.exit(1);
2279
+ }
2280
+ return n;
2281
+ }
2282
+ function resolveBackendDeployFromApmConfig(cfg) {
2283
+ const b = cfg.backendDeploy ?? {};
2284
+ const protoRaw = req(b.remoteProtocol, "remoteProtocol").trim().toLowerCase();
2285
+ if (protoRaw !== "http" && protoRaw !== "https") {
2286
+ console.error(
2287
+ "apm.config.json \u4E2D backendDeploy.remoteProtocol \u53EA\u80FD\u4E3A http \u6216 https"
2288
+ );
2289
+ process.exit(1);
2290
+ }
2291
+ const remoteProtocol = protoRaw;
2292
+ let mappings = [];
2293
+ const rawPorts = b.containerPortsMappings;
2294
+ if (rawPorts !== void 0 && rawPorts !== null) {
2295
+ if (!Array.isArray(rawPorts)) {
2296
+ console.error(
2297
+ "apm.config.json \u4E2D backendDeploy.containerPortsMappings \u987B\u4E3A\u5B57\u7B26\u4E32\u6570\u7EC4\uFF08\u53EF\u4E3A\u7A7A\uFF0C\u7701\u7565\u5219\u4E0D\u52A0\u7AEF\u53E3\u6620\u5C04\uFF09"
2298
+ );
2299
+ process.exit(1);
2300
+ }
2301
+ mappings = rawPorts.map((x) => String(x).trim()).filter(Boolean);
2302
+ }
2303
+ return {
2304
+ name: reqTopLevelName(cfg),
2305
+ registryHost: req(b.registryHost, "registryHost").trim(),
2306
+ registryNamespace: req(b.registryNamespace, "registryNamespace").trim(),
2307
+ registryUser: req(b.registryUser, "registryUser").trim(),
2308
+ registryPassword: req(b.registryPassword, "registryPassword").trim(),
2309
+ remoteHost: req(b.remoteHost, "remoteHost").trim(),
2310
+ remotePort: reqBackendPositiveInt(b.remotePort, "remotePort"),
2311
+ remoteProtocol,
2312
+ caPath: b.caPath?.trim(),
2313
+ certPath: b.certPath?.trim(),
2314
+ keyPath: b.keyPath?.trim(),
2315
+ envFilePath: typeof b.envFilePath === "string" ? b.envFilePath.trim() : "",
2316
+ containerPortsMappings: mappings,
2317
+ dockerNetwork: b.dockerNetwork?.trim() || void 0
2318
+ };
2319
+ }
2320
+ function reqFe(v, field) {
2321
+ if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2322
+ console.error(`apm.config.json \u4E2D frontendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2323
+ process.exit(1);
2324
+ }
2325
+ return v;
2326
+ }
2327
+ function resolveFrontendDeployFromApmConfig(cfg) {
2328
+ const f = cfg.frontendDeploy ?? {};
2329
+ const port = Number(f.port);
2330
+ return {
2331
+ endpoint: reqFe(f.endpoint, "endpoint").trim(),
2332
+ port: Number.isFinite(port) && port > 0 ? port : 9e3,
2333
+ useSsl: Boolean(f.useSsl),
2334
+ accessKey: reqFe(f.accessKey, "accessKey").trim(),
2335
+ secretKey: reqFe(f.secretKey, "secretKey").trim(),
2336
+ bucket: reqFe(f.bucket, "bucket").trim()
2337
+ };
2338
+ }
2339
+ function reqWd(v, field) {
2340
+ if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2341
+ console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2342
+ process.exit(1);
2343
+ }
2344
+ return v;
2345
+ }
2346
+ function reqWisdomPositiveInt(v, field) {
2347
+ const n = Number(v);
2348
+ if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
2349
+ console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
2350
+ process.exit(1);
2351
+ }
2352
+ return n;
2353
+ }
2354
+ function resolveWisdomDeployFromApmConfig(cfg) {
2355
+ const w = cfg.wisdomDeploy ?? {};
2356
+ return {
2357
+ host: reqWd(w.host, "host").trim(),
2358
+ port: reqWisdomPositiveInt(w.port, "port"),
2359
+ username: reqWd(w.username, "username").trim(),
2360
+ password: reqWd(w.password, "password").trim(),
2361
+ remotePath: reqWd(w.remotePath, "remotePath").trim()
2362
+ };
2363
+ }
2364
+ function reqHc(v, field) {
2365
+ if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2366
+ console.error(`apm.config.json \u4E2D healthCheck.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2367
+ process.exit(1);
2368
+ }
2369
+ return v;
2370
+ }
2371
+ function reqWb(v, field) {
2372
+ if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2373
+ console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2374
+ process.exit(1);
2375
+ }
2376
+ return v;
2377
+ }
2378
+ function resolveWisdomBackendDeployFromApmConfig(cfg) {
2379
+ const projectName = reqTopLevelName(cfg);
2380
+ const w = cfg.wisdomDeploy ?? {};
2381
+ const h = cfg.healthCheck ?? {};
2382
+ const jarPath = reqWb(w.jarPath, "jarPath").trim();
2383
+ const remoteAppDir = posixDirname(jarPath);
2384
+ const healthPort = Number(reqHc(h.port, "port"));
2385
+ const healthTimeout = Number(reqHc(h.timeout, "timeout"));
2386
+ if (!Number.isFinite(healthPort) || !Number.isInteger(healthPort) || healthPort < 1) {
2387
+ console.error("apm.config.json \u4E2D healthCheck.port \u987B\u4E3A\u6B63\u6574\u6570");
2388
+ process.exit(1);
2389
+ }
2390
+ if (!Number.isFinite(healthTimeout) || !Number.isInteger(healthTimeout) || healthTimeout < 1) {
2391
+ console.error("apm.config.json \u4E2D healthCheck.timeout \u987B\u4E3A\u6B63\u6574\u6570");
2392
+ process.exit(1);
2393
+ }
2394
+ return {
2395
+ projectName,
2396
+ host: reqWd(w.host, "host").trim(),
2397
+ port: reqWisdomPositiveInt(w.port, "port"),
2398
+ username: reqWd(w.username, "username").trim(),
2399
+ password: reqWd(w.password, "password").trim(),
2400
+ remoteVueDistDir: reqWd(w.remotePath, "remotePath").trim(),
2401
+ remoteAppDir,
2402
+ remoteLibDir: `${remoteAppDir}/lib`,
2403
+ startupJar: posixBasename(jarPath),
2404
+ packageName: `${projectName}.jar.zip`,
2405
+ mavenLocalRepo: reqWb(w.mavenLocalRepo, "mavenLocalRepo").trim(),
2406
+ healthCheckPort: healthPort,
2407
+ healthCheckContext: reqHc(h.context, "context").trim(),
2408
+ healthCheckTimeout: healthTimeout
2409
+ };
2410
+ }
2411
+ function posixDirname(p) {
2412
+ const normalized = p.replace(/\\/g, "/");
2413
+ const idx = normalized.lastIndexOf("/");
2414
+ if (idx <= 0) {
2415
+ return normalized.startsWith("/") ? "/" : ".";
2416
+ }
2417
+ return normalized.slice(0, idx);
2418
+ }
2419
+ function posixBasename(p) {
2420
+ const normalized = p.replace(/\\/g, "/");
2421
+ const idx = normalized.lastIndexOf("/");
2422
+ return idx >= 0 ? normalized.slice(idx + 1) : normalized;
2423
+ }
2424
+
2425
+ // src/commands/deploy/internal/wisdom-backend-deploy.ts
2426
+ import {
2427
+ existsSync as existsSync12,
2428
+ mkdirSync as mkdirSync5,
2429
+ readdirSync as readdirSync5,
2430
+ readFileSync as readFileSync10,
2431
+ statSync as statSync5,
2432
+ writeFileSync as writeFileSync10
2433
+ } from "node:fs";
2434
+ import { spawnSync as spawnSync2 } from "node:child_process";
2435
+ import path2 from "node:path";
2436
+ import { Client } from "ssh2";
2437
+ import JSZip2 from "jszip";
2438
+ import SftpClient2 from "ssh2-sftp-client";
2439
+
2440
+ // src/commands/deploy/internal/wisdom-sftp.ts
2441
+ import { readdir, readFile, unlink, writeFile } from "node:fs/promises";
2442
+ import path from "node:path";
2443
+ import JSZip from "jszip";
2444
+ import SftpClient from "ssh2-sftp-client";
2445
+ async function addDirToZip(dir, zipFolder) {
2446
+ const entries = await readdir(dir, { withFileTypes: true });
2447
+ for (const entry of entries) {
2448
+ const fullPath = path.join(dir, entry.name);
2449
+ if (entry.isDirectory()) {
2450
+ const folder = zipFolder.folder(entry.name);
2451
+ if (folder) {
2452
+ await addDirToZip(fullPath, folder);
2453
+ }
2454
+ } else {
2455
+ const content = await readFile(fullPath);
2456
+ zipFolder.file(entry.name, content);
2457
+ }
2458
+ }
2459
+ }
2460
+ async function zipDirectory(distDir, zipPath) {
2461
+ console.error(`\u538B\u7F29\u76EE\u5F55: ${distDir}`);
2462
+ const zip = new JSZip();
2463
+ await addDirToZip(distDir, zip);
2464
+ const content = await zip.generateAsync({
2465
+ type: "nodebuffer",
2466
+ compression: "DEFLATE",
2467
+ compressionOptions: { level: 6 }
2468
+ });
2469
+ await writeFile(zipPath, content);
2470
+ const sizeMb = (content.length / 1024 / 1024).toFixed(2);
2471
+ console.error(`\u5DF2\u751F\u6210: ${zipPath} (${sizeMb} MB)`);
2472
+ return content.length;
2473
+ }
2474
+ async function ensureRemoteDir(sftp, dir) {
2475
+ const parts = dir.replace(/\\/g, "/").split("/").filter(Boolean);
2476
+ let current = dir.startsWith("/") ? "" : ".";
2477
+ for (const part of parts) {
2478
+ current = current ? `${current}/${part}` : `/${part}`;
2479
+ try {
2480
+ await sftp.mkdir(current, true);
2481
+ } catch {
2482
+ }
2483
+ }
2484
+ }
2485
+ function execCommand(client, command) {
2486
+ return new Promise((resolve5, reject) => {
2487
+ client.exec(command, (err, stream) => {
2488
+ if (err) return reject(err);
2489
+ let stdout = "";
2490
+ let stderr = "";
2491
+ stream.on("close", (code) => {
2492
+ if (code !== 0) {
2493
+ reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
2494
+ return;
2495
+ }
2496
+ resolve5(stdout);
2497
+ }).on("data", (data) => {
2498
+ stdout += data.toString();
2499
+ });
2500
+ stream.stderr.on("data", (data) => {
2501
+ stderr += data.toString();
2502
+ });
2503
+ });
2504
+ });
2505
+ }
2506
+ function shellSingleQuote(value) {
2507
+ return `'${value.replace(/'/g, `'"'"'`)}'`;
2508
+ }
2509
+ function buildClearRemoteDirExceptZipCommand(target) {
2510
+ const normalized = target.replace(/\\/g, "/").replace(/\/$/, "");
2511
+ const quotedTarget = shellSingleQuote(normalized);
2512
+ const script = [
2513
+ `T=${quotedTarget}`,
2514
+ "S=$(mktemp -d)",
2515
+ 'while IFS= read -r -d "" z; do r="${z#${T}/}"',
2516
+ 'mkdir -p "${S}/$(dirname "$r")"',
2517
+ 'mv "$z" "${S}/${r}"',
2518
+ 'done < <(find "$T" -mindepth 1 -type f -iname "*.zip" -print0)',
2519
+ 'rm -rf "${T}"/*',
2520
+ 'while IFS= read -r -d "" r; do r="${r#./}"',
2521
+ 'mkdir -p "${T}/$(dirname "$r")"',
2522
+ 'mv "${S}/${r}" "${T}/${r}"',
2523
+ 'done < <(cd "$S" 2>/dev/null && find . -type f -print0)',
2524
+ 'rm -rf "$S"'
2525
+ ].join("; ");
2526
+ return `bash -c ${shellSingleQuote(script)}`;
2527
+ }
2528
+ async function uploadAndMaybeExtract(settings, localZip, extract) {
2529
+ const remoteZipPath = `${settings.remotePath.replace(/\/$/, "")}/dist.zip`;
2530
+ console.error(
2531
+ `\u8FDE\u63A5 ${settings.username}@${settings.host}:${settings.port} ...`
2532
+ );
2533
+ const sftp = new SftpClient();
2534
+ try {
2535
+ await sftp.connect({
2536
+ host: settings.host,
2537
+ port: settings.port,
2538
+ username: settings.username,
2539
+ password: settings.password,
2540
+ readyTimeout: 2e4,
2541
+ tryKeyboard: true
2542
+ });
2543
+ await ensureRemoteDir(sftp, settings.remotePath);
2544
+ await sftp.put(localZip, remoteZipPath);
2545
+ console.error(` \u2713 ${localZip} -> ${remoteZipPath}`);
2546
+ if (extract) {
2547
+ const target = settings.remotePath.replace(/\/$/, "");
2548
+ const client = sftp.client;
2549
+ const clearCmd = buildClearRemoteDirExceptZipCommand(target);
2550
+ console.error(`\u8FDC\u7A0B\u6E05\u7406\u89E3\u538B\u76EE\u5F55: ${clearCmd}`);
2551
+ await execCommand(client, clearCmd);
2552
+ const unzipCmd = `unzip -o "${remoteZipPath}" -d "${target}"`;
2553
+ console.error(`\u8FDC\u7A0B\u89E3\u538B: ${unzipCmd}`);
2554
+ await execCommand(client, unzipCmd);
2555
+ console.error("\u8FDC\u7A0B\u89E3\u538B\u5B8C\u6210!");
2556
+ }
2557
+ console.error(extract ? "\u90E8\u7F72\u5B8C\u6210!" : "\u4E0A\u4F20\u5B8C\u6210!");
2558
+ } finally {
2559
+ await sftp.end();
2560
+ }
2561
+ }
2562
+ async function runWisdomSftpDeploy(params) {
2563
+ const zipPath = path.join(params.localDir, "..", ".deploy-sftp-dist.zip");
2564
+ const resolvedZipPath = path.resolve(zipPath);
2565
+ let zipSizeBytes = 0;
2566
+ try {
2567
+ zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
2568
+ await uploadAndMaybeExtract(
2569
+ params.settings,
2570
+ resolvedZipPath,
2571
+ params.extract
2572
+ );
2573
+ } finally {
2574
+ try {
2575
+ await unlink(resolvedZipPath);
2576
+ console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
2577
+ } catch {
2578
+ }
2579
+ }
2580
+ return {
2581
+ ok: true,
2582
+ localDir: params.localDir,
2583
+ host: params.settings.host,
2584
+ remotePath: params.settings.remotePath,
2585
+ zipSizeBytes,
2586
+ extracted: params.extract
2587
+ };
2588
+ }
2589
+
2590
+ // src/commands/deploy/internal/wisdom-backend-deploy.ts
2591
+ var SPRINGBOOT_SCRIPT = "springboot.sh";
2592
+ var MAVEN_MODULE = "jeecg-module-system/jeecg-system-start";
2593
+ var MAVEN_PROFILE = "dev";
2594
+ function log(message) {
2595
+ const now = /* @__PURE__ */ new Date();
2596
+ const hh = String(now.getHours()).padStart(2, "0");
2597
+ const mm = String(now.getMinutes()).padStart(2, "0");
2598
+ const ss = String(now.getSeconds()).padStart(2, "0");
2599
+ console.error(`[${hh}:${mm}:${ss}] ${message}`);
2600
+ }
2601
+ function fail(message) {
2602
+ log(`ERROR: ${message}`);
2603
+ process.exit(1);
2604
+ }
2605
+ function expandPath(pathStr) {
2606
+ return path2.resolve(pathStr.replace(/^~(?=\/|$)/, process.env.HOME ?? ""));
2607
+ }
2608
+ function deployCacheDir() {
2609
+ return path2.join(workspaceApmDir(), "deploy", ".deploy_cache");
2610
+ }
2611
+ function manifestFilePath() {
2612
+ return path2.join(deployCacheDir(), "manifest.json");
2613
+ }
2614
+ function getTargetDir(projectRoot) {
2615
+ return path2.join(projectRoot, MAVEN_MODULE, "target");
2616
+ }
2617
+ function relativeKey(projectRoot, filePath) {
2618
+ return path2.relative(projectRoot, filePath).split(path2.sep).join("/");
2619
+ }
2620
+ function fileSignature(filePath) {
2621
+ const stat2 = statSync5(filePath);
2622
+ return { size: stat2.size, mtime: stat2.mtimeMs / 1e3 };
2623
+ }
2624
+ function loadManifest3() {
2625
+ const manifestPath2 = manifestFilePath();
2626
+ if (!existsSync12(manifestPath2)) {
2627
+ return {};
2628
+ }
2629
+ return JSON.parse(readFileSync10(manifestPath2, "utf8"));
2630
+ }
2631
+ function saveManifest3(manifest) {
2632
+ const dir = deployCacheDir();
2633
+ mkdirSync5(dir, { recursive: true });
2634
+ writeFileSync10(manifestFilePath(), JSON.stringify(manifest, null, 2), "utf8");
2635
+ }
2636
+ function isProjectLibJar(jarName) {
2637
+ return jarName.startsWith("jeecg-");
2638
+ }
2639
+ function shouldUploadLibFile(localPath, remoteAttr, manifest, projectRoot) {
2640
+ if (!remoteAttr) {
2641
+ return [false, "\u8FDC\u7A0B\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7"];
2642
+ }
2643
+ const localSize = statSync5(localPath).size;
2644
+ const remoteSize = remoteAttr.size;
2645
+ if (localSize !== remoteSize) {
2646
+ return [true, `\u5927\u5C0F\u53D8\u5316 ${remoteSize} -> ${localSize}`];
2647
+ }
2648
+ if (isProjectLibJar(path2.basename(localPath)) && manifest) {
2649
+ const key = relativeKey(projectRoot, localPath);
2650
+ const current = fileSignature(localPath);
2651
+ const previous = manifest[key];
2652
+ if (!previous) {
2653
+ return [true, "\u9879\u76EE\u6A21\u5757\u672A\u8BB0\u5F55"];
2654
+ }
2655
+ if (previous.size !== current.size) {
2656
+ return [true, "\u9879\u76EE\u6A21\u5757\u5927\u5C0F\u53D8\u5316"];
2657
+ }
2658
+ if (previous.mtime < current.mtime) {
2659
+ return [true, "\u9879\u76EE\u6A21\u5757\u91CD\u65B0\u6784\u5EFA"];
2660
+ }
2661
+ }
2662
+ return [false, "\u5927\u5C0F\u4E00\u81F4\uFF0C\u8DF3\u8FC7"];
2663
+ }
2664
+ function listLibFilesToUpload(localLibDir, remoteStats, projectRoot, manifest = null) {
2665
+ const entries = [];
2666
+ const jarFiles = readdirSync5(localLibDir).filter((name) => name.endsWith(".jar")).sort();
2667
+ for (const jarName of jarFiles) {
2668
+ const jarPath = path2.join(localLibDir, jarName);
2669
+ const remoteAttr = remoteStats.get(jarName);
2670
+ const [shouldUpload, reason] = shouldUploadLibFile(
2671
+ jarPath,
2672
+ remoteAttr,
2673
+ manifest,
2674
+ projectRoot
2675
+ );
2676
+ if (shouldUpload) {
2677
+ entries.push({ path: jarPath, arcname: jarName, reason });
2678
+ }
2679
+ }
2680
+ return entries;
2681
+ }
2682
+ function updateManifestEntries(manifest, entries, projectRoot) {
2683
+ for (const entry of entries) {
2684
+ manifest[relativeKey(projectRoot, entry.path)] = fileSignature(entry.path);
2685
+ }
2686
+ return manifest;
2687
+ }
2688
+ async function createUpdatePackage(entries, packageName) {
2689
+ const dir = deployCacheDir();
2690
+ mkdirSync5(dir, { recursive: true });
2691
+ const zipPath = path2.join(dir, packageName);
2692
+ log(`\u521B\u5EFA\u66F4\u65B0\u5305: ${path2.basename(zipPath)}\uFF08${entries.length} \u4E2A\u6587\u4EF6\uFF09`);
2693
+ const zip = new JSZip2();
2694
+ for (const entry of entries) {
2695
+ const content = readFileSync10(entry.path);
2696
+ zip.file(entry.arcname, content);
2697
+ log(` \u6253\u5305: ${entry.arcname} (${entry.reason})`);
2698
+ }
2699
+ const buffer = await zip.generateAsync({
2700
+ type: "nodebuffer",
2701
+ compression: "DEFLATE",
2702
+ compressionOptions: { level: 6 }
2703
+ });
2704
+ writeFileSync10(zipPath, buffer);
2705
+ return zipPath;
2706
+ }
2707
+ function getMvnExecutable() {
2708
+ const isWin = process.platform === "win32";
2709
+ const candidates = isWin ? ["mvn.cmd", "mvn.bat", "mvn"] : ["mvn"];
2710
+ for (const name of candidates) {
2711
+ const result = spawnSync2(isWin ? "where" : "which", [name], {
2712
+ encoding: "utf8"
2713
+ });
2714
+ if (result.status === 0 && result.stdout.trim()) {
2715
+ return result.stdout.trim().split(/\r?\n/)[0];
2716
+ }
2717
+ }
2718
+ fail("\u672A\u627E\u5230 mvn \u547D\u4EE4\uFF0C\u8BF7\u786E\u8BA4 Maven \u5DF2\u5B89\u88C5\u5E76\u52A0\u5165 PATH");
2719
+ }
2720
+ function runMavenBuild(projectRoot, mavenLocalRepo) {
2721
+ const mavenRepo = expandPath(mavenLocalRepo);
2722
+ const cmd = [
2723
+ getMvnExecutable(),
2724
+ "clean",
2725
+ "package",
2726
+ `-P${MAVEN_PROFILE}`,
2727
+ `-Dmaven.repo.local=${mavenRepo}`,
2728
+ "-DskipTests"
2729
+ ];
2730
+ log(`\u5F00\u59CB Maven \u6784\u5EFA: ${cmd.join(" ")}`);
2731
+ log(`Maven \u672C\u5730\u4ED3\u5E93: ${mavenRepo}`);
2732
+ const result = spawnSync2(cmd[0], cmd.slice(1), {
2733
+ cwd: projectRoot,
2734
+ stdio: "inherit"
2735
+ });
2736
+ if (result.status !== 0) {
2737
+ fail(`Maven \u6784\u5EFA\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${result.status ?? 1}`);
2738
+ }
2739
+ }
2740
+ function locateLibDir(projectRoot) {
2741
+ const targetDir = getTargetDir(projectRoot);
2742
+ if (!existsSync12(targetDir)) {
2743
+ fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
2744
+ }
2745
+ const libDir = path2.join(targetDir, "lib");
2746
+ if (!existsSync12(libDir) || !statSync5(libDir).isDirectory()) {
2747
+ fail(`lib \u76EE\u5F55\u4E0D\u5B58\u5728: ${libDir}`);
2748
+ }
2749
+ const libJars = readdirSync5(libDir).filter((name) => name.endsWith(".jar"));
2750
+ if (libJars.length === 0) {
2751
+ fail(`lib \u76EE\u5F55\u4E0B\u6CA1\u6709\u4F9D\u8D56 JAR: ${libDir}`);
2752
+ }
2753
+ log(`\u5B9A\u4F4D lib \u4EA7\u7269: ${libJars.length} \u4E2A`);
2754
+ return libDir;
2755
+ }
2756
+ async function connectSsh(config) {
2757
+ const client = new Client();
2758
+ log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
2759
+ await new Promise((resolve5, reject) => {
2760
+ client.on("ready", () => resolve5()).on("error", (err) => reject(err)).connect({
2761
+ host: config.host,
2762
+ port: config.port,
2763
+ username: config.username,
2764
+ password: config.password,
2765
+ readyTimeout: 3e4,
2766
+ tryKeyboard: true
2767
+ });
2768
+ });
2769
+ const sftp = new SftpClient2();
2770
+ await sftp.connect({
2771
+ host: config.host,
2772
+ port: config.port,
2773
+ username: config.username,
2774
+ password: config.password,
2775
+ readyTimeout: 3e4,
2776
+ tryKeyboard: true
2777
+ });
2778
+ return { client, sftp };
2779
+ }
2780
+ async function closeSsh(conn) {
2781
+ try {
2782
+ await conn.sftp.end();
2783
+ } catch {
2784
+ }
2785
+ conn.client.end();
2786
+ }
2787
+ async function getRemoteFileStats(sftp, remoteDir) {
2788
+ const stats = /* @__PURE__ */ new Map();
2789
+ try {
2790
+ const listing = await sftp.list(remoteDir);
2791
+ for (const item of listing) {
2792
+ if (item.name.endsWith(".jar")) {
2793
+ stats.set(item.name, { filename: item.name, size: item.size });
2794
+ }
2795
+ }
2796
+ } catch {
2797
+ }
2798
+ return stats;
2799
+ }
2800
+ async function uploadUpdatePackage(sftp, zipPath, config) {
2801
+ const remoteDir = config.remoteVueDistDir.replace(/\/$/, "");
2802
+ const remotePath = `${remoteDir}/${path2.basename(zipPath)}`;
2803
+ log(`\u4E0A\u4F20\u66F4\u65B0\u5305 -> ${remotePath}`);
2804
+ try {
2805
+ await sftp.fastPut(zipPath, remotePath);
2806
+ log("\u66F4\u65B0\u5305\u4E0A\u4F20\u6210\u529F");
2807
+ } catch (err) {
2808
+ fail(`\u66F4\u65B0\u5305\u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
2809
+ }
2810
+ return remotePath;
2811
+ }
2812
+ async function runRemoteCommand(client, command, options) {
2813
+ const check = options?.check ?? true;
2814
+ const stream = options?.stream ?? false;
2815
+ log(`\u8FDC\u7A0B\u6267\u884C: ${command}`);
2816
+ return new Promise((resolve5, reject) => {
2817
+ client.exec(command, (err, execStream) => {
2818
+ if (err) {
2819
+ reject(err);
2820
+ return;
2821
+ }
2822
+ let out = "";
2823
+ let errText = "";
2824
+ execStream.on("data", (data) => {
2825
+ const text = data.toString();
2826
+ out += text;
2827
+ if (stream) {
2828
+ process.stdout.write(text);
2829
+ }
2830
+ });
2831
+ execStream.stderr.on("data", (data) => {
2832
+ errText += data.toString();
2833
+ });
2834
+ execStream.on("close", (code) => {
2835
+ if (!stream) {
2836
+ if (out) {
2837
+ console.log(out.trimEnd());
2838
+ }
2839
+ if (errText) {
2840
+ console.error(errText.trimEnd());
2841
+ }
2842
+ } else if (out && !out.endsWith("\n")) {
2843
+ process.stdout.write("\n");
2844
+ }
2845
+ if (check && code !== 0) {
2846
+ fail(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (exit ${code}): ${command}`);
2847
+ }
2848
+ resolve5({ exitCode: code, out: out.trim(), err: errText.trim() });
2849
+ });
2850
+ });
2851
+ });
2852
+ }
2853
+ function buildExtractUpdatePackageScript(remoteZipPath, remoteLibDir) {
2854
+ const quotedZip = shellSingleQuote(remoteZipPath);
2855
+ const quotedLib = shellSingleQuote(remoteLibDir);
2856
+ return `
2857
+ set -e
2858
+ TMP=$(mktemp -d)
2859
+ trap 'rm -rf "$TMP"' EXIT
2860
+ unzip -oq ${quotedZip} -d "$TMP"
2861
+ updated=0
2862
+ while IFS= read -r -d '' src; do
2863
+ name=$(basename "$src")
2864
+ dest=${quotedLib}/"$name"
2865
+ if [ -f "$dest" ]; then
2866
+ cp -f "$src" "$dest"
2867
+ echo "\u8986\u76D6: $name"
2868
+ updated=$((updated + 1))
2869
+ else
2870
+ echo "\u8DF3\u8FC7(\u8FDC\u7A0B\u4E0D\u5B58\u5728): $name"
2871
+ fi
2872
+ done < <(find "$TMP" -name '*.jar' -type f -print0)
2873
+ echo "UPDATED_COUNT=$updated"
2874
+ `.trim();
2875
+ }
2876
+ async function extractUpdatePackageOnRemote(client, config, remoteZipPath) {
2877
+ const script = buildExtractUpdatePackageScript(
2878
+ remoteZipPath,
2879
+ config.remoteLibDir
2880
+ );
2881
+ const { out } = await runRemoteCommand(client, script);
2882
+ const match = out.match(/UPDATED_COUNT=(\d+)/);
2883
+ if (!match) {
2884
+ fail(`\u8FDC\u7A0B\u89E3\u538B\u5931\u8D25\uFF0C\u672A\u83B7\u53D6\u66F4\u65B0\u6570\u91CF
2885
+ \u8F93\u51FA: ${out || "(\u7A7A)"}`);
2886
+ }
2887
+ const updated = Number.parseInt(match[1], 10);
2888
+ log(`lib \u89E3\u538B\u5B8C\u6210: \u8986\u76D6 ${updated} \u4E2A`);
2889
+ return updated;
2890
+ }
2891
+ function springbootOutputIndicatesSuccess(action, combined) {
2892
+ const lower = combined.toLowerCase();
2893
+ if (action === "health") {
2894
+ return combined.includes("\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7");
2895
+ }
2896
+ if (action === "start" || action === "restart") {
2897
+ return combined.includes("is starting") || lower.includes("is running");
2898
+ }
2899
+ if (action === "stop") {
2900
+ return combined.includes("is stopping") || lower.includes("not running") || lower.includes("please check it");
2901
+ }
2902
+ if (action === "status") {
2903
+ return lower.includes("running") || lower.includes("not running");
2904
+ }
2905
+ return true;
2906
+ }
2907
+ async function runSpringbootAction(client, config, action, ...args) {
2908
+ if (action === "start" || action === "restart") {
2909
+ if (args.length === 0) {
2910
+ fail(`\u8FDC\u7A0B ${action} \u7F3A\u5C11 jar \u53C2\u6570`);
2911
+ }
2912
+ const jar = args[0].trim().split(/\r?\n/)[0].trim();
2913
+ if (!jar) {
2914
+ fail(`\u65E0\u6548\u7684 jar \u540D\u79F0: ${JSON.stringify(args[0])}`);
2915
+ }
2916
+ }
2917
+ const quotedArgs = [action, ...args].map((arg) => shellSingleQuote(arg));
2918
+ const command = [
2919
+ `cd ${shellSingleQuote(config.remoteAppDir)}`,
2920
+ `./${SPRINGBOOT_SCRIPT} ${quotedArgs.join(" ")}`
2921
+ ].join(" && ");
2922
+ const { exitCode, out, err } = await runRemoteCommand(client, command, {
2923
+ check: false
2924
+ });
2925
+ const combined = `${out}
2926
+ ${err}`.trim();
2927
+ const outputOk = springbootOutputIndicatesSuccess(action, combined);
2928
+ if (action === "health") {
2929
+ if (exitCode !== 0 || !outputOk) {
2930
+ fail(`\u5065\u5EB7\u68C0\u67E5\u5931\u8D25
2931
+ \u547D\u4EE4: ${command}
2932
+ \u8F93\u51FA: ${combined || "(\u7A7A)"}`);
2933
+ }
2934
+ return combined;
2935
+ }
2936
+ if (exitCode !== 0 && !outputOk) {
2937
+ fail(`\u8FDC\u7A0B ${action} \u5931\u8D25: ${args.join(" ")}
2938
+ ${combined}`);
2939
+ }
2940
+ if ((action === "start" || action === "restart") && !outputOk) {
2941
+ fail(
2942
+ `\u8FDC\u7A0B ${action} \u672A\u6210\u529F: ${args.join(" ")}
2943
+ \u547D\u4EE4: ${command}
2944
+ \u8F93\u51FA: ${combined || "(\u7A7A)"}`
2945
+ );
2946
+ }
2947
+ return combined;
2948
+ }
2949
+ function stripAnsi(text) {
2950
+ return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
2951
+ }
2952
+ async function getRunningJar(client, config) {
2953
+ const combined = await runSpringbootAction(
2954
+ client,
2955
+ config,
2956
+ "status",
2957
+ config.startupJar
2958
+ );
2959
+ const text = stripAnsi(combined).trim().toLowerCase();
2960
+ if (text.includes("not running")) {
2961
+ return null;
2962
+ }
2963
+ if (text.includes("running")) {
2964
+ return config.startupJar;
2965
+ }
2966
+ return null;
2967
+ }
2968
+ async function healthCheckService(client, config) {
2969
+ const port = String(config.healthCheckPort);
2970
+ const context = config.healthCheckContext;
2971
+ const timeout = String(config.healthCheckTimeout);
2972
+ log(`\u5065\u5EB7\u68C0\u67E5: springboot.sh health ${port} ${context} ${timeout}`);
2973
+ await runSpringbootAction(client, config, "health", port, context, timeout);
2974
+ }
2975
+ async function runWisdomBackendDeploy(options) {
2976
+ const projectRoot = path2.resolve(options.projectRoot ?? process.cwd());
2977
+ const config = options.config;
2978
+ log(`=== \u81EA\u52A8\u90E8\u7F72: ${config.projectName} ===`);
2979
+ log(`\u914D\u7F6E\u6587\u4EF6: ${path2.join(workspaceApmDir(), "apm.config.json")}`);
2980
+ log(`\u9879\u76EE\u6839\u76EE\u5F55: ${projectRoot}`);
2981
+ if (!options.skipMaven) {
2982
+ runMavenBuild(projectRoot, config.mavenLocalRepo);
2983
+ }
2984
+ const libDir = locateLibDir(projectRoot);
2985
+ let manifest = loadManifest3();
2986
+ const conn = await connectSsh(config);
2987
+ try {
2988
+ const remoteLibStats = await getRemoteFileStats(
2989
+ conn.sftp,
2990
+ config.remoteLibDir
2991
+ );
2992
+ log("\u6536\u96C6 JAR \u66F4\u65B0...");
2993
+ const libUploadEntries = listLibFilesToUpload(
2994
+ libDir,
2995
+ remoteLibStats,
2996
+ projectRoot,
2997
+ manifest
2998
+ );
2999
+ let updated = 0;
3000
+ if (libUploadEntries.length > 0) {
3001
+ const zipPath = await createUpdatePackage(
3002
+ libUploadEntries,
3003
+ config.packageName
3004
+ );
3005
+ const remoteZipPath = await uploadUpdatePackage(
3006
+ conn.sftp,
3007
+ zipPath,
3008
+ config
3009
+ );
3010
+ log("\u8FDC\u7A0B\u89E3\u538B lib \u76EE\u5F55\uFF08\u4EC5\u8986\u76D6\u5DF2\u6709 JAR\uFF09...");
3011
+ updated = await extractUpdatePackageOnRemote(
3012
+ conn.client,
3013
+ config,
3014
+ remoteZipPath
3015
+ );
3016
+ } else {
3017
+ log("\u65E0 JAR \u9700\u8981\u66F4\u65B0\uFF0C\u8DF3\u8FC7\u66F4\u65B0\u5305\u4E0A\u4F20");
3018
+ }
3019
+ const runningJar = await getRunningJar(conn.client, config);
3020
+ let needRestart = updated > 0;
3021
+ if (!needRestart && !runningJar) {
3022
+ log("\u670D\u52A1\u672A\u8FD0\u884C\uFF0C\u9700\u8981\u542F\u52A8");
3023
+ needRestart = true;
3024
+ } else if (!needRestart) {
3025
+ log("\u6CA1\u6709\u6587\u4EF6\u9700\u8981\u66F4\u65B0\uFF0C\u8DF3\u8FC7\u91CD\u542F");
3026
+ }
3027
+ if (needRestart) {
3028
+ log("\u91CD\u542F\u670D\u52A1...");
3029
+ await runSpringbootAction(
3030
+ conn.client,
3031
+ config,
3032
+ "restart",
3033
+ config.startupJar
3034
+ );
3035
+ }
3036
+ await healthCheckService(conn.client, config);
3037
+ if (libUploadEntries.length > 0) {
3038
+ manifest = updateManifestEntries(manifest, libUploadEntries, projectRoot);
3039
+ saveManifest3(manifest);
3040
+ }
3041
+ } finally {
3042
+ await closeSsh(conn);
3043
+ }
3044
+ log("\u90E8\u7F72\u5B8C\u6210");
3045
+ }
3046
+
3047
+ // src/commands/deploy/internal/wisdom-auto-deploy.ts
3048
+ function isWisdomLegacyDeploy(cfg) {
3049
+ const w = cfg.wisdomDeploy;
3050
+ if (!w?.host?.trim() || !w.remotePath?.trim()) {
3051
+ return false;
3052
+ }
3053
+ const hasNewFrontend = Boolean(cfg.frontendDeploy?.endpoint?.trim());
3054
+ const hasNewBackend = Boolean(cfg.backendDeploy?.registryHost?.trim());
3055
+ return !hasNewFrontend && !hasNewBackend;
3056
+ }
3057
+ function detectWisdomProjectType(cwd) {
3058
+ return existsSync13(path3.join(cwd, "package.json")) ? "frontend" : "backend";
3059
+ }
3060
+ function readPackageScripts(cwd) {
3061
+ const pkgPath = path3.join(cwd, "package.json");
3062
+ if (!existsSync13(pkgPath)) {
3063
+ return {};
3064
+ }
3065
+ try {
3066
+ const raw = readFileSync11(pkgPath, "utf8");
3067
+ const parsed = JSON.parse(raw);
3068
+ return parsed.scripts ?? {};
3069
+ } catch {
3070
+ return {};
3071
+ }
3072
+ }
3073
+ function resolveFrontendDeployCommand(env, cwd) {
3074
+ const scripts = readPackageScripts(cwd);
3075
+ const deployKey = `deploy:${env}`;
3076
+ if (scripts[deployKey]?.trim()) {
3077
+ return `npm run deploy:${env}`;
3078
+ }
3079
+ return null;
3080
+ }
3081
+ function runShellCommand(command, cwd) {
3082
+ console.error(`==> ${command}`);
3083
+ const result = spawnSync3(command, {
3084
+ cwd,
3085
+ stdio: "inherit",
3086
+ shell: true,
3087
+ env: process.env
3088
+ });
3089
+ if (result.status !== 0) {
3090
+ process.exit(result.status ?? 1);
3091
+ }
3092
+ }
3093
+ async function runWisdomAutoDeploy(options) {
3094
+ const cwd = path3.resolve(options.cwd ?? process.cwd());
3095
+ const projectType = detectWisdomProjectType(cwd);
3096
+ console.error(
3097
+ `[apm] \u533B\u52A1\u5B58\u91CF\u9879\u76EE\u81EA\u52A8\u8BC6\u522B: ${projectType === "frontend" ? "\u524D\u7AEF Vue" : "\u540E\u7AEF Java"}`
3098
+ );
3099
+ if (projectType === "frontend") {
3100
+ const deployCmd = resolveFrontendDeployCommand(options.env, cwd);
3101
+ if (!deployCmd) {
3102
+ console.error(
3103
+ `\u524D\u7AEF\u9879\u76EE ${path3.join(cwd, "package.json")} \u4E2D\u672A\u627E\u5230 deploy:${options.env} \u811A\u672C`
3104
+ );
3105
+ process.exit(1);
3106
+ }
3107
+ runShellCommand(deployCmd, cwd);
3108
+ return { projectType };
3109
+ }
3110
+ const configPath = options.configPath ?? path3.join(workspaceApmDir(cwd), "apm.config.json");
3111
+ const cfg = loadApmConfig({ configPath });
3112
+ const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
3113
+ await runWisdomBackendDeploy({
3114
+ config: settings,
3115
+ projectRoot: cwd,
3116
+ skipMaven: Boolean(options.skipMaven)
3117
+ });
3118
+ return { projectType };
3119
+ }
3120
+
3121
+ // src/commands/connect/deploy-run.ts
2231
3122
  var DEPLOY_LOG_SYNC_INTERVAL_MS = 3e4;
2232
- function readDeployConfig(workdir) {
3123
+ function readApmConfig(workdir) {
2233
3124
  const configPath = join13(workspaceApmDir(workdir), "apm.config.json");
3125
+ if (!existsSync14(configPath)) {
3126
+ return void 0;
3127
+ }
2234
3128
  try {
2235
- const raw = readFileSync9(configPath, "utf8");
2236
- const parsed = JSON.parse(raw);
2237
- return parsed.deploy;
3129
+ const raw = readFileSync12(configPath, "utf8");
3130
+ return JSON.parse(raw);
2238
3131
  } catch {
2239
3132
  return void 0;
2240
3133
  }
2241
3134
  }
3135
+ function readDeployConfig(workdir) {
3136
+ return readApmConfig(workdir)?.deploy;
3137
+ }
2242
3138
  function resolveDeployCommand(workdir, environment) {
2243
3139
  const command = readDeployConfig(workdir)?.[environment];
2244
3140
  if (typeof command === "string" && command.trim()) {
@@ -2252,7 +3148,7 @@ function missingDeployCommandMessage(environment) {
2252
3148
  function buildDeployLog(stdout, stderr) {
2253
3149
  return [stdout, stderr].filter(Boolean).join("\n");
2254
3150
  }
2255
- function runShellCommand(command, cwd, signal, onOutput) {
3151
+ function runShellCommand2(command, cwd, signal, onOutput) {
2256
3152
  return new Promise((resolve5, reject) => {
2257
3153
  const child = spawn(command, {
2258
3154
  cwd,
@@ -2287,15 +3183,15 @@ function runShellCommand(command, cwd, signal, onOutput) {
2287
3183
  });
2288
3184
  child.on("close", (code) => {
2289
3185
  signal.removeEventListener("abort", onAbort);
2290
- const log = buildDeployLog(stdout, stderr);
3186
+ const log2 = buildDeployLog(stdout, stderr);
2291
3187
  if (code === 0) {
2292
- resolve5({ log });
3188
+ resolve5({ log: log2 });
2293
3189
  return;
2294
3190
  }
2295
3191
  const error = new Error(
2296
3192
  `\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${code ?? "unknown"}: ${command}`
2297
3193
  );
2298
- error.log = log;
3194
+ error.log = log2;
2299
3195
  reject(error);
2300
3196
  });
2301
3197
  });
@@ -2322,8 +3218,8 @@ function createDeployLogSyncer(api, deploymentRunId) {
2322
3218
  });
2323
3219
  }, DEPLOY_LOG_SYNC_INTERVAL_MS);
2324
3220
  return {
2325
- updateLog(log) {
2326
- latestLog = log;
3221
+ updateLog(log2) {
3222
+ latestLog = log2;
2327
3223
  },
2328
3224
  async flush() {
2329
3225
  clearInterval(timer);
@@ -2343,6 +3239,39 @@ async function handleInboundDeploy(cfg, msg, signal) {
2343
3239
  status: "DEPLOYING"
2344
3240
  });
2345
3241
  const workdir = requireRemoteWorkdir(msg.workdir);
3242
+ const apmConfig = readApmConfig(workdir);
3243
+ if (apmConfig && isWisdomLegacyDeploy(apmConfig)) {
3244
+ console.log(
3245
+ `[apm] deploy start id=${deploymentRunId} env=${msg.environment} cwd=${workdir} (wisdom auto)`
3246
+ );
3247
+ const logSyncer2 = createDeployLogSyncer(api, deploymentRunId);
3248
+ try {
3249
+ await runWisdomAutoDeploy({
3250
+ env: msg.environment,
3251
+ cwd: workdir
3252
+ });
3253
+ await logSyncer2.flush();
3254
+ await api.cli.completeTaskDeployment({
3255
+ id: deploymentRunId,
3256
+ status: "SUCCESS",
3257
+ log: "\u533B\u52A1\u5B58\u91CF\u9879\u76EE\u81EA\u52A8\u90E8\u7F72\u5B8C\u6210"
3258
+ });
3259
+ console.log(`[apm] deploy success id=${deploymentRunId}`);
3260
+ } catch (error) {
3261
+ const detail = error instanceof Error ? error.message : String(error);
3262
+ await logSyncer2.flush();
3263
+ await api.cli.completeTaskDeployment({
3264
+ id: deploymentRunId,
3265
+ status: "FAILED",
3266
+ log: detail,
3267
+ error: detail
3268
+ });
3269
+ console.error(`[apm] deploy failed id=${deploymentRunId}: ${detail}`);
3270
+ } finally {
3271
+ logSyncer2.dispose();
3272
+ }
3273
+ return;
3274
+ }
2346
3275
  const command = resolveDeployCommand(workdir, msg.environment);
2347
3276
  if (!command) {
2348
3277
  const error = missingDeployCommandMessage(msg.environment);
@@ -2362,28 +3291,28 @@ async function handleInboundDeploy(cfg, msg, signal) {
2362
3291
  const logSyncer = createDeployLogSyncer(api, deploymentRunId);
2363
3292
  let latestLog = "";
2364
3293
  try {
2365
- const { log } = await runShellCommand(command, workdir, signal, (log2) => {
2366
- latestLog = log2;
2367
- logSyncer.updateLog(log2);
3294
+ const { log: log2 } = await runShellCommand2(command, workdir, signal, (log3) => {
3295
+ latestLog = log3;
3296
+ logSyncer.updateLog(log3);
2368
3297
  });
2369
- latestLog = log;
2370
- logSyncer.updateLog(log);
3298
+ latestLog = log2;
3299
+ logSyncer.updateLog(log2);
2371
3300
  await logSyncer.flush();
2372
3301
  await api.cli.completeTaskDeployment({
2373
3302
  id: deploymentRunId,
2374
3303
  status: "SUCCESS",
2375
- log
3304
+ log: log2
2376
3305
  });
2377
3306
  console.log(`[apm] deploy success id=${deploymentRunId}`);
2378
3307
  } catch (error) {
2379
3308
  const detail = error instanceof Error ? error.message : String(error);
2380
- const log = error && typeof error === "object" && "log" in error ? String(error.log ?? latestLog) : latestLog;
2381
- logSyncer.updateLog(log);
3309
+ const log2 = error && typeof error === "object" && "log" in error ? String(error.log ?? latestLog) : latestLog;
3310
+ logSyncer.updateLog(log2);
2382
3311
  await logSyncer.flush();
2383
3312
  await api.cli.completeTaskDeployment({
2384
3313
  id: deploymentRunId,
2385
3314
  status: "FAILED",
2386
- log,
3315
+ log: log2,
2387
3316
  error: detail
2388
3317
  });
2389
3318
  console.error(`[apm] deploy failed id=${deploymentRunId}: ${detail}`);
@@ -2659,17 +3588,17 @@ ${JSON.stringify(event, null, 2)}
2659
3588
  }
2660
3589
 
2661
3590
  // src/commands/connect/agent-session-registry.ts
2662
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync10 } from "node:fs";
2663
- import { dirname as dirname4, resolve as resolve3 } from "node:path";
3591
+ import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync11 } from "node:fs";
3592
+ import { dirname as dirname4, resolve as resolve4 } from "node:path";
2664
3593
  function registryPath(workdir, sessionId) {
2665
- return resolve3(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
3594
+ return resolve4(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
2666
3595
  }
2667
- function readRegistry(path10) {
2668
- if (!existsSync11(path10)) {
3596
+ function readRegistry(path12) {
3597
+ if (!existsSync15(path12)) {
2669
3598
  return {};
2670
3599
  }
2671
3600
  try {
2672
- const parsed = JSON.parse(readFileSync10(path10, "utf8"));
3601
+ const parsed = JSON.parse(readFileSync13(path12, "utf8"));
2673
3602
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
2674
3603
  const result = {};
2675
3604
  for (const [key, value] of Object.entries(
@@ -2685,9 +3614,9 @@ function readRegistry(path10) {
2685
3614
  }
2686
3615
  return {};
2687
3616
  }
2688
- function writeRegistry(path10, registry) {
2689
- mkdirSync5(dirname4(path10), { recursive: true });
2690
- writeFileSync10(path10, `${JSON.stringify(registry, null, 2)}
3617
+ function writeRegistry(path12, registry) {
3618
+ mkdirSync6(dirname4(path12), { recursive: true });
3619
+ writeFileSync11(path12, `${JSON.stringify(registry, null, 2)}
2691
3620
  `, "utf8");
2692
3621
  }
2693
3622
  function loadSessionAgentId(workdir, sessionId, user) {
@@ -2695,19 +3624,19 @@ function loadSessionAgentId(workdir, sessionId, user) {
2695
3624
  return registry[user];
2696
3625
  }
2697
3626
  function saveSessionAgentId(workdir, sessionId, user, agentId) {
2698
- const path10 = registryPath(workdir, sessionId);
2699
- const registry = readRegistry(path10);
3627
+ const path12 = registryPath(workdir, sessionId);
3628
+ const registry = readRegistry(path12);
2700
3629
  registry[user] = agentId;
2701
- writeRegistry(path10, registry);
3630
+ writeRegistry(path12, registry);
2702
3631
  }
2703
3632
  function clearSessionAgentId(workdir, sessionId, user) {
2704
- const path10 = registryPath(workdir, sessionId);
2705
- const registry = readRegistry(path10);
3633
+ const path12 = registryPath(workdir, sessionId);
3634
+ const registry = readRegistry(path12);
2706
3635
  if (!(user in registry)) {
2707
3636
  return;
2708
3637
  }
2709
3638
  delete registry[user];
2710
- writeRegistry(path10, registry);
3639
+ writeRegistry(path12, registry);
2711
3640
  }
2712
3641
 
2713
3642
  // src/commands/connect/cursor-message-log.ts
@@ -3101,20 +4030,20 @@ async function runCursorAgent(cfg, ctx, options) {
3101
4030
  }
3102
4031
 
3103
4032
  // src/commands/connect/cli-version-sync.ts
3104
- import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync11 } from "fs";
4033
+ import { existsSync as existsSync16, readFileSync as readFileSync14, writeFileSync as writeFileSync12 } from "fs";
3105
4034
  import { join as join14 } from "path";
3106
4035
  var CLI_VERSION_FILE = ".cli-version.json";
3107
4036
  function manifestPath(apmDir) {
3108
4037
  return join14(apmDir, CLI_VERSION_FILE);
3109
4038
  }
3110
- function loadManifest3(apmDir) {
3111
- const path10 = toFsPath(manifestPath(apmDir));
3112
- if (!existsSync12(path10)) {
4039
+ function loadManifest4(apmDir) {
4040
+ const path12 = toFsPath(manifestPath(apmDir));
4041
+ if (!existsSync16(path12)) {
3113
4042
  return null;
3114
4043
  }
3115
4044
  try {
3116
4045
  const parsed = JSON.parse(
3117
- readFileSync11(path10, "utf8")
4046
+ readFileSync14(path12, "utf8")
3118
4047
  );
3119
4048
  if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
3120
4049
  return parsed;
@@ -3123,9 +4052,9 @@ function loadManifest3(apmDir) {
3123
4052
  }
3124
4053
  return null;
3125
4054
  }
3126
- function saveManifest3(apmDir, cliVersion) {
4055
+ function saveManifest4(apmDir, cliVersion) {
3127
4056
  const manifest = { version: 1, cliVersion };
3128
- writeFileSync11(
4057
+ writeFileSync12(
3129
4058
  toFsPath(manifestPath(apmDir)),
3130
4059
  `${JSON.stringify(manifest, null, 2)}
3131
4060
  `,
@@ -3138,7 +4067,7 @@ function shouldSyncSkillsForCliVersion(workdir, currentVersion) {
3138
4067
  if (cached === currentVersion) {
3139
4068
  return false;
3140
4069
  }
3141
- const stored = loadManifest3(workspaceApmDir(workdir));
4070
+ const stored = loadManifest4(workspaceApmDir(workdir));
3142
4071
  if (stored?.cliVersion === currentVersion) {
3143
4072
  syncedInSession.set(workdir, currentVersion);
3144
4073
  return false;
@@ -3146,7 +4075,7 @@ function shouldSyncSkillsForCliVersion(workdir, currentVersion) {
3146
4075
  return true;
3147
4076
  }
3148
4077
  function markSkillsSyncedForCliVersion(workdir, cliVersion) {
3149
- saveManifest3(workspaceApmDir(workdir), cliVersion);
4078
+ saveManifest4(workspaceApmDir(workdir), cliVersion);
3150
4079
  syncedInSession.set(workdir, cliVersion);
3151
4080
  }
3152
4081
 
@@ -3373,7 +4302,7 @@ function reexecConnect(options) {
3373
4302
  if (server) {
3374
4303
  args.push("--server", server);
3375
4304
  }
3376
- const result = spawnSync2(process.execPath, args, { stdio: "inherit" });
4305
+ const result = spawnSync4(process.execPath, args, { stdio: "inherit" });
3377
4306
  if (result.error) {
3378
4307
  console.error("[apm] \u91CD\u542F connect \u5931\u8D25:", result.error.message);
3379
4308
  process.exit(1);
@@ -3509,202 +4438,123 @@ async function runConnect(options) {
3509
4438
  activeTasks.delete(task);
3510
4439
  });
3511
4440
  });
3512
- ws.on("close", (code, reason) => {
3513
- console.log(
3514
- `[apm] \u8FDE\u63A5\u5DF2\u65AD\u5F00 code=${code}${reason ? ` reason=${reason.toString()}` : ""}`
3515
- );
3516
- void shutdown();
3517
- });
3518
- ws.on("error", (err) => {
3519
- console.error("[apm] WebSocket \u9519\u8BEF:", err.message);
3520
- reject(err);
3521
- });
3522
- process.on("SIGINT", () => {
3523
- console.log("[apm] \u6B63\u5728\u5173\u95ED\u2026");
3524
- void shutdown();
3525
- });
3526
- process.on("SIGTERM", () => {
3527
- void shutdown();
3528
- });
3529
- });
3530
- }
3531
-
3532
- // src/commands/create-pr.ts
3533
- async function runCreatePr(options) {
3534
- const sessionId = options.sessionId.trim();
3535
- if (!sessionId) {
3536
- console.error("[apm] sessionId \u4E0D\u80FD\u4E3A\u7A7A");
3537
- process.exit(1);
3538
- }
3539
- const title = options.title.trim();
3540
- if (!title) {
3541
- console.error("[apm] \u8BF7\u901A\u8FC7 --title \u6307\u5B9A PR \u6807\u9898");
3542
- process.exit(1);
3543
- }
3544
- const cfg = await ensureLoggedConfig();
3545
- const api = createApmApiClient(cfg);
3546
- const workdir = resolveWorkdirPath(options.cwd ?? process.cwd());
3547
- const pr = await api.cli.createPullRequest({
3548
- sessionId,
3549
- workdir,
3550
- title,
3551
- content: options.content ?? ""
3552
- });
3553
- console.log(`[apm] PR \u5DF2\u5C31\u7EEA #${pr.number} (${pr.state}): ${pr.url}`);
3554
- }
3555
-
3556
- // src/commands/deploy/backend.ts
3557
- import path5 from "node:path";
3558
-
3559
- // src/commands/deploy/internal/apm-config.ts
3560
- import { existsSync as existsSync13, readFileSync as readFileSync12 } from "node:fs";
3561
- import { resolve as resolve4 } from "node:path";
3562
- function loadApmConfig(options) {
3563
- const p = resolve4(
3564
- process.cwd(),
3565
- options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
3566
- );
3567
- if (!existsSync13(p)) {
3568
- console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
3569
- process.exit(1);
3570
- }
3571
- try {
3572
- const raw = readFileSync12(p, "utf8");
3573
- return JSON.parse(raw);
3574
- } catch (e) {
3575
- console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
3576
- process.exit(1);
3577
- }
3578
- }
3579
- function req(v, field) {
3580
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
3581
- console.error(`apm.config.json \u4E2D backendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
3582
- process.exit(1);
3583
- }
3584
- return v;
3585
- }
3586
- function reqTopLevelName(cfg) {
3587
- const n = (cfg.name ?? "").trim();
3588
- if (!n) {
3589
- console.error(
3590
- "\u8BF7\u5728 apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4E0E\u524D\u7AEF\u5236\u54C1\u524D\u7F00\u3001\u540E\u7AEF\u955C\u50CF\u540D\u5171\u7528\uFF09"
3591
- );
3592
- process.exit(1);
3593
- }
3594
- return n;
3595
- }
3596
- function reqBackendPositiveInt(v, field) {
3597
- const n = Number(v);
3598
- if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
3599
- console.error(`apm.config.json \u4E2D backendDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
3600
- process.exit(1);
3601
- }
3602
- return n;
3603
- }
3604
- function resolveBackendDeployFromApmConfig(cfg) {
3605
- const b = cfg.backendDeploy ?? {};
3606
- const protoRaw = req(b.remoteProtocol, "remoteProtocol").trim().toLowerCase();
3607
- if (protoRaw !== "http" && protoRaw !== "https") {
3608
- console.error(
3609
- "apm.config.json \u4E2D backendDeploy.remoteProtocol \u53EA\u80FD\u4E3A http \u6216 https"
3610
- );
3611
- process.exit(1);
3612
- }
3613
- const remoteProtocol = protoRaw;
3614
- let mappings = [];
3615
- const rawPorts = b.containerPortsMappings;
3616
- if (rawPorts !== void 0 && rawPorts !== null) {
3617
- if (!Array.isArray(rawPorts)) {
3618
- console.error(
3619
- "apm.config.json \u4E2D backendDeploy.containerPortsMappings \u987B\u4E3A\u5B57\u7B26\u4E32\u6570\u7EC4\uFF08\u53EF\u4E3A\u7A7A\uFF0C\u7701\u7565\u5219\u4E0D\u52A0\u7AEF\u53E3\u6620\u5C04\uFF09"
3620
- );
3621
- process.exit(1);
3622
- }
3623
- mappings = rawPorts.map((x) => String(x).trim()).filter(Boolean);
3624
- }
3625
- return {
3626
- name: reqTopLevelName(cfg),
3627
- registryHost: req(b.registryHost, "registryHost").trim(),
3628
- registryNamespace: req(b.registryNamespace, "registryNamespace").trim(),
3629
- registryUser: req(b.registryUser, "registryUser").trim(),
3630
- registryPassword: req(b.registryPassword, "registryPassword").trim(),
3631
- remoteHost: req(b.remoteHost, "remoteHost").trim(),
3632
- remotePort: reqBackendPositiveInt(b.remotePort, "remotePort"),
3633
- remoteProtocol,
3634
- caPath: b.caPath?.trim(),
3635
- certPath: b.certPath?.trim(),
3636
- keyPath: b.keyPath?.trim(),
3637
- envFilePath: typeof b.envFilePath === "string" ? b.envFilePath.trim() : "",
3638
- containerPortsMappings: mappings,
3639
- dockerNetwork: b.dockerNetwork?.trim() || void 0
3640
- };
4441
+ ws.on("close", (code, reason) => {
4442
+ console.log(
4443
+ `[apm] \u8FDE\u63A5\u5DF2\u65AD\u5F00 code=${code}${reason ? ` reason=${reason.toString()}` : ""}`
4444
+ );
4445
+ void shutdown();
4446
+ });
4447
+ ws.on("error", (err) => {
4448
+ console.error("[apm] WebSocket \u9519\u8BEF:", err.message);
4449
+ reject(err);
4450
+ });
4451
+ process.on("SIGINT", () => {
4452
+ console.log("[apm] \u6B63\u5728\u5173\u95ED\u2026");
4453
+ void shutdown();
4454
+ });
4455
+ process.on("SIGTERM", () => {
4456
+ void shutdown();
4457
+ });
4458
+ });
3641
4459
  }
3642
- function reqFe(v, field) {
3643
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
3644
- console.error(`apm.config.json \u4E2D frontendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
4460
+
4461
+ // src/commands/create-pr.ts
4462
+ async function runCreatePr(options) {
4463
+ const sessionId = options.sessionId.trim();
4464
+ if (!sessionId) {
4465
+ console.error("[apm] sessionId \u4E0D\u80FD\u4E3A\u7A7A");
3645
4466
  process.exit(1);
3646
4467
  }
3647
- return v;
3648
- }
3649
- function resolveFrontendDeployFromApmConfig(cfg) {
3650
- const f = cfg.frontendDeploy ?? {};
3651
- const port = Number(f.port);
3652
- return {
3653
- endpoint: reqFe(f.endpoint, "endpoint").trim(),
3654
- port: Number.isFinite(port) && port > 0 ? port : 9e3,
3655
- useSsl: Boolean(f.useSsl),
3656
- accessKey: reqFe(f.accessKey, "accessKey").trim(),
3657
- secretKey: reqFe(f.secretKey, "secretKey").trim(),
3658
- bucket: reqFe(f.bucket, "bucket").trim()
3659
- };
3660
- }
3661
- function reqWd(v, field) {
3662
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
3663
- console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
4468
+ const title = options.title.trim();
4469
+ if (!title) {
4470
+ console.error("[apm] \u8BF7\u901A\u8FC7 --title \u6307\u5B9A PR \u6807\u9898");
3664
4471
  process.exit(1);
3665
4472
  }
3666
- return v;
4473
+ const cfg = await ensureLoggedConfig();
4474
+ const api = createApmApiClient(cfg);
4475
+ const workdir = resolveWorkdirPath(options.cwd ?? process.cwd());
4476
+ const pr = await api.cli.createPullRequest({
4477
+ sessionId,
4478
+ workdir,
4479
+ title,
4480
+ content: options.content ?? ""
4481
+ });
4482
+ console.log(`[apm] PR \u5DF2\u5C31\u7EEA #${pr.number} (${pr.state}): ${pr.url}`);
3667
4483
  }
3668
- function reqWisdomPositiveInt(v, field) {
3669
- const n = Number(v);
3670
- if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
3671
- console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
3672
- process.exit(1);
4484
+
4485
+ // src/commands/deploy/deploy.ts
4486
+ import { spawnSync as spawnSync5 } from "node:child_process";
4487
+ function runShellCommand3(command, cwd) {
4488
+ console.error(`==> ${command}`);
4489
+ const result = spawnSync5(command, {
4490
+ cwd,
4491
+ stdio: "inherit",
4492
+ shell: true,
4493
+ env: process.env
4494
+ });
4495
+ if (result.status !== 0) {
4496
+ process.exit(result.status ?? 1);
3673
4497
  }
3674
- return n;
3675
4498
  }
3676
- function resolveWisdomDeployFromApmConfig(cfg) {
3677
- const w = cfg.wisdomDeploy ?? {};
3678
- return {
3679
- host: reqWd(w.host, "host").trim(),
3680
- port: reqWisdomPositiveInt(w.port, "port"),
3681
- username: reqWd(w.username, "username").trim(),
3682
- password: reqWd(w.password, "password").trim(),
3683
- remotePath: reqWd(w.remotePath, "remotePath").trim()
3684
- };
4499
+ function registerDeployMainCommand(program) {
4500
+ program.command("deploy").description(
4501
+ "\u7EDF\u4E00\u90E8\u7F72\uFF1A\u533B\u52A1\u5B58\u91CF\u9879\u76EE\u81EA\u52A8\u8BC6\u522B\u524D\u540E\u7AEF\uFF1B\u5176\u4ED6\u9879\u76EE\u6309 deploy.<\u73AF\u5883> \u6267\u884C shell \u547D\u4EE4"
4502
+ ).argument("<env>", "\u90E8\u7F72\u73AF\u5883\u540D\uFF08\u5982 test\u3001online\uFF09").option(
4503
+ "--config <path>",
4504
+ "apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
4505
+ ).option("--skip-maven", "\u8DF3\u8FC7 Maven \u6784\u5EFA\uFF08\u4EC5\u533B\u52A1\u540E\u7AEF\uFF09").action(
4506
+ async (env, opts) => {
4507
+ const cwd = process.cwd();
4508
+ const cfg = loadApmConfig({ configPath: opts.config });
4509
+ if (isWisdomLegacyDeploy(cfg)) {
4510
+ await runWisdomAutoDeploy({
4511
+ env,
4512
+ cwd,
4513
+ configPath: opts.config,
4514
+ skipMaven: opts.skipMaven
4515
+ });
4516
+ return;
4517
+ }
4518
+ const deployCommands = cfg.deploy ?? {};
4519
+ const command = deployCommands[env]?.trim();
4520
+ if (!command) {
4521
+ const keys = Object.keys(deployCommands);
4522
+ console.error(
4523
+ keys.length > 0 ? `apm.config.json \u4E2D\u672A\u914D\u7F6E deploy.${env}\uFF0C\u53EF\u7528\u73AF\u5883: ${keys.join(
4524
+ ", "
4525
+ )}` : `apm.config.json \u4E2D\u672A\u914D\u7F6E deploy \u6BB5`
4526
+ );
4527
+ process.exit(1);
4528
+ }
4529
+ runShellCommand3(command, cwd);
4530
+ }
4531
+ );
3685
4532
  }
3686
4533
 
4534
+ // src/commands/deploy/backend.ts
4535
+ import path8 from "node:path";
4536
+
3687
4537
  // src/commands/deploy/internal/backend-deploy/backend-deploy-workflow.ts
3688
- import path4 from "node:path";
4538
+ import path7 from "node:path";
3689
4539
 
3690
4540
  // src/commands/deploy/internal/backend-deploy/dockerode-client/client.ts
3691
4541
  import Docker from "dockerode";
3692
4542
 
3693
4543
  // src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
3694
- import { existsSync as existsSync14, readFileSync as readFileSync13 } from "node:fs";
3695
- import path from "node:path";
4544
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
4545
+ import path4 from "node:path";
3696
4546
  function asOptionalTlsBuffer(value) {
3697
4547
  if (typeof value !== "string") {
3698
4548
  console.log("tls filepath not exist");
3699
4549
  return void 0;
3700
4550
  }
3701
- console.log("tls filepath", path.join(process.cwd(), value));
4551
+ console.log("tls filepath", path4.join(process.cwd(), value));
3702
4552
  const normalized = value.trim();
3703
4553
  if (normalized === "") {
3704
4554
  return void 0;
3705
4555
  }
3706
- if (existsSync14(normalized)) {
3707
- return readFileSync13(normalized);
4556
+ if (existsSync17(normalized)) {
4557
+ return readFileSync15(normalized);
3708
4558
  }
3709
4559
  const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
3710
4560
  if (looksLikePath) {
@@ -3914,8 +4764,8 @@ var DockerodeClient = class {
3914
4764
  var createDockerodeClient = (config) => new DockerodeClient(config);
3915
4765
 
3916
4766
  // src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
3917
- import { existsSync as existsSync15, readFileSync as readFileSync14, statSync as statSync5 } from "node:fs";
3918
- import path2 from "node:path";
4767
+ import { existsSync as existsSync18, readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
4768
+ import path5 from "node:path";
3919
4769
  function stripSurroundingQuotes(value) {
3920
4770
  const t = value.trim();
3921
4771
  if (t.length >= 2) {
@@ -3930,11 +4780,11 @@ function loadEnvFromFile(envFilePath) {
3930
4780
  if (!envFilePath) {
3931
4781
  return {};
3932
4782
  }
3933
- const targetPath = path2.resolve(envFilePath);
3934
- if (!existsSync15(targetPath) || !statSync5(targetPath).isFile()) {
4783
+ const targetPath = path5.resolve(envFilePath);
4784
+ if (!existsSync18(targetPath) || !statSync6(targetPath).isFile()) {
3935
4785
  return {};
3936
4786
  }
3937
- const raw = readFileSync14(targetPath, "utf-8");
4787
+ const raw = readFileSync16(targetPath, "utf-8");
3938
4788
  const result = {};
3939
4789
  for (const line of raw.split(/\r?\n/)) {
3940
4790
  const normalized = line.trim();
@@ -4105,12 +4955,12 @@ function dockerPushImage(params, cwd) {
4105
4955
  }
4106
4956
 
4107
4957
  // src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
4108
- import { existsSync as existsSync16 } from "node:fs";
4109
- import path3 from "node:path";
4958
+ import { existsSync as existsSync19 } from "node:fs";
4959
+ import path6 from "node:path";
4110
4960
  function resolveDockerBuildPaths(cwd) {
4111
- const dockerfilePath = path3.join(cwd, "Dockerfile");
4961
+ const dockerfilePath = path6.join(cwd, "Dockerfile");
4112
4962
  Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
4113
- if (!existsSync16(dockerfilePath)) {
4963
+ if (!existsSync19(dockerfilePath)) {
4114
4964
  throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
4115
4965
  }
4116
4966
  Logger.info("\u2713 Dockerfile \u5B58\u5728");
@@ -4165,7 +5015,7 @@ var BackendDeployWorkflow = class {
4165
5015
  serveraddress
4166
5016
  });
4167
5017
  Logger.success("\u8FDC\u7A0B\u62C9\u53D6\u955C\u50CF\u5B8C\u6210");
4168
- const envFilePath = path4.resolve(cwd, this.params.envFilePath || ".env");
5018
+ const envFilePath = path7.resolve(cwd, this.params.envFilePath || ".env");
4169
5019
  const envObj = loadEnvFromFile(envFilePath);
4170
5020
  if (this.params.dockerNetwork?.trim()) {
4171
5021
  Logger.info(`\u8FDC\u7A0B\u5BB9\u5668\u5C06\u52A0\u5165 Docker \u7F51\u7EDC\uFF1A${this.params.dockerNetwork.trim()}`);
@@ -4205,7 +5055,7 @@ function registerDeployBackendCommands(program) {
4205
5055
  assertDeployImageTag(tag);
4206
5056
  const cfg = loadApmConfig({ configPath: opts.config });
4207
5057
  const fromApm = resolveBackendDeployFromApmConfig(cfg);
4208
- const dirAbs = path5.resolve(process.cwd(), opts.dir || "servers/api");
5058
+ const dirAbs = path8.resolve(process.cwd(), opts.dir || "servers/api");
4209
5059
  const params = {
4210
5060
  image: fromApm.name,
4211
5061
  tag,
@@ -4235,18 +5085,18 @@ function registerDeployBackendCommands(program) {
4235
5085
  }
4236
5086
 
4237
5087
  // src/commands/deploy/frontend.ts
4238
- import { copyFile, readdir as readdir2, stat } from "node:fs/promises";
4239
- import path7 from "node:path";
5088
+ import { copyFile, readdir as readdir3, stat } from "node:fs/promises";
5089
+ import path10 from "node:path";
4240
5090
 
4241
5091
  // src/commands/deploy/internal/minio.ts
4242
- import { statSync as statSync6 } from "node:fs";
4243
- import { readdir, readFile } from "node:fs/promises";
4244
- import path6 from "node:path";
5092
+ import { statSync as statSync7 } from "node:fs";
5093
+ import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
5094
+ import path9 from "node:path";
4245
5095
  import * as Minio from "minio";
4246
5096
  var DEFAULT_MAX_FILE_SIZE_MB = 50;
4247
5097
  async function isDirectoryPath(dir) {
4248
5098
  try {
4249
- const st = statSync6(dir);
5099
+ const st = statSync7(dir);
4250
5100
  return st.isDirectory();
4251
5101
  } catch {
4252
5102
  return false;
@@ -4265,18 +5115,18 @@ function sanitizeRelativePath(rel) {
4265
5115
  async function collectFiles(root) {
4266
5116
  const out = [];
4267
5117
  async function walk(dir, prefix) {
4268
- const entries = await readdir(dir, { withFileTypes: true });
5118
+ const entries = await readdir2(dir, { withFileTypes: true });
4269
5119
  for (const e of entries) {
4270
5120
  const name = e.name;
4271
5121
  if (name === "." || name === "..") {
4272
5122
  continue;
4273
5123
  }
4274
- const abs = path6.join(dir, name);
5124
+ const abs = path9.join(dir, name);
4275
5125
  const rel = prefix ? `${prefix}/${name}` : name;
4276
5126
  if (e.isDirectory()) {
4277
5127
  await walk(abs, rel);
4278
5128
  } else if (e.isFile()) {
4279
- const st = statSync6(abs);
5129
+ const st = statSync7(abs);
4280
5130
  out.push({
4281
5131
  absPath: abs,
4282
5132
  relativePath: rel.replace(/\\/g, "/"),
@@ -4290,7 +5140,7 @@ async function collectFiles(root) {
4290
5140
  return out;
4291
5141
  }
4292
5142
  async function readArtifactFile(absPath) {
4293
- return readFile(absPath);
5143
+ return readFile2(absPath);
4294
5144
  }
4295
5145
  function toMB(bytes) {
4296
5146
  return Math.round(bytes / (1024 * 1024) * 1e3) / 1e3;
@@ -4314,7 +5164,7 @@ var MIME = {
4314
5164
  ".map": "application/json"
4315
5165
  };
4316
5166
  function detectMimeType(filePath) {
4317
- const ext = path6.extname(filePath).toLowerCase();
5167
+ const ext = path9.extname(filePath).toLowerCase();
4318
5168
  return MIME[ext] ?? "";
4319
5169
  }
4320
5170
  var MinioClient = class {
@@ -4402,7 +5252,7 @@ function artifactObjectKey(namePrefix, branchSegment, relativePath) {
4402
5252
  return `${base}/${branchSegment}/dist/${rel}`;
4403
5253
  }
4404
5254
  async function ensureArtifactRootIndexHtml(root) {
4405
- const indexHtmlPath = path7.join(root, "index.html");
5255
+ const indexHtmlPath = path10.join(root, "index.html");
4406
5256
  try {
4407
5257
  const st = await stat(indexHtmlPath);
4408
5258
  if (st.isFile()) {
@@ -4412,14 +5262,14 @@ async function ensureArtifactRootIndexHtml(root) {
4412
5262
  }
4413
5263
  let entries;
4414
5264
  try {
4415
- entries = await readdir2(root, { withFileTypes: true });
5265
+ entries = await readdir3(root, { withFileTypes: true });
4416
5266
  } catch (e) {
4417
5267
  console.error(`\u65E0\u6CD5\u8BFB\u53D6\u4EA7\u7269\u76EE\u5F55\uFF1A${root}`, e);
4418
5268
  process.exit(1);
4419
5269
  }
4420
5270
  const dirNames = entries.filter((e) => e.isDirectory()).map((e) => String(e.name)).sort();
4421
5271
  for (const name of dirNames) {
4422
- const candidate = path7.join(root, name, "index.html");
5272
+ const candidate = path10.join(root, name, "index.html");
4423
5273
  try {
4424
5274
  const st = await stat(candidate);
4425
5275
  if (!st.isFile()) {
@@ -4430,7 +5280,7 @@ async function ensureArtifactRootIndexHtml(root) {
4430
5280
  }
4431
5281
  await copyFile(candidate, indexHtmlPath);
4432
5282
  console.error(
4433
- `\u4EA7\u7269\u534F\u8BAE\uFF1A\u5DF2\u5C06 ${path7.join(name, "index.html")} \u590D\u5236\u4E3A\u6839\u76EE\u5F55 index.html`
5283
+ `\u4EA7\u7269\u534F\u8BAE\uFF1A\u5DF2\u5C06 ${path10.join(name, "index.html")} \u590D\u5236\u4E3A\u6839\u76EE\u5F55 index.html`
4434
5284
  );
4435
5285
  return;
4436
5286
  }
@@ -4466,7 +5316,7 @@ function registerDeployFrontendCommands(program) {
4466
5316
  secretKey: settings.secretKey
4467
5317
  });
4468
5318
  const bucket = settings.bucket;
4469
- const root = path7.resolve(process.cwd(), opts.dir || "apps/web/dist");
5319
+ const root = path10.resolve(process.cwd(), opts.dir || "apps/web/dist");
4470
5320
  if (!await isDirectoryPath(root)) {
4471
5321
  console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
4472
5322
  process.exit(1);
@@ -4535,159 +5385,7 @@ function registerDeployFrontendCommands(program) {
4535
5385
  }
4536
5386
 
4537
5387
  // src/commands/deploy/sftp.ts
4538
- import path9 from "node:path";
4539
-
4540
- // src/commands/deploy/internal/wisdom-sftp.ts
4541
- import { readdir as readdir3, readFile as readFile2, unlink, writeFile } from "node:fs/promises";
4542
- import path8 from "node:path";
4543
- import JSZip from "jszip";
4544
- import SftpClient from "ssh2-sftp-client";
4545
- async function addDirToZip(dir, zipFolder) {
4546
- const entries = await readdir3(dir, { withFileTypes: true });
4547
- for (const entry of entries) {
4548
- const fullPath = path8.join(dir, entry.name);
4549
- if (entry.isDirectory()) {
4550
- const folder = zipFolder.folder(entry.name);
4551
- if (folder) {
4552
- await addDirToZip(fullPath, folder);
4553
- }
4554
- } else {
4555
- const content = await readFile2(fullPath);
4556
- zipFolder.file(entry.name, content);
4557
- }
4558
- }
4559
- }
4560
- async function zipDirectory(distDir, zipPath) {
4561
- console.error(`\u538B\u7F29\u76EE\u5F55: ${distDir}`);
4562
- const zip = new JSZip();
4563
- await addDirToZip(distDir, zip);
4564
- const content = await zip.generateAsync({
4565
- type: "nodebuffer",
4566
- compression: "DEFLATE",
4567
- compressionOptions: { level: 6 }
4568
- });
4569
- await writeFile(zipPath, content);
4570
- const sizeMb = (content.length / 1024 / 1024).toFixed(2);
4571
- console.error(`\u5DF2\u751F\u6210: ${zipPath} (${sizeMb} MB)`);
4572
- return content.length;
4573
- }
4574
- async function ensureRemoteDir(sftp, dir) {
4575
- const parts = dir.replace(/\\/g, "/").split("/").filter(Boolean);
4576
- let current = dir.startsWith("/") ? "" : ".";
4577
- for (const part of parts) {
4578
- current = current ? `${current}/${part}` : `/${part}`;
4579
- try {
4580
- await sftp.mkdir(current, true);
4581
- } catch {
4582
- }
4583
- }
4584
- }
4585
- function execCommand(client, command) {
4586
- return new Promise((resolve5, reject) => {
4587
- client.exec(command, (err, stream) => {
4588
- if (err) return reject(err);
4589
- let stdout = "";
4590
- let stderr = "";
4591
- stream.on("close", (code) => {
4592
- if (code !== 0) {
4593
- reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
4594
- return;
4595
- }
4596
- resolve5(stdout);
4597
- }).on("data", (data) => {
4598
- stdout += data.toString();
4599
- });
4600
- stream.stderr.on("data", (data) => {
4601
- stderr += data.toString();
4602
- });
4603
- });
4604
- });
4605
- }
4606
- function shellSingleQuote(value) {
4607
- return `'${value.replace(/'/g, `'"'"'`)}'`;
4608
- }
4609
- function buildClearRemoteDirExceptZipCommand(target) {
4610
- const normalized = target.replace(/\\/g, "/").replace(/\/$/, "");
4611
- const quotedTarget = shellSingleQuote(normalized);
4612
- const script = [
4613
- `T=${quotedTarget}`,
4614
- "S=$(mktemp -d)",
4615
- 'while IFS= read -r -d "" z; do r="${z#${T}/}"',
4616
- 'mkdir -p "${S}/$(dirname "$r")"',
4617
- 'mv "$z" "${S}/${r}"',
4618
- 'done < <(find "$T" -mindepth 1 -type f -iname "*.zip" -print0)',
4619
- 'rm -rf "${T}"/*',
4620
- 'while IFS= read -r -d "" r; do r="${r#./}"',
4621
- 'mkdir -p "${T}/$(dirname "$r")"',
4622
- 'mv "${S}/${r}" "${T}/${r}"',
4623
- 'done < <(cd "$S" 2>/dev/null && find . -type f -print0)',
4624
- 'rm -rf "$S"'
4625
- ].join("; ");
4626
- return `bash -c ${shellSingleQuote(script)}`;
4627
- }
4628
- async function uploadAndMaybeExtract(settings, localZip, extract) {
4629
- const remoteZipPath = `${settings.remotePath.replace(/\/$/, "")}/dist.zip`;
4630
- console.error(
4631
- `\u8FDE\u63A5 ${settings.username}@${settings.host}:${settings.port} ...`
4632
- );
4633
- const sftp = new SftpClient();
4634
- try {
4635
- await sftp.connect({
4636
- host: settings.host,
4637
- port: settings.port,
4638
- username: settings.username,
4639
- password: settings.password,
4640
- readyTimeout: 2e4,
4641
- tryKeyboard: true
4642
- });
4643
- await ensureRemoteDir(sftp, settings.remotePath);
4644
- await sftp.put(localZip, remoteZipPath);
4645
- console.error(` \u2713 ${localZip} -> ${remoteZipPath}`);
4646
- if (extract) {
4647
- const target = settings.remotePath.replace(/\/$/, "");
4648
- const client = sftp.client;
4649
- const clearCmd = buildClearRemoteDirExceptZipCommand(target);
4650
- console.error(`\u8FDC\u7A0B\u6E05\u7406\u89E3\u538B\u76EE\u5F55: ${clearCmd}`);
4651
- await execCommand(client, clearCmd);
4652
- const unzipCmd = `unzip -o "${remoteZipPath}" -d "${target}"`;
4653
- console.error(`\u8FDC\u7A0B\u89E3\u538B: ${unzipCmd}`);
4654
- await execCommand(client, unzipCmd);
4655
- console.error("\u8FDC\u7A0B\u89E3\u538B\u5B8C\u6210!");
4656
- }
4657
- console.error(extract ? "\u90E8\u7F72\u5B8C\u6210!" : "\u4E0A\u4F20\u5B8C\u6210!");
4658
- } finally {
4659
- await sftp.end();
4660
- }
4661
- }
4662
- async function runWisdomSftpDeploy(params) {
4663
- const zipPath = path8.join(params.localDir, "..", ".deploy-sftp-dist.zip");
4664
- const resolvedZipPath = path8.resolve(zipPath);
4665
- let zipSizeBytes = 0;
4666
- try {
4667
- zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
4668
- await uploadAndMaybeExtract(
4669
- params.settings,
4670
- resolvedZipPath,
4671
- params.extract
4672
- );
4673
- } finally {
4674
- try {
4675
- await unlink(resolvedZipPath);
4676
- console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
4677
- } catch {
4678
- }
4679
- }
4680
- return {
4681
- ok: true,
4682
- localDir: params.localDir,
4683
- host: params.settings.host,
4684
- remotePath: params.settings.remotePath,
4685
- zipSizeBytes,
4686
- extracted: params.extract
4687
- };
4688
- }
4689
-
4690
- // src/commands/deploy/sftp.ts
5388
+ import path11 from "node:path";
4691
5389
  function registerDeploySftpCommands(program) {
4692
5390
  program.command("deploy-sftp").description(
4693
5391
  "\u5C06\u6307\u5B9A\u76EE\u5F55\u538B\u7F29\u4E3A zip \u540E\u901A\u8FC7 SFTP \u4E0A\u4F20\u5230\u8FDC\u7A0B\u670D\u52A1\u5668\uFF08\u8FDE\u63A5\u4FE1\u606F\u89C1 apm.config.json wisdomDeploy\uFF09"
@@ -4702,7 +5400,7 @@ function registerDeploySftpCommands(program) {
4702
5400
  async (opts) => {
4703
5401
  const cfg = loadApmConfig({ configPath: opts.config });
4704
5402
  const settings = resolveWisdomDeployFromApmConfig(cfg);
4705
- const root = path9.resolve(process.cwd(), opts.dir || "apps/web/dist");
5403
+ const root = path11.resolve(process.cwd(), opts.dir || "apps/web/dist");
4706
5404
  if (!await isDirectoryPath(root)) {
4707
5405
  console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
4708
5406
  process.exit(1);
@@ -4723,11 +5421,30 @@ function registerDeploySftpCommands(program) {
4723
5421
  );
4724
5422
  }
4725
5423
 
5424
+ // src/commands/deploy/wisdom-backend.ts
5425
+ function registerDeployWisdomBackendCommands(program) {
5426
+ program.command("deploy-wisdom-backend").description(
5427
+ "Maven \u6784\u5EFA\u540E\u901A\u8FC7 SFTP \u589E\u91CF\u66F4\u65B0\u8FDC\u7A0B lib \u76EE\u5F55\u5E76\u91CD\u542F Spring Boot \u670D\u52A1\uFF08\u914D\u7F6E\u89C1 apm.config.json \u7684 wisdomDeploy \u4E0E healthCheck\uFF09"
5428
+ ).option(
5429
+ "--config <path>",
5430
+ "apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
5431
+ ).option("--skip-maven", "\u8DF3\u8FC7 Maven \u6784\u5EFA\uFF0C\u4EC5\u4E0A\u4F20\u5E76\u91CD\u542F").action(async (opts) => {
5432
+ const cfg = loadApmConfig({ configPath: opts.config });
5433
+ const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
5434
+ await runWisdomBackendDeploy({
5435
+ config: settings,
5436
+ skipMaven: Boolean(opts.skipMaven)
5437
+ });
5438
+ });
5439
+ }
5440
+
4726
5441
  // src/commands/deploy/index.ts
4727
5442
  function registerDeployCommands(program) {
5443
+ registerDeployMainCommand(program);
4728
5444
  registerDeployBackendCommands(program);
4729
5445
  registerDeployFrontendCommands(program);
4730
5446
  registerDeploySftpCommands(program);
5447
+ registerDeployWisdomBackendCommands(program);
4731
5448
  }
4732
5449
 
4733
5450
  // src/index.ts