ai-project-manage-cli 6.0.107 → 6.0.109

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -110,8 +110,8 @@ function toFsPath(inputPath) {
110
110
  }
111
111
  return `\\\\?\\${normalized}`;
112
112
  }
113
- function normalizeWorkdirPath(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");
@@ -1593,13 +1593,13 @@ async function downloadAttachment(cfg, attachmentId) {
1593
1593
  return Buffer.from(await res.arrayBuffer());
1594
1594
  }
1595
1595
  function loadManifest(dir) {
1596
- const path13 = join6(dir, MANIFEST_FILE2);
1597
- if (!existsSync4(path13)) {
1596
+ const path19 = join6(dir, MANIFEST_FILE2);
1597
+ if (!existsSync4(path19)) {
1598
1598
  return { version: 1, attachments: {} };
1599
1599
  }
1600
1600
  try {
1601
1601
  const parsed = JSON.parse(
1602
- readFileSync5(path13, "utf8")
1602
+ readFileSync5(path19, "utf8")
1603
1603
  );
1604
1604
  if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
1605
1605
  return parsed;
@@ -1680,8 +1680,8 @@ function sanitizeSkillDirName(name) {
1680
1680
  function listBaseSkillDirNames() {
1681
1681
  if (!existsSync5(BASE_SKILLS_TEMPLATE_DIR)) return [];
1682
1682
  return readdirSync3(BASE_SKILLS_TEMPLATE_DIR).filter((name) => {
1683
- const path13 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
1684
- return statSync2(path13).isDirectory();
1683
+ const path19 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
1684
+ return statSync2(path19).isDirectory();
1685
1685
  });
1686
1686
  }
1687
1687
  function syncAgentsGuide(apmDir) {
@@ -1693,8 +1693,8 @@ function syncAgentsGuide(apmDir) {
1693
1693
  function listBaseRuleFileNames() {
1694
1694
  if (!existsSync5(BASE_RULES_TEMPLATE_DIR)) return [];
1695
1695
  return readdirSync3(BASE_RULES_TEMPLATE_DIR).filter((name) => {
1696
- const path13 = join7(BASE_RULES_TEMPLATE_DIR, name);
1697
- return statSync2(path13).isFile();
1696
+ const path19 = join7(BASE_RULES_TEMPLATE_DIR, name);
1697
+ return statSync2(path19).isFile();
1698
1698
  });
1699
1699
  }
1700
1700
  function syncBaseRules(rulesDir) {
@@ -1757,13 +1757,13 @@ function ruleLocalFileName(ruleName) {
1757
1757
  return `${sanitized}.md`;
1758
1758
  }
1759
1759
  function loadManifest2(rulesDir) {
1760
- const path13 = join8(rulesDir, MANIFEST_FILE3);
1761
- if (!existsSync6(toFsPath(path13))) {
1760
+ const path19 = join8(rulesDir, MANIFEST_FILE3);
1761
+ if (!existsSync6(toFsPath(path19))) {
1762
1762
  return { version: 1, rules: {} };
1763
1763
  }
1764
1764
  try {
1765
1765
  const parsed = JSON.parse(
1766
- readFileSync6(toFsPath(path13), "utf8")
1766
+ readFileSync6(toFsPath(path19), "utf8")
1767
1767
  );
1768
1768
  if (parsed?.version === 1 && parsed.rules && typeof parsed.rules === "object") {
1769
1769
  return parsed;
@@ -2658,93 +2658,17 @@ function validateAgentWsMessage(value, kind) {
2658
2658
  return validateMessagePush(o);
2659
2659
  }
2660
2660
 
2661
- // src/commands/deploy/deploy-log-utils.ts
2662
- import { setTimeout as delay } from "node:timers/promises";
2663
- var DEPLOY_SPAWN_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
2664
- var DEPLOY_LOG_SYNC_MAX_CHUNK_BYTES = 4 * 1024 * 1024;
2665
- var DEPLOY_COMPLETE_LOG_MAX_BYTES = 9 * 1024 * 1024;
2666
- var DEPLOY_LOG_SYNC_MAX_ATTEMPTS = 3;
2667
- async function retryDeployLogSync(fn, attempts = DEPLOY_LOG_SYNC_MAX_ATTEMPTS) {
2668
- let lastError;
2669
- for (let attempt = 1; attempt <= attempts; attempt += 1) {
2670
- try {
2671
- return await fn();
2672
- } catch (error) {
2673
- lastError = error;
2674
- if (attempt < attempts) {
2675
- await delay(1e3 * attempt);
2676
- }
2677
- }
2678
- }
2679
- throw lastError;
2680
- }
2681
- function splitUtf8StringByMaxBytes(value, maxBytes) {
2682
- if (maxBytes <= 0) {
2683
- throw new Error("maxBytes must be positive");
2684
- }
2685
- const bytes = Buffer.from(value, "utf8");
2686
- if (bytes.length <= maxBytes) {
2687
- return [value];
2688
- }
2689
- const chunks = [];
2690
- let offset = 0;
2691
- while (offset < bytes.length) {
2692
- let end = Math.min(offset + maxBytes, bytes.length);
2693
- while (end > offset && (bytes[end] & 192) === 128) {
2694
- end -= 1;
2695
- }
2696
- if (end <= offset) {
2697
- end = Math.min(offset + maxBytes, bytes.length);
2698
- }
2699
- chunks.push(bytes.subarray(offset, end).toString("utf8"));
2700
- offset = end;
2701
- }
2702
- return chunks;
2703
- }
2704
- function truncateDeployLogForComplete(log2) {
2705
- const bytes = Buffer.from(log2, "utf8");
2706
- if (bytes.length <= DEPLOY_COMPLETE_LOG_MAX_BYTES) {
2707
- return { log: log2, truncated: false };
2708
- }
2709
- const tailBudget = Math.max(DEPLOY_COMPLETE_LOG_MAX_BYTES - 512, 1024);
2710
- 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
2711
- `;
2712
- let tail = bytes.subarray(bytes.length - tailBudget).toString("utf8");
2713
- const brokenPrefix = tail.indexOf("\uFFFD");
2714
- if (brokenPrefix >= 0) {
2715
- const newline = tail.indexOf("\n", brokenPrefix);
2716
- tail = newline >= 0 ? tail.slice(newline + 1) : tail.slice(brokenPrefix + 1);
2717
- }
2718
- return { log: prefix + tail, truncated: true };
2719
- }
2720
-
2721
2661
  // src/commands/deploy/deploy-execute.ts
2722
- import path5 from "node:path";
2662
+ import path11 from "node:path";
2723
2663
 
2724
2664
  // src/commands/deploy/internal/apm-config.ts
2725
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "node:fs";
2726
- import { homedir as homedir2 } from "node:os";
2727
- import { join as join13, resolve as resolve3 } from "node:path";
2728
- function loadApmConfig(options) {
2729
- const p = resolve3(
2730
- process.cwd(),
2731
- options?.configPath ?? resolve3(workspaceApmDir(), "apm.config.json")
2732
- );
2733
- if (!existsSync11(p)) {
2734
- console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
2735
- process.exit(1);
2736
- }
2737
- try {
2738
- const raw = readFileSync10(p, "utf8");
2739
- return JSON.parse(raw);
2740
- } catch (e) {
2741
- console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
2742
- process.exit(1);
2743
- }
2744
- }
2745
- 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) {
2746
2670
  if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2747
- 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`);
2748
2672
  process.exit(1);
2749
2673
  }
2750
2674
  return v;
@@ -2759,17 +2683,19 @@ function reqTopLevelName(cfg) {
2759
2683
  }
2760
2684
  return n;
2761
2685
  }
2762
- function reqBackendPositiveInt(v, field) {
2686
+ function reqPositiveInt(v, field, section) {
2763
2687
  const n = Number(v);
2764
2688
  if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
2765
- 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`);
2766
2690
  process.exit(1);
2767
2691
  }
2768
2692
  return n;
2769
2693
  }
2694
+
2695
+ // src/commands/deploy/internal/config/docker-backend-config.ts
2770
2696
  function resolveBackendDeployFromApmConfig(cfg) {
2771
2697
  const b = cfg.backendDeploy ?? {};
2772
- const protoRaw = req(b.remoteProtocol, "remoteProtocol").trim().toLowerCase();
2698
+ const protoRaw = req(b.remoteProtocol, "remoteProtocol", "backendDeploy").trim().toLowerCase();
2773
2699
  if (protoRaw !== "http" && protoRaw !== "https") {
2774
2700
  console.error(
2775
2701
  "apm.config.json \u4E2D backendDeploy.remoteProtocol \u53EA\u80FD\u4E3A http \u6216 https"
@@ -2790,12 +2716,20 @@ function resolveBackendDeployFromApmConfig(cfg) {
2790
2716
  }
2791
2717
  return {
2792
2718
  name: reqTopLevelName(cfg),
2793
- registryHost: req(b.registryHost, "registryHost").trim(),
2794
- registryNamespace: req(b.registryNamespace, "registryNamespace").trim(),
2795
- registryUser: req(b.registryUser, "registryUser").trim(),
2796
- registryPassword: req(b.registryPassword, "registryPassword").trim(),
2797
- remoteHost: req(b.remoteHost, "remoteHost").trim(),
2798
- 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"),
2799
2733
  remoteProtocol,
2800
2734
  caPath: b.caPath?.trim(),
2801
2735
  certPath: b.certPath?.trim(),
@@ -2805,64 +2739,30 @@ function resolveBackendDeployFromApmConfig(cfg) {
2805
2739
  dockerNetwork: b.dockerNetwork?.trim() || void 0
2806
2740
  };
2807
2741
  }
2808
- function reqFe(v, field) {
2809
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2810
- console.error(`apm.config.json \u4E2D frontendDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2811
- process.exit(1);
2812
- }
2813
- return v;
2814
- }
2742
+
2743
+ // src/commands/deploy/internal/config/frontend-minio-config.ts
2815
2744
  function resolveFrontendDeployFromApmConfig(cfg) {
2816
2745
  const f = cfg.frontendDeploy ?? {};
2817
2746
  const port = Number(f.port);
2818
2747
  return {
2819
- endpoint: reqFe(f.endpoint, "endpoint").trim(),
2748
+ endpoint: req(f.endpoint, "endpoint", "frontendDeploy").trim(),
2820
2749
  port: Number.isFinite(port) && port > 0 ? port : 9e3,
2821
2750
  useSsl: Boolean(f.useSsl),
2822
- accessKey: reqFe(f.accessKey, "accessKey").trim(),
2823
- secretKey: reqFe(f.secretKey, "secretKey").trim(),
2824
- bucket: reqFe(f.bucket, "bucket").trim()
2825
- };
2826
- }
2827
- function reqWd(v, field) {
2828
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2829
- console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2830
- process.exit(1);
2831
- }
2832
- return v;
2833
- }
2834
- function reqWisdomPositiveInt(v, field) {
2835
- const n = Number(v);
2836
- if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
2837
- console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u987B\u4E3A\u6B63\u6574\u6570`);
2838
- process.exit(1);
2839
- }
2840
- return n;
2841
- }
2842
- function resolveWisdomDeployFromApmConfig(cfg) {
2843
- const w = cfg.wisdomDeploy ?? {};
2844
- return {
2845
- host: reqWd(w.host, "host").trim(),
2846
- port: reqWisdomPositiveInt(w.port, "port"),
2847
- username: reqWd(w.username, "username").trim(),
2848
- password: reqWd(w.password, "password").trim(),
2849
- 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()
2850
2754
  };
2851
2755
  }
2852
- function reqHc(v, field) {
2853
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2854
- console.error(`apm.config.json \u4E2D healthCheck.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2855
- process.exit(1);
2856
- }
2857
- return v;
2858
- }
2859
- function reqWb(v, field) {
2860
- if (v === void 0 || v === null || typeof v === "string" && !v.trim()) {
2861
- console.error(`apm.config.json \u4E2D wisdomDeploy.${field} \u4E0D\u80FD\u4E3A\u7A7A`);
2862
- process.exit(1);
2863
- }
2864
- return v;
2865
- }
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
+ ];
2866
2766
  function readEnvVar(env, name) {
2867
2767
  if (env[name] !== void 0) {
2868
2768
  return env[name];
@@ -2892,11 +2792,6 @@ function expandUserPath(pathStr, env = process.env) {
2892
2792
  }
2893
2793
  return resolve3(expanded);
2894
2794
  }
2895
- var MAVEN_REPO_ENV_KEYS = [
2896
- "MAVEN_LOCAL_REPO",
2897
- "M2_REPO",
2898
- "MAVEN_REPOSITORY"
2899
- ];
2900
2795
  function readMavenLocalRepoFromMavenOpts(mavenOpts, env = process.env) {
2901
2796
  const match = mavenOpts.match(/-Dmaven\.repo\.local=(?:"([^"]+)"|(\S+))/);
2902
2797
  const raw = match?.[1]?.trim() || match?.[2]?.trim();
@@ -2911,9 +2806,9 @@ function readMavenLocalRepoFromEnv(env = process.env) {
2911
2806
  }
2912
2807
  const mavenOpts = readEnvVar(env, "MAVEN_OPTS")?.trim();
2913
2808
  if (mavenOpts) {
2914
- const path13 = readMavenLocalRepoFromMavenOpts(mavenOpts, env);
2915
- if (path13) {
2916
- return { path: path13, key: "MAVEN_OPTS" };
2809
+ const path19 = readMavenLocalRepoFromMavenOpts(mavenOpts, env);
2810
+ if (path19) {
2811
+ return { path: path19, key: "MAVEN_OPTS" };
2917
2812
  }
2918
2813
  }
2919
2814
  return null;
@@ -2960,6 +2855,18 @@ function resolveMavenLocalRepoWithSource() {
2960
2855
  sourceDetail: "~/.m2/repository"
2961
2856
  };
2962
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
+ }
2963
2870
  function resolveWisdomDeployMode(raw) {
2964
2871
  if (raw === void 0 || raw === null || raw === "") {
2965
2872
  return "default";
@@ -2973,14 +2880,27 @@ function resolveWisdomDeployMode(raw) {
2973
2880
  );
2974
2881
  process.exit(1);
2975
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
+ }
2976
2896
  function resolveWisdomBackendDeployFromApmConfig(cfg) {
2977
2897
  const projectName = reqTopLevelName(cfg);
2978
2898
  const w = cfg.wisdomDeploy ?? {};
2979
2899
  const h = cfg.healthCheck ?? {};
2980
- const jarPath = reqWb(w.jarPath, "jarPath").trim();
2900
+ const jarPath = req(w.jarPath, "jarPath", "wisdomDeploy").trim();
2981
2901
  const remoteAppDir = posixDirname(jarPath);
2982
- const healthPort = Number(reqHc(h.port, "port"));
2983
- 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"));
2984
2904
  if (!Number.isFinite(healthPort) || !Number.isInteger(healthPort) || healthPort < 1) {
2985
2905
  console.error("apm.config.json \u4E2D healthCheck.port \u987B\u4E3A\u6B63\u6574\u6570");
2986
2906
  process.exit(1);
@@ -2992,11 +2912,11 @@ function resolveWisdomBackendDeployFromApmConfig(cfg) {
2992
2912
  const mavenLocalRepo = resolveMavenLocalRepoWithSource();
2993
2913
  return {
2994
2914
  projectName,
2995
- host: reqWd(w.host, "host").trim(),
2996
- port: reqWisdomPositiveInt(w.port, "port"),
2997
- username: reqWd(w.username, "username").trim(),
2998
- password: reqWd(w.password, "password").trim(),
2999
- 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(),
3000
2920
  remoteAppDir,
3001
2921
  remoteLibDir: `${remoteAppDir}/lib`,
3002
2922
  startupJar: posixBasename(jarPath),
@@ -3005,23 +2925,29 @@ function resolveWisdomBackendDeployFromApmConfig(cfg) {
3005
2925
  mavenLocalRepoSource: mavenLocalRepo.source,
3006
2926
  mavenLocalRepoSourceDetail: mavenLocalRepo.sourceDetail,
3007
2927
  healthCheckPort: healthPort,
3008
- healthCheckContext: reqHc(h.context, "context").trim(),
2928
+ healthCheckContext: req(h.context, "context", "healthCheck").trim(),
3009
2929
  healthCheckTimeout: healthTimeout,
3010
2930
  mode: resolveWisdomDeployMode(w.mode)
3011
2931
  };
3012
2932
  }
3013
- function posixDirname(p) {
3014
- const normalized = p.replace(/\\/g, "/");
3015
- const idx = normalized.lastIndexOf("/");
3016
- if (idx <= 0) {
3017
- 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);
3018
2950
  }
3019
- return normalized.slice(0, idx);
3020
- }
3021
- function posixBasename(p) {
3022
- const normalized = p.replace(/\\/g, "/");
3023
- const idx = normalized.lastIndexOf("/");
3024
- return idx >= 0 ? normalized.slice(idx + 1) : normalized;
3025
2951
  }
3026
2952
 
3027
2953
  // src/commands/deploy/internal/deploy-hints.ts
@@ -3061,7 +2987,7 @@ var DeployExecutionError = class extends Error {
3061
2987
 
3062
2988
  // src/commands/deploy/deploy-debug-log.ts
3063
2989
  import { spawnSync as spawnSync4 } from "node:child_process";
3064
- import { existsSync as existsSync14 } from "node:fs";
2990
+ import { existsSync as existsSync15 } from "node:fs";
3065
2991
  import { dirname as dirname5, join as join16 } from "node:path";
3066
2992
 
3067
2993
  // src/commands/deploy/internal/deploy-artifact-minio.ts
@@ -3167,14 +3093,14 @@ var MinioClient = class {
3167
3093
  async deleteObjectsByPrefix(bucket, prefix) {
3168
3094
  const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
3169
3095
  const keys = [];
3170
- await new Promise((resolve5, reject) => {
3096
+ await new Promise((resolve6, reject) => {
3171
3097
  objectsStream.on("data", (obj) => {
3172
3098
  if (obj.name) {
3173
3099
  keys.push(obj.name);
3174
3100
  }
3175
3101
  });
3176
3102
  objectsStream.on("error", reject);
3177
- objectsStream.on("end", resolve5);
3103
+ objectsStream.on("end", resolve6);
3178
3104
  });
3179
3105
  const chunkSize = 500;
3180
3106
  for (let i = 0; i < keys.length; i += chunkSize) {
@@ -3320,15 +3246,15 @@ import { dirname as dirname4 } from "node:path";
3320
3246
 
3321
3247
  // src/commands/daemon.ts
3322
3248
  import { spawnSync as spawnSync2 } from "child_process";
3323
- import { setTimeout as delay2 } from "node:timers/promises";
3324
- 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";
3325
3251
  import { join as join15 } from "path";
3326
3252
 
3327
3253
  // src/commands/connect-lock.ts
3328
3254
  import {
3329
- existsSync as existsSync12,
3255
+ existsSync as existsSync13,
3330
3256
  mkdirSync as mkdirSync5,
3331
- readFileSync as readFileSync11,
3257
+ readFileSync as readFileSync12,
3332
3258
  unlinkSync,
3333
3259
  writeFileSync as writeFileSync10
3334
3260
  } from "fs";
@@ -3360,9 +3286,9 @@ function waitForPm2LockHandoff(timeoutMs = 5e3) {
3360
3286
  }
3361
3287
  }
3362
3288
  function readConnectLock() {
3363
- if (!existsSync12(CONNECT_LOCK_PATH)) return null;
3289
+ if (!existsSync13(CONNECT_LOCK_PATH)) return null;
3364
3290
  try {
3365
- const raw = readFileSync11(CONNECT_LOCK_PATH, "utf8");
3291
+ const raw = readFileSync12(CONNECT_LOCK_PATH, "utf8");
3366
3292
  const parsed = JSON.parse(raw);
3367
3293
  if (typeof parsed.pid !== "number" || parsed.mode !== "foreground" && parsed.mode !== "pm2" || typeof parsed.startedAt !== "string") {
3368
3294
  return null;
@@ -3419,7 +3345,7 @@ function releaseConnectLock() {
3419
3345
  }
3420
3346
  function forceReleaseConnectLock() {
3421
3347
  try {
3422
- if (existsSync12(CONNECT_LOCK_PATH)) {
3348
+ if (existsSync13(CONNECT_LOCK_PATH)) {
3423
3349
  unlinkSync(CONNECT_LOCK_PATH);
3424
3350
  }
3425
3351
  } catch {
@@ -3569,14 +3495,14 @@ function resolvePm2FromNpmRoot() {
3569
3495
  if (!root) return null;
3570
3496
  for (const rel of ["pm2/bin/pm2", "pm2/bin/pm2.js"]) {
3571
3497
  const candidate = join15(root, ...rel.split("/"));
3572
- if (existsSync13(candidate)) {
3498
+ if (existsSync14(candidate)) {
3573
3499
  return candidate;
3574
3500
  }
3575
3501
  }
3576
3502
  return null;
3577
3503
  }
3578
- function isPm2NodeScript(path13) {
3579
- return path13.endsWith(".js") || /[\\/]pm2[\\/]bin[\\/]pm2$/.test(path13);
3504
+ function isPm2NodeScript(path19) {
3505
+ return path19.endsWith(".js") || /[\\/]pm2[\\/]bin[\\/]pm2$/.test(path19);
3580
3506
  }
3581
3507
  function buildPm2SpawnTarget(binPath) {
3582
3508
  if (isPm2NodeScript(binPath)) {
@@ -3606,7 +3532,7 @@ function spawnPm2At(binPath, args, options = {}) {
3606
3532
  return spawnPm2Target(buildPm2SpawnTarget(binPath), args, options);
3607
3533
  }
3608
3534
  function verifyPm2Bin(pm2Bin) {
3609
- if (!pm2Bin.trim() || !existsSync13(pm2Bin)) {
3535
+ if (!pm2Bin.trim() || !existsSync14(pm2Bin)) {
3610
3536
  return false;
3611
3537
  }
3612
3538
  const result = spawnPm2At(pm2Bin, ["--version"], {
@@ -3745,7 +3671,7 @@ function ensureGlobalPm2(options) {
3745
3671
  }
3746
3672
  function resolveApmEntryPath(entryArg = process.argv[1]) {
3747
3673
  const fromArgv = entryArg?.trim();
3748
- if (fromArgv && existsSync13(fromArgv)) {
3674
+ if (fromArgv && existsSync14(fromArgv)) {
3749
3675
  return fromArgv;
3750
3676
  }
3751
3677
  const npmResult = spawnSync2(useNpmShell2 ? "npm.cmd" : "npm", ["root", "-g"], {
@@ -3757,7 +3683,7 @@ function resolveApmEntryPath(entryArg = process.argv[1]) {
3757
3683
  const globalRoot = npmResult.stdout?.toString().trim();
3758
3684
  if (globalRoot) {
3759
3685
  const candidate = join15(globalRoot, CLI_PACKAGE_NAME, "dist", "index.js");
3760
- if (existsSync13(candidate)) {
3686
+ if (existsSync14(candidate)) {
3761
3687
  return candidate;
3762
3688
  }
3763
3689
  }
@@ -3948,7 +3874,7 @@ function writeEcosystemFile(options) {
3948
3874
  formatConnectPm2EcosystemFile(ecosystem),
3949
3875
  "utf8"
3950
3876
  );
3951
- if (existsSync13(LEGACY_PM2_ECOSYSTEM_PATH)) {
3877
+ if (existsSync14(LEGACY_PM2_ECOSYSTEM_PATH)) {
3952
3878
  try {
3953
3879
  unlinkSync2(LEGACY_PM2_ECOSYSTEM_PATH);
3954
3880
  } catch {
@@ -3977,7 +3903,7 @@ async function runDaemonStart(options) {
3977
3903
  const cfg = await prepareEcosystem(options.server);
3978
3904
  removePm2ConnectProcesses();
3979
3905
  runPm2(["start", PM2_ECOSYSTEM_PATH, "--update-env"], { inherit: true });
3980
- await delay2(1e3);
3906
+ await delay(1e3);
3981
3907
  if (!isPm2ConnectOnline()) {
3982
3908
  console.error(
3983
3909
  `[apm] ${PM2_APP_NAME} \u542F\u52A8\u540E\u672A\u5904\u4E8E online \u72B6\u6001\uFF0C\u8BF7\u6267\u884C: apm daemon logs -n 200`
@@ -4010,7 +3936,7 @@ async function runDaemonStop() {
4010
3936
  });
4011
3937
  for (let i = 0; i < 10; i += 1) {
4012
3938
  if (!isPm2ConnectOnline()) break;
4013
- await delay2(500);
3939
+ await delay(500);
4014
3940
  }
4015
3941
  if (isPm2ConnectOnline()) {
4016
3942
  console.log(`[apm] \u4F18\u96C5\u505C\u6B62\u8D85\u65F6\uFF0C\u5F3A\u5236\u79FB\u9664 ${PM2_APP_NAME}\u2026`);
@@ -4245,12 +4171,12 @@ function logExecuteDeployContext(input) {
4245
4171
  `cwdMatchProcess=${input.cwd === input.processCwd ? "yes" : "no"} (connect \u901A\u5E38\u4E3A no)`
4246
4172
  );
4247
4173
  logLine(
4248
- `apm.config=${input.apmConfigPath} exists=${existsSync14(
4174
+ `apm.config=${input.apmConfigPath} exists=${existsSync15(
4249
4175
  input.apmConfigPath
4250
4176
  )}`
4251
4177
  );
4252
4178
  logLine(
4253
- `package.json=${packageJsonPath} exists=${existsSync14(packageJsonPath)}`
4179
+ `package.json=${packageJsonPath} exists=${existsSync15(packageJsonPath)}`
4254
4180
  );
4255
4181
  logLine(
4256
4182
  `flags captureOutput=${input.captureOutput} packOnly=${Boolean(
@@ -4306,18 +4232,64 @@ function logWisdomFrontendDeployContext(input) {
4306
4232
  logLine(
4307
4233
  `buildKey=build:${input.env} buildCmd=${input.buildCmd ?? "(missing)"}`
4308
4234
  );
4309
- logLine(`distDir=${input.distDir} exists=${existsSync14(input.distDir)}`);
4235
+ logLine(`distDir=${input.distDir} exists=${existsSync15(input.distDir)}`);
4310
4236
  logLine(
4311
4237
  `packOnly=${input.packOnly} archiveDeployArtifact=${input.archiveDeployArtifact}`
4312
4238
  );
4313
4239
  }
4314
4240
 
4315
4241
  // src/commands/deploy/internal/wisdom-deploy.ts
4316
- import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync7 } from "node:fs";
4317
- 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";
4318
4244
 
4319
4245
  // src/commands/deploy/deploy-shell-run.ts
4320
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
4321
4293
  function runDeployShellCommand(command, cwd, captureOutput) {
4322
4294
  logRunDeployShellContext({ command, cwd, captureOutput });
4323
4295
  const shellEnv = buildDeployShellEnv();
@@ -4360,30 +4332,80 @@ function runDeployShellCommand(command, cwd, captureOutput) {
4360
4332
  return output;
4361
4333
  }
4362
4334
 
4363
- // 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
4364
4339
  import {
4365
- existsSync as existsSync15,
4366
- mkdirSync as mkdirSync7,
4340
+ mkdirSync as mkdirSync8,
4367
4341
  readdirSync as readdirSync5,
4368
- readFileSync as readFileSync12,
4342
+ readFileSync as readFileSync14,
4343
+ statSync as statSync7,
4344
+ writeFileSync as writeFileSync13
4345
+ } from "node:fs";
4346
+ import path6 from "node:path";
4347
+ import JSZip2 from "jszip";
4348
+
4349
+ // src/commands/deploy/internal/wisdom-backend/manifest.ts
4350
+ import {
4351
+ existsSync as existsSync16,
4352
+ mkdirSync as mkdirSync7,
4353
+ readFileSync as readFileSync13,
4369
4354
  statSync as statSync6,
4370
4355
  writeFileSync as writeFileSync12
4371
4356
  } from "node:fs";
4372
- import { spawnSync as spawnSync6 } from "node:child_process";
4373
- import path3 from "node:path";
4374
- import { Client as Client2 } from "ssh2";
4375
- import JSZip2 from "jszip";
4376
- import SftpClient2 from "ssh2-sftp-client";
4357
+ import path2 from "node:path";
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 {};
4375
+ }
4376
+ return JSON.parse(readFileSync13(manifestPath2, "utf8"));
4377
+ }
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";
4377
4395
 
4378
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
4379
4402
  import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
4380
- import path2 from "node:path";
4403
+ import path3 from "node:path";
4381
4404
  import JSZip from "jszip";
4382
- import SftpClient from "ssh2-sftp-client";
4383
4405
  async function addDirToZip(dir, zipFolder) {
4384
4406
  const entries = await readdir2(dir, { withFileTypes: true });
4385
4407
  for (const entry of entries) {
4386
- const fullPath = path2.join(dir, entry.name);
4408
+ const fullPath = path3.join(dir, entry.name);
4387
4409
  if (entry.isDirectory()) {
4388
4410
  const folder = zipFolder.folder(entry.name);
4389
4411
  if (folder) {
@@ -4409,7 +4431,66 @@ async function zipDirectory(distDir, zipPath) {
4409
4431
  console.error(`\u5DF2\u751F\u6210: ${zipPath} (${sizeMb} MB)`);
4410
4432
  return content.length;
4411
4433
  }
4412
- var SFTP_UPLOAD_MAX_ATTEMPTS = 3;
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
4493
+ var SFTP_UPLOAD_MAX_ATTEMPTS = 3;
4413
4494
  var SFTP_FAST_PUT_OPTIONS = {
4414
4495
  chunkSize: 64 * 1024,
4415
4496
  concurrency: 4
@@ -4427,7 +4508,7 @@ function buildSftpConnectOptions(settings) {
4427
4508
  };
4428
4509
  }
4429
4510
  async function sleep(ms) {
4430
- await new Promise((resolve5) => setTimeout(resolve5, ms));
4511
+ await new Promise((resolve6) => setTimeout(resolve6, ms));
4431
4512
  }
4432
4513
  async function uploadZipWithRetry(settings, localZip, remoteZipPath) {
4433
4514
  let lastError;
@@ -4471,7 +4552,7 @@ async function ensureRemoteDir(sftp, dir) {
4471
4552
  }
4472
4553
  }
4473
4554
  function execCommand(client, command) {
4474
- return new Promise((resolve5, reject) => {
4555
+ return new Promise((resolve6, reject) => {
4475
4556
  client.exec(command, (err, stream) => {
4476
4557
  if (err) return reject(err);
4477
4558
  let stdout = "";
@@ -4481,7 +4562,7 @@ function execCommand(client, command) {
4481
4562
  reject(new Error(`\u8FDC\u7A0B\u547D\u4EE4\u5931\u8D25 (${code}): ${stderr || stdout}`));
4482
4563
  return;
4483
4564
  }
4484
- resolve5(stdout);
4565
+ resolve6(stdout);
4485
4566
  }).on("data", (data) => {
4486
4567
  stdout += data.toString();
4487
4568
  });
@@ -4548,8 +4629,8 @@ function resolveDeployArtifactUpload(input) {
4548
4629
  return { upload: false, uploadWithoutRunId: false };
4549
4630
  }
4550
4631
  async function runWisdomSftpDeploy(params) {
4551
- const zipPath = path2.join(params.localDir, "..", ".deploy-sftp-dist.zip");
4552
- const resolvedZipPath = path2.resolve(zipPath);
4632
+ const zipPath = path4.join(params.localDir, "..", ".deploy-sftp-dist.zip");
4633
+ const resolvedZipPath = path4.resolve(zipPath);
4553
4634
  const packOnly = Boolean(params.packOnly);
4554
4635
  const archiveDeployArtifact = Boolean(params.archiveDeployArtifact);
4555
4636
  const deploymentRunId = resolveDeploymentRunIdFromEnv();
@@ -4560,38 +4641,44 @@ async function runWisdomSftpDeploy(params) {
4560
4641
  });
4561
4642
  let zipSizeBytes = 0;
4562
4643
  let artifactUploaded = false;
4563
- try {
4564
- zipSizeBytes = await zipDirectory(params.localDir, resolvedZipPath);
4565
- 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);
4566
4659
  await uploadAndMaybeExtract(
4567
4660
  params.settings,
4568
4661
  resolvedZipPath,
4569
4662
  params.extract
4570
4663
  );
4571
- } else {
4572
- console.error("[apm] \u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u8DF3\u8FC7 SFTP \u8FDC\u7A0B\u4E0A\u4F20");
4573
- }
4574
- if (artifactUpload.upload) {
4575
- const artifact = await uploadDeployArtifactZip({
4576
- zipPath: resolvedZipPath,
4577
- projectName: params.projectName,
4578
- kind: "frontend",
4579
- uploadWithoutRunId: artifactUpload.uploadWithoutRunId
4580
- });
4581
- artifactUploaded = artifact !== null;
4582
- }
4583
- if (artifactUploaded) {
4584
- if (packOnly) {
4585
- console.error("\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09");
4586
- } 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) {
4587
4674
  console.error("[apm] SFTP \u90E8\u7F72\u5B8C\u6210\uFF0C\u90E8\u7F72\u4EA7\u7269\u5DF2\u5F52\u6863 MinIO");
4588
4675
  }
4589
- }
4590
- } finally {
4591
- try {
4592
- await unlink(resolvedZipPath);
4593
- console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${resolvedZipPath}`);
4594
- } 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
+ }
4595
4682
  }
4596
4683
  }
4597
4684
  return {
@@ -4606,7 +4693,7 @@ async function runWisdomSftpDeploy(params) {
4606
4693
  };
4607
4694
  }
4608
4695
 
4609
- // src/commands/deploy/internal/wisdom-backend-deploy.ts
4696
+ // src/commands/deploy/internal/wisdom-backend/internal-utils.ts
4610
4697
  var SPRINGBOOT_JAVA_OPTS = "-XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -Xms512M -Xmx1G";
4611
4698
  var MAVEN_MODULE = "jeecg-module-system/jeecg-system-start";
4612
4699
  var MAVEN_PROFILE = "dev";
@@ -4619,11 +4706,11 @@ function log(message) {
4619
4706
  }
4620
4707
  function fail(message) {
4621
4708
  log(`ERROR: ${message}`);
4622
- process.exit(1);
4709
+ throw new DeployExecutionError(message, 1);
4623
4710
  }
4624
4711
  function expandPath(pathStr) {
4625
4712
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
4626
- return path3.resolve(pathStr.replace(/^~(?=\/|\\|$)/, home));
4713
+ return path5.resolve(pathStr.replace(/^~(?=\/|\\|$)/, home));
4627
4714
  }
4628
4715
  function quoteForShell(value) {
4629
4716
  if (process.platform === "win32") {
@@ -4637,34 +4724,14 @@ function formatMavenLocalRepoArg(repoPath) {
4637
4724
  }
4638
4725
  return `-Dmaven.repo.local=${repoPath}`;
4639
4726
  }
4640
- function deployCacheDir() {
4641
- return path3.join(workspaceApmDir(), "deploy", ".deploy_cache");
4642
- }
4643
- function manifestFilePath() {
4644
- return path3.join(deployCacheDir(), "manifest.json");
4645
- }
4646
4727
  function getTargetDir(projectRoot) {
4647
- return path3.join(projectRoot, MAVEN_MODULE, "target");
4648
- }
4649
- function relativeKey(projectRoot, filePath) {
4650
- return path3.relative(projectRoot, filePath).split(path3.sep).join("/");
4651
- }
4652
- function fileSignature(filePath) {
4653
- const stat2 = statSync6(filePath);
4654
- return { size: stat2.size, mtime: stat2.mtimeMs / 1e3 };
4728
+ return path5.join(projectRoot, MAVEN_MODULE, "target");
4655
4729
  }
4656
- function loadManifest3() {
4657
- const manifestPath2 = manifestFilePath();
4658
- if (!existsSync15(manifestPath2)) {
4659
- return {};
4660
- }
4661
- return JSON.parse(readFileSync12(manifestPath2, "utf8"));
4662
- }
4663
- function saveManifest3(manifest) {
4664
- const dir = deployCacheDir();
4665
- mkdirSync7(dir, { recursive: true });
4666
- writeFileSync12(manifestFilePath(), JSON.stringify(manifest, null, 2), "utf8");
4730
+ function stripAnsi(text) {
4731
+ return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
4667
4732
  }
4733
+
4734
+ // src/commands/deploy/internal/wisdom-backend/jar-incremental.ts
4668
4735
  function isProjectLibJar(jarName) {
4669
4736
  return jarName.startsWith("jeecg-");
4670
4737
  }
@@ -4672,12 +4739,12 @@ function shouldUploadLibFile(localPath, remoteAttr, manifest, projectRoot) {
4672
4739
  if (!remoteAttr) {
4673
4740
  return [false, "\u8FDC\u7A0B\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7"];
4674
4741
  }
4675
- const localSize = statSync6(localPath).size;
4742
+ const localSize = statSync7(localPath).size;
4676
4743
  const remoteSize = remoteAttr.size;
4677
4744
  if (localSize !== remoteSize) {
4678
4745
  return [true, `\u5927\u5C0F\u53D8\u5316 ${remoteSize} -> ${localSize}`];
4679
4746
  }
4680
- if (isProjectLibJar(path3.basename(localPath)) && manifest) {
4747
+ if (isProjectLibJar(path6.basename(localPath)) && manifest) {
4681
4748
  const key = relativeKey(projectRoot, localPath);
4682
4749
  const current = fileSignature(localPath);
4683
4750
  const previous = manifest[key];
@@ -4697,7 +4764,7 @@ function listLibFilesToUpload(localLibDir, remoteStats, projectRoot, manifest =
4697
4764
  const entries = [];
4698
4765
  const jarFiles = readdirSync5(localLibDir).filter((name) => name.endsWith(".jar")).sort();
4699
4766
  for (const jarName of jarFiles) {
4700
- const jarPath = path3.join(localLibDir, jarName);
4767
+ const jarPath = path6.join(localLibDir, jarName);
4701
4768
  const remoteAttr = remoteStats.get(jarName);
4702
4769
  const [shouldUpload, reason] = shouldUploadLibFile(
4703
4770
  jarPath,
@@ -4711,20 +4778,14 @@ function listLibFilesToUpload(localLibDir, remoteStats, projectRoot, manifest =
4711
4778
  }
4712
4779
  return entries;
4713
4780
  }
4714
- function updateManifestEntries(manifest, entries, projectRoot) {
4715
- for (const entry of entries) {
4716
- manifest[relativeKey(projectRoot, entry.path)] = fileSignature(entry.path);
4717
- }
4718
- return manifest;
4719
- }
4720
4781
  async function createUpdatePackage(entries, packageName) {
4721
- const dir = deployCacheDir();
4722
- mkdirSync7(dir, { recursive: true });
4723
- const zipPath = path3.join(dir, packageName);
4724
- 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`);
4725
4786
  const zip = new JSZip2();
4726
4787
  for (const entry of entries) {
4727
- const content = readFileSync12(entry.path);
4788
+ const content = readFileSync14(entry.path);
4728
4789
  zip.file(entry.arcname, content);
4729
4790
  log(` \u6253\u5305: ${entry.arcname} (${entry.reason})`);
4730
4791
  }
@@ -4733,9 +4794,21 @@ async function createUpdatePackage(entries, packageName) {
4733
4794
  compression: "DEFLATE",
4734
4795
  compressionOptions: { level: 6 }
4735
4796
  });
4736
- writeFileSync12(zipPath, buffer);
4797
+ writeFileSync13(zipPath, buffer);
4737
4798
  return zipPath;
4738
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";
4739
4812
  function getMvnExecutable() {
4740
4813
  const isWin = process.platform === "win32";
4741
4814
  const candidates = isWin ? ["mvn.cmd", "mvn.bat", "mvn"] : ["mvn"];
@@ -4782,14 +4855,14 @@ function runMavenBuild(projectRoot, mavenLocalRepo, repoSource) {
4782
4855
  }
4783
4856
  function locateLibDir(projectRoot) {
4784
4857
  const targetDir = getTargetDir(projectRoot);
4785
- if (!existsSync15(targetDir)) {
4858
+ if (!existsSync18(targetDir)) {
4786
4859
  fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
4787
4860
  }
4788
- const libDir = path3.join(targetDir, "lib");
4789
- if (!existsSync15(libDir) || !statSync6(libDir).isDirectory()) {
4861
+ const libDir = path7.join(targetDir, "lib");
4862
+ if (!existsSync18(libDir) || !statSync8(libDir).isDirectory()) {
4790
4863
  fail(`lib \u76EE\u5F55\u4E0D\u5B58\u5728: ${libDir}`);
4791
4864
  }
4792
- const libJars = readdirSync5(libDir).filter((name) => name.endsWith(".jar"));
4865
+ const libJars = readdirSync6(libDir).filter((name) => name.endsWith(".jar"));
4793
4866
  if (libJars.length === 0) {
4794
4867
  fail(`lib \u76EE\u5F55\u4E0B\u6CA1\u6709\u4F9D\u8D56 JAR: ${libDir}`);
4795
4868
  }
@@ -4798,124 +4871,24 @@ function locateLibDir(projectRoot) {
4798
4871
  }
4799
4872
  function locateMainJar(projectRoot) {
4800
4873
  const targetDir = getTargetDir(projectRoot);
4801
- if (!existsSync15(targetDir)) {
4874
+ if (!existsSync18(targetDir)) {
4802
4875
  fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
4803
4876
  }
4804
- 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);
4805
4878
  if (jarFiles.length === 0) {
4806
4879
  fail(`target \u76EE\u5F55\u4E0B\u6CA1\u6709\u4E3B JAR: ${targetDir}`);
4807
4880
  }
4808
4881
  const mainJar = jarFiles[0];
4809
- log(`\u5B9A\u4F4D\u4E3B JAR \u4EA7\u7269: ${path3.basename(mainJar)}`);
4882
+ log(`\u5B9A\u4F4D\u4E3B JAR \u4EA7\u7269: ${path7.basename(mainJar)}`);
4810
4883
  return mainJar;
4811
4884
  }
4812
- async function connectSsh(config) {
4813
- const client = new Client2();
4814
- log(`\u8FDE\u63A5\u670D\u52A1\u5668 ${config.username}@${config.host}:${config.port}`);
4815
- await new Promise((resolve5, reject) => {
4816
- client.on("ready", () => resolve5()).on("error", (err) => reject(err)).connect({
4817
- host: config.host,
4818
- port: config.port,
4819
- username: config.username,
4820
- password: config.password,
4821
- readyTimeout: 3e4,
4822
- tryKeyboard: true
4823
- });
4824
- });
4825
- const sftp = new SftpClient2();
4826
- await sftp.connect({
4827
- host: config.host,
4828
- port: config.port,
4829
- username: config.username,
4830
- password: config.password,
4831
- readyTimeout: 3e4,
4832
- tryKeyboard: true
4833
- });
4834
- return { client, sftp };
4835
- }
4836
- async function closeSsh(conn) {
4837
- try {
4838
- await conn.sftp.end();
4839
- } catch {
4840
- }
4841
- conn.client.end();
4842
- }
4843
- async function getRemoteFileStats(sftp, remoteDir) {
4844
- const stats = /* @__PURE__ */ new Map();
4845
- try {
4846
- const listing = await sftp.list(remoteDir);
4847
- for (const item of listing) {
4848
- if (item.name.endsWith(".jar")) {
4849
- stats.set(item.name, { filename: item.name, size: item.size });
4850
- }
4851
- }
4852
- } catch {
4853
- }
4854
- return stats;
4855
- }
4856
- async function uploadUpdatePackage(sftp, zipPath, config) {
4857
- const remoteDir = config.remoteVueDistDir.replace(/\/$/, "");
4858
- const remotePath = `${remoteDir}/${path3.basename(zipPath)}`;
4859
- log(`\u4E0A\u4F20\u66F4\u65B0\u5305 -> ${remotePath}`);
4860
- try {
4861
- await sftp.fastPut(zipPath, remotePath);
4862
- log("\u66F4\u65B0\u5305\u4E0A\u4F20\u6210\u529F");
4863
- } catch (err) {
4864
- fail(`\u66F4\u65B0\u5305\u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
4865
- }
4866
- return remotePath;
4867
- }
4868
- async function uploadFullJar(sftp, localJarPath, config) {
4869
- const remoteDir = config.remoteAppDir.replace(/\/$/, "");
4870
- const remotePath = `${remoteDir}/${config.startupJar}`;
4871
- log(`\u4E0A\u4F20\u5168\u91CF JAR (${path3.basename(localJarPath)}) -> ${remotePath}`);
4872
- try {
4873
- await sftp.mkdir(remoteDir, true);
4874
- await sftp.fastPut(localJarPath, remotePath);
4875
- log("\u5168\u91CF JAR \u4E0A\u4F20\u6210\u529F");
4876
- } catch (err) {
4877
- fail(`\u5168\u91CF JAR \u4E0A\u4F20\u5931\u8D25: ${err instanceof Error ? err.message : err}`);
4878
- }
4879
- }
4880
- async function runRemoteCommand(client, command, options) {
4881
- const check = options?.check ?? true;
4882
- const stream = options?.stream ?? false;
4883
- const label = options?.label ?? "\u8FDC\u7A0B\u547D\u4EE4";
4884
- return new Promise((resolve5, reject) => {
4885
- client.exec(command, (err, execStream) => {
4886
- if (err) {
4887
- reject(err);
4888
- return;
4889
- }
4890
- let out = "";
4891
- let errText = "";
4892
- execStream.on("data", (data) => {
4893
- const text = data.toString();
4894
- out += text;
4895
- if (stream) {
4896
- process.stdout.write(text);
4897
- }
4898
- });
4899
- execStream.stderr.on("data", (data) => {
4900
- errText += data.toString();
4901
- });
4902
- execStream.on("close", (code) => {
4903
- if (stream && out && !out.endsWith("\n")) {
4904
- process.stdout.write("\n");
4905
- }
4906
- if (check && code !== 0) {
4907
- const combined = `${out}
4908
- ${errText}`.trim();
4909
- fail(
4910
- `${label}\u5931\u8D25 (exit ${code})` + (combined ? `
4911
- \u8F93\u51FA: ${combined}` : "")
4912
- );
4913
- }
4914
- resolve5({ exitCode: code, out: out.trim(), err: errText.trim() });
4915
- });
4916
- });
4917
- });
4918
- }
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
4919
4892
  function buildExtractUpdatePackageScript(remoteZipPath, remoteLibDir) {
4920
4893
  const quotedZip = shellSingleQuote(remoteZipPath);
4921
4894
  const quotedLib = shellSingleQuote(remoteLibDir);
@@ -4939,39 +4912,6 @@ done < <(find "$TMP" -name '*.jar' -type f -print0)
4939
4912
  echo "UPDATED_COUNT=$updated"
4940
4913
  `.trim();
4941
4914
  }
4942
- async function extractUpdatePackageOnRemote(client, config, remoteZipPath) {
4943
- const script = buildExtractUpdatePackageScript(
4944
- remoteZipPath,
4945
- config.remoteLibDir
4946
- );
4947
- const { out } = await runRemoteCommand(client, script, {
4948
- label: "\u8FDC\u7A0B\u89E3\u538B"
4949
- });
4950
- const match = out.match(/UPDATED_COUNT=(\d+)/);
4951
- if (!match) {
4952
- fail(`\u8FDC\u7A0B\u89E3\u538B\u5931\u8D25\uFF0C\u672A\u83B7\u53D6\u66F4\u65B0\u6570\u91CF
4953
- \u8F93\u51FA: ${out || "(\u7A7A)"}`);
4954
- }
4955
- const updated = Number.parseInt(match[1], 10);
4956
- log(`lib \u89E3\u538B\u5B8C\u6210: \u8986\u76D6 ${updated} \u4E2A`);
4957
- return updated;
4958
- }
4959
- function springbootOutputIndicatesSuccess(action, combined) {
4960
- const lower = combined.toLowerCase();
4961
- if (action === "health") {
4962
- return combined.includes("\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7");
4963
- }
4964
- if (action === "start" || action === "restart") {
4965
- return combined.includes("is starting") || lower.includes("is running");
4966
- }
4967
- if (action === "stop") {
4968
- return combined.includes("is stopping") || lower.includes("not running") || lower.includes("please check it");
4969
- }
4970
- if (action === "status") {
4971
- return lower.includes("running") || lower.includes("not running");
4972
- }
4973
- return true;
4974
- }
4975
4915
  function buildRemoteStatusScript(remoteAppDir, appName) {
4976
4916
  const dir = shellSingleQuote(remoteAppDir);
4977
4917
  const jar = shellSingleQuote(appName);
@@ -5070,6 +5010,150 @@ echo -e "\\033[31m\u5065\u5EB7\u68C0\u67E5\u8D85\u65F6 (\${timeout}s): \${check_
5070
5010
  exit 1
5071
5011
  `.trim();
5072
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
5073
5157
  async function runRemoteServiceScript(client, script, action) {
5074
5158
  const { exitCode, out, err } = await runRemoteCommand(client, script, {
5075
5159
  check: false,
@@ -5095,9 +5179,6 @@ ${combined}`);
5095
5179
  }
5096
5180
  return combined;
5097
5181
  }
5098
- function stripAnsi(text) {
5099
- return text.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "");
5100
- }
5101
5182
  async function getRunningJar(client, config) {
5102
5183
  const script = buildRemoteStatusScript(
5103
5184
  config.remoteAppDir,
@@ -5126,19 +5207,14 @@ async function restartRemoteService(client, config) {
5126
5207
  const script = buildRemoteRestartScript(config.remoteAppDir);
5127
5208
  await runRemoteServiceScript(client, script, "restart");
5128
5209
  }
5129
- function listAllLibFilesForArchive(libDir) {
5130
- return readdirSync5(libDir).filter((name) => name.endsWith(".jar")).sort().map((jarName) => ({
5131
- path: path3.join(libDir, jarName),
5132
- arcname: jarName,
5133
- reason: "\u4EC5\u6253\u5305\u5F52\u6863"
5134
- }));
5135
- }
5210
+
5211
+ // src/commands/deploy/internal/wisdom-backend/index.ts
5136
5212
  async function runWisdomBackendDeploy(options) {
5137
- const projectRoot = path3.resolve(options.projectRoot ?? process.cwd());
5213
+ const projectRoot = path9.resolve(options.projectRoot ?? process.cwd());
5138
5214
  const config = options.config;
5139
5215
  const packOnly = Boolean(options.packOnly);
5140
5216
  log(`=== \u81EA\u52A8\u90E8\u7F72: ${config.projectName} ===`);
5141
- log(`\u914D\u7F6E\u6587\u4EF6: ${path3.join(workspaceApmDir(), "apm.config.json")}`);
5217
+ log(`\u914D\u7F6E\u6587\u4EF6: ${path9.join(workspaceApmDir(), "apm.config.json")}`);
5142
5218
  log(`\u9879\u76EE\u6839\u76EE\u5F55: ${projectRoot}`);
5143
5219
  log(
5144
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" : ""}`
@@ -5155,7 +5231,7 @@ async function runWisdomBackendDeploy(options) {
5155
5231
  [
5156
5232
  {
5157
5233
  path: mainJar,
5158
- arcname: path3.basename(mainJar),
5234
+ arcname: path9.basename(mainJar),
5159
5235
  reason: "\u5168\u91CF JAR \u5F52\u6863"
5160
5236
  }
5161
5237
  ],
@@ -5193,7 +5269,7 @@ async function runWisdomBackendDeploy(options) {
5193
5269
  [
5194
5270
  {
5195
5271
  path: mainJar,
5196
- arcname: path3.basename(mainJar),
5272
+ arcname: path9.basename(mainJar),
5197
5273
  reason: "\u5168\u91CF JAR \u5F52\u6863"
5198
5274
  }
5199
5275
  ],
@@ -5277,15 +5353,15 @@ function isWisdomDeployConfigured(cfg) {
5277
5353
  return Boolean(w?.host?.trim() && w?.remotePath?.trim());
5278
5354
  }
5279
5355
  function detectWisdomProjectType(cwd) {
5280
- return existsSync16(path4.join(cwd, "package.json")) ? "frontend" : "backend";
5356
+ return existsSync19(path10.join(cwd, "package.json")) ? "frontend" : "backend";
5281
5357
  }
5282
5358
  function readPackageScripts(cwd) {
5283
- const pkgPath = path4.join(cwd, "package.json");
5284
- if (!existsSync16(pkgPath)) {
5359
+ const pkgPath = path10.join(cwd, "package.json");
5360
+ if (!existsSync19(pkgPath)) {
5285
5361
  return {};
5286
5362
  }
5287
5363
  try {
5288
- const raw = readFileSync13(pkgPath, "utf8");
5364
+ const raw = readFileSync15(pkgPath, "utf8");
5289
5365
  const parsed = JSON.parse(raw);
5290
5366
  return parsed.scripts ?? {};
5291
5367
  } catch {
@@ -5306,15 +5382,15 @@ function resolveFrontendBuildCommand(env, cwd) {
5306
5382
  function resolveFrontendDistDir(cwd) {
5307
5383
  const candidates = ["dist", "apps/web/dist"];
5308
5384
  for (const rel of candidates) {
5309
- const full = path4.join(cwd, rel);
5385
+ const full = path10.join(cwd, rel);
5310
5386
  try {
5311
- if (existsSync16(full) && statSync7(full).isDirectory()) {
5387
+ if (existsSync19(full) && statSync9(full).isDirectory()) {
5312
5388
  return full;
5313
5389
  }
5314
5390
  } catch {
5315
5391
  }
5316
5392
  }
5317
- return path4.join(cwd, "dist");
5393
+ return path10.join(cwd, "dist");
5318
5394
  }
5319
5395
  async function executeWisdomFrontendDeploy(options) {
5320
5396
  const { cwd, cfg, captureOutput, packOnly, archiveDeployArtifact } = options;
@@ -5331,7 +5407,7 @@ async function executeWisdomFrontendDeploy(options) {
5331
5407
  if (!buildCmd) {
5332
5408
  const lines = formatWisdomFrontendBuildNotConfiguredLines(
5333
5409
  options.env,
5334
- path4.join(cwd, "package.json")
5410
+ path10.join(cwd, "package.json")
5335
5411
  );
5336
5412
  throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
5337
5413
  }
@@ -5339,16 +5415,9 @@ async function executeWisdomFrontendDeploy(options) {
5339
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" : ""))
5340
5416
  );
5341
5417
  runDeployShellCommand(buildCmd, cwd, captureOutput);
5342
- let projectName = (cfg.name ?? "").trim();
5343
- if ((packOnly || archiveDeployArtifact) && !projectName) {
5344
- throw new DeployExecutionError(
5345
- "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09",
5346
- 1
5347
- );
5348
- }
5349
- if (!projectName) {
5350
- projectName = path4.basename(cwd);
5351
- }
5418
+ const projectName = resolveProjectNameForDeploy(cfg, cwd, {
5419
+ requireName: packOnly || archiveDeployArtifact
5420
+ });
5352
5421
  const settings = resolveWisdomDeployFromApmConfig(cfg);
5353
5422
  await runWisdomSftpDeploy({
5354
5423
  localDir: distDir,
@@ -5376,12 +5445,12 @@ async function executeWisdomBackendDeployFlow(options) {
5376
5445
  });
5377
5446
  }
5378
5447
  async function executeWisdomDeploy(options) {
5379
- const cwd = path4.resolve(options.cwd);
5448
+ const cwd = path10.resolve(options.cwd);
5380
5449
  const captureOutput = options.captureOutput ?? false;
5381
5450
  const packOnly = Boolean(options.packOnly);
5382
5451
  const archiveDeployArtifact = Boolean(options.archiveDeployArtifact);
5383
5452
  const projectType = detectWisdomProjectType(cwd);
5384
- const configPath = options.configPath ?? path4.join(workspaceApmDir(cwd), "apm.config.json");
5453
+ const configPath = options.configPath ?? path10.join(workspaceApmDir(cwd), "apm.config.json");
5385
5454
  const cfg = loadApmConfig({ configPath });
5386
5455
  console.error(
5387
5456
  `[apm] ${projectType === "frontend" ? "Vue \u524D\u7AEF" : "Java \u540E\u7AEF"}${packOnly ? "\uFF08\u4EC5\u6253\u5305\uFF09" : ""}`
@@ -5544,7 +5613,7 @@ async function executeDeploy(options) {
5544
5613
  throw new DeployExecutionError("[apm] executeDeploy \u7F3A\u5C11\u5DE5\u4F5C\u76EE\u5F55 cwd", 1);
5545
5614
  }
5546
5615
  const cwd = resolveWorkdirPath(cwdInput);
5547
- const apmConfigPath = options.configPath ?? path5.join(workspaceApmDir(cwd), "apm.config.json");
5616
+ const apmConfigPath = options.configPath ?? path11.join(workspaceApmDir(cwd), "apm.config.json");
5548
5617
  const captureOutput = options.captureOutput ?? false;
5549
5618
  const outputParts = [];
5550
5619
  logExecuteDeployContext({
@@ -5613,11 +5682,36 @@ function printDeployExecutionError(error) {
5613
5682
  console.error(error.message);
5614
5683
  }
5615
5684
 
5616
- // src/commands/connect/deploy-run.ts
5617
- var DEPLOY_LOG_SYNC_INTERVAL_MS = 3e4;
5618
- function resolveDeployCommand(environment, packOnly) {
5619
- 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
+ };
5620
5711
  }
5712
+
5713
+ // src/commands/deploy/platform/deploy-log-syncer.ts
5714
+ var DEPLOY_LOG_SYNC_INTERVAL_MS = 1e4;
5621
5715
  function logDeploySyncFailure(error) {
5622
5716
  console.error(
5623
5717
  "[apm] deploy log sync failed:",
@@ -5627,7 +5721,9 @@ function logDeploySyncFailure(error) {
5627
5721
  function createDeployLogSyncer(api, deploymentRunId) {
5628
5722
  let lastSyncedLog = "";
5629
5723
  let latestLog = "";
5630
- let timer = null;
5724
+ let lastRunAt = 0;
5725
+ let timer;
5726
+ let syncChain = Promise.resolve();
5631
5727
  const syncDelta = async (delta, append) => {
5632
5728
  const chunks = splitUtf8StringByMaxBytes(
5633
5729
  delta,
@@ -5652,29 +5748,58 @@ function createDeployLogSyncer(api, deploymentRunId) {
5652
5748
  if (!delta) {
5653
5749
  return;
5654
5750
  }
5655
- await syncDelta(delta, lastSyncedLog.length > 0);
5656
- 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
+ }
5657
5788
  };
5658
- timer = setInterval(() => {
5659
- void syncIfChanged().catch(logDeploySyncFailure);
5660
- }, DEPLOY_LOG_SYNC_INTERVAL_MS);
5661
5789
  return {
5662
5790
  updateLog(log2) {
5663
5791
  latestLog = log2;
5792
+ schedule();
5664
5793
  },
5665
5794
  async flush() {
5666
- if (timer) {
5667
- clearInterval(timer);
5668
- timer = null;
5669
- }
5795
+ stopTimer();
5796
+ await syncChain;
5670
5797
  await syncIfChanged();
5671
5798
  },
5672
5799
  async flushSafe() {
5673
- if (timer) {
5674
- clearInterval(timer);
5675
- timer = null;
5676
- }
5800
+ stopTimer();
5677
5801
  try {
5802
+ await syncChain;
5678
5803
  await syncIfChanged();
5679
5804
  return true;
5680
5805
  } catch (error) {
@@ -5683,15 +5808,12 @@ function createDeployLogSyncer(api, deploymentRunId) {
5683
5808
  }
5684
5809
  },
5685
5810
  dispose() {
5686
- if (timer) {
5687
- clearInterval(timer);
5688
- timer = null;
5689
- }
5811
+ stopTimer();
5690
5812
  }
5691
5813
  };
5692
5814
  }
5693
5815
  async function finalizeTaskDeployment(api, deploymentRunId, logSyncer, input) {
5694
- const synced = await logSyncer.flushSafe();
5816
+ await logSyncer.flushSafe();
5695
5817
  const payload = {
5696
5818
  id: deploymentRunId,
5697
5819
  status: input.status
@@ -5699,76 +5821,48 @@ async function finalizeTaskDeployment(api, deploymentRunId, logSyncer, input) {
5699
5821
  if (input.error) {
5700
5822
  payload.error = input.error;
5701
5823
  }
5702
- if (!synced) {
5703
- payload.log = truncateDeployLogForComplete(input.fullLog).log;
5704
- }
5705
- await retryDeployLogSync(() => api.cli.completeTaskDeployment(payload));
5824
+ await retryDeployStatusComplete(
5825
+ () => api.cli.completeTaskDeployment(payload)
5826
+ );
5706
5827
  }
5707
- function captureDeployConsole(logSyncer) {
5708
- const chunks = [];
5709
- const appendLog = (line) => {
5710
- if (!line) return;
5711
- chunks.push(line);
5712
- logSyncer.updateLog(chunks.join("\n"));
5713
- };
5714
- const originalLog = console.log;
5715
- const originalError = console.error;
5716
- console.log = (...args) => {
5717
- appendLog(args.map(String).join(" "));
5718
- originalLog.apply(console, args);
5719
- };
5720
- console.error = (...args) => {
5721
- appendLog(args.map(String).join(" "));
5722
- originalError.apply(console, args);
5723
- };
5724
- return {
5725
- appendLog,
5726
- restore: () => {
5727
- console.log = originalLog;
5728
- console.error = originalError;
5729
- },
5730
- getLog: () => chunks.join("\n")
5731
- };
5828
+ async function ensureDeploymentStatusSynced(api, deploymentRunId, logSyncer, outcome) {
5829
+ await finalizeTaskDeployment(api, deploymentRunId, logSyncer, outcome);
5732
5830
  }
5733
- async function handleInboundDeploy(cfg, msg, signal) {
5734
- const api = createApmApiClient(cfg);
5735
- const deploymentRunId = msg.deploymentRunId;
5736
- if (signal.aborted) return;
5737
- await api.cli.updateTaskDeploymentStatus({
5738
- id: deploymentRunId,
5739
- status: "DEPLOYING"
5740
- });
5741
- const workdir = requireRemoteWorkdir(msg.workdir);
5742
- const displayCommand = resolveDeployCommand(msg.environment, msg.packOnly);
5743
- console.log(
5744
- `[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)
5745
5837
  );
5746
- 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;
5747
5845
  const logSyncer = createDeployLogSyncer(api, deploymentRunId);
5748
5846
  const previousDeploymentRunId = process.env[APM_DEPLOYMENT_RUN_ID_ENV];
5749
5847
  process.env[APM_DEPLOYMENT_RUN_ID_ENV] = deploymentRunId;
5750
5848
  const capture = captureDeployConsole(logSyncer);
5751
- const deployOptions = {
5752
- env: msg.environment,
5753
- cwd: workdir,
5754
- packOnly: msg.packOnly,
5755
- captureOutput: true,
5756
- archiveDeployArtifact: true,
5757
- 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;
5758
5861
  };
5759
5862
  try {
5760
- if (signal.aborted) return;
5761
- const output = await executeDeploy(deployOptions);
5762
- if (output.trim()) {
5763
- capture.appendLog(output);
5764
- }
5765
- await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
5766
- status: "SUCCESS",
5767
- fullLog: capture.getLog()
5768
- });
5769
- console.log(`[apm] deploy success id=${deploymentRunId}`);
5863
+ outcome = await run(capture.appendLog);
5770
5864
  } catch (error) {
5771
- const deployError = error instanceof DeployExecutionError ? error : new DeployExecutionError(
5865
+ deployError = error instanceof DeployExecutionError ? error : new DeployExecutionError(
5772
5866
  error instanceof Error ? error.message : String(error),
5773
5867
  1
5774
5868
  );
@@ -5777,22 +5871,18 @@ async function handleInboundDeploy(cfg, msg, signal) {
5777
5871
  } else {
5778
5872
  capture.appendLog(deployError.message);
5779
5873
  }
5780
- try {
5781
- await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
5782
- status: "FAILED",
5783
- fullLog: capture.getLog(),
5784
- error: deployError.message
5785
- });
5786
- } catch (finalizeError) {
5787
- console.error(
5788
- `[apm] deploy finalize failed id=${deploymentRunId}:`,
5789
- finalizeError instanceof Error ? finalizeError.message : String(finalizeError)
5790
- );
5791
- }
5792
- console.error(
5793
- `[apm] deploy failed id=${deploymentRunId}: ${deployError.message}`
5794
- );
5874
+ outcome = { status: "FAILED", error: deployError.message };
5795
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
+ }
5796
5886
  capture.restore();
5797
5887
  if (previousDeploymentRunId === void 0) {
5798
5888
  delete process.env[APM_DEPLOYMENT_RUN_ID_ENV];
@@ -5801,6 +5891,58 @@ async function handleInboundDeploy(cfg, msg, signal) {
5801
5891
  }
5802
5892
  logSyncer.dispose();
5803
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
+ }
5804
5946
  }
5805
5947
 
5806
5948
  // src/commands/connect/abort-signal-debug.ts
@@ -6070,17 +6212,17 @@ ${JSON.stringify(event, null, 2)}
6070
6212
  }
6071
6213
 
6072
6214
  // src/commands/connect/agent-session-registry.ts
6073
- import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "node:fs";
6074
- 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";
6075
6217
  function registryPath(workdir, sessionId) {
6076
- return resolve4(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
6218
+ return resolve5(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
6077
6219
  }
6078
- function readRegistry(path13) {
6079
- if (!existsSync17(path13)) {
6220
+ function readRegistry(path19) {
6221
+ if (!existsSync20(path19)) {
6080
6222
  return {};
6081
6223
  }
6082
6224
  try {
6083
- const parsed = JSON.parse(readFileSync14(path13, "utf8"));
6225
+ const parsed = JSON.parse(readFileSync16(path19, "utf8"));
6084
6226
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
6085
6227
  const result = {};
6086
6228
  for (const [key, value] of Object.entries(
@@ -6096,9 +6238,9 @@ function readRegistry(path13) {
6096
6238
  }
6097
6239
  return {};
6098
6240
  }
6099
- function writeRegistry(path13, registry) {
6100
- mkdirSync8(dirname6(path13), { recursive: true });
6101
- 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)}
6102
6244
  `, "utf8");
6103
6245
  }
6104
6246
  function loadSessionAgentId(workdir, sessionId, user) {
@@ -6106,19 +6248,19 @@ function loadSessionAgentId(workdir, sessionId, user) {
6106
6248
  return registry[user];
6107
6249
  }
6108
6250
  function saveSessionAgentId(workdir, sessionId, user, agentId) {
6109
- const path13 = registryPath(workdir, sessionId);
6110
- const registry = readRegistry(path13);
6251
+ const path19 = registryPath(workdir, sessionId);
6252
+ const registry = readRegistry(path19);
6111
6253
  registry[user] = agentId;
6112
- writeRegistry(path13, registry);
6254
+ writeRegistry(path19, registry);
6113
6255
  }
6114
6256
  function clearSessionAgentId(workdir, sessionId, user) {
6115
- const path13 = registryPath(workdir, sessionId);
6116
- const registry = readRegistry(path13);
6257
+ const path19 = registryPath(workdir, sessionId);
6258
+ const registry = readRegistry(path19);
6117
6259
  if (!(user in registry)) {
6118
6260
  return;
6119
6261
  }
6120
6262
  delete registry[user];
6121
- writeRegistry(path13, registry);
6263
+ writeRegistry(path19, registry);
6122
6264
  }
6123
6265
 
6124
6266
  // src/commands/connect/cursor-message-log.ts
@@ -6548,20 +6690,20 @@ async function ensureMessageHasReply(cfg, sessionId, messageId, fallback) {
6548
6690
  }
6549
6691
 
6550
6692
  // src/commands/connect/cli-version-sync.ts
6551
- 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";
6552
6694
  import { join as join17 } from "path";
6553
6695
  var CLI_VERSION_FILE = ".cli-version.json";
6554
6696
  function manifestPath(apmDir) {
6555
6697
  return join17(apmDir, CLI_VERSION_FILE);
6556
6698
  }
6557
6699
  function loadManifest4(apmDir) {
6558
- const path13 = toFsPath(manifestPath(apmDir));
6559
- if (!existsSync18(path13)) {
6700
+ const path19 = toFsPath(manifestPath(apmDir));
6701
+ if (!existsSync21(path19)) {
6560
6702
  return null;
6561
6703
  }
6562
6704
  try {
6563
6705
  const parsed = JSON.parse(
6564
- readFileSync15(path13, "utf8")
6706
+ readFileSync17(path19, "utf8")
6565
6707
  );
6566
6708
  if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
6567
6709
  return parsed;
@@ -6572,7 +6714,7 @@ function loadManifest4(apmDir) {
6572
6714
  }
6573
6715
  function saveManifest4(apmDir, cliVersion) {
6574
6716
  const manifest = { version: 1, cliVersion };
6575
- writeFileSync14(
6717
+ writeFileSync15(
6576
6718
  toFsPath(manifestPath(apmDir)),
6577
6719
  `${JSON.stringify(manifest, null, 2)}
6578
6720
  `,
@@ -6651,7 +6793,7 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {})
6651
6793
  );
6652
6794
  }
6653
6795
  const queuedAt = Date.now();
6654
- return new Promise((resolve5) => {
6796
+ return new Promise((resolve6) => {
6655
6797
  waiters.push(() => {
6656
6798
  active += 1;
6657
6799
  const waitedMs = Date.now() - queuedAt;
@@ -6662,7 +6804,7 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {})
6662
6804
  )}s\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`
6663
6805
  );
6664
6806
  }
6665
- resolve5();
6807
+ resolve6();
6666
6808
  });
6667
6809
  });
6668
6810
  };
@@ -6837,11 +6979,11 @@ async function handleInboundMessage(cfg, msg, signal, ctx) {
6837
6979
  }
6838
6980
  function interruptibleSleep(ms, signal) {
6839
6981
  if (signal.aborted) return Promise.resolve();
6840
- return new Promise((resolve5) => {
6841
- const timer = setTimeout(resolve5, ms);
6982
+ return new Promise((resolve6) => {
6983
+ const timer = setTimeout(resolve6, ms);
6842
6984
  const onAbort = () => {
6843
6985
  clearTimeout(timer);
6844
- resolve5();
6986
+ resolve6();
6845
6987
  };
6846
6988
  signal.addEventListener("abort", onAbort, { once: true });
6847
6989
  });
@@ -6981,7 +7123,7 @@ function attachWsHandlers(ws, ctx, onOpen) {
6981
7123
  });
6982
7124
  }
6983
7125
  function connectOnce(url, ctx, connectionAbort, onConnected) {
6984
- return new Promise((resolve5, reject) => {
7126
+ return new Promise((resolve6, reject) => {
6985
7127
  const ws = new WebSocket(url);
6986
7128
  let stopHeartbeat;
6987
7129
  let settled = false;
@@ -7010,7 +7152,7 @@ function connectOnce(url, ctx, connectionAbort, onConnected) {
7010
7152
  finish(() => reject(new Error("shutdown")));
7011
7153
  return;
7012
7154
  }
7013
- finish(resolve5);
7155
+ finish(resolve6);
7014
7156
  });
7015
7157
  ws.on("error", (err) => {
7016
7158
  console.error("[apm] WebSocket \u9519\u8BEF:", err.message);
@@ -7290,14 +7432,6 @@ function normalizeDeployEnvironment(env) {
7290
7432
  if (normalized === "online") return "ONLINE";
7291
7433
  return null;
7292
7434
  }
7293
- async function completeTrackedDeploy(api, deploymentRunId, logSyncer, input) {
7294
- logSyncer.updateLog(input.log);
7295
- await finalizeTaskDeployment(api, deploymentRunId, logSyncer, {
7296
- status: input.status,
7297
- fullLog: input.log,
7298
- error: input.error
7299
- });
7300
- }
7301
7435
  async function runDeployWithBackendTracking(options) {
7302
7436
  const cfg = await tryReadApmConfig();
7303
7437
  if (!cfg || !resolveApiKey(cfg)) {
@@ -7319,7 +7453,7 @@ async function runDeployWithBackendTracking(options) {
7319
7453
  const run = await api.cli.createTaskDeployment({
7320
7454
  sessionId: options.sessionId,
7321
7455
  environment,
7322
- workdirPath: options.cwd
7456
+ workdirPath: resolveWorkdirPath(options.cwd)
7323
7457
  });
7324
7458
  deploymentRunId = run.id;
7325
7459
  console.log(
@@ -7335,67 +7469,25 @@ async function runDeployWithBackendTracking(options) {
7335
7469
  id: deploymentRunId,
7336
7470
  status: "DEPLOYING"
7337
7471
  });
7338
- const logSyncer = createDeployLogSyncer(api, deploymentRunId);
7339
- const previousDeploymentRunId = process.env[APM_DEPLOYMENT_RUN_ID_ENV];
7340
- process.env[APM_DEPLOYMENT_RUN_ID_ENV] = deploymentRunId;
7341
- const chunks = [];
7342
- const appendLog = (line) => {
7343
- if (!line) return;
7344
- chunks.push(line);
7345
- logSyncer.updateLog(chunks.join("\n"));
7346
- };
7347
- const originalLog = console.log;
7348
- const originalError = console.error;
7349
- console.log = (...args) => {
7350
- appendLog(args.map(String).join(" "));
7351
- originalLog.apply(console, args);
7352
- };
7353
- console.error = (...args) => {
7354
- appendLog(args.map(String).join(" "));
7355
- originalError.apply(console, args);
7356
- };
7357
- try {
7358
- const output = await executeDeploy({
7359
- ...options,
7360
- captureOutput: true,
7361
- archiveDeployArtifact: true
7362
- });
7363
- if (output.trim()) {
7364
- appendLog(output);
7365
- }
7366
- const log2 = chunks.join("\n");
7367
- await completeTrackedDeploy(api, deploymentRunId, logSyncer, {
7368
- status: "SUCCESS",
7369
- log: log2
7370
- });
7371
- console.log(`[apm] deploy success id=${deploymentRunId}`);
7372
- } catch (error) {
7373
- const deployError = error instanceof DeployExecutionError ? error : new DeployExecutionError(
7374
- error instanceof Error ? error.message : String(error),
7375
- 1
7376
- );
7377
- if (deployError.output.trim()) {
7378
- appendLog(deployError.output);
7379
- } else {
7380
- 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" };
7381
7486
  }
7382
- const log2 = chunks.join("\n");
7383
- await completeTrackedDeploy(api, deploymentRunId, logSyncer, {
7384
- status: "FAILED",
7385
- log: log2,
7386
- error: deployError.message
7387
- });
7487
+ });
7488
+ if (deployError) {
7388
7489
  printDeployExecutionError(deployError);
7389
7490
  process.exit(deployError.exitCode);
7390
- } finally {
7391
- if (previousDeploymentRunId === void 0) {
7392
- delete process.env[APM_DEPLOYMENT_RUN_ID_ENV];
7393
- } else {
7394
- process.env[APM_DEPLOYMENT_RUN_ID_ENV] = previousDeploymentRunId;
7395
- }
7396
- console.log = originalLog;
7397
- console.error = originalError;
7398
- logSyncer.dispose();
7399
7491
  }
7400
7492
  }
7401
7493
 
@@ -7448,29 +7540,29 @@ function registerDeployMainCommand(program) {
7448
7540
  }
7449
7541
 
7450
7542
  // src/commands/deploy/backend.ts
7451
- import path10 from "node:path";
7543
+ import path16 from "node:path";
7452
7544
 
7453
7545
  // src/commands/deploy/internal/backend-deploy/backend-deploy-workflow.ts
7454
- import path9 from "node:path";
7546
+ import path15 from "node:path";
7455
7547
 
7456
7548
  // src/commands/deploy/internal/backend-deploy/dockerode-client/client.ts
7457
7549
  import Docker from "dockerode";
7458
7550
 
7459
7551
  // src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
7460
- import { existsSync as existsSync19, readFileSync as readFileSync16 } from "node:fs";
7461
- import path6 from "node:path";
7552
+ import { existsSync as existsSync22, readFileSync as readFileSync18 } from "node:fs";
7553
+ import path12 from "node:path";
7462
7554
  function asOptionalTlsBuffer(value) {
7463
7555
  if (typeof value !== "string") {
7464
7556
  console.log("tls filepath not exist");
7465
7557
  return void 0;
7466
7558
  }
7467
- console.log("tls filepath", path6.join(process.cwd(), value));
7559
+ console.log("tls filepath", path12.join(process.cwd(), value));
7468
7560
  const normalized = value.trim();
7469
7561
  if (normalized === "") {
7470
7562
  return void 0;
7471
7563
  }
7472
- if (existsSync19(normalized)) {
7473
- return readFileSync16(normalized);
7564
+ if (existsSync22(normalized)) {
7565
+ return readFileSync18(normalized);
7474
7566
  }
7475
7567
  const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
7476
7568
  if (looksLikePath) {
@@ -7595,17 +7687,17 @@ var DockerodeClient = class {
7595
7687
  await this.client.getImage(image).remove({ force: true });
7596
7688
  }
7597
7689
  async pullImage(image, auth) {
7598
- const stream = await new Promise((resolve5, reject) => {
7690
+ const stream = await new Promise((resolve6, reject) => {
7599
7691
  const pullOptions = auth ? { authconfig: auth } : void 0;
7600
7692
  this.client.pull(image, pullOptions, (err, output) => {
7601
7693
  if (err || !output) {
7602
7694
  reject(err ?? new Error("docker pull \u8FD4\u56DE\u7A7A\u8F93\u51FA"));
7603
7695
  return;
7604
7696
  }
7605
- resolve5(output);
7697
+ resolve6(output);
7606
7698
  });
7607
7699
  });
7608
- await new Promise((resolve5, reject) => {
7700
+ await new Promise((resolve6, reject) => {
7609
7701
  this.client.modem.followProgress(
7610
7702
  stream,
7611
7703
  (err) => {
@@ -7613,7 +7705,7 @@ var DockerodeClient = class {
7613
7705
  reject(err);
7614
7706
  return;
7615
7707
  }
7616
- resolve5();
7708
+ resolve6();
7617
7709
  },
7618
7710
  () => void 0
7619
7711
  );
@@ -7680,8 +7772,8 @@ var DockerodeClient = class {
7680
7772
  var createDockerodeClient = (config) => new DockerodeClient(config);
7681
7773
 
7682
7774
  // src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
7683
- import { existsSync as existsSync20, readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
7684
- 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";
7685
7777
  function stripSurroundingQuotes(value) {
7686
7778
  const t = value.trim();
7687
7779
  if (t.length >= 2) {
@@ -7696,11 +7788,11 @@ function loadEnvFromFile(envFilePath) {
7696
7788
  if (!envFilePath) {
7697
7789
  return {};
7698
7790
  }
7699
- const targetPath = path7.resolve(envFilePath);
7700
- if (!existsSync20(targetPath) || !statSync8(targetPath).isFile()) {
7791
+ const targetPath = path13.resolve(envFilePath);
7792
+ if (!existsSync23(targetPath) || !statSync10(targetPath).isFile()) {
7701
7793
  return {};
7702
7794
  }
7703
- const raw = readFileSync17(targetPath, "utf-8");
7795
+ const raw = readFileSync19(targetPath, "utf-8");
7704
7796
  const result = {};
7705
7797
  for (const line of raw.split(/\r?\n/)) {
7706
7798
  const normalized = line.trim();
@@ -7871,12 +7963,12 @@ function dockerPushImage(params, cwd) {
7871
7963
  }
7872
7964
 
7873
7965
  // src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
7874
- import { existsSync as existsSync21 } from "node:fs";
7875
- import path8 from "node:path";
7966
+ import { existsSync as existsSync24 } from "node:fs";
7967
+ import path14 from "node:path";
7876
7968
  function resolveDockerBuildPaths(cwd) {
7877
- const dockerfilePath = path8.join(cwd, "Dockerfile");
7969
+ const dockerfilePath = path14.join(cwd, "Dockerfile");
7878
7970
  Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
7879
- if (!existsSync21(dockerfilePath)) {
7971
+ if (!existsSync24(dockerfilePath)) {
7880
7972
  throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
7881
7973
  }
7882
7974
  Logger.info("\u2713 Dockerfile \u5B58\u5728");
@@ -7931,7 +8023,7 @@ var BackendDeployWorkflow = class {
7931
8023
  serveraddress
7932
8024
  });
7933
8025
  Logger.success("\u8FDC\u7A0B\u62C9\u53D6\u955C\u50CF\u5B8C\u6210");
7934
- const envFilePath = path9.resolve(cwd, this.params.envFilePath || ".env");
8026
+ const envFilePath = path15.resolve(cwd, this.params.envFilePath || ".env");
7935
8027
  const envObj = loadEnvFromFile(envFilePath);
7936
8028
  if (this.params.dockerNetwork?.trim()) {
7937
8029
  Logger.info(`\u8FDC\u7A0B\u5BB9\u5668\u5C06\u52A0\u5165 Docker \u7F51\u7EDC\uFF1A${this.params.dockerNetwork.trim()}`);
@@ -7971,7 +8063,7 @@ function registerDeployBackendCommands(program) {
7971
8063
  assertDeployImageTag(tag);
7972
8064
  const cfg = loadApmConfig({ configPath: opts.config });
7973
8065
  const fromApm = resolveBackendDeployFromApmConfig(cfg);
7974
- const dirAbs = path10.resolve(process.cwd(), opts.dir || "servers/api");
8066
+ const dirAbs = path16.resolve(process.cwd(), opts.dir || "servers/api");
7975
8067
  const params = {
7976
8068
  image: fromApm.name,
7977
8069
  tag,
@@ -8001,34 +8093,15 @@ function registerDeployBackendCommands(program) {
8001
8093
  }
8002
8094
 
8003
8095
  // src/commands/deploy/frontend.ts
8004
- import { copyFile, readdir as readdir3, stat, unlink as unlink2 } from "node:fs/promises";
8005
- import path11 from "node:path";
8006
- function resolveArtifactNamePrefix(cfg) {
8007
- const nameRaw = (cfg.name ?? "").trim();
8008
- if (!nameRaw) {
8009
- console.error(
8010
- "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A MinIO \u5BF9\u8C61\u952E\u524D\u7F00\uFF09"
8011
- );
8012
- process.exit(1);
8013
- }
8014
- if (nameRaw.includes(":")) {
8015
- console.error("apm.config.json \u7684 name \u4E0D\u80FD\u5305\u542B ':'");
8016
- process.exit(1);
8017
- }
8018
- try {
8019
- return sanitizeRelativePath(nameRaw.replace(/\\/g, "/"));
8020
- } catch {
8021
- console.error("apm.config.json \u7684 name \u975E\u6CD5\uFF08\u8DEF\u5F84\u7247\u6BB5\u4E0D\u80FD\u4E3A . \u6216 ..\uFF09");
8022
- process.exit(1);
8023
- }
8024
- }
8096
+ import { copyFile, readdir as readdir3, stat } from "node:fs/promises";
8097
+ import path17 from "node:path";
8025
8098
  function artifactObjectKey(namePrefix, branchSegment, relativePath) {
8026
8099
  const base = sanitizeRelativePath(namePrefix);
8027
8100
  const rel = sanitizeRelativePath(relativePath);
8028
8101
  return `${base}/${branchSegment}/dist/${rel}`;
8029
8102
  }
8030
8103
  async function ensureArtifactRootIndexHtml(root) {
8031
- const indexHtmlPath = path11.join(root, "index.html");
8104
+ const indexHtmlPath = path17.join(root, "index.html");
8032
8105
  try {
8033
8106
  const st = await stat(indexHtmlPath);
8034
8107
  if (st.isFile()) {
@@ -8040,12 +8113,11 @@ async function ensureArtifactRootIndexHtml(root) {
8040
8113
  try {
8041
8114
  entries = await readdir3(root, { withFileTypes: true });
8042
8115
  } catch (e) {
8043
- console.error(`\u65E0\u6CD5\u8BFB\u53D6\u4EA7\u7269\u76EE\u5F55\uFF1A${root}`, e);
8044
- process.exit(1);
8116
+ throw new DeployExecutionError(`\u65E0\u6CD5\u8BFB\u53D6\u4EA7\u7269\u76EE\u5F55\uFF1A${root}`, 1, String(e));
8045
8117
  }
8046
8118
  const dirNames = entries.filter((e) => e.isDirectory()).map((e) => String(e.name)).sort();
8047
8119
  for (const name of dirNames) {
8048
- const candidate = path11.join(root, name, "index.html");
8120
+ const candidate = path17.join(root, name, "index.html");
8049
8121
  try {
8050
8122
  const st = await stat(candidate);
8051
8123
  if (!st.isFile()) {
@@ -8056,52 +8128,39 @@ async function ensureArtifactRootIndexHtml(root) {
8056
8128
  }
8057
8129
  await copyFile(candidate, indexHtmlPath);
8058
8130
  console.error(
8059
- `\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`
8060
8132
  );
8061
8133
  return;
8062
8134
  }
8063
- console.error(
8064
- `\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
8065
8138
  );
8066
- process.exit(1);
8067
8139
  }
8068
8140
  async function runFrontendPackOnlyDeploy(root, namePrefix) {
8069
- const zipPath = path11.resolve(root, "..", ".deploy-frontend-dist.zip");
8070
- let zipSizeBytes = 0;
8071
- let artifactUploaded = false;
8072
- try {
8073
- zipSizeBytes = await zipDirectory(root, zipPath);
8074
- console.error("[apm] \u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u8DF3\u8FC7\u524D\u7AEF\u8BBF\u95EE\u6876\u4E0A\u4F20");
8075
- const artifact = await uploadDeployArtifactZip({
8076
- zipPath,
8077
- projectName: namePrefix,
8078
- kind: "frontend",
8079
- uploadWithoutRunId: true
8080
- });
8081
- artifactUploaded = artifact !== null;
8082
- if (artifactUploaded) {
8083
- console.error("\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5F52\u6863\u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u81F3\u524D\u7AEF\u8BBF\u95EE\u6876\uFF09");
8084
- }
8085
- console.log(
8086
- JSON.stringify(
8087
- {
8088
- ok: true,
8089
- packOnly: true,
8090
- namePrefix,
8091
- zipSizeBytes,
8092
- artifactUploaded
8093
- },
8094
- null,
8095
- 2
8096
- )
8097
- );
8098
- } finally {
8099
- try {
8100
- await unlink2(zipPath);
8101
- console.error(`\u5DF2\u6E05\u7406\u672C\u5730\u4E34\u65F6\u6587\u4EF6: ${zipPath}`);
8102
- } catch {
8103
- }
8104
- }
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
+ );
8105
8164
  }
8106
8165
  function registerDeployFrontendCommands(program) {
8107
8166
  program.command("deploy-frontend").description(
@@ -8122,91 +8181,97 @@ function registerDeployFrontendCommands(program) {
8122
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"
8123
8182
  ).action(
8124
8183
  async (name, opts) => {
8125
- const cfg = loadApmConfig({ configPath: opts.config });
8126
- const namePrefix = resolveArtifactNamePrefix(cfg);
8127
- const root = path11.resolve(process.cwd(), opts.dir || "apps/web/dist");
8128
- if (!await isDirectoryPath(root)) {
8129
- console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
8130
- process.exit(1);
8131
- }
8132
- await ensureArtifactRootIndexHtml(root);
8133
- if (opts.packOnly) {
8134
- await runFrontendPackOnlyDeploy(root, namePrefix);
8135
- return;
8136
- }
8137
- const settings = resolveFrontendDeployFromApmConfig(cfg);
8138
- const minio = new MinioClient({
8139
- endPoint: settings.endpoint,
8140
- port: settings.port,
8141
- useSSL: settings.useSsl,
8142
- accessKey: settings.accessKey,
8143
- secretKey: settings.secretKey
8144
- });
8145
- const bucket = settings.bucket;
8146
- const maxBytes = Math.max(
8147
- 1,
8148
- Number.isFinite(opts.maxFileSizeMb) ? Math.floor(
8149
- (opts.maxFileSizeMb ?? DEFAULT_MAX_FILE_SIZE_MB) * 1024 * 1024
8150
- ) : DEFAULT_MAX_FILE_SIZE_MB * 1024 * 1024
8151
- );
8152
- const files = await collectFiles(root);
8153
- if (files.length === 0) {
8154
- console.error(`\u76EE\u5F55\u4E3A\u7A7A\uFF1A${root}`);
8155
- process.exit(1);
8156
- }
8157
- let uploaded = 0;
8158
- let totalBytes = 0;
8159
- console.error(`\u5F00\u59CB\u76F4\u8FDE MinIO \u4E0A\u4F20\uFF0C\u5171 ${files.length} \u4E2A\u6587\u4EF6\u2026`);
8160
- await minio.ensureBucket(bucket);
8161
- await minio.deleteObjectsByPrefix(
8162
- bucket,
8163
- `${namePrefix}/${name}/dist/`
8164
- );
8165
- for (const f of files) {
8166
- 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;
8167
8241
  console.error(
8168
- `\u6587\u4EF6\u8FC7\u5927\uFF0C\u5DF2\u62D2\u7EDD\uFF1A${f.relativePath}\uFF08${toMB(f.size)}MB > ${toMB(
8169
- maxBytes
8170
- )}MB\uFF09`
8242
+ `[${uploaded}/${files.length}] ${f.relativePath} -> ${objectKey}`
8171
8243
  );
8172
- process.exit(1);
8173
8244
  }
8174
- const buf = await readArtifactFile(f.absPath);
8175
- const cleanRel = sanitizeRelativePath(f.relativePath);
8176
- const objectKey = artifactObjectKey(namePrefix, name, cleanRel);
8177
- const mimeType = detectMimeType(f.relativePath).trim().toLowerCase() || "application/octet-stream";
8178
- await minio.putObject(bucket, objectKey, buf, {
8179
- "Content-Type": mimeType
8180
- });
8181
- uploaded += 1;
8182
- totalBytes += buf.length;
8183
- console.error(
8184
- `[${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
+ )
8185
8261
  );
8262
+ } catch (error) {
8263
+ if (error instanceof DeployExecutionError) {
8264
+ printDeployExecutionError(error);
8265
+ process.exit(error.exitCode);
8266
+ }
8267
+ throw error;
8186
8268
  }
8187
- console.error("\u6B63\u5728\u8BBE\u7F6E\u6876\u7B56\u7565\uFF08\u533F\u540D\u53EF\u8BFB\u5BF9\u8C61\uFF0C\u4FBF\u4E8E HTTP \u76F4\u94FE\uFF09\u2026");
8188
- await minio.setBucketPublicRead(bucket);
8189
- console.log(
8190
- JSON.stringify(
8191
- {
8192
- ok: true,
8193
- namePrefix,
8194
- envName: name,
8195
- bucket,
8196
- fileCount: uploaded,
8197
- totalBytes,
8198
- bucketPublicRead: true
8199
- },
8200
- null,
8201
- 2
8202
- )
8203
- );
8204
8269
  }
8205
8270
  );
8206
8271
  }
8207
8272
 
8208
8273
  // src/commands/deploy/sftp.ts
8209
- import path12 from "node:path";
8274
+ import path18 from "node:path";
8210
8275
  function registerDeploySftpCommands(program) {
8211
8276
  program.command("deploy-sftp").description(
8212
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"
@@ -8222,25 +8287,22 @@ function registerDeploySftpCommands(program) {
8222
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"
8223
8288
  ).action(
8224
8289
  async (opts) => {
8225
- const cfg = loadApmConfig({ configPath: opts.config });
8226
- const settings = resolveWisdomDeployFromApmConfig(cfg);
8227
- const projectName = (cfg.name ?? "").trim();
8228
- if (!projectName) {
8229
- console.error(
8230
- "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09"
8231
- );
8232
- process.exit(1);
8233
- }
8234
- const root = path12.resolve(process.cwd(), opts.dir || "apps/web/dist");
8235
- if (!await isDirectoryPath(root)) {
8236
- console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
8237
- process.exit(1);
8238
- }
8239
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
+ }
8240
8300
  const packOnly = Boolean(opts.packOnly);
8241
8301
  if (packOnly && opts.extract) {
8242
- console.error("--pack-only \u4E0E --extract \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
8243
- process.exit(1);
8302
+ throw new DeployExecutionError(
8303
+ "--pack-only \u4E0E --extract \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528",
8304
+ 1
8305
+ );
8244
8306
  }
8245
8307
  const result = await runWisdomSftpDeploy({
8246
8308
  localDir: root,
@@ -8250,8 +8312,12 @@ function registerDeploySftpCommands(program) {
8250
8312
  packOnly
8251
8313
  });
8252
8314
  console.log(JSON.stringify(result, null, 2));
8253
- } catch (err) {
8254
- 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);
8255
8321
  const action = opts.packOnly ? "\u6253\u5305" : opts.extract ? "\u90E8\u7F72" : "\u4E0A\u4F20";
8256
8322
  console.error(`${action}\u5931\u8D25:`, message);
8257
8323
  process.exit(1);
@@ -8268,11 +8334,19 @@ function registerDeployWisdomBackendCommands(program) {
8268
8334
  "--config <path>",
8269
8335
  "apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
8270
8336
  ).action(async (opts) => {
8271
- const cfg = loadApmConfig({ configPath: opts.config });
8272
- const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
8273
- await runWisdomBackendDeploy({
8274
- config: settings
8275
- });
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
+ }
8276
8350
  });
8277
8351
  }
8278
8352