ai-project-manage-cli 6.0.106 → 6.0.108-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +979 -888
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -110,8 +110,8 @@ function toFsPath(inputPath) {
110
110
  }
111
111
  return `\\\\?\\${normalized}`;
112
112
  }
113
- function normalizeWorkdirPath(path13) {
114
- let normalized = path13.trim().replace(/\\/g, "/").normalize("NFC");
113
+ function normalizeWorkdirPath(path19) {
114
+ let normalized = path19.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 path13 = join2(apmDir, item);
330
- if (!existsSync(toFsPath(path13))) {
331
- throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path13}`);
329
+ const path19 = join2(apmDir, item);
330
+ if (!existsSync(toFsPath(path19))) {
331
+ throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path19}`);
332
332
  }
333
333
  }
334
334
  const leakedRules = join2(workdir, "rules");
@@ -790,14 +790,14 @@ function projectDocumentLocalPath(apmRoot, documentPath) {
790
790
  const normalized = normalizeLocalDocumentPath(documentPath);
791
791
  return join4(projectDocumentsDir(apmRoot), ...normalized.split("/"));
792
792
  }
793
- function normalizeLocalDocumentPath(path13) {
794
- const trimmed = path13.trim().replace(/\\/g, "/");
793
+ function normalizeLocalDocumentPath(path19) {
794
+ const trimmed = path19.trim().replace(/\\/g, "/");
795
795
  if (!trimmed || trimmed.startsWith("/") || /^[a-zA-Z]:/.test(trimmed)) {
796
- throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path13}`);
796
+ throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path19}`);
797
797
  }
798
798
  const segments = trimmed.split("/").filter(Boolean);
799
799
  if (segments.some((segment) => segment === ".." || segment === ".")) {
800
- throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path13}`);
800
+ throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path19}`);
801
801
  }
802
802
  return segments.join("/");
803
803
  }
@@ -848,15 +848,15 @@ function diffManifestPaths(remote, local) {
848
848
  (local?.documents ?? []).map((doc) => [doc.path, doc.contentHash])
849
849
  );
850
850
  const download = [];
851
- for (const [path13, hash] of remoteMap) {
852
- if (localMap.get(path13) !== hash) {
853
- download.push(path13);
851
+ for (const [path19, hash] of remoteMap) {
852
+ if (localMap.get(path19) !== hash) {
853
+ download.push(path19);
854
854
  }
855
855
  }
856
856
  const deleteLocal = [];
857
- for (const path13 of localMap.keys()) {
858
- if (!remoteMap.has(path13)) {
859
- deleteLocal.push(path13);
857
+ for (const path19 of localMap.keys()) {
858
+ if (!remoteMap.has(path19)) {
859
+ deleteLocal.push(path19);
860
860
  }
861
861
  }
862
862
  return { download, deleteLocal };
@@ -916,8 +916,8 @@ ${diagnostic ?? ""}`
916
916
  }
917
917
  }
918
918
  let deleted = 0;
919
- for (const path13 of deleteLocal) {
920
- const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path13));
919
+ for (const path19 of deleteLocal) {
920
+ const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path19));
921
921
  if (existsSync2(absPath)) {
922
922
  rmSync(absPath, { force: true });
923
923
  deleted += 1;
@@ -962,21 +962,21 @@ async function syncRepositoryProjectDocumentsPush(cfg, workdirPath, apmRoot) {
962
962
  ])
963
963
  );
964
964
  let synced = 0;
965
- for (const path13 of localPaths) {
966
- const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path13));
965
+ for (const path19 of localPaths) {
966
+ const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path19));
967
967
  const content = readFileSync3(absPath, "utf8");
968
968
  const contentHash = hashLocalFileContent(content);
969
- if (remoteHashByPath.get(path13) === contentHash) {
969
+ if (remoteHashByPath.get(path19) === contentHash) {
970
970
  continue;
971
971
  }
972
972
  await api.cli.upsertRepositoryProjectDocument({
973
973
  repositoryId,
974
- path: path13,
974
+ path: path19,
975
975
  content,
976
- description: remoteDescriptionByPath.get(path13) ?? void 0
976
+ description: remoteDescriptionByPath.get(path19) ?? void 0
977
977
  });
978
978
  synced += 1;
979
- console.log(`[apm] \u5DF2\u540C\u6B65\u4ED3\u5E93\u9879\u76EE\u6587\u6863: ${path13}`);
979
+ console.log(`[apm] \u5DF2\u540C\u6B65\u4ED3\u5E93\u9879\u76EE\u6587\u6863: ${path19}`);
980
980
  }
981
981
  if (synced === 0) {
982
982
  console.log("[apm] \u4ED3\u5E93\u9879\u76EE\u6587\u6863\u65E0\u53D8\u5316\uFF0C\u8DF3\u8FC7\u63A8\u9001");
@@ -1228,6 +1228,7 @@ var TASK_STATUS_LABEL = {
1228
1228
  IN_PROGRESS: "\u8FDB\u884C\u4E2D",
1229
1229
  COMPLETED: "\u5DF2\u5B8C\u6210",
1230
1230
  FAILED: "\u5DF2\u5931\u8D25",
1231
+ CLOSED: "\u5DF2\u5173\u95ED",
1231
1232
  SUSPENDED: "\u5DF2\u6682\u505C"
1232
1233
  };
1233
1234
  function taskStatusLabel(status) {
@@ -1265,6 +1266,9 @@ function shouldDeleteMode2(input) {
1265
1266
  if (input.taskStatus === "FAILED") {
1266
1267
  return { delete: true, reason: "\u4EFB\u52A1\u5DF2\u5931\u8D25" };
1267
1268
  }
1269
+ if (input.taskStatus === "CLOSED") {
1270
+ return { delete: true, reason: "\u4EFB\u52A1\u5DF2\u5173\u95ED" };
1271
+ }
1268
1272
  return { delete: false, reason: "" };
1269
1273
  }
1270
1274
  function buildSessionBranchRow(input) {
@@ -1589,13 +1593,13 @@ async function downloadAttachment(cfg, attachmentId) {
1589
1593
  return Buffer.from(await res.arrayBuffer());
1590
1594
  }
1591
1595
  function loadManifest(dir) {
1592
- const path13 = join6(dir, MANIFEST_FILE2);
1593
- if (!existsSync4(path13)) {
1596
+ const path19 = join6(dir, MANIFEST_FILE2);
1597
+ if (!existsSync4(path19)) {
1594
1598
  return { version: 1, attachments: {} };
1595
1599
  }
1596
1600
  try {
1597
1601
  const parsed = JSON.parse(
1598
- readFileSync5(path13, "utf8")
1602
+ readFileSync5(path19, "utf8")
1599
1603
  );
1600
1604
  if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
1601
1605
  return parsed;
@@ -1676,8 +1680,8 @@ function sanitizeSkillDirName(name) {
1676
1680
  function listBaseSkillDirNames() {
1677
1681
  if (!existsSync5(BASE_SKILLS_TEMPLATE_DIR)) return [];
1678
1682
  return readdirSync3(BASE_SKILLS_TEMPLATE_DIR).filter((name) => {
1679
- const path13 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
1680
- return statSync2(path13).isDirectory();
1683
+ const path19 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
1684
+ return statSync2(path19).isDirectory();
1681
1685
  });
1682
1686
  }
1683
1687
  function syncAgentsGuide(apmDir) {
@@ -1689,8 +1693,8 @@ function syncAgentsGuide(apmDir) {
1689
1693
  function listBaseRuleFileNames() {
1690
1694
  if (!existsSync5(BASE_RULES_TEMPLATE_DIR)) return [];
1691
1695
  return readdirSync3(BASE_RULES_TEMPLATE_DIR).filter((name) => {
1692
- const path13 = join7(BASE_RULES_TEMPLATE_DIR, name);
1693
- return statSync2(path13).isFile();
1696
+ const path19 = join7(BASE_RULES_TEMPLATE_DIR, name);
1697
+ return statSync2(path19).isFile();
1694
1698
  });
1695
1699
  }
1696
1700
  function syncBaseRules(rulesDir) {
@@ -1753,13 +1757,13 @@ function ruleLocalFileName(ruleName) {
1753
1757
  return `${sanitized}.md`;
1754
1758
  }
1755
1759
  function loadManifest2(rulesDir) {
1756
- const path13 = join8(rulesDir, MANIFEST_FILE3);
1757
- if (!existsSync6(toFsPath(path13))) {
1760
+ const path19 = join8(rulesDir, MANIFEST_FILE3);
1761
+ if (!existsSync6(toFsPath(path19))) {
1758
1762
  return { version: 1, rules: {} };
1759
1763
  }
1760
1764
  try {
1761
1765
  const parsed = JSON.parse(
1762
- readFileSync6(toFsPath(path13), "utf8")
1766
+ readFileSync6(toFsPath(path19), "utf8")
1763
1767
  );
1764
1768
  if (parsed?.version === 1 && parsed.rules && typeof parsed.rules === "object") {
1765
1769
  return parsed;
@@ -2654,93 +2658,17 @@ function validateAgentWsMessage(value, kind) {
2654
2658
  return validateMessagePush(o);
2655
2659
  }
2656
2660
 
2657
- // src/commands/deploy/deploy-log-utils.ts
2658
- import { setTimeout as delay } from "node:timers/promises";
2659
- var DEPLOY_SPAWN_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
2660
- var DEPLOY_LOG_SYNC_MAX_CHUNK_BYTES = 4 * 1024 * 1024;
2661
- var DEPLOY_COMPLETE_LOG_MAX_BYTES = 9 * 1024 * 1024;
2662
- var DEPLOY_LOG_SYNC_MAX_ATTEMPTS = 3;
2663
- async function retryDeployLogSync(fn, attempts = DEPLOY_LOG_SYNC_MAX_ATTEMPTS) {
2664
- let lastError;
2665
- for (let attempt = 1; attempt <= attempts; attempt += 1) {
2666
- try {
2667
- return await fn();
2668
- } catch (error) {
2669
- lastError = error;
2670
- if (attempt < attempts) {
2671
- await delay(1e3 * attempt);
2672
- }
2673
- }
2674
- }
2675
- throw lastError;
2676
- }
2677
- function splitUtf8StringByMaxBytes(value, maxBytes) {
2678
- if (maxBytes <= 0) {
2679
- throw new Error("maxBytes must be positive");
2680
- }
2681
- const bytes = Buffer.from(value, "utf8");
2682
- if (bytes.length <= maxBytes) {
2683
- return [value];
2684
- }
2685
- const chunks = [];
2686
- let offset = 0;
2687
- while (offset < bytes.length) {
2688
- let end = Math.min(offset + maxBytes, bytes.length);
2689
- while (end > offset && (bytes[end] & 192) === 128) {
2690
- end -= 1;
2691
- }
2692
- if (end <= offset) {
2693
- end = Math.min(offset + maxBytes, bytes.length);
2694
- }
2695
- chunks.push(bytes.subarray(offset, end).toString("utf8"));
2696
- offset = end;
2697
- }
2698
- return chunks;
2699
- }
2700
- function truncateDeployLogForComplete(log2) {
2701
- const bytes = Buffer.from(log2, "utf8");
2702
- if (bytes.length <= DEPLOY_COMPLETE_LOG_MAX_BYTES) {
2703
- return { log: log2, truncated: false };
2704
- }
2705
- const tailBudget = Math.max(DEPLOY_COMPLETE_LOG_MAX_BYTES - 512, 1024);
2706
- const prefix = `[apm] \u65E5\u5FD7\u8FC7\u957F\uFF08${Math.ceil(bytes.length / 1024)}KB\uFF09\uFF0C\u4EC5\u4FDD\u7559\u672B\u5C3E ${Math.floor(tailBudget / 1024)}KB
2707
- `;
2708
- let tail = bytes.subarray(bytes.length - tailBudget).toString("utf8");
2709
- const brokenPrefix = tail.indexOf("\uFFFD");
2710
- if (brokenPrefix >= 0) {
2711
- const newline = tail.indexOf("\n", brokenPrefix);
2712
- tail = newline >= 0 ? tail.slice(newline + 1) : tail.slice(brokenPrefix + 1);
2713
- }
2714
- return { log: prefix + tail, truncated: true };
2715
- }
2716
-
2717
2661
  // src/commands/deploy/deploy-execute.ts
2718
- import path5 from "node:path";
2662
+ import path11 from "node:path";
2719
2663
 
2720
2664
  // src/commands/deploy/internal/apm-config.ts
2721
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "node:fs";
2722
- import { homedir as homedir2 } from "node:os";
2723
- import { join as join13, resolve as resolve3 } from "node:path";
2724
- function loadApmConfig(options) {
2725
- const p = resolve3(
2726
- process.cwd(),
2727
- options?.configPath ?? resolve3(workspaceApmDir(), "apm.config.json")
2728
- );
2729
- if (!existsSync11(p)) {
2730
- console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
2731
- process.exit(1);
2732
- }
2733
- try {
2734
- const raw = readFileSync10(p, "utf8");
2735
- return JSON.parse(raw);
2736
- } catch (e) {
2737
- console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
2738
- process.exit(1);
2739
- }
2740
- }
2741
- function req(v, field) {
2665
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "node:fs";
2666
+ import { resolve as resolve4 } from "node:path";
2667
+
2668
+ // src/commands/deploy/internal/config/config-validation.ts
2669
+ function req(v, field, section) {
2742
2670
  if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2743
- console.error(`apm.config.json \u4E2D backendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2671
+ console.error(`apm.config.json \u4E2D ${section}.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2744
2672
  process.exit(1);
2745
2673
  }
2746
2674
  return v;
@@ -2755,17 +2683,19 @@ function reqTopLevelName(cfg) {
2755
2683
  }
2756
2684
  return n;
2757
2685
  }
2758
- function reqBackendPositiveInt(v, field) {
2686
+ function reqPositiveInt(v, field, section) {
2759
2687
  const n = Number(v);
2760
2688
  if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
2761
- console.error(`apm.config.json \u4E2D backendDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
2689
+ console.error(`apm.config.json \u4E2D ${section}.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
2762
2690
  process.exit(1);
2763
2691
  }
2764
2692
  return n;
2765
2693
  }
2694
+
2695
+ // src/commands/deploy/internal/config/docker-backend-config.ts
2766
2696
  function resolveBackendDeployFromApmConfig(cfg) {
2767
2697
  const b = cfg.backendDeploy ?? {};
2768
- const protoRaw = req(b.remoteProtocol, "remoteProtocol").trim().toLowerCase();
2698
+ const protoRaw = req(b.remoteProtocol, "remoteProtocol", "backendDeploy").trim().toLowerCase();
2769
2699
  if (protoRaw !== "http" && protoRaw !== "https") {
2770
2700
  console.error(
2771
2701
  "apm.config.json \u4E2D backendDeploy.remoteProtocol \u53EA\u80FD\u4E3A http \u6216 https"
@@ -2786,12 +2716,20 @@ function resolveBackendDeployFromApmConfig(cfg) {
2786
2716
  }
2787
2717
  return {
2788
2718
  name: reqTopLevelName(cfg),
2789
- registryHost: req(b.registryHost, "registryHost").trim(),
2790
- registryNamespace: req(b.registryNamespace, "registryNamespace").trim(),
2791
- registryUser: req(b.registryUser, "registryUser").trim(),
2792
- registryPassword: req(b.registryPassword, "registryPassword").trim(),
2793
- remoteHost: req(b.remoteHost, "remoteHost").trim(),
2794
- remotePort: reqBackendPositiveInt(b.remotePort, "remotePort"),
2719
+ registryHost: req(b.registryHost, "registryHost", "backendDeploy").trim(),
2720
+ registryNamespace: req(
2721
+ b.registryNamespace,
2722
+ "registryNamespace",
2723
+ "backendDeploy"
2724
+ ).trim(),
2725
+ registryUser: req(b.registryUser, "registryUser", "backendDeploy").trim(),
2726
+ registryPassword: req(
2727
+ b.registryPassword,
2728
+ "registryPassword",
2729
+ "backendDeploy"
2730
+ ).trim(),
2731
+ remoteHost: req(b.remoteHost, "remoteHost", "backendDeploy").trim(),
2732
+ remotePort: reqPositiveInt(b.remotePort, "remotePort", "backendDeploy"),
2795
2733
  remoteProtocol,
2796
2734
  caPath: b.caPath?.trim(),
2797
2735
  certPath: b.certPath?.trim(),
@@ -2801,64 +2739,30 @@ function resolveBackendDeployFromApmConfig(cfg) {
2801
2739
  dockerNetwork: b.dockerNetwork?.trim() || void 0
2802
2740
  };
2803
2741
  }
2804
- function reqFe(v, field) {
2805
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2806
- console.error(`apm.config.json \u4E2D frontendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2807
- process.exit(1);
2808
- }
2809
- return v;
2810
- }
2742
+
2743
+ // src/commands/deploy/internal/config/frontend-minio-config.ts
2811
2744
  function resolveFrontendDeployFromApmConfig(cfg) {
2812
2745
  const f = cfg.frontendDeploy ?? {};
2813
2746
  const port = Number(f.port);
2814
2747
  return {
2815
- endpoint: reqFe(f.endpoint, "endpoint").trim(),
2748
+ endpoint: req(f.endpoint, "endpoint", "frontendDeploy").trim(),
2816
2749
  port: Number.isFinite(port) && port > 0 ? port : 9e3,
2817
2750
  useSsl: Boolean(f.useSsl),
2818
- accessKey: reqFe(f.accessKey, "accessKey").trim(),
2819
- secretKey: reqFe(f.secretKey, "secretKey").trim(),
2820
- bucket: reqFe(f.bucket, "bucket").trim()
2821
- };
2822
- }
2823
- function reqWd(v, field) {
2824
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2825
- console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2826
- process.exit(1);
2827
- }
2828
- return v;
2829
- }
2830
- function reqWisdomPositiveInt(v, field) {
2831
- const n = Number(v);
2832
- if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
2833
- console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
2834
- process.exit(1);
2835
- }
2836
- return n;
2837
- }
2838
- function resolveWisdomDeployFromApmConfig(cfg) {
2839
- const w = cfg.wisdomDeploy ?? {};
2840
- return {
2841
- host: reqWd(w.host, "host").trim(),
2842
- port: reqWisdomPositiveInt(w.port, "port"),
2843
- username: reqWd(w.username, "username").trim(),
2844
- password: reqWd(w.password, "password").trim(),
2845
- remotePath: reqWd(w.remotePath, "remotePath").trim()
2751
+ accessKey: req(f.accessKey, "accessKey", "frontendDeploy").trim(),
2752
+ secretKey: req(f.secretKey, "secretKey", "frontendDeploy").trim(),
2753
+ bucket: req(f.bucket, "bucket", "frontendDeploy").trim()
2846
2754
  };
2847
2755
  }
2848
- function reqHc(v, field) {
2849
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2850
- console.error(`apm.config.json \u4E2D healthCheck.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2851
- process.exit(1);
2852
- }
2853
- return v;
2854
- }
2855
- function reqWb(v, field) {
2856
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2857
- console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2858
- process.exit(1);
2859
- }
2860
- return v;
2861
- }
2756
+
2757
+ // src/commands/deploy/internal/config/maven-repo.ts
2758
+ import { existsSync as existsSync11, readFileSync as readFileSync10 } from "node:fs";
2759
+ import { homedir as homedir2 } from "node:os";
2760
+ import { join as join13, resolve as resolve3 } from "node:path";
2761
+ var MAVEN_REPO_ENV_KEYS = [
2762
+ "MAVEN_LOCAL_REPO",
2763
+ "M2_REPO",
2764
+ "MAVEN_REPOSITORY"
2765
+ ];
2862
2766
  function readEnvVar(env, name) {
2863
2767
  if (env[name] !== void 0) {
2864
2768
  return env[name];
@@ -2888,11 +2792,6 @@ function expandUserPath(pathStr, env = process.env) {
2888
2792
  }
2889
2793
  return resolve3(expanded);
2890
2794
  }
2891
- var MAVEN_REPO_ENV_KEYS = [
2892
- "MAVEN_LOCAL_REPO",
2893
- "M2_REPO",
2894
- "MAVEN_REPOSITORY"
2895
- ];
2896
2795
  function readMavenLocalRepoFromMavenOpts(mavenOpts, env = process.env) {
2897
2796
  const match = mavenOpts.match(/-Dmaven\.repo\.local=(?:"([^"]+)"|(\S+))/);
2898
2797
  const raw = match?.[1]?.trim() || match?.[2]?.trim();
@@ -2907,9 +2806,9 @@ function readMavenLocalRepoFromEnv(env = process.env) {
2907
2806
  }
2908
2807
  const mavenOpts = readEnvVar(env, "MAVEN_OPTS")?.trim();
2909
2808
  if (mavenOpts) {
2910
- const path13 = readMavenLocalRepoFromMavenOpts(mavenOpts, env);
2911
- if (path13) {
2912
- return { path: path13, key: "MAVEN_OPTS" };
2809
+ const path19 = readMavenLocalRepoFromMavenOpts(mavenOpts, env);
2810
+ if (path19) {
2811
+ return { path: path19, key: "MAVEN_OPTS" };
2913
2812
  }
2914
2813
  }
2915
2814
  return null;
@@ -2956,6 +2855,18 @@ function resolveMavenLocalRepoWithSource() {
2956
2855
  sourceDetail: "~/.m2/repository"
2957
2856
  };
2958
2857
  }
2858
+
2859
+ // src/commands/deploy/internal/config/wisdom-config.ts
2860
+ function resolveWisdomDeployFromApmConfig(cfg) {
2861
+ const w = cfg.wisdomDeploy ?? {};
2862
+ return {
2863
+ host: req(w.host, "host", "wisdomDeploy").trim(),
2864
+ port: reqPositiveInt(w.port, "port", "wisdomDeploy"),
2865
+ username: req(w.username, "username", "wisdomDeploy").trim(),
2866
+ password: req(w.password, "password", "wisdomDeploy").trim(),
2867
+ remotePath: req(w.remotePath, "remotePath", "wisdomDeploy").trim()
2868
+ };
2869
+ }
2959
2870
  function resolveWisdomDeployMode(raw) {
2960
2871
  if (raw === void 0 || raw === null || raw === "") {
2961
2872
  return "default";
@@ -2969,14 +2880,27 @@ function resolveWisdomDeployMode(raw) {
2969
2880
  );
2970
2881
  process.exit(1);
2971
2882
  }
2883
+ function posixDirname(p) {
2884
+ const normalized = p.replace(/\\/g, "/");
2885
+ const idx = normalized.lastIndexOf("/");
2886
+ if (idx <= 0) {
2887
+ return normalized.startsWith("/") ? "/" : ".";
2888
+ }
2889
+ return normalized.slice(0, idx);
2890
+ }
2891
+ function posixBasename(p) {
2892
+ const normalized = p.replace(/\\/g, "/");
2893
+ const idx = normalized.lastIndexOf("/");
2894
+ return idx >= 0 ? normalized.slice(idx + 1) : normalized;
2895
+ }
2972
2896
  function resolveWisdomBackendDeployFromApmConfig(cfg) {
2973
2897
  const projectName = reqTopLevelName(cfg);
2974
2898
  const w = cfg.wisdomDeploy ?? {};
2975
2899
  const h = cfg.healthCheck ?? {};
2976
- const jarPath = reqWb(w.jarPath, "jarPath").trim();
2900
+ const jarPath = req(w.jarPath, "jarPath", "wisdomDeploy").trim();
2977
2901
  const remoteAppDir = posixDirname(jarPath);
2978
- const healthPort = Number(reqHc(h.port, "port"));
2979
- const healthTimeout = Number(reqHc(h.timeout, "timeout"));
2902
+ const healthPort = Number(req(h.port, "port", "healthCheck"));
2903
+ const healthTimeout = Number(req(h.timeout, "timeout", "healthCheck"));
2980
2904
  if (!Number.isFinite(healthPort) || !Number.isInteger(healthPort) || healthPort < 1) {
2981
2905
  console.error("apm.config.json \u4E2D healthCheck.port \u987B\u4E3A\u6B63\u6574\u6570");
2982
2906
  process.exit(1);
@@ -2988,11 +2912,11 @@ function resolveWisdomBackendDeployFromApmConfig(cfg) {
2988
2912
  const mavenLocalRepo = resolveMavenLocalRepoWithSource();
2989
2913
  return {
2990
2914
  projectName,
2991
- host: reqWd(w.host, "host").trim(),
2992
- port: reqWisdomPositiveInt(w.port, "port"),
2993
- username: reqWd(w.username, "username").trim(),
2994
- password: reqWd(w.password, "password").trim(),
2995
- remoteVueDistDir: reqWd(w.remotePath, "remotePath").trim(),
2915
+ host: req(w.host, "host", "wisdomDeploy").trim(),
2916
+ port: reqPositiveInt(w.port, "port", "wisdomDeploy"),
2917
+ username: req(w.username, "username", "wisdomDeploy").trim(),
2918
+ password: req(w.password, "password", "wisdomDeploy").trim(),
2919
+ remoteVueDistDir: req(w.remotePath, "remotePath", "wisdomDeploy").trim(),
2996
2920
  remoteAppDir,
2997
2921
  remoteLibDir: `${remoteAppDir}/lib`,
2998
2922
  startupJar: posixBasename(jarPath),
@@ -3001,35 +2925,51 @@ function resolveWisdomBackendDeployFromApmConfig(cfg) {
3001
2925
  mavenLocalRepoSource: mavenLocalRepo.source,
3002
2926
  mavenLocalRepoSourceDetail: mavenLocalRepo.sourceDetail,
3003
2927
  healthCheckPort: healthPort,
3004
- healthCheckContext: reqHc(h.context, "context").trim(),
2928
+ healthCheckContext: req(h.context, "context", "healthCheck").trim(),
3005
2929
  healthCheckTimeout: healthTimeout,
3006
2930
  mode: resolveWisdomDeployMode(w.mode)
3007
2931
  };
3008
2932
  }
3009
- function posixDirname(p) {
3010
- const normalized = p.replace(/\\/g, "/");
3011
- const idx = normalized.lastIndexOf("/");
3012
- if (idx <= 0) {
3013
- return normalized.startsWith("/") ? "/" : ".";
2933
+
2934
+ // src/commands/deploy/internal/apm-config.ts
2935
+ function loadApmConfig(options) {
2936
+ const p = resolve4(
2937
+ process.cwd(),
2938
+ options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
2939
+ );
2940
+ if (!existsSync12(p)) {
2941
+ console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
2942
+ process.exit(1);
2943
+ }
2944
+ try {
2945
+ const raw = readFileSync11(p, "utf8");
2946
+ return JSON.parse(raw);
2947
+ } catch (e) {
2948
+ console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
2949
+ process.exit(1);
3014
2950
  }
3015
- return normalized.slice(0, idx);
3016
- }
3017
- function posixBasename(p) {
3018
- const normalized = p.replace(/\\/g, "/");
3019
- const idx = normalized.lastIndexOf("/");
3020
- return idx >= 0 ? normalized.slice(idx + 1) : normalized;
3021
2951
  }
3022
2952
 
3023
2953
  // src/commands/deploy/internal/deploy-hints.ts
2954
+ function isProductionDeployEnv(env) {
2955
+ const normalized = env.trim().toLowerCase();
2956
+ return normalized === "online" || normalized === "production" || normalized === "prod";
2957
+ }
3024
2958
  function formatMissingWisdomDeployLines() {
3025
2959
  return [
3026
2960
  "[apm] \u65E0\u6CD5\u6267\u884C apm deploy\uFF1A\u8BF7\u5728 apm.config.json \u4E2D\u914D\u7F6E wisdomDeploy\uFF08host\u3001remotePath\uFF09"
3027
2961
  ];
3028
2962
  }
3029
2963
  function formatWisdomFrontendBuildNotConfiguredLines(env, packageJsonPath) {
2964
+ if (isProductionDeployEnv(env)) {
2965
+ return [
2966
+ `[apm] \u65E0\u6CD5\u6267\u884C\u524D\u7AEF\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u6216 build \u811A\u672C`,
2967
+ "[apm] \u8BF7\u914D\u7F6E npm run build:online \u6216 npm run build \u540E\u518D\u8BD5"
2968
+ ];
2969
+ }
3030
2970
  return [
3031
2971
  `[apm] \u65E0\u6CD5\u6267\u884C\u524D\u7AEF\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u811A\u672C`,
3032
- "[apm] \u8BF7\u914D\u7F6E npm run build:test / build:online \u540E\u518D\u8BD5"
2972
+ "[apm] \u8BF7\u914D\u7F6E npm run build:test \u540E\u518D\u8BD5"
3033
2973
  ];
3034
2974
  }
3035
2975
 
@@ -3047,7 +2987,7 @@ var DeployExecutionError = class extends Error {
3047
2987
 
3048
2988
  // src/commands/deploy/deploy-debug-log.ts
3049
2989
  import { spawnSync as spawnSync4 } from "node:child_process";
3050
- import { existsSync as existsSync14 } from "node:fs";
2990
+ import { existsSync as existsSync15 } from "node:fs";
3051
2991
  import { dirname as dirname5, join as join16 } from "node:path";
3052
2992
 
3053
2993
  // src/commands/deploy/internal/deploy-artifact-minio.ts
@@ -3153,14 +3093,14 @@ var MinioClient = class {
3153
3093
  async deleteObjectsByPrefix(bucket, prefix) {
3154
3094
  const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
3155
3095
  const keys = [];
3156
- await new Promise((resolve5, reject) => {
3096
+ await new Promise((resolve6, reject) => {
3157
3097
  objectsStream.on("data", (obj) => {
3158
3098
  if (obj.name) {
3159
3099
  keys.push(obj.name);
3160
3100
  }
3161
3101
  });
3162
3102
  objectsStream.on("error", reject);
3163
- objectsStream.on("end", resolve5);
3103
+ objectsStream.on("end", resolve6);
3164
3104
  });
3165
3105
  const chunkSize = 500;
3166
3106
  for (let i = 0; i < keys.length; i += chunkSize) {
@@ -3306,15 +3246,15 @@ import { dirname as dirname4 } from "node:path";
3306
3246
 
3307
3247
  // src/commands/daemon.ts
3308
3248
  import { spawnSync as spawnSync2 } from "child_process";
3309
- import { setTimeout as delay2 } from "node:timers/promises";
3310
- import { existsSync as existsSync13, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
3249
+ import { setTimeout as delay } from "node:timers/promises";
3250
+ import { existsSync as existsSync14, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
3311
3251
  import { join as join15 } from "path";
3312
3252
 
3313
3253
  // src/commands/connect-lock.ts
3314
3254
  import {
3315
- existsSync as existsSync12,
3255
+ existsSync as existsSync13,
3316
3256
  mkdirSync as mkdirSync5,
3317
- readFileSync as readFileSync11,
3257
+ readFileSync as readFileSync12,
3318
3258
  unlinkSync,
3319
3259
  writeFileSync as writeFileSync10
3320
3260
  } from "fs";
@@ -3346,9 +3286,9 @@ function waitForPm2LockHandoff(timeoutMs = 5e3) {
3346
3286
  }
3347
3287
  }
3348
3288
  function readConnectLock() {
3349
- if (!existsSync12(CONNECT_LOCK_PATH)) return null;
3289
+ if (!existsSync13(CONNECT_LOCK_PATH)) return null;
3350
3290
  try {
3351
- const raw = readFileSync11(CONNECT_LOCK_PATH, "utf8");
3291
+ const raw = readFileSync12(CONNECT_LOCK_PATH, "utf8");
3352
3292
  const parsed = JSON.parse(raw);
3353
3293
  if (typeof parsed.pid !== "number" || parsed.mode !== "foreground" && parsed.mode !== "pm2" || typeof parsed.startedAt !== "string") {
3354
3294
  return null;
@@ -3405,7 +3345,7 @@ function releaseConnectLock() {
3405
3345
  }
3406
3346
  function forceReleaseConnectLock() {
3407
3347
  try {
3408
- if (existsSync12(CONNECT_LOCK_PATH)) {
3348
+ if (existsSync13(CONNECT_LOCK_PATH)) {
3409
3349
  unlinkSync(CONNECT_LOCK_PATH);
3410
3350
  }
3411
3351
  } catch {
@@ -3555,14 +3495,14 @@ function resolvePm2FromNpmRoot() {
3555
3495
  if (!root) return null;
3556
3496
  for (const rel of ["pm2/bin/pm2", "pm2/bin/pm2.js"]) {
3557
3497
  const candidate = join15(root, ...rel.split("/"));
3558
- if (existsSync13(candidate)) {
3498
+ if (existsSync14(candidate)) {
3559
3499
  return candidate;
3560
3500
  }
3561
3501
  }
3562
3502
  return null;
3563
3503
  }
3564
- function isPm2NodeScript(path13) {
3565
- return path13.endsWith(".js") || /[\\/]pm2[\\/]bin[\\/]pm2$/.test(path13);
3504
+ function isPm2NodeScript(path19) {
3505
+ return path19.endsWith(".js") || /[\\/]pm2[\\/]bin[\\/]pm2$/.test(path19);
3566
3506
  }
3567
3507
  function buildPm2SpawnTarget(binPath) {
3568
3508
  if (isPm2NodeScript(binPath)) {
@@ -3592,7 +3532,7 @@ function spawnPm2At(binPath, args, options = {}) {
3592
3532
  return spawnPm2Target(buildPm2SpawnTarget(binPath), args, options);
3593
3533
  }
3594
3534
  function verifyPm2Bin(pm2Bin) {
3595
- if (!pm2Bin.trim() || !existsSync13(pm2Bin)) {
3535
+ if (!pm2Bin.trim() || !existsSync14(pm2Bin)) {
3596
3536
  return false;
3597
3537
  }
3598
3538
  const result = spawnPm2At(pm2Bin, ["--version"], {
@@ -3731,7 +3671,7 @@ function ensureGlobalPm2(options) {
3731
3671
  }
3732
3672
  function resolveApmEntryPath(entryArg = process.argv[1]) {
3733
3673
  const fromArgv = entryArg?.trim();
3734
- if (fromArgv && existsSync13(fromArgv)) {
3674
+ if (fromArgv && existsSync14(fromArgv)) {
3735
3675
  return fromArgv;
3736
3676
  }
3737
3677
  const npmResult = spawnSync2(useNpmShell2 ? "npm.cmd" : "npm", ["root", "-g"], {
@@ -3743,7 +3683,7 @@ function resolveApmEntryPath(entryArg = process.argv[1]) {
3743
3683
  const globalRoot = npmResult.stdout?.toString().trim();
3744
3684
  if (globalRoot) {
3745
3685
  const candidate = join15(globalRoot, CLI_PACKAGE_NAME, "dist", "index.js");
3746
- if (existsSync13(candidate)) {
3686
+ if (existsSync14(candidate)) {
3747
3687
  return candidate;
3748
3688
  }
3749
3689
  }
@@ -3934,7 +3874,7 @@ function writeEcosystemFile(options) {
3934
3874
  formatConnectPm2EcosystemFile(ecosystem),
3935
3875
  "utf8"
3936
3876
  );
3937
- if (existsSync13(LEGACY_PM2_ECOSYSTEM_PATH)) {
3877
+ if (existsSync14(LEGACY_PM2_ECOSYSTEM_PATH)) {
3938
3878
  try {
3939
3879
  unlinkSync2(LEGACY_PM2_ECOSYSTEM_PATH);
3940
3880
  } catch {
@@ -3963,7 +3903,7 @@ async function runDaemonStart(options) {
3963
3903
  const cfg = await prepareEcosystem(options.server);
3964
3904
  removePm2ConnectProcesses();
3965
3905
  runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
3966
- await delay2(1e3);
3906
+ await delay(1e3);
3967
3907
  if (!isPm2ConnectOnline()) {
3968
3908
  console.error(
3969
3909
  `[apm] ${PM2_APP_NAME} \u542F\u52A8\u540E\u672A\u5904\u4E8E online \u72B6\u6001\uFF0C\u8BF7\u6267\u884C: apm daemon logs -n 200`
@@ -3996,7 +3936,7 @@ async function runDaemonStop() {
3996
3936
  });
3997
3937
  for (let i = 0; i < 10; i += 1) {
3998
3938
  if (!isPm2ConnectOnline()) break;
3999
- await delay2(500);
3939
+ await delay(500);
4000
3940
  }
4001
3941
  if (isPm2ConnectOnline()) {
4002
3942
  console.log(`[apm] \u4F18\u96C5\u505C\u6B62\u8D85\u65F6\uFF0C\u5F3A\u5236\u79FB\u9664 ${PM2_APP_NAME}\u2026`);
@@ -4231,12 +4171,12 @@ function logExecuteDeployContext(input) {
4231
4171
  `cwdMatchProcess=${input.cwd === input.processCwd ? "yes" : "no"} (connect \u901A\u5E38\u4E3A no)`
4232
4172
  );
4233
4173
  logLine(
4234
- `apm.config=${input.apmConfigPath} exists=${existsSync14(
4174
+ `apm.config=${input.apmConfigPath} exists=${existsSync15(
4235
4175
  input.apmConfigPath
4236
4176
  )}`
4237
4177
  );
4238
4178
  logLine(
4239
- `package.json=${packageJsonPath} exists=${existsSync14(packageJsonPath)}`
4179
+ `package.json=${packageJsonPath} exists=${existsSync15(packageJsonPath)}`
4240
4180
  );
4241
4181
  logLine(
4242
4182
  `flags captureOutput=${input.captureOutput} packOnly=${Boolean(
@@ -4292,18 +4232,64 @@ function logWisdomFrontendDeployContext(input) {
4292
4232
  logLine(
4293
4233
  `buildKey=build:${input.env} buildCmd=${input.buildCmd ?? "(missing)"}`
4294
4234
  );
4295
- logLine(`distDir=${input.distDir} exists=${existsSync14(input.distDir)}`);
4235
+ logLine(`distDir=${input.distDir} exists=${existsSync15(input.distDir)}`);
4296
4236
  logLine(
4297
4237
  `packOnly=${input.packOnly} archiveDeployArtifact=${input.archiveDeployArtifact}`
4298
4238
  );
4299
4239
  }
4300
4240
 
4301
4241
  // src/commands/deploy/internal/wisdom-deploy.ts
4302
- import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync7 } from "node:fs";
4303
- import path4 from "node:path";
4242
+ import { existsSync as existsSync19, readFileSync as readFileSync15, statSync as statSync9 } from "node:fs";
4243
+ import path10 from "node:path";
4304
4244
 
4305
4245
  // src/commands/deploy/deploy-shell-run.ts
4306
4246
  import { spawnSync as spawnSync5 } from "node:child_process";
4247
+
4248
+ // src/commands/deploy/deploy-log-utils.ts
4249
+ import { setTimeout as delay2 } from "node:timers/promises";
4250
+ var DEPLOY_SPAWN_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
4251
+ var DEPLOY_LOG_SYNC_MAX_CHUNK_BYTES = 4 * 1024 * 1024;
4252
+ var DEPLOY_LOG_SYNC_MAX_ATTEMPTS = 3;
4253
+ async function retryDeployLogSync(fn, attempts = DEPLOY_LOG_SYNC_MAX_ATTEMPTS) {
4254
+ let lastError;
4255
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
4256
+ try {
4257
+ return await fn();
4258
+ } catch (error) {
4259
+ lastError = error;
4260
+ if (attempt < attempts) {
4261
+ await delay2(1e3 * attempt);
4262
+ }
4263
+ }
4264
+ }
4265
+ throw lastError;
4266
+ }
4267
+ var retryDeployStatusComplete = retryDeployLogSync;
4268
+ function splitUtf8StringByMaxBytes(value, maxBytes) {
4269
+ if (maxBytes <= 0) {
4270
+ throw new Error("maxBytes must be positive");
4271
+ }
4272
+ const bytes = Buffer.from(value, "utf8");
4273
+ if (bytes.length <= maxBytes) {
4274
+ return [value];
4275
+ }
4276
+ const chunks = [];
4277
+ let offset = 0;
4278
+ while (offset < bytes.length) {
4279
+ let end = Math.min(offset + maxBytes, bytes.length);
4280
+ while (end > offset && (bytes[end] & 192) === 128) {
4281
+ end -= 1;
4282
+ }
4283
+ if (end <= offset) {
4284
+ end = Math.min(offset + maxBytes, bytes.length);
4285
+ }
4286
+ chunks.push(bytes.subarray(offset, end).toString("utf8"));
4287
+ offset = end;
4288
+ }
4289
+ return chunks;
4290
+ }
4291
+
4292
+ // src/commands/deploy/deploy-shell-run.ts
4307
4293
  function runDeployShellCommand(command, cwd, captureOutput) {
4308
4294
  logRunDeployShellContext({ command, cwd, captureOutput });
4309
4295
  const shellEnv = buildDeployShellEnv();
@@ -4346,43 +4332,93 @@ function runDeployShellCommand(command, cwd, captureOutput) {
4346
4332
  return output;
4347
4333
  }
4348
4334
 
4349
- // src/commands/deploy/internal/wisdom-backend-deploy.ts
4335
+ // src/commands/deploy/internal/wisdom-backend/index.ts
4336
+ import path9 from "node:path";
4337
+
4338
+ // src/commands/deploy/internal/wisdom-backend/jar-incremental.ts
4350
4339
  import {
4351
- existsSync as existsSync15,
4352
- mkdirSync as mkdirSync7,
4340
+ mkdirSync as mkdirSync8,
4353
4341
  readdirSync as readdirSync5,
4354
- readFileSync as readFileSync12,
4355
- statSync as statSync6,
4356
- writeFileSync as writeFileSync12
4342
+ readFileSync as readFileSync14,
4343
+ statSync as statSync7,
4344
+ writeFileSync as writeFileSync13
4357
4345
  } from "node:fs";
4358
- import { spawnSync as spawnSync6 } from "node:child_process";
4359
- import path3 from "node:path";
4360
- import { Client as Client2 } from "ssh2";
4346
+ import path6 from "node:path";
4361
4347
  import JSZip2 from "jszip";
4362
- import SftpClient2 from "ssh2-sftp-client";
4363
4348
 
4364
- // src/commands/deploy/internal/wisdom-sftp.ts
4365
- import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
4349
+ // src/commands/deploy/internal/wisdom-backend/manifest.ts
4350
+ import {
4351
+ existsSync as existsSync16,
4352
+ mkdirSync as mkdirSync7,
4353
+ readFileSync as readFileSync13,
4354
+ statSync as statSync6,
4355
+ writeFileSync as writeFileSync12
4356
+ } from "node:fs";
4366
4357
  import path2 from "node:path";
4367
- import JSZip from "jszip";
4368
- import SftpClient from "ssh2-sftp-client";
4369
- async function addDirToZip(dir, zipFolder) {
4370
- const entries = await readdir2(dir, { withFileTypes: true });
4371
- for (const entry of entries) {
4372
- const fullPath = path2.join(dir, entry.name);
4373
- if (entry.isDirectory()) {
4374
- const folder = zipFolder.folder(entry.name);
4375
- if (folder) {
4376
- await addDirToZip(fullPath, folder);
4377
- }
4378
- } else {
4379
- const content = await readFile3(fullPath);
4380
- zipFolder.file(entry.name, content);
4381
- }
4358
+ function deployCacheDir() {
4359
+ return path2.join(workspaceApmDir(), "deploy", ".deploy_cache");
4360
+ }
4361
+ function manifestFilePath() {
4362
+ return path2.join(deployCacheDir(), "manifest.json");
4363
+ }
4364
+ function relativeKey(projectRoot, filePath) {
4365
+ return path2.relative(projectRoot, filePath).split(path2.sep).join("/");
4366
+ }
4367
+ function fileSignature(filePath) {
4368
+ const stat2 = statSync6(filePath);
4369
+ return { size: stat2.size, mtime: stat2.mtimeMs / 1e3 };
4370
+ }
4371
+ function loadManifest3() {
4372
+ const manifestPath2 = manifestFilePath();
4373
+ if (!existsSync16(manifestPath2)) {
4374
+ return {};
4382
4375
  }
4376
+ return JSON.parse(readFileSync13(manifestPath2, "utf8"));
4383
4377
  }
4384
- async function zipDirectory(distDir, zipPath) {
4385
- console.error(`\u538B\u7F29\u76EE\u5F55: ${distDir}`);
4378
+ function saveManifest3(manifest) {
4379
+ const dir = deployCacheDir();
4380
+ mkdirSync7(dir, { recursive: true });
4381
+ writeFileSync12(manifestFilePath(), JSON.stringify(manifest, null, 2), "utf8");
4382
+ }
4383
+ function updateManifestEntries(manifest, entries, projectRoot) {
4384
+ for (const entry of entries) {
4385
+ manifest[relativeKey(projectRoot, entry.path)] = fileSignature(entry.path);
4386
+ }
4387
+ return manifest;
4388
+ }
4389
+ function deployCacheDirectory() {
4390
+ return deployCacheDir();
4391
+ }
4392
+
4393
+ // src/commands/deploy/internal/wisdom-backend/internal-utils.ts
4394
+ import path5 from "node:path";
4395
+
4396
+ // src/commands/deploy/internal/wisdom-sftp.ts
4397
+ import { unlink as unlink2 } from "node:fs/promises";
4398
+ import path4 from "node:path";
4399
+ import SftpClient from "ssh2-sftp-client";
4400
+
4401
+ // src/commands/deploy/internal/artifact-packaging.ts
4402
+ import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
4403
+ import path3 from "node:path";
4404
+ import JSZip from "jszip";
4405
+ async function addDirToZip(dir, zipFolder) {
4406
+ const entries = await readdir2(dir, { withFileTypes: true });
4407
+ for (const entry of entries) {
4408
+ const fullPath = path3.join(dir, entry.name);
4409
+ if (entry.isDirectory()) {
4410
+ const folder = zipFolder.folder(entry.name);
4411
+ if (folder) {
4412
+ await addDirToZip(fullPath, folder);
4413
+ }
4414
+ } else {
4415
+ const content = await readFile3(fullPath);
4416
+ zipFolder.file(entry.name, content);
4417
+ }
4418
+ }
4419
+ }
4420
+ async function zipDirectory(distDir, zipPath) {
4421
+ console.error(`\u538B\u7F29\u76EE\u5F55: ${distDir}`);
4386
4422
  const zip = new JSZip();
4387
4423
  await addDirToZip(distDir, zip);
4388
4424
  const content = await zip.generateAsync({
@@ -4395,6 +4431,65 @@ async function zipDirectory(distDir, zipPath) {
4395
4431
  console.error(`\u5DF2\u751F\u6210: ${zipPath} (${sizeMb} MB)`);
4396
4432
  return content.length;
4397
4433
  }
4434
+ function resolveProjectNameForDeploy(cfg, cwd, options) {
4435
+ const name = (cfg.name ?? "").trim();
4436
+ if (options?.requireName && !name) {
4437
+ throw new DeployExecutionError(
4438
+ "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09",
4439
+ 1
4440
+ );
4441
+ }
4442
+ if (name) {
4443
+ return name;
4444
+ }
4445
+ return path3.basename(cwd);
4446
+ }
4447
+ function resolveArtifactNamePrefix(cfg) {
4448
+ const nameRaw = resolveProjectNameForDeploy(cfg, process.cwd(), {
4449
+ requireName: true
4450
+ });
4451
+ if (nameRaw.includes(":")) {
4452
+ throw new DeployExecutionError("apm.config.json \u7684 name \u4E0D\u80FD\u5305\u542B ':'", 1);
4453
+ }
4454
+ try {
4455
+ return sanitizeRelativePath(nameRaw.replace(/\\/g, "/"));
4456
+ } catch {
4457
+ throw new DeployExecutionError(
4458
+ "apm.config.json \u7684 name \u975E\u6CD5\uFF08\u8DEF\u5F84\u7247\u6BB5\u4E0D\u80FD\u4E3A . \u6216 ..\uFF09",
4459
+ 1
4460
+ );
4461
+ }
4462
+ }
4463
+ async function packDirectoryWithMinioArchive(input) {
4464
+ const resolvedZipPath = path3.resolve(input.zipPath);
4465
+ let zipSizeBytes = 0;
4466
+ let artifactUploaded = false;
4467
+ try {
4468
+ zipSizeBytes = await zipDirectory(input.localDir, resolvedZipPath);
4469
+ if (input.skipMessage) {
4470
+ console.error(input.skipMessage);
4471
+ }
4472
+ const artifact = await uploadDeployArtifactZip({
4473
+ zipPath: resolvedZipPath,
4474
+ projectName: input.projectName,
4475
+ kind: input.kind,
4476
+ uploadWithoutRunId: input.uploadWithoutRunId
4477
+ });
4478
+ artifactUploaded = artifact !== null;
4479
+ if (artifactUploaded && input.successMessage) {
4480
+ console.error(input.successMessage);
4481
+ }
4482
+ return { zipSizeBytes, artifactUploaded };
4483
+ } finally {
4484
+ try {
4485
+ await unlink(resolvedZipPath);
4486
+ console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
4487
+ } catch {
4488
+ }
4489
+ }
4490
+ }
4491
+
4492
+ // src/commands/deploy/internal/wisdom-sftp.ts
4398
4493
  var SFTP_UPLOAD_MAX_ATTEMPTS = 3;
4399
4494
  var SFTP_FAST_PUT_OPTIONS = {
4400
4495
  chunkSize: 64 * 1024,
@@ -4413,7 +4508,7 @@ function buildSftpConnectOptions(settings) {
4413
4508
  };
4414
4509
  }
4415
4510
  async function sleep(ms) {
4416
- await new Promise((resolve5) => setTimeout(resolve5, ms));
4511
+ await new Promise((resolve6) => setTimeout(resolve6, ms));
4417
4512
  }
4418
4513
  async function uploadZipWithRetry(settings, localZip, remoteZipPath) {
4419
4514
  let lastError;
@@ -4457,7 +4552,7 @@ async function ensureRemoteDir(sftp, dir) {
4457
4552
  }
4458
4553
  }
4459
4554
  function execCommand(client, command) {
4460
- return new Promise((resolve5, reject) => {
4555
+ return new Promise((resolve6, reject) => {
4461
4556
  client.exec(command, (err, stream) => {
4462
4557
  if (err) return reject(err);
4463
4558
  let stdout = "";
@@ -4467,7 +4562,7 @@ function execCommand(client, command) {
4467
4562
  reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
4468
4563
  return;
4469
4564
  }
4470
- resolve5(stdout);
4565
+ resolve6(stdout);
4471
4566
  }).on("data", (data) => {
4472
4567
  stdout += data.toString();
4473
4568
  });
@@ -4534,8 +4629,8 @@ function resolveDeployArtifactUpload(input) {
4534
4629
  return { upload: false, uploadWithoutRunId: false };
4535
4630
  }
4536
4631
  async function runWisdomSftpDeploy(params) {
4537
- const zipPath = path2.join(params.localDir, "..", ".deploy-sftp-dist.zip");
4538
- const resolvedZipPath = path2.resolve(zipPath);
4632
+ const zipPath = path4.join(params.localDir, "..", ".deploy-sftp-dist.zip");
4633
+ const resolvedZipPath = path4.resolve(zipPath);
4539
4634
  const packOnly = Boolean(params.packOnly);
4540
4635
  const archiveDeployArtifact = Boolean(params.archiveDeployArtifact);
4541
4636
  const deploymentRunId = resolveDeploymentRunIdFromEnv();
@@ -4546,38 +4641,44 @@ async function runWisdomSftpDeploy(params) {
4546
4641
  });
4547
4642
  let zipSizeBytes = 0;
4548
4643
  let artifactUploaded = false;
4549
- try {
4550
- zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
4551
- if (!packOnly) {
4644
+ if (packOnly && artifactUpload.upload) {
4645
+ const packed = await packDirectoryWithMinioArchive({
4646
+ localDir: params.localDir,
4647
+ zipPath: resolvedZipPath,
4648
+ projectName: params.projectName,
4649
+ kind: "frontend",
4650
+ uploadWithoutRunId: artifactUpload.uploadWithoutRunId,
4651
+ skipMessage: "[apm] \u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u8DF3\u8FC7 SFTP \u8FDC\u7A0B\u4E0A\u4F20",
4652
+ successMessage: "\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09"
4653
+ });
4654
+ zipSizeBytes = packed.zipSizeBytes;
4655
+ artifactUploaded = packed.artifactUploaded;
4656
+ } else {
4657
+ try {
4658
+ zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
4552
4659
  await uploadAndMaybeExtract(
4553
4660
  params.settings,
4554
4661
  resolvedZipPath,
4555
4662
  params.extract
4556
4663
  );
4557
- } else {
4558
- console.error("[apm] \u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u8DF3\u8FC7 SFTP \u8FDC\u7A0B\u4E0A\u4F20");
4559
- }
4560
- if (artifactUpload.upload) {
4561
- const artifact = await uploadDeployArtifactZip({
4562
- zipPath: resolvedZipPath,
4563
- projectName: params.projectName,
4564
- kind: "frontend",
4565
- uploadWithoutRunId: artifactUpload.uploadWithoutRunId
4566
- });
4567
- artifactUploaded = artifact !== null;
4568
- }
4569
- if (artifactUploaded) {
4570
- if (packOnly) {
4571
- console.error("\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09");
4572
- } else {
4664
+ if (artifactUpload.upload) {
4665
+ const artifact = await uploadDeployArtifactZip({
4666
+ zipPath: resolvedZipPath,
4667
+ projectName: params.projectName,
4668
+ kind: "frontend",
4669
+ uploadWithoutRunId: artifactUpload.uploadWithoutRunId
4670
+ });
4671
+ artifactUploaded = artifact !== null;
4672
+ }
4673
+ if (artifactUploaded) {
4573
4674
  console.error("[apm] SFTP \u90E8\u7F72\u5B8C\u6210\uFF0C\u90E8\u7F72\u4EA7\u7269\u5DF2\u5F52\u6863 MinIO");
4574
4675
  }
4575
- }
4576
- } finally {
4577
- try {
4578
- await unlink(resolvedZipPath);
4579
- console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
4580
- } catch {
4676
+ } finally {
4677
+ try {
4678
+ await unlink2(resolvedZipPath);
4679
+ console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
4680
+ } catch {
4681
+ }
4581
4682
  }
4582
4683
  }
4583
4684
  return {
@@ -4592,7 +4693,7 @@ async function runWisdomSftpDeploy(params) {
4592
4693
  };
4593
4694
  }
4594
4695
 
4595
- // src/commands/deploy/internal/wisdom-backend-deploy.ts
4696
+ // src/commands/deploy/internal/wisdom-backend/internal-utils.ts
4596
4697
  var SPRINGBOOT_JAVA_OPTS = "-XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -Xms512M -Xmx1G";
4597
4698
  var MAVEN_MODULE = "jeecg-module-system/jeecg-system-start";
4598
4699
  var MAVEN_PROFILE = "dev";
@@ -4605,11 +4706,11 @@ function log(message) {
4605
4706
  }
4606
4707
  function fail(message) {
4607
4708
  log(`ERROR: ${message}`);
4608
- process.exit(1);
4709
+ throw new DeployExecutionError(message, 1);
4609
4710
  }
4610
4711
  function expandPath(pathStr) {
4611
4712
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
4612
- return path3.resolve(pathStr.replace(/^~(?=\/|\\|$)/, home));
4713
+ return path5.resolve(pathStr.replace(/^~(?=\/|\\|$)/, home));
4613
4714
  }
4614
4715
  function quoteForShell(value) {
4615
4716
  if (process.platform === "win32") {
@@ -4623,34 +4724,14 @@ function formatMavenLocalRepoArg(repoPath) {
4623
4724
  }
4624
4725
  return `-Dmaven.repo.local=${repoPath}`;
4625
4726
  }
4626
- function deployCacheDir() {
4627
- return path3.join(workspaceApmDir(), "deploy", ".deploy_cache");
4628
- }
4629
- function manifestFilePath() {
4630
- return path3.join(deployCacheDir(), "manifest.json");
4631
- }
4632
4727
  function getTargetDir(projectRoot) {
4633
- return path3.join(projectRoot, MAVEN_MODULE, "target");
4634
- }
4635
- function relativeKey(projectRoot, filePath) {
4636
- return path3.relative(projectRoot, filePath).split(path3.sep).join("/");
4637
- }
4638
- function fileSignature(filePath) {
4639
- const stat2 = statSync6(filePath);
4640
- return { size: stat2.size, mtime: stat2.mtimeMs / 1e3 };
4641
- }
4642
- function loadManifest3() {
4643
- const manifestPath2 = manifestFilePath();
4644
- if (!existsSync15(manifestPath2)) {
4645
- return {};
4646
- }
4647
- return JSON.parse(readFileSync12(manifestPath2, "utf8"));
4728
+ return path5.join(projectRoot, MAVEN_MODULE, "target");
4648
4729
  }
4649
- function saveManifest3(manifest) {
4650
- const dir = deployCacheDir();
4651
- mkdirSync7(dir, { recursive: true });
4652
- writeFileSync12(manifestFilePath(), JSON.stringify(manifest, null, 2), "utf8");
4730
+ function stripAnsi(text) {
4731
+ return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
4653
4732
  }
4733
+
4734
+ // src/commands/deploy/internal/wisdom-backend/jar-incremental.ts
4654
4735
  function isProjectLibJar(jarName) {
4655
4736
  return jarName.startsWith("jeecg-");
4656
4737
  }
@@ -4658,12 +4739,12 @@ function shouldUploadLibFile(localPath, remoteAttr, manifest, projectRoot) {
4658
4739
  if (!remoteAttr) {
4659
4740
  return [false, "\u8FDC\u7A0B\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7"];
4660
4741
  }
4661
- const localSize = statSync6(localPath).size;
4742
+ const localSize = statSync7(localPath).size;
4662
4743
  const remoteSize = remoteAttr.size;
4663
4744
  if (localSize !== remoteSize) {
4664
4745
  return [true, `\u5927\u5C0F\u53D8\u5316 ${remoteSize} -> ${localSize}`];
4665
4746
  }
4666
- if (isProjectLibJar(path3.basename(localPath)) && manifest) {
4747
+ if (isProjectLibJar(path6.basename(localPath)) && manifest) {
4667
4748
  const key = relativeKey(projectRoot, localPath);
4668
4749
  const current = fileSignature(localPath);
4669
4750
  const previous = manifest[key];
@@ -4683,7 +4764,7 @@ function listLibFilesToUpload(localLibDir, remoteStats, projectRoot, manifest =
4683
4764
  const entries = [];
4684
4765
  const jarFiles = readdirSync5(localLibDir).filter((name) => name.endsWith(".jar")).sort();
4685
4766
  for (const jarName of jarFiles) {
4686
- const jarPath = path3.join(localLibDir, jarName);
4767
+ const jarPath = path6.join(localLibDir, jarName);
4687
4768
  const remoteAttr = remoteStats.get(jarName);
4688
4769
  const [shouldUpload, reason] = shouldUploadLibFile(
4689
4770
  jarPath,
@@ -4697,20 +4778,14 @@ function listLibFilesToUpload(localLibDir, remoteStats, projectRoot, manifest =
4697
4778
  }
4698
4779
  return entries;
4699
4780
  }
4700
- function updateManifestEntries(manifest, entries, projectRoot) {
4701
- for (const entry of entries) {
4702
- manifest[relativeKey(projectRoot, entry.path)] = fileSignature(entry.path);
4703
- }
4704
- return manifest;
4705
- }
4706
4781
  async function createUpdatePackage(entries, packageName) {
4707
- const dir = deployCacheDir();
4708
- mkdirSync7(dir, { recursive: true });
4709
- const zipPath = path3.join(dir, packageName);
4710
- log(`\u521B\u5EFA\u66F4\u65B0\u5305: ${path3.basename(zipPath)}\uFF08${entries.length} \u4E2A\u6587\u4EF6\uFF09`);
4782
+ const dir = deployCacheDirectory();
4783
+ mkdirSync8(dir, { recursive: true });
4784
+ const zipPath = path6.join(dir, packageName);
4785
+ log(`\u521B\u5EFA\u66F4\u65B0\u5305: ${path6.basename(zipPath)}\uFF08${entries.length} \u4E2A\u6587\u4EF6\uFF09`);
4711
4786
  const zip = new JSZip2();
4712
4787
  for (const entry of entries) {
4713
- const content = readFileSync12(entry.path);
4788
+ const content = readFileSync14(entry.path);
4714
4789
  zip.file(entry.arcname, content);
4715
4790
  log(` \u6253\u5305: ${entry.arcname} (${entry.reason})`);
4716
4791
  }
@@ -4719,9 +4794,21 @@ async function createUpdatePackage(entries, packageName) {
4719
4794
  compression: "DEFLATE",
4720
4795
  compressionOptions: { level: 6 }
4721
4796
  });
4722
- writeFileSync12(zipPath, buffer);
4797
+ writeFileSync13(zipPath, buffer);
4723
4798
  return zipPath;
4724
4799
  }
4800
+ function listAllLibFilesForArchive(libDir) {
4801
+ return readdirSync5(libDir).filter((name) => name.endsWith(".jar")).sort().map((jarName) => ({
4802
+ path: path6.join(libDir, jarName),
4803
+ arcname: jarName,
4804
+ reason: "\u4EC5\u6253\u5305\u5F52\u6863"
4805
+ }));
4806
+ }
4807
+
4808
+ // src/commands/deploy/internal/wisdom-backend/maven-build.ts
4809
+ import { existsSync as existsSync18, readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
4810
+ import path7 from "node:path";
4811
+ import { spawnSync as spawnSync6 } from "node:child_process";
4725
4812
  function getMvnExecutable() {
4726
4813
  const isWin = process.platform === "win32";
4727
4814
  const candidates = isWin ? ["mvn.cmd", "mvn.bat", "mvn"] : ["mvn"];
@@ -4768,14 +4855,14 @@ function runMavenBuild(projectRoot, mavenLocalRepo, repoSource) {
4768
4855
  }
4769
4856
  function locateLibDir(projectRoot) {
4770
4857
  const targetDir = getTargetDir(projectRoot);
4771
- if (!existsSync15(targetDir)) {
4858
+ if (!existsSync18(targetDir)) {
4772
4859
  fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
4773
4860
  }
4774
- const libDir = path3.join(targetDir, "lib");
4775
- if (!existsSync15(libDir) || !statSync6(libDir).isDirectory()) {
4861
+ const libDir = path7.join(targetDir, "lib");
4862
+ if (!existsSync18(libDir) || !statSync8(libDir).isDirectory()) {
4776
4863
  fail(`lib \u76EE\u5F55\u4E0D\u5B58\u5728: ${libDir}`);
4777
4864
  }
4778
- const libJars = readdirSync5(libDir).filter((name) => name.endsWith(".jar"));
4865
+ const libJars = readdirSync6(libDir).filter((name) => name.endsWith(".jar"));
4779
4866
  if (libJars.length === 0) {
4780
4867
  fail(`lib \u76EE\u5F55\u4E0B\u6CA1\u6709\u4F9D\u8D56 JAR: ${libDir}`);
4781
4868
  }
@@ -4784,124 +4871,24 @@ function locateLibDir(projectRoot) {
4784
4871
  }
4785
4872
  function locateMainJar(projectRoot) {
4786
4873
  const targetDir = getTargetDir(projectRoot);
4787
- if (!existsSync15(targetDir)) {
4874
+ if (!existsSync18(targetDir)) {
4788
4875
  fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
4789
4876
  }
4790
- const jarFiles = readdirSync5(targetDir).filter((name) => name.endsWith(".jar") && !name.endsWith(".jar.original")).map((name) => path3.join(targetDir, name)).sort((a, b) => statSync6(b).mtimeMs - statSync6(a).mtimeMs);
4877
+ const jarFiles = readdirSync6(targetDir).filter((name) => name.endsWith(".jar") && !name.endsWith(".jar.original")).map((name) => path7.join(targetDir, name)).sort((a, b) => statSync8(b).mtimeMs - statSync8(a).mtimeMs);
4791
4878
  if (jarFiles.length === 0) {
4792
4879
  fail(`target \u76EE\u5F55\u4E0B\u6CA1\u6709\u4E3B JAR: ${targetDir}`);
4793
4880
  }
4794
4881
  const mainJar = jarFiles[0];
4795
- log(`\u5B9A\u4F4D\u4E3B JAR \u4EA7\u7269: ${path3.basename(mainJar)}`);
4882
+ log(`\u5B9A\u4F4D\u4E3B JAR \u4EA7\u7269: ${path7.basename(mainJar)}`);
4796
4883
  return mainJar;
4797
4884
  }
4798
- async function connectSsh(config) {
4799
- const client = new Client2();
4800
- log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
4801
- await new Promise((resolve5, reject) => {
4802
- client.on("ready", () => resolve5()).on("error", (err) => reject(err)).connect({
4803
- host: config.host,
4804
- port: config.port,
4805
- username: config.username,
4806
- password: config.password,
4807
- readyTimeout: 3e4,
4808
- tryKeyboard: true
4809
- });
4810
- });
4811
- const sftp = new SftpClient2();
4812
- await sftp.connect({
4813
- host: config.host,
4814
- port: config.port,
4815
- username: config.username,
4816
- password: config.password,
4817
- readyTimeout: 3e4,
4818
- tryKeyboard: true
4819
- });
4820
- return { client, sftp };
4821
- }
4822
- async function closeSsh(conn) {
4823
- try {
4824
- await conn.sftp.end();
4825
- } catch {
4826
- }
4827
- conn.client.end();
4828
- }
4829
- async function getRemoteFileStats(sftp, remoteDir) {
4830
- const stats = /* @__PURE__ */ new Map();
4831
- try {
4832
- const listing = await sftp.list(remoteDir);
4833
- for (const item of listing) {
4834
- if (item.name.endsWith(".jar")) {
4835
- stats.set(item.name, { filename: item.name, size: item.size });
4836
- }
4837
- }
4838
- } catch {
4839
- }
4840
- return stats;
4841
- }
4842
- async function uploadUpdatePackage(sftp, zipPath, config) {
4843
- const remoteDir = config.remoteVueDistDir.replace(/\/$/, "");
4844
- const remotePath = `${remoteDir}/${path3.basename(zipPath)}`;
4845
- log(`\u4E0A\u4F20\u66F4\u65B0\u5305 -> ${remotePath}`);
4846
- try {
4847
- await sftp.fastPut(zipPath, remotePath);
4848
- log("\u66F4\u65B0\u5305\u4E0A\u4F20\u6210\u529F");
4849
- } catch (err) {
4850
- fail(`\u66F4\u65B0\u5305\u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
4851
- }
4852
- return remotePath;
4853
- }
4854
- async function uploadFullJar(sftp, localJarPath, config) {
4855
- const remoteDir = config.remoteAppDir.replace(/\/$/, "");
4856
- const remotePath = `${remoteDir}/${config.startupJar}`;
4857
- log(`\u4E0A\u4F20\u5168\u91CF JAR (${path3.basename(localJarPath)}) -> ${remotePath}`);
4858
- try {
4859
- await sftp.mkdir(remoteDir, true);
4860
- await sftp.fastPut(localJarPath, remotePath);
4861
- log("\u5168\u91CF JAR \u4E0A\u4F20\u6210\u529F");
4862
- } catch (err) {
4863
- fail(`\u5168\u91CF JAR \u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
4864
- }
4865
- }
4866
- async function runRemoteCommand(client, command, options) {
4867
- const check = options?.check ?? true;
4868
- const stream = options?.stream ?? false;
4869
- const label = options?.label ?? "\u8FDC\u7A0B\u547D\u4EE4";
4870
- return new Promise((resolve5, reject) => {
4871
- client.exec(command, (err, execStream) => {
4872
- if (err) {
4873
- reject(err);
4874
- return;
4875
- }
4876
- let out = "";
4877
- let errText = "";
4878
- execStream.on("data", (data) => {
4879
- const text = data.toString();
4880
- out += text;
4881
- if (stream) {
4882
- process.stdout.write(text);
4883
- }
4884
- });
4885
- execStream.stderr.on("data", (data) => {
4886
- errText += data.toString();
4887
- });
4888
- execStream.on("close", (code) => {
4889
- if (stream && out && !out.endsWith("\n")) {
4890
- process.stdout.write("\n");
4891
- }
4892
- if (check && code !== 0) {
4893
- const combined = `${out}
4894
- ${errText}`.trim();
4895
- fail(
4896
- `${label}\u5931\u8D25 (exit ${code})` + (combined ? `
4897
- \u8F93\u51FA: ${combined}` : "")
4898
- );
4899
- }
4900
- resolve5({ exitCode: code, out: out.trim(), err: errText.trim() });
4901
- });
4902
- });
4903
- });
4904
- }
4885
+
4886
+ // src/commands/deploy/internal/wisdom-backend/remote-deploy.ts
4887
+ import path8 from "node:path";
4888
+ import { Client as Client2 } from "ssh2";
4889
+ import SftpClient2 from "ssh2-sftp-client";
4890
+
4891
+ // src/commands/deploy/internal/wisdom-backend/remote-scripts.ts
4905
4892
  function buildExtractUpdatePackageScript(remoteZipPath, remoteLibDir) {
4906
4893
  const quotedZip = shellSingleQuote(remoteZipPath);
4907
4894
  const quotedLib = shellSingleQuote(remoteLibDir);
@@ -4925,39 +4912,6 @@ done < <(find "$TMP" -name '*.jar' -type f -print0)
4925
4912
  echo "UPDATED_COUNT=$updated"
4926
4913
  `.trim();
4927
4914
  }
4928
- async function extractUpdatePackageOnRemote(client, config, remoteZipPath) {
4929
- const script = buildExtractUpdatePackageScript(
4930
- remoteZipPath,
4931
- config.remoteLibDir
4932
- );
4933
- const { out } = await runRemoteCommand(client, script, {
4934
- label: "\u8FDC\u7A0B\u89E3\u538B"
4935
- });
4936
- const match = out.match(/UPDATED_COUNT=(\d+)/);
4937
- if (!match) {
4938
- fail(`\u8FDC\u7A0B\u89E3\u538B\u5931\u8D25\uFF0C\u672A\u83B7\u53D6\u66F4\u65B0\u6570\u91CF
4939
- \u8F93\u51FA: ${out || "(\u7A7A)"}`);
4940
- }
4941
- const updated = Number.parseInt(match[1], 10);
4942
- log(`lib \u89E3\u538B\u5B8C\u6210: \u8986\u76D6 ${updated} \u4E2A`);
4943
- return updated;
4944
- }
4945
- function springbootOutputIndicatesSuccess(action, combined) {
4946
- const lower = combined.toLowerCase();
4947
- if (action === "health") {
4948
- return combined.includes("\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7");
4949
- }
4950
- if (action === "start" || action === "restart") {
4951
- return combined.includes("is starting") || lower.includes("is running");
4952
- }
4953
- if (action === "stop") {
4954
- return combined.includes("is stopping") || lower.includes("not running") || lower.includes("please check it");
4955
- }
4956
- if (action === "status") {
4957
- return lower.includes("running") || lower.includes("not running");
4958
- }
4959
- return true;
4960
- }
4961
4915
  function buildRemoteStatusScript(remoteAppDir, appName) {
4962
4916
  const dir = shellSingleQuote(remoteAppDir);
4963
4917
  const jar = shellSingleQuote(appName);
@@ -5056,6 +5010,150 @@ echo -e "\\033[31m\u5065\u5EB7\u68C0\u67E5\u8D85\u65F6 (\${timeout}s): \${check_
5056
5010
  exit 1
5057
5011
  `.trim();
5058
5012
  }
5013
+ function springbootOutputIndicatesSuccess(action, combined) {
5014
+ const lower = combined.toLowerCase();
5015
+ if (action === "health") {
5016
+ return combined.includes("\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7");
5017
+ }
5018
+ if (action === "start" || action === "restart") {
5019
+ return combined.includes("is starting") || lower.includes("is running");
5020
+ }
5021
+ if (action === "stop") {
5022
+ return combined.includes("is stopping") || lower.includes("not running") || lower.includes("please check it");
5023
+ }
5024
+ if (action === "status") {
5025
+ return lower.includes("running") || lower.includes("not running");
5026
+ }
5027
+ return true;
5028
+ }
5029
+
5030
+ // src/commands/deploy/internal/wisdom-backend/remote-deploy.ts
5031
+ async function connectSsh(config) {
5032
+ const client = new Client2();
5033
+ log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
5034
+ await new Promise((resolve6, reject) => {
5035
+ client.on("ready", () => resolve6()).on("error", (err) => reject(err)).connect({
5036
+ host: config.host,
5037
+ port: config.port,
5038
+ username: config.username,
5039
+ password: config.password,
5040
+ readyTimeout: 3e4,
5041
+ tryKeyboard: true
5042
+ });
5043
+ });
5044
+ const sftp = new SftpClient2();
5045
+ await sftp.connect({
5046
+ host: config.host,
5047
+ port: config.port,
5048
+ username: config.username,
5049
+ password: config.password,
5050
+ readyTimeout: 3e4,
5051
+ tryKeyboard: true
5052
+ });
5053
+ return { client, sftp };
5054
+ }
5055
+ async function closeSsh(conn) {
5056
+ try {
5057
+ await conn.sftp.end();
5058
+ } catch {
5059
+ }
5060
+ conn.client.end();
5061
+ }
5062
+ async function getRemoteFileStats(sftp, remoteDir) {
5063
+ const stats = /* @__PURE__ */ new Map();
5064
+ try {
5065
+ const listing = await sftp.list(remoteDir);
5066
+ for (const item of listing) {
5067
+ if (item.name.endsWith(".jar")) {
5068
+ stats.set(item.name, { filename: item.name, size: item.size });
5069
+ }
5070
+ }
5071
+ } catch {
5072
+ }
5073
+ return stats;
5074
+ }
5075
+ async function uploadUpdatePackage(sftp, zipPath, config) {
5076
+ const remoteDir = config.remoteVueDistDir.replace(/\/$/, "");
5077
+ const remotePath = `${remoteDir}/${path8.basename(zipPath)}`;
5078
+ log(`\u4E0A\u4F20\u66F4\u65B0\u5305 -> ${remotePath}`);
5079
+ try {
5080
+ await sftp.fastPut(zipPath, remotePath);
5081
+ log("\u66F4\u65B0\u5305\u4E0A\u4F20\u6210\u529F");
5082
+ } catch (err) {
5083
+ fail(`\u66F4\u65B0\u5305\u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
5084
+ }
5085
+ return remotePath;
5086
+ }
5087
+ async function uploadFullJar(sftp, localJarPath, config) {
5088
+ const remoteDir = config.remoteAppDir.replace(/\/$/, "");
5089
+ const remotePath = `${remoteDir}/${config.startupJar}`;
5090
+ log(`\u4E0A\u4F20\u5168\u91CF JAR (${path8.basename(localJarPath)}) -> ${remotePath}`);
5091
+ try {
5092
+ await sftp.mkdir(remoteDir, true);
5093
+ await sftp.fastPut(localJarPath, remotePath);
5094
+ log("\u5168\u91CF JAR \u4E0A\u4F20\u6210\u529F");
5095
+ } catch (err) {
5096
+ fail(`\u5168\u91CF JAR \u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
5097
+ }
5098
+ }
5099
+ async function runRemoteCommand(client, command, options) {
5100
+ const check = options?.check ?? true;
5101
+ const stream = options?.stream ?? false;
5102
+ const label = options?.label ?? "\u8FDC\u7A0B\u547D\u4EE4";
5103
+ return new Promise((resolve6, reject) => {
5104
+ client.exec(command, (err, execStream) => {
5105
+ if (err) {
5106
+ reject(err);
5107
+ return;
5108
+ }
5109
+ let out = "";
5110
+ let errText = "";
5111
+ execStream.on("data", (data) => {
5112
+ const text = data.toString();
5113
+ out += text;
5114
+ if (stream) {
5115
+ process.stdout.write(text);
5116
+ }
5117
+ });
5118
+ execStream.stderr.on("data", (data) => {
5119
+ errText += data.toString();
5120
+ });
5121
+ execStream.on("close", (code) => {
5122
+ if (stream && out && !out.endsWith("\n")) {
5123
+ process.stdout.write("\n");
5124
+ }
5125
+ if (check && code !== 0) {
5126
+ const combined = `${out}
5127
+ ${errText}`.trim();
5128
+ fail(
5129
+ `${label}\u5931\u8D25 (exit ${code})` + (combined ? `
5130
+ \u8F93\u51FA: ${combined}` : "")
5131
+ );
5132
+ }
5133
+ resolve6({ exitCode: code, out: out.trim(), err: errText.trim() });
5134
+ });
5135
+ });
5136
+ });
5137
+ }
5138
+ async function extractUpdatePackageOnRemote(client, config, remoteZipPath) {
5139
+ const script = buildExtractUpdatePackageScript(
5140
+ remoteZipPath,
5141
+ config.remoteLibDir
5142
+ );
5143
+ const { out } = await runRemoteCommand(client, script, {
5144
+ label: "\u8FDC\u7A0B\u89E3\u538B"
5145
+ });
5146
+ const match = out.match(/UPDATED_COUNT=(\d+)/);
5147
+ if (!match) {
5148
+ fail(`\u8FDC\u7A0B\u89E3\u538B\u5931\u8D25\uFF0C\u672A\u83B7\u53D6\u66F4\u65B0\u6570\u91CF
5149
+ \u8F93\u51FA: ${out || "(\u7A7A)"}`);
5150
+ }
5151
+ const updated = Number.parseInt(match[1], 10);
5152
+ log(`lib \u89E3\u538B\u5B8C\u6210: \u8986\u76D6 ${updated} \u4E2A`);
5153
+ return updated;
5154
+ }
5155
+
5156
+ // src/commands/deploy/internal/wisdom-backend/health-check.ts
5059
5157
  async function runRemoteServiceScript(client, script, action) {
5060
5158
  const { exitCode, out, err } = await runRemoteCommand(client, script, {
5061
5159
  check: false,
@@ -5081,9 +5179,6 @@ ${combined}`);
5081
5179
  }
5082
5180
  return combined;
5083
5181
  }
5084
- function stripAnsi(text) {
5085
- return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
5086
- }
5087
5182
  async function getRunningJar(client, config) {
5088
5183
  const script = buildRemoteStatusScript(
5089
5184
  config.remoteAppDir,
@@ -5112,19 +5207,14 @@ async function restartRemoteService(client, config) {
5112
5207
  const script = buildRemoteRestartScript(config.remoteAppDir);
5113
5208
  await runRemoteServiceScript(client, script, "restart");
5114
5209
  }
5115
- function listAllLibFilesForArchive(libDir) {
5116
- return readdirSync5(libDir).filter((name) => name.endsWith(".jar")).sort().map((jarName) => ({
5117
- path: path3.join(libDir, jarName),
5118
- arcname: jarName,
5119
- reason: "\u4EC5\u6253\u5305\u5F52\u6863"
5120
- }));
5121
- }
5210
+
5211
+ // src/commands/deploy/internal/wisdom-backend/index.ts
5122
5212
  async function runWisdomBackendDeploy(options) {
5123
- const projectRoot = path3.resolve(options.projectRoot ?? process.cwd());
5213
+ const projectRoot = path9.resolve(options.projectRoot ?? process.cwd());
5124
5214
  const config = options.config;
5125
5215
  const packOnly = Boolean(options.packOnly);
5126
5216
  log(`=== \u81EA\u52A8\u90E8\u7F72: ${config.projectName} ===`);
5127
- log(`\u914D\u7F6E\u6587\u4EF6: ${path3.join(workspaceApmDir(), "apm.config.json")}`);
5217
+ log(`\u914D\u7F6E\u6587\u4EF6: ${path9.join(workspaceApmDir(), "apm.config.json")}`);
5128
5218
  log(`\u9879\u76EE\u6839\u76EE\u5F55: ${projectRoot}`);
5129
5219
  log(
5130
5220
  `\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"}${packOnly ? "\uFF1B\u4EC5\u6253\u5305\uFF08\u4E0D\u4E0A\u4F20\u8FDC\u7A0B\uFF09" : ""}`
@@ -5141,7 +5231,7 @@ async function runWisdomBackendDeploy(options) {
5141
5231
  [
5142
5232
  {
5143
5233
  path: mainJar,
5144
- arcname: path3.basename(mainJar),
5234
+ arcname: path9.basename(mainJar),
5145
5235
  reason: "\u5168\u91CF JAR \u5F52\u6863"
5146
5236
  }
5147
5237
  ],
@@ -5179,7 +5269,7 @@ async function runWisdomBackendDeploy(options) {
5179
5269
  [
5180
5270
  {
5181
5271
  path: mainJar,
5182
- arcname: path3.basename(mainJar),
5272
+ arcname: path9.basename(mainJar),
5183
5273
  reason: "\u5168\u91CF JAR \u5F52\u6863"
5184
5274
  }
5185
5275
  ],
@@ -5263,15 +5353,15 @@ function isWisdomDeployConfigured(cfg) {
5263
5353
  return Boolean(w?.host?.trim() && w?.remotePath?.trim());
5264
5354
  }
5265
5355
  function detectWisdomProjectType(cwd) {
5266
- return existsSync16(path4.join(cwd, "package.json")) ? "frontend" : "backend";
5356
+ return existsSync19(path10.join(cwd, "package.json")) ? "frontend" : "backend";
5267
5357
  }
5268
5358
  function readPackageScripts(cwd) {
5269
- const pkgPath = path4.join(cwd, "package.json");
5270
- if (!existsSync16(pkgPath)) {
5359
+ const pkgPath = path10.join(cwd, "package.json");
5360
+ if (!existsSync19(pkgPath)) {
5271
5361
  return {};
5272
5362
  }
5273
5363
  try {
5274
- const raw = readFileSync13(pkgPath, "utf8");
5364
+ const raw = readFileSync15(pkgPath, "utf8");
5275
5365
  const parsed = JSON.parse(raw);
5276
5366
  return parsed.scripts ?? {};
5277
5367
  } catch {
@@ -5284,20 +5374,23 @@ function resolveFrontendBuildCommand(env, cwd) {
5284
5374
  if (scripts[buildKey]?.trim()) {
5285
5375
  return `npm run build:${env}`;
5286
5376
  }
5377
+ if (isProductionDeployEnv(env) && scripts.build?.trim()) {
5378
+ return "npm run build";
5379
+ }
5287
5380
  return null;
5288
5381
  }
5289
5382
  function resolveFrontendDistDir(cwd) {
5290
5383
  const candidates = ["dist", "apps/web/dist"];
5291
5384
  for (const rel of candidates) {
5292
- const full = path4.join(cwd, rel);
5385
+ const full = path10.join(cwd, rel);
5293
5386
  try {
5294
- if (existsSync16(full) && statSync7(full).isDirectory()) {
5387
+ if (existsSync19(full) && statSync9(full).isDirectory()) {
5295
5388
  return full;
5296
5389
  }
5297
5390
  } catch {
5298
5391
  }
5299
5392
  }
5300
- return path4.join(cwd, "dist");
5393
+ return path10.join(cwd, "dist");
5301
5394
  }
5302
5395
  async function executeWisdomFrontendDeploy(options) {
5303
5396
  const { cwd, cfg, captureOutput, packOnly, archiveDeployArtifact } = options;
@@ -5314,7 +5407,7 @@ async function executeWisdomFrontendDeploy(options) {
5314
5407
  if (!buildCmd) {
5315
5408
  const lines = formatWisdomFrontendBuildNotConfiguredLines(
5316
5409
  options.env,
5317
- path4.join(cwd, "package.json")
5410
+ path10.join(cwd, "package.json")
5318
5411
  );
5319
5412
  throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
5320
5413
  }
@@ -5322,16 +5415,9 @@ async function executeWisdomFrontendDeploy(options) {
5322
5415
  `[apm] Vue\uFF1A${buildCmd}` + (packOnly ? "\uFF08\u4EC5\u6253\u5305\uFF0C\u8DF3\u8FC7 SFTP\uFF09" : " \u2192 SFTP \u4E0A\u4F20\u5E76\u8FDC\u7A0B\u89E3\u538B" + (archiveDeployArtifact ? " \u2192 \u5E73\u53F0\u90E8\u7F72\u4EA7\u7269\u5F52\u6863" : ""))
5323
5416
  );
5324
5417
  runDeployShellCommand(buildCmd, cwd, captureOutput);
5325
- let projectName = (cfg.name ?? "").trim();
5326
- if ((packOnly || archiveDeployArtifact) && !projectName) {
5327
- throw new DeployExecutionError(
5328
- "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09",
5329
- 1
5330
- );
5331
- }
5332
- if (!projectName) {
5333
- projectName = path4.basename(cwd);
5334
- }
5418
+ const projectName = resolveProjectNameForDeploy(cfg, cwd, {
5419
+ requireName: packOnly || archiveDeployArtifact
5420
+ });
5335
5421
  const settings = resolveWisdomDeployFromApmConfig(cfg);
5336
5422
  await runWisdomSftpDeploy({
5337
5423
  localDir: distDir,
@@ -5359,12 +5445,12 @@ async function executeWisdomBackendDeployFlow(options) {
5359
5445
  });
5360
5446
  }
5361
5447
  async function executeWisdomDeploy(options) {
5362
- const cwd = path4.resolve(options.cwd);
5448
+ const cwd = path10.resolve(options.cwd);
5363
5449
  const captureOutput = options.captureOutput ?? false;
5364
5450
  const packOnly = Boolean(options.packOnly);
5365
5451
  const archiveDeployArtifact = Boolean(options.archiveDeployArtifact);
5366
5452
  const projectType = detectWisdomProjectType(cwd);
5367
- const configPath = options.configPath ?? path4.join(workspaceApmDir(cwd), "apm.config.json");
5453
+ const configPath = options.configPath ?? path10.join(workspaceApmDir(cwd), "apm.config.json");
5368
5454
  const cfg = loadApmConfig({ configPath });
5369
5455
  console.error(
5370
5456
  `[apm] ${projectType === "frontend" ? "Vue \u524D\u7AEF" : "Java \u540E\u7AEF"}${packOnly ? "\uFF08\u4EC5\u6253\u5305\uFF09" : ""}`
@@ -5527,7 +5613,7 @@ async function executeDeploy(options) {
5527
5613
  throw new DeployExecutionError("[apm] executeDeploy \u7F3A\u5C11\u5DE5\u4F5C\u76EE\u5F55 cwd", 1);
5528
5614
  }
5529
5615
  const cwd = resolveWorkdirPath(cwdInput);
5530
- const apmConfigPath = options.configPath ?? path5.join(workspaceApmDir(cwd), "apm.config.json");
5616
+ const apmConfigPath = options.configPath ?? path11.join(workspaceApmDir(cwd), "apm.config.json");
5531
5617
  const captureOutput = options.captureOutput ?? false;
5532
5618
  const outputParts = [];
5533
5619
  logExecuteDeployContext({
@@ -5596,11 +5682,36 @@ function printDeployExecutionError(error) {
5596
5682
  console.error(error.message);
5597
5683
  }
5598
5684
 
5599
- // src/commands/connect/deploy-run.ts
5600
- var DEPLOY_LOG_SYNC_INTERVAL_MS = 3e4;
5601
- function resolveDeployCommand(environment, packOnly) {
5602
- return packOnly ? `apm deploy ${environment} --pack-only` : `apm deploy ${environment}`;
5685
+ // src/commands/deploy/platform/deploy-console-capture.ts
5686
+ function captureDeployConsole(logSyncer) {
5687
+ const chunks = [];
5688
+ const appendLog = (line) => {
5689
+ if (!line) return;
5690
+ chunks.push(line);
5691
+ logSyncer.updateLog(chunks.join("\n"));
5692
+ };
5693
+ const originalLog = console.log;
5694
+ const originalError = console.error;
5695
+ console.log = (...args) => {
5696
+ appendLog(args.map(String).join(" "));
5697
+ originalLog.apply(console, args);
5698
+ };
5699
+ console.error = (...args) => {
5700
+ appendLog(args.map(String).join(" "));
5701
+ originalError.apply(console, args);
5702
+ };
5703
+ return {
5704
+ appendLog,
5705
+ restore: () => {
5706
+ console.log = originalLog;
5707
+ console.error = originalError;
5708
+ },
5709
+ getLog: () => chunks.join("\n")
5710
+ };
5603
5711
  }
5712
+
5713
+ // src/commands/deploy/platform/deploy-log-syncer.ts
5714
+ var DEPLOY_LOG_SYNC_INTERVAL_MS = 1e4;
5604
5715
  function logDeploySyncFailure(error) {
5605
5716
  console.error(
5606
5717
  "[apm] deploy log sync failed:",
@@ -5610,7 +5721,9 @@ function logDeploySyncFailure(error) {
5610
5721
  function createDeployLogSyncer(api, deploymentRunId) {
5611
5722
  let lastSyncedLog = "";
5612
5723
  let latestLog = "";
5613
- let timer = null;
5724
+ let lastRunAt = 0;
5725
+ let timer;
5726
+ let syncChain = Promise.resolve();
5614
5727
  const syncDelta = async (delta, append) => {
5615
5728
  const chunks = splitUtf8StringByMaxBytes(
5616
5729
  delta,
@@ -5635,29 +5748,58 @@ function createDeployLogSyncer(api, deploymentRunId) {
5635
5748
  if (!delta) {
5636
5749
  return;
5637
5750
  }
5638
- await syncDelta(delta, lastSyncedLog.length > 0);
5639
- lastSyncedLog = latestLog;
5751
+ await syncDelta(delta, lastSyncedLog.length > 0);
5752
+ lastSyncedLog = latestLog;
5753
+ };
5754
+ const enqueueSync = () => {
5755
+ syncChain = syncChain.then(async () => {
5756
+ try {
5757
+ await syncIfChanged();
5758
+ lastRunAt = Date.now();
5759
+ } catch (error) {
5760
+ logDeploySyncFailure(error);
5761
+ }
5762
+ });
5763
+ };
5764
+ const schedule = () => {
5765
+ const now = Date.now();
5766
+ const elapsed = now - lastRunAt;
5767
+ if (elapsed >= DEPLOY_LOG_SYNC_INTERVAL_MS) {
5768
+ if (timer) {
5769
+ clearTimeout(timer);
5770
+ timer = void 0;
5771
+ }
5772
+ enqueueSync();
5773
+ return;
5774
+ }
5775
+ if (timer) {
5776
+ return;
5777
+ }
5778
+ timer = setTimeout(() => {
5779
+ timer = void 0;
5780
+ enqueueSync();
5781
+ }, DEPLOY_LOG_SYNC_INTERVAL_MS - elapsed);
5782
+ };
5783
+ const stopTimer = () => {
5784
+ if (timer) {
5785
+ clearTimeout(timer);
5786
+ timer = void 0;
5787
+ }
5640
5788
  };
5641
- timer = setInterval(() => {
5642
- void syncIfChanged().catch(logDeploySyncFailure);
5643
- }, DEPLOY_LOG_SYNC_INTERVAL_MS);
5644
5789
  return {
5645
5790
  updateLog(log2) {
5646
5791
  latestLog = log2;
5792
+ schedule();
5647
5793
  },
5648
5794
  async flush() {
5649
- if (timer) {
5650
- clearInterval(timer);
5651
- timer = null;
5652
- }
5795
+ stopTimer();
5796
+ await syncChain;
5653
5797
  await syncIfChanged();
5654
5798
  },
5655
5799
  async flushSafe() {
5656
- if (timer) {
5657
- clearInterval(timer);
5658
- timer = null;
5659
- }
5800
+ stopTimer();
5660
5801
  try {
5802
+ await syncChain;
5661
5803
  await syncIfChanged();
5662
5804
  return true;
5663
5805
  } catch (error) {
@@ -5666,15 +5808,12 @@ function createDeployLogSyncer(api, deploymentRunId) {
5666
5808
  }
5667
5809
  },
5668
5810
  dispose() {
5669
- if (timer) {
5670
- clearInterval(timer);
5671
- timer = null;
5672
- }
5811
+ stopTimer();
5673
5812
  }
5674
5813
  };
5675
5814
  }
5676
5815
  async function finalizeTaskDeployment(api, deploymentRunId, logSyncer, input) {
5677
- const synced = await logSyncer.flushSafe();
5816
+ await logSyncer.flushSafe();
5678
5817
  const payload = {
5679
5818
  id: deploymentRunId,
5680
5819
  status: input.status
@@ -5682,76 +5821,48 @@ async function finalizeTaskDeployment(api, deploymentRunId, logSyncer, input) {
5682
5821
  if (input.error) {
5683
5822
  payload.error = input.error;
5684
5823
  }
5685
- if (!synced) {
5686
- payload.log = truncateDeployLogForComplete(input.fullLog).log;
5687
- }
5688
- await retryDeployLogSync(() => api.cli.completeTaskDeployment(payload));
5824
+ await retryDeployStatusComplete(
5825
+ () => api.cli.completeTaskDeployment(payload)
5826
+ );
5689
5827
  }
5690
- function captureDeployConsole(logSyncer) {
5691
- const chunks = [];
5692
- const appendLog = (line) => {
5693
- if (!line) return;
5694
- chunks.push(line);
5695
- logSyncer.updateLog(chunks.join("\n"));
5696
- };
5697
- const originalLog = console.log;
5698
- const originalError = console.error;
5699
- console.log = (...args) => {
5700
- appendLog(args.map(String).join(" "));
5701
- originalLog.apply(console, args);
5702
- };
5703
- console.error = (...args) => {
5704
- appendLog(args.map(String).join(" "));
5705
- originalError.apply(console, args);
5706
- };
5707
- return {
5708
- appendLog,
5709
- restore: () => {
5710
- console.log = originalLog;
5711
- console.error = originalError;
5712
- },
5713
- getLog: () => chunks.join("\n")
5714
- };
5828
+ async function ensureDeploymentStatusSynced(api, deploymentRunId, logSyncer, outcome) {
5829
+ await finalizeTaskDeployment(api, deploymentRunId, logSyncer, outcome);
5715
5830
  }
5716
- async function handleInboundDeploy(cfg, msg, signal) {
5717
- const api = createApmApiClient(cfg);
5718
- const deploymentRunId = msg.deploymentRunId;
5719
- if (signal.aborted) return;
5720
- await api.cli.updateTaskDeploymentStatus({
5721
- id: deploymentRunId,
5722
- status: "DEPLOYING"
5723
- });
5724
- const workdir = requireRemoteWorkdir(msg.workdir);
5725
- const displayCommand = resolveDeployCommand(msg.environment, msg.packOnly);
5726
- console.log(
5727
- `[apm] deploy start id=${deploymentRunId} env=${msg.environment} cwd=${workdir}`
5831
+
5832
+ // src/commands/deploy/platform/deploy-run-coordinator.ts
5833
+ function logDeployStatusSyncFailure(error) {
5834
+ console.error(
5835
+ "[apm] deploy status sync failed:",
5836
+ error instanceof Error ? error.message : String(error)
5728
5837
  );
5729
- console.log(`[apm] deploy command: ${displayCommand}`);
5838
+ }
5839
+ async function runTrackedDeploy(input) {
5840
+ const { api, deploymentRunId, run } = input;
5841
+ let deploymentStarted = true;
5842
+ let outcome = null;
5843
+ let statusSynced = false;
5844
+ let deployError;
5730
5845
  const logSyncer = createDeployLogSyncer(api, deploymentRunId);
5731
5846
  const previousDeploymentRunId = process.env[APM_DEPLOYMENT_RUN_ID_ENV];
5732
5847
  process.env[APM_DEPLOYMENT_RUN_ID_ENV] = deploymentRunId;
5733
5848
  const capture = captureDeployConsole(logSyncer);
5734
- const deployOptions = {
5735
- env: msg.environment,
5736
- cwd: workdir,
5737
- packOnly: msg.packOnly,
5738
- captureOutput: true,
5739
- archiveDeployArtifact: true,
5740
- deployTrigger: "connect"
5849
+ const ensureStatusSynced = async () => {
5850
+ if (statusSynced || !outcome) {
5851
+ return;
5852
+ }
5853
+ logSyncer.updateLog(capture.getLog());
5854
+ await ensureDeploymentStatusSynced(
5855
+ api,
5856
+ deploymentRunId,
5857
+ logSyncer,
5858
+ outcome
5859
+ );
5860
+ statusSynced = true;
5741
5861
  };
5742
5862
  try {
5743
- if (signal.aborted) return;
5744
- const output = await executeDeploy(deployOptions);
5745
- if (output.trim()) {
5746
- capture.appendLog(output);
5747
- }
5748
- await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
5749
- status: "SUCCESS",
5750
- fullLog: capture.getLog()
5751
- });
5752
- console.log(`[apm] deploy success id=${deploymentRunId}`);
5863
+ outcome = await run(capture.appendLog);
5753
5864
  } catch (error) {
5754
- const deployError = error instanceof DeployExecutionError ? error : new DeployExecutionError(
5865
+ deployError = error instanceof DeployExecutionError ? error : new DeployExecutionError(
5755
5866
  error instanceof Error ? error.message : String(error),
5756
5867
  1
5757
5868
  );
@@ -5760,22 +5871,18 @@ async function handleInboundDeploy(cfg, msg, signal) {
5760
5871
  } else {
5761
5872
  capture.appendLog(deployError.message);
5762
5873
  }
5763
- try {
5764
- await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
5765
- status: "FAILED",
5766
- fullLog: capture.getLog(),
5767
- error: deployError.message
5768
- });
5769
- } catch (finalizeError) {
5770
- console.error(
5771
- `[apm] deploy finalize failed id=${deploymentRunId}:`,
5772
- finalizeError instanceof Error ? finalizeError.message : String(finalizeError)
5773
- );
5774
- }
5775
- console.error(
5776
- `[apm] deploy failed id=${deploymentRunId}: ${deployError.message}`
5777
- );
5874
+ outcome = { status: "FAILED", error: deployError.message };
5778
5875
  } finally {
5876
+ if (deploymentStarted && !statusSynced) {
5877
+ if (!outcome) {
5878
+ outcome = { status: "FAILED", error: "\u90E8\u7F72\u672A\u5B8C\u6210" };
5879
+ }
5880
+ try {
5881
+ await ensureStatusSynced();
5882
+ } catch (error) {
5883
+ logDeployStatusSyncFailure(error);
5884
+ }
5885
+ }
5779
5886
  capture.restore();
5780
5887
  if (previousDeploymentRunId === void 0) {
5781
5888
  delete process.env[APM_DEPLOYMENT_RUN_ID_ENV];
@@ -5784,6 +5891,58 @@ async function handleInboundDeploy(cfg, msg, signal) {
5784
5891
  }
5785
5892
  logSyncer.dispose();
5786
5893
  }
5894
+ return { outcome, error: deployError };
5895
+ }
5896
+
5897
+ // src/commands/connect/deploy-run.ts
5898
+ function resolveDeployCommand(environment, packOnly) {
5899
+ return packOnly ? `apm deploy ${environment} --pack-only` : `apm deploy ${environment}`;
5900
+ }
5901
+ async function handleInboundDeploy(cfg, msg, signal) {
5902
+ if (signal.aborted) return;
5903
+ const api = createApmApiClient(cfg);
5904
+ const deploymentRunId = msg.deploymentRunId;
5905
+ await api.cli.updateTaskDeploymentStatus({
5906
+ id: deploymentRunId,
5907
+ status: "DEPLOYING"
5908
+ });
5909
+ const { error: deployError } = await runTrackedDeploy({
5910
+ api,
5911
+ deploymentRunId,
5912
+ run: async (appendLog) => {
5913
+ const workdir = requireRemoteWorkdir(msg.workdir);
5914
+ const displayCommand = resolveDeployCommand(
5915
+ msg.environment,
5916
+ msg.packOnly
5917
+ );
5918
+ console.log(
5919
+ `[apm] deploy start id=${deploymentRunId} env=${msg.environment} cwd=${workdir}`
5920
+ );
5921
+ console.log(`[apm] deploy command: ${displayCommand}`);
5922
+ if (signal.aborted) {
5923
+ return { status: "FAILED", error: "\u90E8\u7F72\u5DF2\u53D6\u6D88" };
5924
+ }
5925
+ const deployOptions = {
5926
+ env: msg.environment,
5927
+ cwd: workdir,
5928
+ packOnly: msg.packOnly,
5929
+ captureOutput: true,
5930
+ archiveDeployArtifact: true,
5931
+ deployTrigger: "connect"
5932
+ };
5933
+ const output = await executeDeploy(deployOptions);
5934
+ if (output.trim()) {
5935
+ appendLog(output);
5936
+ }
5937
+ console.log(`[apm] deploy success id=${deploymentRunId}`);
5938
+ return { status: "SUCCESS" };
5939
+ }
5940
+ });
5941
+ if (deployError) {
5942
+ console.error(
5943
+ `[apm] deploy failed id=${deploymentRunId}: ${deployError.message}`
5944
+ );
5945
+ }
5787
5946
  }
5788
5947
 
5789
5948
  // src/commands/connect/abort-signal-debug.ts
@@ -6053,17 +6212,17 @@ ${JSON.stringify(event, null, 2)}
6053
6212
  }
6054
6213
 
6055
6214
  // src/commands/connect/agent-session-registry.ts
6056
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "node:fs";
6057
- import { dirname as dirname6, resolve as resolve4 } from "node:path";
6215
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "node:fs";
6216
+ import { dirname as dirname6, resolve as resolve5 } from "node:path";
6058
6217
  function registryPath(workdir, sessionId) {
6059
- return resolve4(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
6218
+ return resolve5(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
6060
6219
  }
6061
- function readRegistry(path13) {
6062
- if (!existsSync17(path13)) {
6220
+ function readRegistry(path19) {
6221
+ if (!existsSync20(path19)) {
6063
6222
  return {};
6064
6223
  }
6065
6224
  try {
6066
- const parsed = JSON.parse(readFileSync14(path13, "utf8"));
6225
+ const parsed = JSON.parse(readFileSync16(path19, "utf8"));
6067
6226
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
6068
6227
  const result = {};
6069
6228
  for (const [key, value] of Object.entries(
@@ -6079,9 +6238,9 @@ function readRegistry(path13) {
6079
6238
  }
6080
6239
  return {};
6081
6240
  }
6082
- function writeRegistry(path13, registry) {
6083
- mkdirSync8(dirname6(path13), { recursive: true });
6084
- writeFileSync13(path13, `${JSON.stringify(registry, null, 2)}
6241
+ function writeRegistry(path19, registry) {
6242
+ mkdirSync9(dirname6(path19), { recursive: true });
6243
+ writeFileSync14(path19, `${JSON.stringify(registry, null, 2)}
6085
6244
  `, "utf8");
6086
6245
  }
6087
6246
  function loadSessionAgentId(workdir, sessionId, user) {
@@ -6089,19 +6248,19 @@ function loadSessionAgentId(workdir, sessionId, user) {
6089
6248
  return registry[user];
6090
6249
  }
6091
6250
  function saveSessionAgentId(workdir, sessionId, user, agentId) {
6092
- const path13 = registryPath(workdir, sessionId);
6093
- const registry = readRegistry(path13);
6251
+ const path19 = registryPath(workdir, sessionId);
6252
+ const registry = readRegistry(path19);
6094
6253
  registry[user] = agentId;
6095
- writeRegistry(path13, registry);
6254
+ writeRegistry(path19, registry);
6096
6255
  }
6097
6256
  function clearSessionAgentId(workdir, sessionId, user) {
6098
- const path13 = registryPath(workdir, sessionId);
6099
- const registry = readRegistry(path13);
6257
+ const path19 = registryPath(workdir, sessionId);
6258
+ const registry = readRegistry(path19);
6100
6259
  if (!(user in registry)) {
6101
6260
  return;
6102
6261
  }
6103
6262
  delete registry[user];
6104
- writeRegistry(path13, registry);
6263
+ writeRegistry(path19, registry);
6105
6264
  }
6106
6265
 
6107
6266
  // src/commands/connect/cursor-message-log.ts
@@ -6531,20 +6690,20 @@ async function ensureMessageHasReply(cfg, sessionId, messageId, fallback) {
6531
6690
  }
6532
6691
 
6533
6692
  // src/commands/connect/cli-version-sync.ts
6534
- import { existsSync as existsSync18, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "fs";
6693
+ import { existsSync as existsSync21, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "fs";
6535
6694
  import { join as join17 } from "path";
6536
6695
  var CLI_VERSION_FILE = ".cli-version.json";
6537
6696
  function manifestPath(apmDir) {
6538
6697
  return join17(apmDir, CLI_VERSION_FILE);
6539
6698
  }
6540
6699
  function loadManifest4(apmDir) {
6541
- const path13 = toFsPath(manifestPath(apmDir));
6542
- if (!existsSync18(path13)) {
6700
+ const path19 = toFsPath(manifestPath(apmDir));
6701
+ if (!existsSync21(path19)) {
6543
6702
  return null;
6544
6703
  }
6545
6704
  try {
6546
6705
  const parsed = JSON.parse(
6547
- readFileSync15(path13, "utf8")
6706
+ readFileSync17(path19, "utf8")
6548
6707
  );
6549
6708
  if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
6550
6709
  return parsed;
@@ -6555,7 +6714,7 @@ function loadManifest4(apmDir) {
6555
6714
  }
6556
6715
  function saveManifest4(apmDir, cliVersion) {
6557
6716
  const manifest = { version: 1, cliVersion };
6558
- writeFileSync14(
6717
+ writeFileSync15(
6559
6718
  toFsPath(manifestPath(apmDir)),
6560
6719
  `${JSON.stringify(manifest, null, 2)}
6561
6720
  `,
@@ -6634,7 +6793,7 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {})
6634
6793
  );
6635
6794
  }
6636
6795
  const queuedAt = Date.now();
6637
- return new Promise((resolve5) => {
6796
+ return new Promise((resolve6) => {
6638
6797
  waiters.push(() => {
6639
6798
  active += 1;
6640
6799
  const waitedMs = Date.now() - queuedAt;
@@ -6645,7 +6804,7 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {})
6645
6804
  )}s\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`
6646
6805
  );
6647
6806
  }
6648
- resolve5();
6807
+ resolve6();
6649
6808
  });
6650
6809
  });
6651
6810
  };
@@ -6820,11 +6979,11 @@ async function handleInboundMessage(cfg, msg, signal, ctx) {
6820
6979
  }
6821
6980
  function interruptibleSleep(ms, signal) {
6822
6981
  if (signal.aborted) return Promise.resolve();
6823
- return new Promise((resolve5) => {
6824
- const timer = setTimeout(resolve5, ms);
6982
+ return new Promise((resolve6) => {
6983
+ const timer = setTimeout(resolve6, ms);
6825
6984
  const onAbort = () => {
6826
6985
  clearTimeout(timer);
6827
- resolve5();
6986
+ resolve6();
6828
6987
  };
6829
6988
  signal.addEventListener("abort", onAbort, { once: true });
6830
6989
  });
@@ -6964,7 +7123,7 @@ function attachWsHandlers(ws, ctx, onOpen) {
6964
7123
  });
6965
7124
  }
6966
7125
  function connectOnce(url, ctx, connectionAbort, onConnected) {
6967
- return new Promise((resolve5, reject) => {
7126
+ return new Promise((resolve6, reject) => {
6968
7127
  const ws = new WebSocket(url);
6969
7128
  let stopHeartbeat;
6970
7129
  let settled = false;
@@ -6993,7 +7152,7 @@ function connectOnce(url, ctx, connectionAbort, onConnected) {
6993
7152
  finish(() => reject(new Error("shutdown")));
6994
7153
  return;
6995
7154
  }
6996
- finish(resolve5);
7155
+ finish(resolve6);
6997
7156
  });
6998
7157
  ws.on("error", (err) => {
6999
7158
  console.error("[apm] WebSocket \u9519\u8BEF:", err.message);
@@ -7273,14 +7432,6 @@ function normalizeDeployEnvironment(env) {
7273
7432
  if (normalized === "online") return "ONLINE";
7274
7433
  return null;
7275
7434
  }
7276
- async function completeTrackedDeploy(api, deploymentRunId, logSyncer, input) {
7277
- logSyncer.updateLog(input.log);
7278
- await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
7279
- status: input.status,
7280
- fullLog: input.log,
7281
- error: input.error
7282
- });
7283
- }
7284
7435
  async function runDeployWithBackendTracking(options) {
7285
7436
  const cfg = await tryReadApmConfig();
7286
7437
  if (!cfg || !resolveApiKey(cfg)) {
@@ -7318,67 +7469,25 @@ async function runDeployWithBackendTracking(options) {
7318
7469
  id: deploymentRunId,
7319
7470
  status: "DEPLOYING"
7320
7471
  });
7321
- const logSyncer = createDeployLogSyncer(api, deploymentRunId);
7322
- const previousDeploymentRunId = process.env[APM_DEPLOYMENT_RUN_ID_ENV];
7323
- process.env[APM_DEPLOYMENT_RUN_ID_ENV] = deploymentRunId;
7324
- const chunks = [];
7325
- const appendLog = (line) => {
7326
- if (!line) return;
7327
- chunks.push(line);
7328
- logSyncer.updateLog(chunks.join("\n"));
7329
- };
7330
- const originalLog = console.log;
7331
- const originalError = console.error;
7332
- console.log = (...args) => {
7333
- appendLog(args.map(String).join(" "));
7334
- originalLog.apply(console, args);
7335
- };
7336
- console.error = (...args) => {
7337
- appendLog(args.map(String).join(" "));
7338
- originalError.apply(console, args);
7339
- };
7340
- try {
7341
- const output = await executeDeploy({
7342
- ...options,
7343
- captureOutput: true,
7344
- archiveDeployArtifact: true
7345
- });
7346
- if (output.trim()) {
7347
- appendLog(output);
7348
- }
7349
- const log2 = chunks.join("\n");
7350
- await completeTrackedDeploy(api, deploymentRunId, logSyncer, {
7351
- status: "SUCCESS",
7352
- log: log2
7353
- });
7354
- console.log(`[apm] deploy success id=${deploymentRunId}`);
7355
- } catch (error) {
7356
- const deployError = error instanceof DeployExecutionError ? error : new DeployExecutionError(
7357
- error instanceof Error ? error.message : String(error),
7358
- 1
7359
- );
7360
- if (deployError.output.trim()) {
7361
- appendLog(deployError.output);
7362
- } else {
7363
- appendLog(deployError.message);
7472
+ const { error: deployError } = await runTrackedDeploy({
7473
+ api,
7474
+ deploymentRunId,
7475
+ run: async (appendLog) => {
7476
+ const output = await executeDeploy({
7477
+ ...options,
7478
+ captureOutput: true,
7479
+ archiveDeployArtifact: true
7480
+ });
7481
+ if (output.trim()) {
7482
+ appendLog(output);
7483
+ }
7484
+ console.log(`[apm] deploy success id=${deploymentRunId}`);
7485
+ return { status: "SUCCESS" };
7364
7486
  }
7365
- const log2 = chunks.join("\n");
7366
- await completeTrackedDeploy(api, deploymentRunId, logSyncer, {
7367
- status: "FAILED",
7368
- log: log2,
7369
- error: deployError.message
7370
- });
7487
+ });
7488
+ if (deployError) {
7371
7489
  printDeployExecutionError(deployError);
7372
7490
  process.exit(deployError.exitCode);
7373
- } finally {
7374
- if (previousDeploymentRunId === void 0) {
7375
- delete process.env[APM_DEPLOYMENT_RUN_ID_ENV];
7376
- } else {
7377
- process.env[APM_DEPLOYMENT_RUN_ID_ENV] = previousDeploymentRunId;
7378
- }
7379
- console.log = originalLog;
7380
- console.error = originalError;
7381
- logSyncer.dispose();
7382
7491
  }
7383
7492
  }
7384
7493
 
@@ -7431,29 +7540,29 @@ function registerDeployMainCommand(program) {
7431
7540
  }
7432
7541
 
7433
7542
  // src/commands/deploy/backend.ts
7434
- import path10 from "node:path";
7543
+ import path16 from "node:path";
7435
7544
 
7436
7545
  // src/commands/deploy/internal/backend-deploy/backend-deploy-workflow.ts
7437
- import path9 from "node:path";
7546
+ import path15 from "node:path";
7438
7547
 
7439
7548
  // src/commands/deploy/internal/backend-deploy/dockerode-client/client.ts
7440
7549
  import Docker from "dockerode";
7441
7550
 
7442
7551
  // src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
7443
- import { existsSync as existsSync19, readFileSync as readFileSync16 } from "node:fs";
7444
- import path6 from "node:path";
7552
+ import { existsSync as existsSync22, readFileSync as readFileSync18 } from "node:fs";
7553
+ import path12 from "node:path";
7445
7554
  function asOptionalTlsBuffer(value) {
7446
7555
  if (typeof value !== "string") {
7447
7556
  console.log("tls filepath not exist");
7448
7557
  return void 0;
7449
7558
  }
7450
- console.log("tls filepath", path6.join(process.cwd(), value));
7559
+ console.log("tls filepath", path12.join(process.cwd(), value));
7451
7560
  const normalized = value.trim();
7452
7561
  if (normalized === "") {
7453
7562
  return void 0;
7454
7563
  }
7455
- if (existsSync19(normalized)) {
7456
- return readFileSync16(normalized);
7564
+ if (existsSync22(normalized)) {
7565
+ return readFileSync18(normalized);
7457
7566
  }
7458
7567
  const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
7459
7568
  if (looksLikePath) {
@@ -7578,17 +7687,17 @@ var DockerodeClient = class {
7578
7687
  await this.client.getImage(image).remove({ force: true });
7579
7688
  }
7580
7689
  async pullImage(image, auth) {
7581
- const stream = await new Promise((resolve5, reject) => {
7690
+ const stream = await new Promise((resolve6, reject) => {
7582
7691
  const pullOptions = auth ? { authconfig: auth } : void 0;
7583
7692
  this.client.pull(image, pullOptions, (err, output) => {
7584
7693
  if (err || !output) {
7585
7694
  reject(err ?? new Error("docker pull \u8FD4\u56DE\u7A7A\u8F93\u51FA"));
7586
7695
  return;
7587
7696
  }
7588
- resolve5(output);
7697
+ resolve6(output);
7589
7698
  });
7590
7699
  });
7591
- await new Promise((resolve5, reject) => {
7700
+ await new Promise((resolve6, reject) => {
7592
7701
  this.client.modem.followProgress(
7593
7702
  stream,
7594
7703
  (err) => {
@@ -7596,7 +7705,7 @@ var DockerodeClient = class {
7596
7705
  reject(err);
7597
7706
  return;
7598
7707
  }
7599
- resolve5();
7708
+ resolve6();
7600
7709
  },
7601
7710
  () => void 0
7602
7711
  );
@@ -7663,8 +7772,8 @@ var DockerodeClient = class {
7663
7772
  var createDockerodeClient = (config) => new DockerodeClient(config);
7664
7773
 
7665
7774
  // src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
7666
- import { existsSync as existsSync20, readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
7667
- import path7 from "node:path";
7775
+ import { existsSync as existsSync23, readFileSync as readFileSync19, statSync as statSync10 } from "node:fs";
7776
+ import path13 from "node:path";
7668
7777
  function stripSurroundingQuotes(value) {
7669
7778
  const t = value.trim();
7670
7779
  if (t.length >= 2) {
@@ -7679,11 +7788,11 @@ function loadEnvFromFile(envFilePath) {
7679
7788
  if (!envFilePath) {
7680
7789
  return {};
7681
7790
  }
7682
- const targetPath = path7.resolve(envFilePath);
7683
- if (!existsSync20(targetPath) || !statSync8(targetPath).isFile()) {
7791
+ const targetPath = path13.resolve(envFilePath);
7792
+ if (!existsSync23(targetPath) || !statSync10(targetPath).isFile()) {
7684
7793
  return {};
7685
7794
  }
7686
- const raw = readFileSync17(targetPath, "utf-8");
7795
+ const raw = readFileSync19(targetPath, "utf-8");
7687
7796
  const result = {};
7688
7797
  for (const line of raw.split(/\r?\n/)) {
7689
7798
  const normalized = line.trim();
@@ -7854,12 +7963,12 @@ function dockerPushImage(params, cwd) {
7854
7963
  }
7855
7964
 
7856
7965
  // src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
7857
- import { existsSync as existsSync21 } from "node:fs";
7858
- import path8 from "node:path";
7966
+ import { existsSync as existsSync24 } from "node:fs";
7967
+ import path14 from "node:path";
7859
7968
  function resolveDockerBuildPaths(cwd) {
7860
- const dockerfilePath = path8.join(cwd, "Dockerfile");
7969
+ const dockerfilePath = path14.join(cwd, "Dockerfile");
7861
7970
  Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
7862
- if (!existsSync21(dockerfilePath)) {
7971
+ if (!existsSync24(dockerfilePath)) {
7863
7972
  throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
7864
7973
  }
7865
7974
  Logger.info("\u2713 Dockerfile \u5B58\u5728");
@@ -7914,7 +8023,7 @@ var BackendDeployWorkflow = class {
7914
8023
  serveraddress
7915
8024
  });
7916
8025
  Logger.success("\u8FDC\u7A0B\u62C9\u53D6\u955C\u50CF\u5B8C\u6210");
7917
- const envFilePath = path9.resolve(cwd, this.params.envFilePath || ".env");
8026
+ const envFilePath = path15.resolve(cwd, this.params.envFilePath || ".env");
7918
8027
  const envObj = loadEnvFromFile(envFilePath);
7919
8028
  if (this.params.dockerNetwork?.trim()) {
7920
8029
  Logger.info(`\u8FDC\u7A0B\u5BB9\u5668\u5C06\u52A0\u5165 Docker \u7F51\u7EDC\uFF1A${this.params.dockerNetwork.trim()}`);
@@ -7954,7 +8063,7 @@ function registerDeployBackendCommands(program) {
7954
8063
  assertDeployImageTag(tag);
7955
8064
  const cfg = loadApmConfig({ configPath: opts.config });
7956
8065
  const fromApm = resolveBackendDeployFromApmConfig(cfg);
7957
- const dirAbs = path10.resolve(process.cwd(), opts.dir || "servers/api");
8066
+ const dirAbs = path16.resolve(process.cwd(), opts.dir || "servers/api");
7958
8067
  const params = {
7959
8068
  image: fromApm.name,
7960
8069
  tag,
@@ -7984,34 +8093,15 @@ function registerDeployBackendCommands(program) {
7984
8093
  }
7985
8094
 
7986
8095
  // src/commands/deploy/frontend.ts
7987
- import { copyFile, readdir as readdir3, stat, unlink as unlink2 } from "node:fs/promises";
7988
- import path11 from "node:path";
7989
- function resolveArtifactNamePrefix(cfg) {
7990
- const nameRaw = (cfg.name ?? "").trim();
7991
- if (!nameRaw) {
7992
- console.error(
7993
- "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A MinIO \u5BF9\u8C61\u952E\u524D\u7F00\uFF09"
7994
- );
7995
- process.exit(1);
7996
- }
7997
- if (nameRaw.includes(":")) {
7998
- console.error("apm.config.json \u7684 name \u4E0D\u80FD\u5305\u542B ':'");
7999
- process.exit(1);
8000
- }
8001
- try {
8002
- return sanitizeRelativePath(nameRaw.replace(/\\/g, "/"));
8003
- } catch {
8004
- console.error("apm.config.json \u7684 name \u975E\u6CD5\uFF08\u8DEF\u5F84\u7247\u6BB5\u4E0D\u80FD\u4E3A . \u6216 ..\uFF09");
8005
- process.exit(1);
8006
- }
8007
- }
8096
+ import { copyFile, readdir as readdir3, stat } from "node:fs/promises";
8097
+ import path17 from "node:path";
8008
8098
  function artifactObjectKey(namePrefix, branchSegment, relativePath) {
8009
8099
  const base = sanitizeRelativePath(namePrefix);
8010
8100
  const rel = sanitizeRelativePath(relativePath);
8011
8101
  return `${base}/${branchSegment}/dist/${rel}`;
8012
8102
  }
8013
8103
  async function ensureArtifactRootIndexHtml(root) {
8014
- const indexHtmlPath = path11.join(root, "index.html");
8104
+ const indexHtmlPath = path17.join(root, "index.html");
8015
8105
  try {
8016
8106
  const st = await stat(indexHtmlPath);
8017
8107
  if (st.isFile()) {
@@ -8023,12 +8113,11 @@ async function ensureArtifactRootIndexHtml(root) {
8023
8113
  try {
8024
8114
  entries = await readdir3(root, { withFileTypes: true });
8025
8115
  } catch (e) {
8026
- console.error(`\u65E0\u6CD5\u8BFB\u53D6\u4EA7\u7269\u76EE\u5F55\uFF1A${root}`, e);
8027
- process.exit(1);
8116
+ throw new DeployExecutionError(`\u65E0\u6CD5\u8BFB\u53D6\u4EA7\u7269\u76EE\u5F55\uFF1A${root}`, 1, String(e));
8028
8117
  }
8029
8118
  const dirNames = entries.filter((e) => e.isDirectory()).map((e) => String(e.name)).sort();
8030
8119
  for (const name of dirNames) {
8031
- const candidate = path11.join(root, name, "index.html");
8120
+ const candidate = path17.join(root, name, "index.html");
8032
8121
  try {
8033
8122
  const st = await stat(candidate);
8034
8123
  if (!st.isFile()) {
@@ -8039,52 +8128,39 @@ async function ensureArtifactRootIndexHtml(root) {
8039
8128
  }
8040
8129
  await copyFile(candidate, indexHtmlPath);
8041
8130
  console.error(
8042
- `\u4EA7\u7269\u534F\u8BAE\uFF1A\u5DF2\u5C06 ${path11.join(name, "index.html")} \u590D\u5236\u4E3A\u6839\u76EE\u5F55 index.html`
8131
+ `\u4EA7\u7269\u534F\u8BAE\uFF1A\u5DF2\u5C06 ${path17.join(name, "index.html")} \u590D\u5236\u4E3A\u6839\u76EE\u5F55 index.html`
8043
8132
  );
8044
8133
  return;
8045
8134
  }
8046
- console.error(
8047
- `\u4EA7\u7269\u534F\u8BAE\uFF1A\u9700\u5728\u4EA7\u7269\u6839\u76EE\u5F55\u5B58\u5728 index.html\uFF0C\u6216\u5728\u5176\u4E00\u7EA7\u5B50\u76EE\u5F55\u4E2D\u5B58\u5728\u53EF\u590D\u5236\u7684 index.html\uFF08\u672A\u5728 ${root} \u4E0B\u627E\u5230\uFF09`
8135
+ throw new DeployExecutionError(
8136
+ `\u4EA7\u7269\u534F\u8BAE\uFF1A\u9700\u5728\u4EA7\u7269\u6839\u76EE\u5F55\u5B58\u5728 index.html\uFF0C\u6216\u5728\u5176\u4E00\u7EA7\u5B50\u76EE\u5F55\u4E2D\u5B58\u5728\u53EF\u590D\u5236\u7684 index.html\uFF08\u672A\u5728 ${root} \u4E0B\u627E\u5230\uFF09`,
8137
+ 1
8048
8138
  );
8049
- process.exit(1);
8050
8139
  }
8051
8140
  async function runFrontendPackOnlyDeploy(root, namePrefix) {
8052
- const zipPath = path11.resolve(root, "..", ".deploy-frontend-dist.zip");
8053
- let zipSizeBytes = 0;
8054
- let artifactUploaded = false;
8055
- try {
8056
- zipSizeBytes = await zipDirectory(root, zipPath);
8057
- console.error("[apm] \u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u8DF3\u8FC7\u524D\u7AEF\u8BBF\u95EE\u6876\u4E0A\u4F20");
8058
- const artifact = await uploadDeployArtifactZip({
8059
- zipPath,
8060
- projectName: namePrefix,
8061
- kind: "frontend",
8062
- uploadWithoutRunId: true
8063
- });
8064
- artifactUploaded = artifact !== null;
8065
- if (artifactUploaded) {
8066
- console.error("\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5F52\u6863\u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u81F3\u524D\u7AEF\u8BBF\u95EE\u6876\uFF09");
8067
- }
8068
- console.log(
8069
- JSON.stringify(
8070
- {
8071
- ok: true,
8072
- packOnly: true,
8073
- namePrefix,
8074
- zipSizeBytes,
8075
- artifactUploaded
8076
- },
8077
- null,
8078
- 2
8079
- )
8080
- );
8081
- } finally {
8082
- try {
8083
- await unlink2(zipPath);
8084
- console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${zipPath}`);
8085
- } catch {
8086
- }
8087
- }
8141
+ const zipPath = path17.resolve(root, "..", ".deploy-frontend-dist.zip");
8142
+ const { zipSizeBytes, artifactUploaded } = await packDirectoryWithMinioArchive({
8143
+ localDir: root,
8144
+ zipPath,
8145
+ projectName: namePrefix,
8146
+ kind: "frontend",
8147
+ uploadWithoutRunId: true,
8148
+ skipMessage: "[apm] \u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u8DF3\u8FC7\u524D\u7AEF\u8BBF\u95EE\u6876\u4E0A\u4F20",
8149
+ successMessage: "\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5F52\u6863\u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u81F3\u524D\u7AEF\u8BBF\u95EE\u6876\uFF09"
8150
+ });
8151
+ console.log(
8152
+ JSON.stringify(
8153
+ {
8154
+ ok: true,
8155
+ packOnly: true,
8156
+ namePrefix,
8157
+ zipSizeBytes,
8158
+ artifactUploaded
8159
+ },
8160
+ null,
8161
+ 2
8162
+ )
8163
+ );
8088
8164
  }
8089
8165
  function registerDeployFrontendCommands(program) {
8090
8166
  program.command("deploy-frontend").description(
@@ -8105,91 +8181,97 @@ function registerDeployFrontendCommands(program) {
8105
8181
  "\u4EC5\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5F52\u6863\uFF0C\u4E0D\u4E0A\u4F20\u81F3\u524D\u7AEF\u8BBF\u95EE\u6876\uFF08\u9ED8\u8BA4\u5173\u95ED\uFF09"
8106
8182
  ).action(
8107
8183
  async (name, opts) => {
8108
- const cfg = loadApmConfig({ configPath: opts.config });
8109
- const namePrefix = resolveArtifactNamePrefix(cfg);
8110
- const root = path11.resolve(process.cwd(), opts.dir || "apps/web/dist");
8111
- if (!await isDirectoryPath(root)) {
8112
- console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
8113
- process.exit(1);
8114
- }
8115
- await ensureArtifactRootIndexHtml(root);
8116
- if (opts.packOnly) {
8117
- await runFrontendPackOnlyDeploy(root, namePrefix);
8118
- return;
8119
- }
8120
- const settings = resolveFrontendDeployFromApmConfig(cfg);
8121
- const minio = new MinioClient({
8122
- endPoint: settings.endpoint,
8123
- port: settings.port,
8124
- useSSL: settings.useSsl,
8125
- accessKey: settings.accessKey,
8126
- secretKey: settings.secretKey
8127
- });
8128
- const bucket = settings.bucket;
8129
- const maxBytes = Math.max(
8130
- 1,
8131
- Number.isFinite(opts.maxFileSizeMb) ? Math.floor(
8132
- (opts.maxFileSizeMb ?? DEFAULT_MAX_FILE_SIZE_MB) * 1024 * 1024
8133
- ) : DEFAULT_MAX_FILE_SIZE_MB * 1024 * 1024
8134
- );
8135
- const files = await collectFiles(root);
8136
- if (files.length === 0) {
8137
- console.error(`\u76EE\u5F55\u4E3A\u7A7A\uFF1A${root}`);
8138
- process.exit(1);
8139
- }
8140
- let uploaded = 0;
8141
- let totalBytes = 0;
8142
- console.error(`\u5F00\u59CB\u76F4\u8FDE MinIO \u4E0A\u4F20\uFF0C\u5171 ${files.length} \u4E2A\u6587\u4EF6\u2026`);
8143
- await minio.ensureBucket(bucket);
8144
- await minio.deleteObjectsByPrefix(
8145
- bucket,
8146
- `${namePrefix}/${name}/dist/`
8147
- );
8148
- for (const f of files) {
8149
- if (f.size > maxBytes) {
8184
+ try {
8185
+ const cfg = loadApmConfig({ configPath: opts.config });
8186
+ const namePrefix = resolveArtifactNamePrefix(cfg);
8187
+ const root = path17.resolve(process.cwd(), opts.dir || "apps/web/dist");
8188
+ if (!await isDirectoryPath(root)) {
8189
+ throw new DeployExecutionError(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`, 1);
8190
+ }
8191
+ await ensureArtifactRootIndexHtml(root);
8192
+ if (opts.packOnly) {
8193
+ await runFrontendPackOnlyDeploy(root, namePrefix);
8194
+ return;
8195
+ }
8196
+ const settings = resolveFrontendDeployFromApmConfig(cfg);
8197
+ const minio = new MinioClient({
8198
+ endPoint: settings.endpoint,
8199
+ port: settings.port,
8200
+ useSSL: settings.useSsl,
8201
+ accessKey: settings.accessKey,
8202
+ secretKey: settings.secretKey
8203
+ });
8204
+ const bucket = settings.bucket;
8205
+ const maxBytes = Math.max(
8206
+ 1,
8207
+ Number.isFinite(opts.maxFileSizeMb) ? Math.floor(
8208
+ (opts.maxFileSizeMb ?? DEFAULT_MAX_FILE_SIZE_MB) * 1024 * 1024
8209
+ ) : DEFAULT_MAX_FILE_SIZE_MB * 1024 * 1024
8210
+ );
8211
+ const files = await collectFiles(root);
8212
+ if (files.length === 0) {
8213
+ throw new DeployExecutionError(`\u76EE\u5F55\u4E3A\u7A7A\uFF1A${root}`, 1);
8214
+ }
8215
+ let uploaded = 0;
8216
+ let totalBytes = 0;
8217
+ console.error(`\u5F00\u59CB\u76F4\u8FDE MinIO \u4E0A\u4F20\uFF0C\u5171 ${files.length} \u4E2A\u6587\u4EF6\u2026`);
8218
+ await minio.ensureBucket(bucket);
8219
+ await minio.deleteObjectsByPrefix(
8220
+ bucket,
8221
+ `${namePrefix}/${name}/dist/`
8222
+ );
8223
+ for (const f of files) {
8224
+ if (f.size > maxBytes) {
8225
+ throw new DeployExecutionError(
8226
+ `\u6587\u4EF6\u8FC7\u5927\uFF0C\u5DF2\u62D2\u7EDD\uFF1A${f.relativePath}\uFF08${toMB(
8227
+ f.size
8228
+ )}MB > ${toMB(maxBytes)}MB\uFF09`,
8229
+ 1
8230
+ );
8231
+ }
8232
+ const buf = await readArtifactFile(f.absPath);
8233
+ const cleanRel = sanitizeRelativePath(f.relativePath);
8234
+ const objectKey = artifactObjectKey(namePrefix, name, cleanRel);
8235
+ const mimeType = detectMimeType(f.relativePath).trim().toLowerCase() || "application/octet-stream";
8236
+ await minio.putObject(bucket, objectKey, buf, {
8237
+ "Content-Type": mimeType
8238
+ });
8239
+ uploaded += 1;
8240
+ totalBytes += buf.length;
8150
8241
  console.error(
8151
- `\u6587\u4EF6\u8FC7\u5927\uFF0C\u5DF2\u62D2\u7EDD\uFF1A${f.relativePath}\uFF08${toMB(f.size)}MB > ${toMB(
8152
- maxBytes
8153
- )}MB\uFF09`
8242
+ `[${uploaded}/${files.length}] ${f.relativePath} -> ${objectKey}`
8154
8243
  );
8155
- process.exit(1);
8156
8244
  }
8157
- const buf = await readArtifactFile(f.absPath);
8158
- const cleanRel = sanitizeRelativePath(f.relativePath);
8159
- const objectKey = artifactObjectKey(namePrefix, name, cleanRel);
8160
- const mimeType = detectMimeType(f.relativePath).trim().toLowerCase() || "application/octet-stream";
8161
- await minio.putObject(bucket, objectKey, buf, {
8162
- "Content-Type": mimeType
8163
- });
8164
- uploaded += 1;
8165
- totalBytes += buf.length;
8166
- console.error(
8167
- `[${uploaded}/${files.length}] ${f.relativePath} -> ${objectKey}`
8245
+ console.error("\u6B63\u5728\u8BBE\u7F6E\u6876\u7B56\u7565\uFF08\u533F\u540D\u53EF\u8BFB\u5BF9\u8C61\uFF0C\u4FBF\u4E8E HTTP \u76F4\u94FE\uFF09\u2026");
8246
+ await minio.setBucketPublicRead(bucket);
8247
+ console.log(
8248
+ JSON.stringify(
8249
+ {
8250
+ ok: true,
8251
+ namePrefix,
8252
+ envName: name,
8253
+ bucket,
8254
+ fileCount: uploaded,
8255
+ totalBytes,
8256
+ bucketPublicRead: true
8257
+ },
8258
+ null,
8259
+ 2
8260
+ )
8168
8261
  );
8262
+ } catch (error) {
8263
+ if (error instanceof DeployExecutionError) {
8264
+ printDeployExecutionError(error);
8265
+ process.exit(error.exitCode);
8266
+ }
8267
+ throw error;
8169
8268
  }
8170
- console.error("\u6B63\u5728\u8BBE\u7F6E\u6876\u7B56\u7565\uFF08\u533F\u540D\u53EF\u8BFB\u5BF9\u8C61\uFF0C\u4FBF\u4E8E HTTP \u76F4\u94FE\uFF09\u2026");
8171
- await minio.setBucketPublicRead(bucket);
8172
- console.log(
8173
- JSON.stringify(
8174
- {
8175
- ok: true,
8176
- namePrefix,
8177
- envName: name,
8178
- bucket,
8179
- fileCount: uploaded,
8180
- totalBytes,
8181
- bucketPublicRead: true
8182
- },
8183
- null,
8184
- 2
8185
- )
8186
- );
8187
8269
  }
8188
8270
  );
8189
8271
  }
8190
8272
 
8191
8273
  // src/commands/deploy/sftp.ts
8192
- import path12 from "node:path";
8274
+ import path18 from "node:path";
8193
8275
  function registerDeploySftpCommands(program) {
8194
8276
  program.command("deploy-sftp").description(
8195
8277
  "\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"
@@ -8205,25 +8287,22 @@ function registerDeploySftpCommands(program) {
8205
8287
  "\u4EC5\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5F52\u6863\uFF0C\u4E0D\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF08\u4E0E --extract \u4E92\u65A5\uFF09"
8206
8288
  ).action(
8207
8289
  async (opts) => {
8208
- const cfg = loadApmConfig({ configPath: opts.config });
8209
- const settings = resolveWisdomDeployFromApmConfig(cfg);
8210
- const projectName = (cfg.name ?? "").trim();
8211
- if (!projectName) {
8212
- console.error(
8213
- "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09"
8214
- );
8215
- process.exit(1);
8216
- }
8217
- const root = path12.resolve(process.cwd(), opts.dir || "apps/web/dist");
8218
- if (!await isDirectoryPath(root)) {
8219
- console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
8220
- process.exit(1);
8221
- }
8222
8290
  try {
8291
+ const cfg = loadApmConfig({ configPath: opts.config });
8292
+ const settings = resolveWisdomDeployFromApmConfig(cfg);
8293
+ const projectName = resolveProjectNameForDeploy(cfg, process.cwd(), {
8294
+ requireName: true
8295
+ });
8296
+ const root = path18.resolve(process.cwd(), opts.dir || "apps/web/dist");
8297
+ if (!await isDirectoryPath(root)) {
8298
+ throw new DeployExecutionError(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`, 1);
8299
+ }
8223
8300
  const packOnly = Boolean(opts.packOnly);
8224
8301
  if (packOnly && opts.extract) {
8225
- console.error("--pack-only \u4E0E --extract \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
8226
- process.exit(1);
8302
+ throw new DeployExecutionError(
8303
+ "--pack-only \u4E0E --extract \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528",
8304
+ 1
8305
+ );
8227
8306
  }
8228
8307
  const result = await runWisdomSftpDeploy({
8229
8308
  localDir: root,
@@ -8233,8 +8312,12 @@ function registerDeploySftpCommands(program) {
8233
8312
  packOnly
8234
8313
  });
8235
8314
  console.log(JSON.stringify(result, null, 2));
8236
- } catch (err) {
8237
- const message = err instanceof Error ? err.message : String(err);
8315
+ } catch (error) {
8316
+ if (error instanceof DeployExecutionError) {
8317
+ printDeployExecutionError(error);
8318
+ process.exit(error.exitCode);
8319
+ }
8320
+ const message = error instanceof Error ? error.message : String(error);
8238
8321
  const action = opts.packOnly ? "\u6253\u5305" : opts.extract ? "\u90E8\u7F72" : "\u4E0A\u4F20";
8239
8322
  console.error(`${action}\u5931\u8D25:`, message);
8240
8323
  process.exit(1);
@@ -8251,11 +8334,19 @@ function registerDeployWisdomBackendCommands(program) {
8251
8334
  "--config <path>",
8252
8335
  "apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
8253
8336
  ).action(async (opts) => {
8254
- const cfg = loadApmConfig({ configPath: opts.config });
8255
- const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
8256
- await runWisdomBackendDeploy({
8257
- config: settings
8258
- });
8337
+ try {
8338
+ const cfg = loadApmConfig({ configPath: opts.config });
8339
+ const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
8340
+ await runWisdomBackendDeploy({
8341
+ config: settings
8342
+ });
8343
+ } catch (error) {
8344
+ if (error instanceof DeployExecutionError) {
8345
+ printDeployExecutionError(error);
8346
+ process.exit(error.exitCode);
8347
+ }
8348
+ throw error;
8349
+ }
8259
8350
  });
8260
8351
  }
8261
8352