ai-project-manage-cli 6.0.103 → 6.0.105

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +734 -469
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2035,6 +2035,9 @@ import { basename as basename3 } from "path";
2035
2035
  // src/assumptions/local-validate.ts
2036
2036
  var NO_ASSUMPTIONS_RE = /无[,,]?\s*口径均有依据/;
2037
2037
  var BLOCK_HEADER_RE = /^####\s+(A\d+)\s*$/im;
2038
+ function formatAssumptionQuestionId(source, code) {
2039
+ return `${source}:${code}`;
2040
+ }
2038
2041
  var DEV_PATTERNS = [
2039
2042
  { pattern: /status\s*=/i, message: "\u5305\u542B status= \u7B49\u6280\u672F\u679A\u4E3E" },
2040
2043
  { pattern: /\.(java|vue|ts|tsx|jsx|sql)\b/i, message: "\u5305\u542B\u6587\u4EF6\u8DEF\u5F84" },
@@ -2064,7 +2067,7 @@ function parseField(block, label) {
2064
2067
  const value = match?.[1]?.trim();
2065
2068
  return value || void 0;
2066
2069
  }
2067
- function parseStructuredBlock(code, block) {
2070
+ function parseStructuredBlock(code, block, source) {
2068
2071
  const pmQuestion = parseField(block, "\u95EE") ?? parseField(block, "prompt");
2069
2072
  if (!pmQuestion) return null;
2070
2073
  const optionsSection = block.match(
@@ -2073,7 +2076,7 @@ function parseStructuredBlock(code, block) {
2073
2076
  const options = optionsSection ? parseOptionsBlock(optionsSection[1]) : [];
2074
2077
  return {
2075
2078
  code,
2076
- questionId: code,
2079
+ questionId: formatAssumptionQuestionId(source, code),
2077
2080
  pmQuestion,
2078
2081
  context: parseField(block, "\u573A\u666F"),
2079
2082
  options,
@@ -2104,7 +2107,7 @@ function parseAssumptionsDocument(markdown, _source) {
2104
2107
  for (const block of blocks) {
2105
2108
  const headerMatch = block.match(BLOCK_HEADER_RE);
2106
2109
  if (!headerMatch) continue;
2107
- const parsed = parseStructuredBlock(headerMatch[1], block);
2110
+ const parsed = parseStructuredBlock(headerMatch[1], block, _source);
2108
2111
  if (parsed) results.push(parsed);
2109
2112
  }
2110
2113
  return results;
@@ -2878,33 +2881,17 @@ function posixBasename(p) {
2878
2881
  }
2879
2882
 
2880
2883
  // src/commands/deploy/internal/deploy-hints.ts
2881
- function formatDeployNotConfiguredLines(env, deployCommands) {
2882
- const configuredEnvs = Object.keys(deployCommands).filter(
2883
- (key) => deployCommands[key]?.trim()
2884
- );
2885
- if (configuredEnvs.length > 0) {
2886
- return [
2887
- `[apm] \u65E0\u6CD5\u6267\u884C\u90E8\u7F72\uFF1Aapm.config.json \u4E2D\u672A\u914D\u7F6E deploy.${env}`,
2888
- `[apm] \u5F53\u524D\u5DF2\u914D\u7F6E\u7684\u73AF\u5883: ${configuredEnvs.join(", ")}`
2889
- ];
2890
- }
2884
+ function formatMissingWisdomDeployLines() {
2891
2885
  return [
2892
- "[apm] \u65E0\u6CD5\u6267\u884C\u90E8\u7F72\uFF1A\u5F53\u524D\u9879\u76EE\u672A\u914D\u7F6E\u81EA\u52A8\u5316\u90E8\u7F72\uFF08apm.config.json \u4E2D\u65E0 deploy \u6BB5\uFF09",
2893
- "[apm] \u90E8\u5206\u9879\u76EE\u4E0D\u652F\u6301\u6216\u672A\u542F\u7528\u81EA\u52A8\u5316\u90E8\u7F72\uFF0C\u5C5E\u6B63\u5E38\u60C5\u51B5\uFF0C\u53EF\u8DF3\u8FC7\u90E8\u7F72"
2886
+ "[apm] \u65E0\u6CD5\u6267\u884C apm deploy\uFF1A\u8BF7\u5728 apm.config.json \u4E2D\u914D\u7F6E wisdomDeploy\uFF08host\u3001remotePath\uFF09"
2894
2887
  ];
2895
2888
  }
2896
2889
  function formatWisdomFrontendBuildNotConfiguredLines(env, packageJsonPath) {
2897
2890
  return [
2898
- `[apm] \u65E0\u6CD5\u6267\u884C\u4EC5\u6253\u5305\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u811A\u672C`,
2891
+ `[apm] \u65E0\u6CD5\u6267\u884C\u524D\u7AEF\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u811A\u672C`,
2899
2892
  "[apm] \u8BF7\u914D\u7F6E npm run build:test / build:online \u540E\u518D\u8BD5"
2900
2893
  ];
2901
2894
  }
2902
- function formatWisdomFrontendDeployNotConfiguredLines(env, packageJsonPath) {
2903
- return [
2904
- `[apm] \u65E0\u6CD5\u6267\u884C\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 deploy:${env} \u811A\u672C`,
2905
- "[apm] \u82E5\u672C\u9879\u76EE\u4E0D\u652F\u6301\u81EA\u52A8\u5316\u90E8\u7F72\uFF0C\u5C5E\u6B63\u5E38\u60C5\u51B5\uFF0C\u53EF\u8DF3\u8FC7\u90E8\u7F72"
2906
- ];
2907
- }
2908
2895
 
2909
2896
  // src/commands/deploy/deploy-errors.ts
2910
2897
  var DeployExecutionError = class extends Error {
@@ -2918,8 +2905,260 @@ var DeployExecutionError = class extends Error {
2918
2905
  }
2919
2906
  };
2920
2907
 
2921
- // src/commands/deploy/deploy-shell-run.ts
2908
+ // src/commands/deploy/deploy-debug-log.ts
2922
2909
  import { spawnSync as spawnSync4 } from "node:child_process";
2910
+ import { existsSync as existsSync14 } from "node:fs";
2911
+ import { dirname as dirname5, join as join16 } from "node:path";
2912
+
2913
+ // src/commands/deploy/internal/deploy-artifact-minio.ts
2914
+ import { readFile as readFile2 } from "node:fs/promises";
2915
+
2916
+ // src/commands/deploy/internal/minio.ts
2917
+ import { statSync as statSync5 } from "node:fs";
2918
+ import { readdir, readFile } from "node:fs/promises";
2919
+ import path from "node:path";
2920
+ import * as Minio from "minio";
2921
+ var DEFAULT_MAX_FILE_SIZE_MB = 50;
2922
+ async function isDirectoryPath(dir) {
2923
+ try {
2924
+ const st = statSync5(dir);
2925
+ return st.isDirectory();
2926
+ } catch {
2927
+ return false;
2928
+ }
2929
+ }
2930
+ function sanitizeRelativePath(rel) {
2931
+ const norm = rel.replace(/\\/g, "/").replace(/^\/+/, "");
2932
+ const segments = norm.split("/").filter(Boolean);
2933
+ for (const s of segments) {
2934
+ if (s === "." || s === "..") {
2935
+ throw new Error(`\u975E\u6CD5\u76F8\u5BF9\u8DEF\u5F84\u7247\u6BB5\uFF1A${s}`);
2936
+ }
2937
+ }
2938
+ return segments.join("/");
2939
+ }
2940
+ async function collectFiles(root) {
2941
+ const out = [];
2942
+ async function walk(dir, prefix) {
2943
+ const entries = await readdir(dir, { withFileTypes: true });
2944
+ for (const e of entries) {
2945
+ const name = e.name;
2946
+ if (name === "." || name === "..") {
2947
+ continue;
2948
+ }
2949
+ const abs = path.join(dir, name);
2950
+ const rel = prefix ? `${prefix}/${name}` : name;
2951
+ if (e.isDirectory()) {
2952
+ await walk(abs, rel);
2953
+ } else if (e.isFile()) {
2954
+ const st = statSync5(abs);
2955
+ out.push({
2956
+ absPath: abs,
2957
+ relativePath: rel.replace(/\\/g, "/"),
2958
+ size: st.size
2959
+ });
2960
+ }
2961
+ }
2962
+ }
2963
+ await walk(root, "");
2964
+ out.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
2965
+ return out;
2966
+ }
2967
+ async function readArtifactFile(absPath) {
2968
+ return readFile(absPath);
2969
+ }
2970
+ function toMB(bytes) {
2971
+ return Math.round(bytes / (1024 * 1024) * 1e3) / 1e3;
2972
+ }
2973
+ var MIME = {
2974
+ ".html": "text/html; charset=utf-8",
2975
+ ".css": "text/css; charset=utf-8",
2976
+ ".js": "application/javascript; charset=utf-8",
2977
+ ".json": "application/json; charset=utf-8",
2978
+ ".svg": "image/svg+xml",
2979
+ ".png": "image/png",
2980
+ ".jpg": "image/jpeg",
2981
+ ".jpeg": "image/jpeg",
2982
+ ".gif": "image/gif",
2983
+ ".webp": "image/webp",
2984
+ ".woff": "font/woff",
2985
+ ".woff2": "font/woff2",
2986
+ ".ttf": "font/ttf",
2987
+ ".ico": "image/x-icon",
2988
+ ".txt": "text/plain; charset=utf-8",
2989
+ ".map": "application/json"
2990
+ };
2991
+ function detectMimeType(filePath) {
2992
+ const ext = path.extname(filePath).toLowerCase();
2993
+ return MIME[ext] ?? "";
2994
+ }
2995
+ var MinioClient = class {
2996
+ inner;
2997
+ constructor(opts) {
2998
+ const endPoint = opts.endPoint.replace(/^https?:\/\//i, "").split("/")[0] ?? opts.endPoint;
2999
+ this.inner = new Minio.Client({
3000
+ endPoint,
3001
+ port: opts.port,
3002
+ useSSL: opts.useSSL,
3003
+ accessKey: opts.accessKey,
3004
+ secretKey: opts.secretKey
3005
+ });
3006
+ }
3007
+ async ensureBucket(bucket) {
3008
+ const exists = await this.inner.bucketExists(bucket);
3009
+ if (!exists) {
3010
+ await this.inner.makeBucket(bucket);
3011
+ }
3012
+ }
3013
+ async deleteObjectsByPrefix(bucket, prefix) {
3014
+ const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
3015
+ const keys = [];
3016
+ await new Promise((resolve5, reject) => {
3017
+ objectsStream.on("data", (obj) => {
3018
+ if (obj.name) {
3019
+ keys.push(obj.name);
3020
+ }
3021
+ });
3022
+ objectsStream.on("error", reject);
3023
+ objectsStream.on("end", resolve5);
3024
+ });
3025
+ const chunkSize = 500;
3026
+ for (let i = 0; i < keys.length; i += chunkSize) {
3027
+ const chunk = keys.slice(i, i + chunkSize);
3028
+ await this.inner.removeObjects(
3029
+ bucket,
3030
+ chunk.map((name) => name)
3031
+ );
3032
+ }
3033
+ }
3034
+ async putObject(bucket, objectKey, body, meta) {
3035
+ await this.inner.putObject(bucket, objectKey, body, body.length, meta);
3036
+ }
3037
+ /** 匿名可读当前桶全部对象(便于静态站点直链) */
3038
+ async setBucketPublicRead(bucket) {
3039
+ const policy = {
3040
+ Version: "2012-10-17",
3041
+ Statement: [
3042
+ {
3043
+ Effect: "Allow",
3044
+ Principal: { AWS: ["*"] },
3045
+ Action: ["s3:GetObject"],
3046
+ Resource: [`arn:aws:s3:::${bucket}/*`]
3047
+ }
3048
+ ]
3049
+ };
3050
+ await this.inner.setBucketPolicy(bucket, JSON.stringify(policy));
3051
+ }
3052
+ };
3053
+
3054
+ // src/commands/deploy/internal/deploy-artifact-minio.ts
3055
+ var APM_DEPLOYMENT_RUN_ID_ENV = "APM_DEPLOYMENT_RUN_ID";
3056
+ function formatDeployArtifactTimestamp(date = /* @__PURE__ */ new Date()) {
3057
+ const pad = (n) => String(n).padStart(2, "0");
3058
+ return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
3059
+ }
3060
+ function sanitizeDeployProjectName(name) {
3061
+ const trimmed = name.trim().replace(/\\/g, "/");
3062
+ const base = trimmed.split("/").filter(Boolean).pop() ?? trimmed;
3063
+ try {
3064
+ return sanitizeRelativePath(base.replace(/[/\\:*?"<>|]/g, "_"));
3065
+ } catch {
3066
+ return "project";
3067
+ }
3068
+ }
3069
+ function buildDeployArtifactFileName(kind, projectName, timestamp = formatDeployArtifactTimestamp()) {
3070
+ const safeName = sanitizeDeployProjectName(projectName);
3071
+ const suffix = kind === "frontend" ? "dist.zip" : "jar.zip";
3072
+ return `${timestamp}-${safeName}.${suffix}`;
3073
+ }
3074
+ function buildDeployArtifactObjectKey(projectName, fileName) {
3075
+ const safeProject = sanitizeDeployProjectName(projectName);
3076
+ return `deploy/${safeProject}/${fileName}`;
3077
+ }
3078
+ function resolveDeploymentRunIdFromEnv() {
3079
+ const raw = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim();
3080
+ return raw || null;
3081
+ }
3082
+ async function fetchDeployArtifactStorage(api) {
3083
+ return api.cli.getDeployArtifactStorage(void 0);
3084
+ }
3085
+ async function uploadDeployArtifactZip(options) {
3086
+ const deploymentRunId = options.deploymentRunId ?? resolveDeploymentRunIdFromEnv();
3087
+ if (!deploymentRunId && !options.uploadWithoutRunId) {
3088
+ return null;
3089
+ }
3090
+ const cfg = await tryReadApmConfig();
3091
+ if (!cfg || !resolveApiKey(cfg)) {
3092
+ console.warn("[apm] \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7 MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863");
3093
+ return null;
3094
+ }
3095
+ const api = options.api ?? createApmApiClient(cfg);
3096
+ let storage;
3097
+ try {
3098
+ storage = await fetchDeployArtifactStorage(api);
3099
+ } catch (error) {
3100
+ const detail = error instanceof Error ? error.message : String(error);
3101
+ console.warn(`[apm] \u83B7\u53D6 MinIO \u914D\u7F6E\u5931\u8D25\uFF0C\u8DF3\u8FC7\u90E8\u7F72\u4EA7\u7269\u5F52\u6863: ${detail}`);
3102
+ return null;
3103
+ }
3104
+ const fileName = buildDeployArtifactFileName(
3105
+ options.kind,
3106
+ options.projectName,
3107
+ options.timestamp
3108
+ );
3109
+ const objectKey = buildDeployArtifactObjectKey(options.projectName, fileName);
3110
+ let body;
3111
+ try {
3112
+ body = await readFile2(options.zipPath);
3113
+ } catch (error) {
3114
+ const detail = error instanceof Error ? error.message : String(error);
3115
+ console.warn(`[apm] \u8BFB\u53D6\u90E8\u7F72\u4EA7\u7269 zip \u5931\u8D25\uFF0C\u8DF3\u8FC7 MinIO \u5F52\u6863: ${detail}`);
3116
+ return null;
3117
+ }
3118
+ try {
3119
+ const client = new MinioClient({
3120
+ endPoint: storage.endpoint,
3121
+ port: storage.port,
3122
+ useSSL: storage.useSsl,
3123
+ accessKey: storage.accessKey,
3124
+ secretKey: storage.secretKey
3125
+ });
3126
+ await client.ensureBucket(storage.bucket);
3127
+ await client.putObject(storage.bucket, objectKey, body, {
3128
+ "Content-Type": "application/zip"
3129
+ });
3130
+ console.error(
3131
+ `[apm] \u672C\u5730\u76F4\u4F20 MinIO\uFF08\u4E0D\u7ECF\u5E73\u53F0\u670D\u52A1\u5668\uFF09: ${storage.endpoint}:${storage.port}/${storage.bucket}/${objectKey} (${(body.length / 1024 / 1024).toFixed(
3132
+ 2
3133
+ )} MB)`
3134
+ );
3135
+ } catch (error) {
3136
+ const detail = error instanceof Error ? error.message : String(error);
3137
+ console.warn(`[apm] MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863\u5931\u8D25: ${detail}`);
3138
+ return null;
3139
+ }
3140
+ if (deploymentRunId) {
3141
+ try {
3142
+ await api.cli.attachTaskDeploymentArtifact({
3143
+ id: deploymentRunId,
3144
+ artifactObjectKey: objectKey,
3145
+ artifactFileName: fileName
3146
+ });
3147
+ console.error(
3148
+ `[apm] \u5DF2\u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55 id=${deploymentRunId} file=${fileName}`
3149
+ );
3150
+ } catch (error) {
3151
+ const detail = error instanceof Error ? error.message : String(error);
3152
+ console.warn(`[apm] \u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55\u5931\u8D25: ${detail}`);
3153
+ return null;
3154
+ }
3155
+ }
3156
+ return {
3157
+ objectKey,
3158
+ fileName,
3159
+ bucket: storage.bucket
3160
+ };
3161
+ }
2923
3162
 
2924
3163
  // src/commands/deploy/internal/deploy-shell-env.ts
2925
3164
  import { spawnSync as spawnSync3 } from "node:child_process";
@@ -3741,316 +3980,252 @@ function buildDeployShellEnv(extra) {
3741
3980
  return env;
3742
3981
  }
3743
3982
 
3744
- // src/commands/deploy/deploy-shell-run.ts
3745
- function runDeployShellCommand(command, cwd, captureOutput) {
3746
- const result = spawnSync4(command, {
3747
- cwd,
3748
- shell: true,
3749
- env: buildDeployShellEnv(),
3750
- encoding: "utf8",
3751
- maxBuffer: DEPLOY_SPAWN_MAX_BUFFER_BYTES,
3752
- stdio: captureOutput ? ["inherit", "pipe", "pipe"] : "inherit"
3753
- });
3754
- const stdout = captureOutput ? String(result.stdout ?? "") : "";
3755
- const stderr = captureOutput ? String(result.stderr ?? "") : "";
3756
- const output = [stdout, stderr].filter(Boolean).join("\n");
3757
- if (captureOutput) {
3758
- if (stdout) process.stdout.write(stdout);
3759
- if (stderr) process.stderr.write(stderr);
3760
- }
3761
- if (result.error) {
3762
- throw new DeployExecutionError(
3763
- `\u90E8\u7F72\u547D\u4EE4\u6267\u884C\u5931\u8D25: ${result.error.message}`,
3764
- 1,
3765
- output
3766
- );
3767
- }
3768
- if (result.status !== 0) {
3769
- throw new DeployExecutionError(
3770
- `\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${result.status ?? "unknown"}: ${command}`,
3771
- result.status ?? 1,
3772
- output
3773
- );
3774
- }
3775
- return output;
3776
- }
3777
-
3778
- // src/commands/deploy/internal/wisdom-auto-deploy.ts
3779
- import { existsSync as existsSync15, readFileSync as readFileSync13, statSync as statSync7 } from "node:fs";
3780
- import path4 from "node:path";
3781
-
3782
- // src/commands/deploy/internal/wisdom-backend-deploy.ts
3783
- import {
3784
- existsSync as existsSync14,
3785
- mkdirSync as mkdirSync7,
3786
- readdirSync as readdirSync5,
3787
- readFileSync as readFileSync12,
3788
- statSync as statSync6,
3789
- writeFileSync as writeFileSync12
3790
- } from "node:fs";
3791
- import { spawnSync as spawnSync5 } from "node:child_process";
3792
- import path3 from "node:path";
3793
- import { Client as Client2 } from "ssh2";
3794
- import JSZip2 from "jszip";
3795
- import SftpClient2 from "ssh2-sftp-client";
3796
-
3797
- // src/commands/deploy/internal/wisdom-sftp.ts
3798
- import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
3799
- import path2 from "node:path";
3800
- import JSZip from "jszip";
3801
- import SftpClient from "ssh2-sftp-client";
3802
-
3803
- // src/commands/deploy/internal/deploy-artifact-minio.ts
3804
- import { readFile as readFile2 } from "node:fs/promises";
3805
-
3806
- // src/commands/deploy/internal/minio.ts
3807
- import { statSync as statSync5 } from "node:fs";
3808
- import { readdir, readFile } from "node:fs/promises";
3809
- import path from "node:path";
3810
- import * as Minio from "minio";
3811
- var DEFAULT_MAX_FILE_SIZE_MB = 50;
3812
- async function isDirectoryPath(dir) {
3813
- try {
3814
- const st = statSync5(dir);
3815
- return st.isDirectory();
3816
- } catch {
3817
- return false;
3818
- }
3819
- }
3820
- function sanitizeRelativePath(rel) {
3821
- const norm = rel.replace(/\\/g, "/").replace(/^\/+/, "");
3822
- const segments = norm.split("/").filter(Boolean);
3823
- for (const s of segments) {
3824
- if (s === "." || s === "..") {
3825
- throw new Error(`\u975E\u6CD5\u76F8\u5BF9\u8DEF\u5F84\u7247\u6BB5\uFF1A${s}`);
3826
- }
3827
- }
3828
- return segments.join("/");
3829
- }
3830
- async function collectFiles(root) {
3831
- const out = [];
3832
- async function walk(dir, prefix) {
3833
- const entries = await readdir(dir, { withFileTypes: true });
3834
- for (const e of entries) {
3835
- const name = e.name;
3836
- if (name === "." || name === "..") {
3837
- continue;
3838
- }
3839
- const abs = path.join(dir, name);
3840
- const rel = prefix ? `${prefix}/${name}` : name;
3841
- if (e.isDirectory()) {
3842
- await walk(abs, rel);
3843
- } else if (e.isFile()) {
3844
- const st = statSync5(abs);
3845
- out.push({
3846
- absPath: abs,
3847
- relativePath: rel.replace(/\\/g, "/"),
3848
- size: st.size
3849
- });
3850
- }
3983
+ // src/commands/deploy/deploy-debug-log.ts
3984
+ var LOG_PREFIX = "[apm:deploy-debug]";
3985
+ var SENSITIVE_ENV_KEY = /(password|secret|token|api[_-]?key|authorization|credential|private|passwd)/i;
3986
+ var PATH_SEP2 = process.platform === "win32" ? ";" : ":";
3987
+ function logLine(message) {
3988
+ console.error(`${LOG_PREFIX} ${message}`);
3989
+ }
3990
+ function pathEntries(value) {
3991
+ if (!value?.trim()) return [];
3992
+ return value.split(PATH_SEP2).filter(Boolean);
3993
+ }
3994
+ function summarizePath(value, maxEntries = 12) {
3995
+ const entries = pathEntries(value);
3996
+ if (entries.length === 0) return "(empty)";
3997
+ const head = entries.slice(0, maxEntries).join(PATH_SEP2);
3998
+ if (entries.length <= maxEntries) return head;
3999
+ return `${head}${PATH_SEP2}\u2026 (+${entries.length - maxEntries} more)`;
4000
+ }
4001
+ function pickEnvKeys(env, keys) {
4002
+ const out = {};
4003
+ for (const key of keys) {
4004
+ const value = env[key];
4005
+ if (value !== void 0 && value !== "") {
4006
+ out[key] = value;
3851
4007
  }
3852
4008
  }
3853
- await walk(root, "");
3854
- out.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
3855
4009
  return out;
3856
4010
  }
3857
- async function readArtifactFile(absPath) {
3858
- return readFile(absPath);
3859
- }
3860
- function toMB(bytes) {
3861
- return Math.round(bytes / (1024 * 1024) * 1e3) / 1e3;
3862
- }
3863
- var MIME = {
3864
- ".html": "text/html; charset=utf-8",
3865
- ".css": "text/css; charset=utf-8",
3866
- ".js": "application/javascript; charset=utf-8",
3867
- ".json": "application/json; charset=utf-8",
3868
- ".svg": "image/svg+xml",
3869
- ".png": "image/png",
3870
- ".jpg": "image/jpeg",
3871
- ".jpeg": "image/jpeg",
3872
- ".gif": "image/gif",
3873
- ".webp": "image/webp",
3874
- ".woff": "font/woff",
3875
- ".woff2": "font/woff2",
3876
- ".ttf": "font/ttf",
3877
- ".ico": "image/x-icon",
3878
- ".txt": "text/plain; charset=utf-8",
3879
- ".map": "application/json"
3880
- };
3881
- function detectMimeType(filePath) {
3882
- const ext = path.extname(filePath).toLowerCase();
3883
- return MIME[ext] ?? "";
3884
- }
3885
- var MinioClient = class {
3886
- inner;
3887
- constructor(opts) {
3888
- const endPoint = opts.endPoint.replace(/^https?:\/\//i, "").split("/")[0] ?? opts.endPoint;
3889
- this.inner = new Minio.Client({
3890
- endPoint,
3891
- port: opts.port,
3892
- useSSL: opts.useSSL,
3893
- accessKey: opts.accessKey,
3894
- secretKey: opts.secretKey
3895
- });
3896
- }
3897
- async ensureBucket(bucket) {
3898
- const exists = await this.inner.bucketExists(bucket);
3899
- if (!exists) {
3900
- await this.inner.makeBucket(bucket);
4011
+ function collectInterestingEnv(env) {
4012
+ const keys = /* @__PURE__ */ new Set([
4013
+ "PATH",
4014
+ "HOME",
4015
+ "USER",
4016
+ "LOGNAME",
4017
+ "SHELL",
4018
+ "LANG",
4019
+ "LC_ALL",
4020
+ "NODE_ENV",
4021
+ "npm_config_registry",
4022
+ "NPM_CONFIG_REGISTRY",
4023
+ "npm_config_prefix",
4024
+ "NPM_CONFIG_PREFIX",
4025
+ APM_DEPLOYMENT_RUN_ID_ENV
4026
+ ]);
4027
+ for (const key of Object.keys(env)) {
4028
+ if (/^npm_config_/i.test(key) || /^NPM_CONFIG_/i.test(key)) {
4029
+ keys.add(key);
3901
4030
  }
3902
- }
3903
- async deleteObjectsByPrefix(bucket, prefix) {
3904
- const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
3905
- const keys = [];
3906
- await new Promise((resolve5, reject) => {
3907
- objectsStream.on("data", (obj) => {
3908
- if (obj.name) {
3909
- keys.push(obj.name);
3910
- }
3911
- });
3912
- objectsStream.on("error", reject);
3913
- objectsStream.on("end", resolve5);
3914
- });
3915
- const chunkSize = 500;
3916
- for (let i = 0; i < keys.length; i += chunkSize) {
3917
- const chunk = keys.slice(i, i + chunkSize);
3918
- await this.inner.removeObjects(
3919
- bucket,
3920
- chunk.map((name) => name)
3921
- );
4031
+ if (/^APM_/i.test(key) && !SENSITIVE_ENV_KEY.test(key)) {
4032
+ keys.add(key);
3922
4033
  }
3923
4034
  }
3924
- async putObject(bucket, objectKey, body, meta) {
3925
- await this.inner.putObject(bucket, objectKey, body, body.length, meta);
3926
- }
3927
- /** 匿名可读当前桶全部对象(便于静态站点直链) */
3928
- async setBucketPublicRead(bucket) {
3929
- const policy = {
3930
- Version: "2012-10-17",
3931
- Statement: [
3932
- {
3933
- Effect: "Allow",
3934
- Principal: { AWS: ["*"] },
3935
- Action: ["s3:GetObject"],
3936
- Resource: [`arn:aws:s3:::${bucket}/*`]
3937
- }
3938
- ]
3939
- };
3940
- await this.inner.setBucketPolicy(bucket, JSON.stringify(policy));
3941
- }
3942
- };
3943
-
3944
- // src/commands/deploy/internal/deploy-artifact-minio.ts
3945
- var APM_DEPLOYMENT_RUN_ID_ENV = "APM_DEPLOYMENT_RUN_ID";
3946
- function formatDeployArtifactTimestamp(date = /* @__PURE__ */ new Date()) {
3947
- const pad = (n) => String(n).padStart(2, "0");
3948
- return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
3949
- }
3950
- function sanitizeDeployProjectName(name) {
3951
- const trimmed = name.trim().replace(/\\/g, "/");
3952
- const base = trimmed.split("/").filter(Boolean).pop() ?? trimmed;
3953
- try {
3954
- return sanitizeRelativePath(base.replace(/[/\\:*?"<>|]/g, "_"));
3955
- } catch {
3956
- return "project";
3957
- }
4035
+ const picked = {};
4036
+ for (const key of [...keys].sort()) {
4037
+ const value = env[key];
4038
+ if (value === void 0 || value === "") continue;
4039
+ picked[key] = SENSITIVE_ENV_KEY.test(key) ? "***" : value;
4040
+ }
4041
+ return picked;
3958
4042
  }
3959
- function buildDeployArtifactFileName(kind, projectName, timestamp = formatDeployArtifactTimestamp()) {
3960
- const safeName = sanitizeDeployProjectName(projectName);
3961
- const suffix = kind === "frontend" ? "dist.zip" : "jar.zip";
3962
- return `${timestamp}-${safeName}.${suffix}`;
4043
+ function describePathDelta(before, after) {
4044
+ const beforeSet = new Set(pathEntries(before));
4045
+ const added = pathEntries(after).filter((entry) => !beforeSet.has(entry));
4046
+ if (added.length === 0) return "buildDeployShellEnv \u672A prepend \u65B0 PATH \u6BB5";
4047
+ return `prepend: ${added.join(PATH_SEP2)}`;
3963
4048
  }
3964
- function buildDeployArtifactObjectKey(projectName, fileName) {
3965
- const safeProject = sanitizeDeployProjectName(projectName);
3966
- return `deploy/${safeProject}/${fileName}`;
4049
+ function probeCommand(label, command, cwd, env) {
4050
+ const result = spawnSync4(command, {
4051
+ cwd,
4052
+ shell: true,
4053
+ env,
4054
+ encoding: "utf8",
4055
+ stdio: ["ignore", "pipe", "pipe"]
4056
+ });
4057
+ const stdout = String(result.stdout ?? "").trim();
4058
+ const stderr = String(result.stderr ?? "").trim();
4059
+ const detail = stdout || stderr || "(no output)";
4060
+ logLine(
4061
+ `probe ${label}: exit=${result.status ?? "null"} output=${detail.slice(
4062
+ 0,
4063
+ 500
4064
+ )}`
4065
+ );
3967
4066
  }
3968
- function resolveDeploymentRunIdFromEnv() {
3969
- const raw = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim();
3970
- return raw || null;
4067
+ function probeShellTooling(cwd, env) {
4068
+ logLine("--- shell \u5DE5\u5177\u63A2\u6D4B\uFF08\u4E0E runDeployShellCommand \u76F8\u540C env/cwd\uFF09---");
4069
+ probeCommand("node -v", "node -v", cwd, env);
4070
+ probeCommand("npm -v", "npm -v", cwd, env);
4071
+ if (process.platform === "win32") {
4072
+ probeCommand("where node", "where node", cwd, env);
4073
+ probeCommand("where npm", "where npm", cwd, env);
4074
+ } else {
4075
+ probeCommand("which node", "which node", cwd, env);
4076
+ probeCommand("which npm", "which npm", cwd, env);
4077
+ }
4078
+ }
4079
+ function logExecuteDeployContext(input) {
4080
+ const trigger = input.trigger ?? "cli";
4081
+ const deploymentRunId = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim() || null;
4082
+ const shellEnv = buildDeployShellEnv();
4083
+ const npmGlobalBin = resolveNpmGlobalBin2();
4084
+ const packageJsonPath = join16(input.cwd, "package.json");
4085
+ logLine("========== executeDeploy \u4E0A\u4E0B\u6587 ==========");
4086
+ logLine(`trigger=${trigger} deployEnv=${input.env}`);
4087
+ logLine(`cwd(input)=${input.cwdInput}`);
4088
+ logLine(`cwd(resolved)=${input.cwd}`);
4089
+ logLine(`process.cwd()=${input.processCwd}`);
4090
+ logLine(
4091
+ `cwdMatchProcess=${input.cwd === input.processCwd ? "yes" : "no"} (connect \u901A\u5E38\u4E3A no)`
4092
+ );
4093
+ logLine(
4094
+ `apm.config=${input.apmConfigPath} exists=${existsSync14(
4095
+ input.apmConfigPath
4096
+ )}`
4097
+ );
4098
+ logLine(
4099
+ `package.json=${packageJsonPath} exists=${existsSync14(packageJsonPath)}`
4100
+ );
4101
+ logLine(
4102
+ `flags captureOutput=${input.captureOutput} packOnly=${Boolean(
4103
+ input.packOnly
4104
+ )} archiveDeployArtifact=${Boolean(input.archiveDeployArtifact)}`
4105
+ );
4106
+ logLine(`configPathOption=${input.configPathOption ?? "(default)"}`);
4107
+ logLine(`${APM_DEPLOYMENT_RUN_ID_ENV}=${deploymentRunId ?? "(unset)"}`);
4108
+ logLine(
4109
+ `process execPath=${process.execPath} pid=${process.pid} platform=${process.platform} arch=${process.arch}`
4110
+ );
4111
+ logLine(`process argv=${process.argv.join(" ")}`);
4112
+ logLine(`npmGlobalBin=${npmGlobalBin ?? "(resolve failed)"}`);
4113
+ logLine(`nodeDir=${dirname5(process.execPath)}`);
4114
+ logLine("--- process.env\uFF08\u8282\u9009\uFF09---");
4115
+ for (const [key, value] of Object.entries(
4116
+ collectInterestingEnv(process.env)
4117
+ )) {
4118
+ logLine(` ${key}=${value}`);
4119
+ }
4120
+ logLine(`process.env.PATH=${summarizePath(process.env.PATH)}`);
4121
+ logLine("--- buildDeployShellEnv()\uFF08\u5B50\u8FDB\u7A0B\u5B9E\u9645 env\uFF09---");
4122
+ logLine(describePathDelta(process.env.PATH, shellEnv.PATH));
4123
+ logLine(`shellEnv.PATH=${summarizePath(shellEnv.PATH)}`);
4124
+ for (const [key, value] of Object.entries(
4125
+ pickEnvKeys(shellEnv, [APM_DEPLOYMENT_RUN_ID_ENV, "NODE_ENV"])
4126
+ )) {
4127
+ logLine(` shellEnv.${key}=${value}`);
4128
+ }
4129
+ probeShellTooling(input.cwd, shellEnv);
4130
+ logLine("==========================================");
4131
+ }
4132
+ function logRunDeployShellContext(input) {
4133
+ const shellEnv = buildDeployShellEnv();
4134
+ logLine("---------- runDeployShellCommand ----------");
4135
+ logLine(`command=${input.command}`);
4136
+ logLine(`cwd=${input.cwd}`);
4137
+ logLine(`captureOutput=${input.captureOutput}`);
4138
+ logLine(
4139
+ `stdio=${input.captureOutput ? "stdin=inherit stdout=pipe stderr=pipe" : "inherit"}`
4140
+ );
4141
+ logLine(`shell=true maxBuffer=${50 * 1024 * 1024}`);
4142
+ logLine(`shellEnv.PATH(head)=${summarizePath(shellEnv.PATH, 8)}`);
4143
+ logLine("--------------------------------------------");
3971
4144
  }
3972
- async function fetchDeployArtifactStorage(api) {
3973
- return api.cli.getDeployArtifactStorage(void 0);
4145
+ function logRunDeployShellResult(input) {
4146
+ logLine(
4147
+ `runDeployShellCommand done command=${input.command} exit=${input.exitCode ?? "null"} signal=${input.signal ?? "null"} capturedBytes=${input.outputBytes}${input.errorMessage ? ` error=${input.errorMessage}` : ""}`
4148
+ );
3974
4149
  }
3975
- async function uploadDeployArtifactZip(options) {
3976
- const deploymentRunId = options.deploymentRunId ?? resolveDeploymentRunIdFromEnv();
3977
- if (!deploymentRunId && !options.uploadWithoutRunId) {
3978
- return null;
3979
- }
3980
- const cfg = await tryReadApmConfig();
3981
- if (!cfg || !resolveApiKey(cfg)) {
3982
- console.warn("[apm] \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7 MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863");
3983
- return null;
3984
- }
3985
- const api = options.api ?? createApmApiClient(cfg);
3986
- let storage;
3987
- try {
3988
- storage = await fetchDeployArtifactStorage(api);
3989
- } catch (error) {
3990
- const detail = error instanceof Error ? error.message : String(error);
3991
- console.warn(`[apm] \u83B7\u53D6 MinIO \u914D\u7F6E\u5931\u8D25\uFF0C\u8DF3\u8FC7\u90E8\u7F72\u4EA7\u7269\u5F52\u6863: ${detail}`);
3992
- return null;
3993
- }
3994
- const fileName = buildDeployArtifactFileName(
3995
- options.kind,
3996
- options.projectName,
3997
- options.timestamp
4150
+ function logWisdomFrontendDeployContext(input) {
4151
+ logLine("--- wisdom Vue \u524D\u7AEF ---");
4152
+ logLine(
4153
+ `buildKey=build:${input.env} buildCmd=${input.buildCmd ?? "(missing)"}`
3998
4154
  );
3999
- const objectKey = buildDeployArtifactObjectKey(options.projectName, fileName);
4000
- let body;
4001
- try {
4002
- body = await readFile2(options.zipPath);
4003
- } catch (error) {
4004
- const detail = error instanceof Error ? error.message : String(error);
4005
- console.warn(`[apm] \u8BFB\u53D6\u90E8\u7F72\u4EA7\u7269 zip \u5931\u8D25\uFF0C\u8DF3\u8FC7 MinIO \u5F52\u6863: ${detail}`);
4006
- return null;
4155
+ logLine(`distDir=${input.distDir} exists=${existsSync14(input.distDir)}`);
4156
+ logLine(
4157
+ `packOnly=${input.packOnly} archiveDeployArtifact=${input.archiveDeployArtifact}`
4158
+ );
4159
+ }
4160
+
4161
+ // src/commands/deploy/internal/wisdom-deploy.ts
4162
+ import { existsSync as existsSync16, readFileSync as readFileSync13, statSync as statSync7 } from "node:fs";
4163
+ import path4 from "node:path";
4164
+
4165
+ // src/commands/deploy/deploy-shell-run.ts
4166
+ import { spawnSync as spawnSync5 } from "node:child_process";
4167
+ function runDeployShellCommand(command, cwd, captureOutput) {
4168
+ logRunDeployShellContext({ command, cwd, captureOutput });
4169
+ const shellEnv = buildDeployShellEnv();
4170
+ const result = spawnSync5(command, {
4171
+ cwd,
4172
+ shell: true,
4173
+ env: shellEnv,
4174
+ encoding: "utf8",
4175
+ maxBuffer: DEPLOY_SPAWN_MAX_BUFFER_BYTES,
4176
+ stdio: captureOutput ? ["inherit", "pipe", "pipe"] : "inherit"
4177
+ });
4178
+ const stdout = captureOutput ? String(result.stdout ?? "") : "";
4179
+ const stderr = captureOutput ? String(result.stderr ?? "") : "";
4180
+ const output = [stdout, stderr].filter(Boolean).join("\n");
4181
+ logRunDeployShellResult({
4182
+ command,
4183
+ exitCode: result.status,
4184
+ signal: result.signal,
4185
+ errorMessage: result.error?.message,
4186
+ outputBytes: Buffer.byteLength(output, "utf8")
4187
+ });
4188
+ if (captureOutput) {
4189
+ if (stdout) process.stdout.write(stdout);
4190
+ if (stderr) process.stderr.write(stderr);
4007
4191
  }
4008
- try {
4009
- const client = new MinioClient({
4010
- endPoint: storage.endpoint,
4011
- port: storage.port,
4012
- useSSL: storage.useSsl,
4013
- accessKey: storage.accessKey,
4014
- secretKey: storage.secretKey
4015
- });
4016
- await client.ensureBucket(storage.bucket);
4017
- await client.putObject(storage.bucket, objectKey, body, {
4018
- "Content-Type": "application/zip"
4019
- });
4020
- console.error(
4021
- `[apm] \u672C\u5730\u76F4\u4F20 MinIO\uFF08\u4E0D\u7ECF\u5E73\u53F0\u670D\u52A1\u5668\uFF09: ${storage.endpoint}:${storage.port}/${storage.bucket}/${objectKey} (${(body.length / 1024 / 1024).toFixed(
4022
- 2
4023
- )} MB)`
4192
+ if (result.error) {
4193
+ throw new DeployExecutionError(
4194
+ `\u90E8\u7F72\u547D\u4EE4\u6267\u884C\u5931\u8D25: ${result.error.message}`,
4195
+ 1,
4196
+ output
4024
4197
  );
4025
- } catch (error) {
4026
- const detail = error instanceof Error ? error.message : String(error);
4027
- console.warn(`[apm] MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863\u5931\u8D25: ${detail}`);
4028
- return null;
4029
4198
  }
4030
- if (deploymentRunId) {
4031
- try {
4032
- await api.cli.attachTaskDeploymentArtifact({
4033
- id: deploymentRunId,
4034
- artifactObjectKey: objectKey,
4035
- artifactFileName: fileName
4036
- });
4037
- console.error(
4038
- `[apm] \u5DF2\u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55 id=${deploymentRunId} file=${fileName}`
4039
- );
4040
- } catch (error) {
4041
- const detail = error instanceof Error ? error.message : String(error);
4042
- console.warn(`[apm] \u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55\u5931\u8D25: ${detail}`);
4043
- return null;
4044
- }
4199
+ if (result.status !== 0) {
4200
+ throw new DeployExecutionError(
4201
+ `\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${result.status ?? "unknown"}: ${command}`,
4202
+ result.status ?? 1,
4203
+ output
4204
+ );
4045
4205
  }
4046
- return {
4047
- objectKey,
4048
- fileName,
4049
- bucket: storage.bucket
4050
- };
4206
+ return output;
4051
4207
  }
4052
4208
 
4209
+ // src/commands/deploy/internal/wisdom-backend-deploy.ts
4210
+ import {
4211
+ existsSync as existsSync15,
4212
+ mkdirSync as mkdirSync7,
4213
+ readdirSync as readdirSync5,
4214
+ readFileSync as readFileSync12,
4215
+ statSync as statSync6,
4216
+ writeFileSync as writeFileSync12
4217
+ } from "node:fs";
4218
+ import { spawnSync as spawnSync6 } from "node:child_process";
4219
+ import path3 from "node:path";
4220
+ import { Client as Client2 } from "ssh2";
4221
+ import JSZip2 from "jszip";
4222
+ import SftpClient2 from "ssh2-sftp-client";
4223
+
4053
4224
  // src/commands/deploy/internal/wisdom-sftp.ts
4225
+ import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
4226
+ import path2 from "node:path";
4227
+ import JSZip from "jszip";
4228
+ import SftpClient from "ssh2-sftp-client";
4054
4229
  async function addDirToZip(dir, zipFolder) {
4055
4230
  const entries = await readdir2(dir, { withFileTypes: true });
4056
4231
  for (const entry of entries) {
@@ -4208,10 +4383,27 @@ async function uploadAndMaybeExtract(settings, localZip, extract) {
4208
4383
  await sftp.end();
4209
4384
  }
4210
4385
  }
4386
+ function resolveDeployArtifactUpload(input) {
4387
+ const { packOnly, archiveDeployArtifact, deploymentRunId } = input;
4388
+ if (deploymentRunId) {
4389
+ return { upload: true, uploadWithoutRunId: false };
4390
+ }
4391
+ if (archiveDeployArtifact || packOnly) {
4392
+ return { upload: true, uploadWithoutRunId: true };
4393
+ }
4394
+ return { upload: false, uploadWithoutRunId: false };
4395
+ }
4211
4396
  async function runWisdomSftpDeploy(params) {
4212
4397
  const zipPath = path2.join(params.localDir, "..", ".deploy-sftp-dist.zip");
4213
4398
  const resolvedZipPath = path2.resolve(zipPath);
4214
4399
  const packOnly = Boolean(params.packOnly);
4400
+ const archiveDeployArtifact = Boolean(params.archiveDeployArtifact);
4401
+ const deploymentRunId = resolveDeploymentRunIdFromEnv();
4402
+ const artifactUpload = resolveDeployArtifactUpload({
4403
+ packOnly,
4404
+ archiveDeployArtifact,
4405
+ deploymentRunId
4406
+ });
4215
4407
  let zipSizeBytes = 0;
4216
4408
  let artifactUploaded = false;
4217
4409
  try {
@@ -4225,15 +4417,21 @@ async function runWisdomSftpDeploy(params) {
4225
4417
  } else {
4226
4418
  console.error("[apm] \u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u8DF3\u8FC7 SFTP \u8FDC\u7A0B\u4E0A\u4F20");
4227
4419
  }
4228
- const artifact = await uploadDeployArtifactZip({
4229
- zipPath: resolvedZipPath,
4230
- projectName: params.projectName,
4231
- kind: "frontend",
4232
- uploadWithoutRunId: packOnly && !resolveDeploymentRunIdFromEnv()
4233
- });
4234
- artifactUploaded = artifact !== null;
4235
- if (packOnly && artifactUploaded) {
4236
- console.error("\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09");
4420
+ if (artifactUpload.upload) {
4421
+ const artifact = await uploadDeployArtifactZip({
4422
+ zipPath: resolvedZipPath,
4423
+ projectName: params.projectName,
4424
+ kind: "frontend",
4425
+ uploadWithoutRunId: artifactUpload.uploadWithoutRunId
4426
+ });
4427
+ artifactUploaded = artifact !== null;
4428
+ }
4429
+ if (artifactUploaded) {
4430
+ if (packOnly) {
4431
+ console.error("\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5B8C\u6210\uFF08\u672A\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF09");
4432
+ } else {
4433
+ console.error("[apm] SFTP \u90E8\u7F72\u5B8C\u6210\uFF0C\u90E8\u7F72\u4EA7\u7269\u5DF2\u5F52\u6863 MinIO");
4434
+ }
4237
4435
  }
4238
4436
  } finally {
4239
4437
  try {
@@ -4303,7 +4501,7 @@ function fileSignature(filePath) {
4303
4501
  }
4304
4502
  function loadManifest3() {
4305
4503
  const manifestPath2 = manifestFilePath();
4306
- if (!existsSync14(manifestPath2)) {
4504
+ if (!existsSync15(manifestPath2)) {
4307
4505
  return {};
4308
4506
  }
4309
4507
  return JSON.parse(readFileSync12(manifestPath2, "utf8"));
@@ -4388,7 +4586,7 @@ function getMvnExecutable() {
4388
4586
  const isWin = process.platform === "win32";
4389
4587
  const candidates = isWin ? ["mvn.cmd", "mvn.bat", "mvn"] : ["mvn"];
4390
4588
  for (const name of candidates) {
4391
- const result = spawnSync5(isWin ? `where ${name}` : `which ${name}`, {
4589
+ const result = spawnSync6(isWin ? `where ${name}` : `which ${name}`, {
4392
4590
  encoding: "utf8",
4393
4591
  shell: true
4394
4592
  });
@@ -4418,7 +4616,7 @@ function runMavenBuild(projectRoot, mavenLocalRepo, repoSource) {
4418
4616
  log(`Maven \u672C\u5730\u4ED3\u5E93: ${mavenRepo}`);
4419
4617
  }
4420
4618
  log(`\u6784\u5EFA\u76EE\u5F55: ${projectRoot}`);
4421
- const result = spawnSync5(command, {
4619
+ const result = spawnSync6(command, {
4422
4620
  cwd: projectRoot,
4423
4621
  stdio: "inherit",
4424
4622
  shell: true,
@@ -4430,11 +4628,11 @@ function runMavenBuild(projectRoot, mavenLocalRepo, repoSource) {
4430
4628
  }
4431
4629
  function locateLibDir(projectRoot) {
4432
4630
  const targetDir = getTargetDir(projectRoot);
4433
- if (!existsSync14(targetDir)) {
4631
+ if (!existsSync15(targetDir)) {
4434
4632
  fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
4435
4633
  }
4436
4634
  const libDir = path3.join(targetDir, "lib");
4437
- if (!existsSync14(libDir) || !statSync6(libDir).isDirectory()) {
4635
+ if (!existsSync15(libDir) || !statSync6(libDir).isDirectory()) {
4438
4636
  fail(`lib \u76EE\u5F55\u4E0D\u5B58\u5728: ${libDir}`);
4439
4637
  }
4440
4638
  const libJars = readdirSync5(libDir).filter((name) => name.endsWith(".jar"));
@@ -4446,7 +4644,7 @@ function locateLibDir(projectRoot) {
4446
4644
  }
4447
4645
  function locateMainJar(projectRoot) {
4448
4646
  const targetDir = getTargetDir(projectRoot);
4449
- if (!existsSync14(targetDir)) {
4647
+ if (!existsSync15(targetDir)) {
4450
4648
  fail(`\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728: ${targetDir}`);
4451
4649
  }
4452
4650
  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);
@@ -4919,22 +5117,17 @@ async function runWisdomBackendDeploy(options) {
4919
5117
  log("\u90E8\u7F72\u5B8C\u6210");
4920
5118
  }
4921
5119
 
4922
- // src/commands/deploy/internal/wisdom-auto-deploy.ts
4923
- function isWisdomLegacyDeploy(cfg) {
5120
+ // src/commands/deploy/internal/wisdom-deploy.ts
5121
+ function isWisdomDeployConfigured(cfg) {
4924
5122
  const w = cfg.wisdomDeploy;
4925
- if (!w?.host?.trim() || !w.remotePath?.trim()) {
4926
- return false;
4927
- }
4928
- const hasNewFrontend = Boolean(cfg.frontendDeploy?.endpoint?.trim());
4929
- const hasNewBackend = Boolean(cfg.backendDeploy?.registryHost?.trim());
4930
- return !hasNewFrontend && !hasNewBackend;
5123
+ return Boolean(w?.host?.trim() && w?.remotePath?.trim());
4931
5124
  }
4932
5125
  function detectWisdomProjectType(cwd) {
4933
- return existsSync15(path4.join(cwd, "package.json")) ? "frontend" : "backend";
5126
+ return existsSync16(path4.join(cwd, "package.json")) ? "frontend" : "backend";
4934
5127
  }
4935
5128
  function readPackageScripts(cwd) {
4936
5129
  const pkgPath = path4.join(cwd, "package.json");
4937
- if (!existsSync15(pkgPath)) {
5130
+ if (!existsSync16(pkgPath)) {
4938
5131
  return {};
4939
5132
  }
4940
5133
  try {
@@ -4945,14 +5138,6 @@ function readPackageScripts(cwd) {
4945
5138
  return {};
4946
5139
  }
4947
5140
  }
4948
- function resolveFrontendDeployCommand(env, cwd) {
4949
- const scripts = readPackageScripts(cwd);
4950
- const deployKey = `deploy:${env}`;
4951
- if (scripts[deployKey]?.trim()) {
4952
- return `npm run deploy:${env}`;
4953
- }
4954
- return null;
4955
- }
4956
5141
  function resolveFrontendBuildCommand(env, cwd) {
4957
5142
  const scripts = readPackageScripts(cwd);
4958
5143
  const buildKey = `build:${env}`;
@@ -4966,7 +5151,7 @@ function resolveFrontendDistDir(cwd) {
4966
5151
  for (const rel of candidates) {
4967
5152
  const full = path4.join(cwd, rel);
4968
5153
  try {
4969
- if (existsSync15(full) && statSync7(full).isDirectory()) {
5154
+ if (existsSync16(full) && statSync7(full).isDirectory()) {
4970
5155
  return full;
4971
5156
  }
4972
5157
  } catch {
@@ -4974,62 +5159,57 @@ function resolveFrontendDistDir(cwd) {
4974
5159
  }
4975
5160
  return path4.join(cwd, "dist");
4976
5161
  }
4977
- async function runWisdomAutoDeploy(options) {
4978
- const cwd = path4.resolve(options.cwd ?? process.cwd());
4979
- const captureOutput = options.captureOutput ?? false;
4980
- const packOnly = Boolean(options.packOnly);
4981
- const projectType = detectWisdomProjectType(cwd);
4982
- const configPath = options.configPath ?? path4.join(workspaceApmDir(cwd), "apm.config.json");
4983
- const cfg = loadApmConfig({ configPath });
5162
+ async function executeWisdomFrontendDeploy(options) {
5163
+ const { cwd, cfg, captureOutput, packOnly, archiveDeployArtifact } = options;
5164
+ const buildCmd = resolveFrontendBuildCommand(options.env, cwd);
5165
+ const distDir = resolveFrontendDistDir(cwd);
5166
+ logWisdomFrontendDeployContext({
5167
+ env: options.env,
5168
+ cwd,
5169
+ buildCmd,
5170
+ distDir,
5171
+ packOnly,
5172
+ archiveDeployArtifact
5173
+ });
5174
+ if (!buildCmd) {
5175
+ const lines = formatWisdomFrontendBuildNotConfiguredLines(
5176
+ options.env,
5177
+ path4.join(cwd, "package.json")
5178
+ );
5179
+ throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
5180
+ }
4984
5181
  console.error(
4985
- `[apm] \u533B\u52A1\u5B58\u91CF\u9879\u76EE\u81EA\u52A8\u8BC6\u522B: ${projectType === "frontend" ? "\u524D\u7AEF Vue" : "\u540E\u7AEF Java"}${packOnly ? "\uFF08\u4EC5\u6253\u5305\u6A21\u5F0F\uFF09" : ""}`
5182
+ `[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" : ""))
4986
5183
  );
4987
- if (projectType === "frontend") {
4988
- if (packOnly) {
4989
- const buildCmd = resolveFrontendBuildCommand(options.env, cwd);
4990
- if (!buildCmd) {
4991
- const lines = formatWisdomFrontendBuildNotConfiguredLines(
4992
- options.env,
4993
- path4.join(cwd, "package.json")
4994
- );
4995
- throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
4996
- }
4997
- console.error(`[apm] \u524D\u7AEF\u4EC5\u6253\u5305\u6A21\u5F0F\uFF1A\u6267\u884C ${buildCmd}`);
4998
- runDeployShellCommand(buildCmd, cwd, captureOutput);
4999
- const projectName = (cfg.name ?? "").trim();
5000
- if (!projectName) {
5001
- throw new DeployExecutionError(
5002
- "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09",
5003
- 1
5004
- );
5005
- }
5006
- const settings2 = resolveWisdomDeployFromApmConfig(cfg);
5007
- await runWisdomSftpDeploy({
5008
- localDir: resolveFrontendDistDir(cwd),
5009
- settings: settings2,
5010
- extract: false,
5011
- projectName,
5012
- packOnly: true
5013
- });
5014
- return { projectType };
5015
- }
5016
- const deployCmd = resolveFrontendDeployCommand(options.env, cwd);
5017
- if (!deployCmd) {
5018
- const lines = formatWisdomFrontendDeployNotConfiguredLines(
5019
- options.env,
5020
- path4.join(cwd, "package.json")
5021
- );
5022
- throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
5023
- }
5024
- runDeployShellCommand(deployCmd, cwd, captureOutput);
5025
- return { projectType };
5184
+ runDeployShellCommand(buildCmd, cwd, captureOutput);
5185
+ let projectName = (cfg.name ?? "").trim();
5186
+ if ((packOnly || archiveDeployArtifact) && !projectName) {
5187
+ throw new DeployExecutionError(
5188
+ "\u8BF7\u5728 .apm/apm.config.json \u9876\u5C42\u914D\u7F6E name\uFF08\u4F5C\u4E3A\u90E8\u7F72\u4EA7\u7269\u9879\u76EE\u540D\uFF09",
5189
+ 1
5190
+ );
5191
+ }
5192
+ if (!projectName) {
5193
+ projectName = path4.basename(cwd);
5026
5194
  }
5195
+ const settings = resolveWisdomDeployFromApmConfig(cfg);
5196
+ await runWisdomSftpDeploy({
5197
+ localDir: distDir,
5198
+ settings,
5199
+ extract: !packOnly,
5200
+ projectName,
5201
+ packOnly,
5202
+ archiveDeployArtifact
5203
+ });
5204
+ }
5205
+ async function executeWisdomBackendDeployFlow(options) {
5206
+ const { cwd, cfg, packOnly } = options;
5027
5207
  const settings = resolveWisdomBackendDeployFromApmConfig(cfg);
5028
5208
  if (packOnly) {
5029
- console.error(`[apm] \u540E\u7AEF\u4EC5\u6253\u5305\u6A21\u5F0F\uFF0C\u5FFD\u7565\u73AF\u5883\u53C2\u6570: ${options.env}`);
5209
+ console.error(`[apm] Java\uFF1AMaven \u6784\u5EFA\uFF08\u4EC5\u6253\u5305\uFF0C\u5FFD\u7565\u73AF\u5883 ${options.env}\uFF09`);
5030
5210
  } else {
5031
5211
  console.error(
5032
- `[apm] \u540E\u7AEF\u90E8\u7F72\u4E0D\u533A\u5206 test/online\uFF0C\u5FFD\u7565\u73AF\u5883\u53C2\u6570: ${options.env}`
5212
+ `[apm] Java\uFF1AMaven \u6784\u5EFA\u5E76\u90E8\u7F72\uFF08\u4E0D\u533A\u5206 test/online\uFF0C\u5FFD\u7565\u73AF\u5883 ${options.env}\uFF09`
5033
5213
  );
5034
5214
  }
5035
5215
  await runWisdomBackendDeploy({
@@ -5037,11 +5217,40 @@ async function runWisdomAutoDeploy(options) {
5037
5217
  projectRoot: cwd,
5038
5218
  packOnly
5039
5219
  });
5220
+ }
5221
+ async function executeWisdomDeploy(options) {
5222
+ const cwd = path4.resolve(options.cwd);
5223
+ const captureOutput = options.captureOutput ?? false;
5224
+ const packOnly = Boolean(options.packOnly);
5225
+ const archiveDeployArtifact = Boolean(options.archiveDeployArtifact);
5226
+ const projectType = detectWisdomProjectType(cwd);
5227
+ const configPath = options.configPath ?? path4.join(workspaceApmDir(cwd), "apm.config.json");
5228
+ const cfg = loadApmConfig({ configPath });
5229
+ console.error(
5230
+ `[apm] ${projectType === "frontend" ? "Vue \u524D\u7AEF" : "Java \u540E\u7AEF"}${packOnly ? "\uFF08\u4EC5\u6253\u5305\uFF09" : ""}`
5231
+ );
5232
+ if (projectType === "frontend") {
5233
+ await executeWisdomFrontendDeploy({
5234
+ ...options,
5235
+ cwd,
5236
+ cfg,
5237
+ captureOutput,
5238
+ packOnly,
5239
+ archiveDeployArtifact
5240
+ });
5241
+ return { projectType };
5242
+ }
5243
+ await executeWisdomBackendDeployFlow({
5244
+ ...options,
5245
+ cwd,
5246
+ cfg,
5247
+ packOnly
5248
+ });
5040
5249
  return { projectType };
5041
5250
  }
5042
5251
 
5043
5252
  // src/commands/deploy/internal/deploy-baseline-sync.ts
5044
- var LOG_PREFIX = "[apm] \u90E8\u7F72\u524D\u57FA\u7EBF\u540C\u6B65:";
5253
+ var LOG_PREFIX2 = "[apm] \u90E8\u7F72\u524D\u57FA\u7EBF\u540C\u6B65:";
5045
5254
  function formatGitError(error) {
5046
5255
  return error instanceof Error ? error.message : String(error);
5047
5256
  }
@@ -5077,20 +5286,20 @@ async function restoreWorkingTree(cwd) {
5077
5286
  }
5078
5287
  async function mergeBaselineBranch(cwd, baselineBranch, currentBranch, note) {
5079
5288
  const mergeTarget = `origin/${baselineBranch}`;
5080
- note(`${LOG_PREFIX} \u5F00\u59CB\u5408\u5E76 ${mergeTarget} \u5230\u5F53\u524D\u5206\u652F ${currentBranch}`);
5289
+ note(`${LOG_PREFIX2} \u5F00\u59CB\u5408\u5E76 ${mergeTarget} \u5230\u5F53\u524D\u5206\u652F ${currentBranch}`);
5081
5290
  try {
5082
5291
  if (currentBranch === baselineBranch) {
5083
5292
  await execGit(cwd, ["merge", "--ff-only", mergeTarget]);
5084
5293
  } else {
5085
5294
  await execGit(cwd, ["merge", mergeTarget, "--no-edit"]);
5086
5295
  }
5087
- note(`${LOG_PREFIX} \u5DF2\u5408\u5E76 ${mergeTarget} \u6700\u65B0\u4EE3\u7801`);
5296
+ note(`${LOG_PREFIX2} \u5DF2\u5408\u5E76 ${mergeTarget} \u6700\u65B0\u4EE3\u7801`);
5088
5297
  return { merged: true, conflictRollback: false };
5089
5298
  } catch (error) {
5090
5299
  await abortMergeIfNeeded(cwd);
5091
- note(`${LOG_PREFIX} \u5408\u5E76 ${mergeTarget} \u5931\u8D25: ${formatGitError(error)}`);
5092
- note(`${LOG_PREFIX} \u5DF2\u6267\u884C git merge --abort \u56DE\u9000\u5230\u5408\u5E76\u524D\u72B6\u6001`);
5093
- note(`${LOG_PREFIX} \u5C06\u4F7F\u7528\u56DE\u9000\u540E\u7684\u4EE3\u7801\u7EE7\u7EED\u90E8\u7F72`);
5300
+ note(`${LOG_PREFIX2} \u5408\u5E76 ${mergeTarget} \u5931\u8D25: ${formatGitError(error)}`);
5301
+ note(`${LOG_PREFIX2} \u5DF2\u6267\u884C git merge --abort \u56DE\u9000\u5230\u5408\u5E76\u524D\u72B6\u6001`);
5302
+ note(`${LOG_PREFIX2} \u5C06\u4F7F\u7528\u56DE\u9000\u540E\u7684\u4EE3\u7801\u7EE7\u7EED\u90E8\u7F72`);
5094
5303
  return { merged: false, conflictRollback: true };
5095
5304
  }
5096
5305
  }
@@ -5098,17 +5307,17 @@ async function restoreStashIfNeeded(cwd, stashed, note) {
5098
5307
  if (!stashed) {
5099
5308
  return false;
5100
5309
  }
5101
- note(`${LOG_PREFIX} \u6B63\u5728\u6062\u590D stash \u4E2D\u7684\u672A\u63D0\u4EA4\u6539\u52A8`);
5310
+ note(`${LOG_PREFIX2} \u6B63\u5728\u6062\u590D stash \u4E2D\u7684\u672A\u63D0\u4EA4\u6539\u52A8`);
5102
5311
  try {
5103
5312
  await execGit(cwd, ["stash", "pop"], true);
5104
- note(`${LOG_PREFIX} \u5DF2\u6062\u590D stash \u4E2D\u7684\u672A\u63D0\u4EA4\u6539\u52A8`);
5313
+ note(`${LOG_PREFIX2} \u5DF2\u6062\u590D stash \u4E2D\u7684\u672A\u63D0\u4EA4\u6539\u52A8`);
5105
5314
  return false;
5106
5315
  } catch (error) {
5107
5316
  await abortMergeIfNeeded(cwd);
5108
5317
  await restoreWorkingTree(cwd);
5109
- note(`${LOG_PREFIX} \u6062\u590D stash \u5931\u8D25: ${formatGitError(error)}`);
5110
- note(`${LOG_PREFIX} \u5DF2\u56DE\u9000\u5DE5\u4F5C\u533A\uFF08git reset --hard HEAD\uFF09\uFF0Cstash \u4ECD\u4FDD\u7559`);
5111
- note(`${LOG_PREFIX} \u5C06\u4F7F\u7528\u56DE\u9000\u540E\u7684\u4EE3\u7801\u7EE7\u7EED\u90E8\u7F72`);
5318
+ note(`${LOG_PREFIX2} \u6062\u590D stash \u5931\u8D25: ${formatGitError(error)}`);
5319
+ note(`${LOG_PREFIX2} \u5DF2\u56DE\u9000\u5DE5\u4F5C\u533A\uFF08git reset --hard HEAD\uFF09\uFF0Cstash \u4ECD\u4FDD\u7559`);
5320
+ note(`${LOG_PREFIX2} \u5C06\u4F7F\u7528\u56DE\u9000\u540E\u7684\u4EE3\u7801\u7EE7\u7EED\u90E8\u7F72`);
5112
5321
  return true;
5113
5322
  }
5114
5323
  }
@@ -5127,30 +5336,30 @@ async function syncDeployBaselineBeforeDeploy(cwd) {
5127
5336
  ...partial
5128
5337
  });
5129
5338
  if (!await isGitRepo(cwd)) {
5130
- note(`${LOG_PREFIX} \u5F53\u524D\u76EE\u5F55\u4E0D\u662F git \u4ED3\u5E93\uFF0C\u8DF3\u8FC7`);
5339
+ note(`${LOG_PREFIX2} \u5F53\u524D\u76EE\u5F55\u4E0D\u662F git \u4ED3\u5E93\uFF0C\u8DF3\u8FC7`);
5131
5340
  return emptyResult();
5132
5341
  }
5133
5342
  const cfg = await tryReadApmConfig();
5134
5343
  if (!cfg || !resolveApiKey(cfg)) {
5135
- note(`${LOG_PREFIX} \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7`);
5344
+ note(`${LOG_PREFIX2} \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7`);
5136
5345
  return emptyResult();
5137
5346
  }
5138
5347
  await ensureGitRepo(cwd);
5139
5348
  const api = createApmApiClient(cfg);
5140
5349
  const baselineBranch = await resolveBaselineBranch2(cwd, api);
5141
- note(`${LOG_PREFIX} \u57FA\u7EBF\u5206\u652F ${baselineBranch}`);
5142
- note(`${LOG_PREFIX} \u6B63\u5728 fetch origin ${baselineBranch}`);
5350
+ note(`${LOG_PREFIX2} \u57FA\u7EBF\u5206\u652F ${baselineBranch}`);
5351
+ note(`${LOG_PREFIX2} \u6B63\u5728 fetch origin ${baselineBranch}`);
5143
5352
  await execGit(cwd, ["fetch", "origin", baselineBranch], true);
5144
5353
  if (!await remoteBranchExists(cwd, baselineBranch)) {
5145
5354
  throw new Error(
5146
5355
  `\u8FDC\u7A0B\u4E0D\u5B58\u5728\u57FA\u7EBF\u5206\u652F origin/${baselineBranch}\uFF0C\u8BF7\u786E\u8BA4\u4ED3\u5E93\u9ED8\u8BA4\u5206\u652F\u5DF2\u63A8\u9001\u5230 origin`
5147
5356
  );
5148
5357
  }
5149
- note(`${LOG_PREFIX} fetch \u5B8C\u6210`);
5358
+ note(`${LOG_PREFIX2} fetch \u5B8C\u6210`);
5150
5359
  const currentBranch = await getCurrentBranch(cwd);
5151
5360
  let stashed = false;
5152
5361
  if (await isWorkingTreeDirty(cwd)) {
5153
- note(`${LOG_PREFIX} \u68C0\u6D4B\u5230\u672A\u63D0\u4EA4\u6539\u52A8\uFF0C\u5148 stash`);
5362
+ note(`${LOG_PREFIX2} \u68C0\u6D4B\u5230\u672A\u63D0\u4EA4\u6539\u52A8\uFF0C\u5148 stash`);
5154
5363
  await execGit(cwd, [
5155
5364
  "stash",
5156
5365
  "push",
@@ -5159,7 +5368,7 @@ async function syncDeployBaselineBeforeDeploy(cwd) {
5159
5368
  "apm: deploy baseline sync"
5160
5369
  ]);
5161
5370
  stashed = true;
5162
- note(`${LOG_PREFIX} \u5DF2 stash \u672A\u63D0\u4EA4\u6539\u52A8`);
5371
+ note(`${LOG_PREFIX2} \u5DF2 stash \u672A\u63D0\u4EA4\u6539\u52A8`);
5163
5372
  }
5164
5373
  const { merged, conflictRollback } = await mergeBaselineBranch(
5165
5374
  cwd,
@@ -5169,10 +5378,10 @@ async function syncDeployBaselineBeforeDeploy(cwd) {
5169
5378
  );
5170
5379
  const stashConflict = await restoreStashIfNeeded(cwd, stashed, note);
5171
5380
  if (conflictRollback || stashConflict) {
5172
- note(`${LOG_PREFIX} \u57FA\u7EBF\u540C\u6B65\u672A\u5B8C\u6210\uFF08\u5B58\u5728\u51B2\u7A81\u5E76\u5DF2\u56DE\u9000\uFF09\uFF0C\u7EE7\u7EED\u6267\u884C\u90E8\u7F72`);
5381
+ note(`${LOG_PREFIX2} \u57FA\u7EBF\u540C\u6B65\u672A\u5B8C\u6210\uFF08\u5B58\u5728\u51B2\u7A81\u5E76\u5DF2\u56DE\u9000\uFF09\uFF0C\u7EE7\u7EED\u6267\u884C\u90E8\u7F72`);
5173
5382
  } else if (merged) {
5174
5383
  note(
5175
- `${LOG_PREFIX} \u5B8C\u6210\uFF08\u5F53\u524D\u5206\u652F ${currentBranch} \u5DF2\u5305\u542B ${baselineBranch} \u6700\u65B0\u4EE3\u7801\uFF09`
5384
+ `${LOG_PREFIX2} \u5B8C\u6210\uFF08\u5F53\u524D\u5206\u652F ${currentBranch} \u5DF2\u5305\u542B ${baselineBranch} \u6700\u65B0\u4EE3\u7801\uFF09`
5176
5385
  );
5177
5386
  }
5178
5387
  return {
@@ -5186,10 +5395,26 @@ async function syncDeployBaselineBeforeDeploy(cwd) {
5186
5395
 
5187
5396
  // src/commands/deploy/deploy-execute.ts
5188
5397
  async function executeDeploy(options) {
5189
- const cwd = resolveWorkdirPath(options.cwd ?? process.cwd());
5398
+ const cwdInput = options.cwd.trim();
5399
+ if (!cwdInput) {
5400
+ throw new DeployExecutionError("[apm] executeDeploy \u7F3A\u5C11\u5DE5\u4F5C\u76EE\u5F55 cwd", 1);
5401
+ }
5402
+ const cwd = resolveWorkdirPath(cwdInput);
5190
5403
  const apmConfigPath = options.configPath ?? path5.join(workspaceApmDir(cwd), "apm.config.json");
5191
5404
  const captureOutput = options.captureOutput ?? false;
5192
5405
  const outputParts = [];
5406
+ logExecuteDeployContext({
5407
+ trigger: options.deployTrigger,
5408
+ env: options.env,
5409
+ cwd,
5410
+ cwdInput,
5411
+ processCwd: process.cwd(),
5412
+ apmConfigPath,
5413
+ captureOutput,
5414
+ packOnly: options.packOnly,
5415
+ archiveDeployArtifact: options.archiveDeployArtifact,
5416
+ configPathOption: options.configPath
5417
+ });
5193
5418
  try {
5194
5419
  const configSyncResult = await syncRemoteDeploymentConfig(
5195
5420
  cwd,
@@ -5212,36 +5437,29 @@ async function executeDeploy(options) {
5212
5437
  detail
5213
5438
  );
5214
5439
  }
5440
+ const preDeployLog = outputParts.join("\n");
5215
5441
  const cfg = loadApmConfig({ configPath: apmConfigPath });
5216
- if (isWisdomLegacyDeploy(cfg)) {
5217
- try {
5218
- await runWisdomAutoDeploy({
5219
- env: options.env,
5220
- cwd,
5221
- configPath: apmConfigPath,
5222
- captureOutput,
5223
- packOnly: options.packOnly
5224
- });
5225
- return outputParts.join("\n");
5226
- } catch (error) {
5227
- if (error instanceof DeployExecutionError) {
5228
- throw error;
5229
- }
5230
- const detail = error instanceof Error ? error.message : String(error);
5231
- throw new DeployExecutionError(detail, 1);
5232
- }
5233
- }
5234
- const deployCommands = cfg.deploy ?? {};
5235
- const command = deployCommands[options.env]?.trim();
5236
- if (!command) {
5237
- const lines = formatDeployNotConfiguredLines(options.env, deployCommands);
5442
+ if (!isWisdomDeployConfigured(cfg)) {
5443
+ const lines = formatMissingWisdomDeployLines();
5238
5444
  throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
5239
5445
  }
5240
- const commandOutput = runDeployShellCommand(command, cwd, captureOutput);
5241
- if (commandOutput.trim()) {
5242
- outputParts.push(commandOutput);
5446
+ try {
5447
+ await executeWisdomDeploy({
5448
+ env: options.env,
5449
+ cwd,
5450
+ configPath: apmConfigPath,
5451
+ captureOutput,
5452
+ packOnly: options.packOnly,
5453
+ archiveDeployArtifact: options.archiveDeployArtifact
5454
+ });
5455
+ return preDeployLog;
5456
+ } catch (error) {
5457
+ if (error instanceof DeployExecutionError) {
5458
+ throw error;
5459
+ }
5460
+ const detail = error instanceof Error ? error.message : String(error);
5461
+ throw new DeployExecutionError(detail, 1);
5243
5462
  }
5244
- return outputParts.join("\n");
5245
5463
  }
5246
5464
  function printDeployExecutionError(error) {
5247
5465
  if (error.output.trim()) {
@@ -5390,7 +5608,9 @@ async function handleInboundDeploy(cfg, msg, signal) {
5390
5608
  env: msg.environment,
5391
5609
  cwd: workdir,
5392
5610
  packOnly: msg.packOnly,
5393
- captureOutput: true
5611
+ captureOutput: true,
5612
+ archiveDeployArtifact: true,
5613
+ deployTrigger: "connect"
5394
5614
  };
5395
5615
  try {
5396
5616
  if (signal.aborted) return;
@@ -5706,13 +5926,13 @@ ${JSON.stringify(event, null, 2)}
5706
5926
  }
5707
5927
 
5708
5928
  // src/commands/connect/agent-session-registry.ts
5709
- import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "node:fs";
5710
- import { dirname as dirname5, resolve as resolve4 } from "node:path";
5929
+ import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync13 } from "node:fs";
5930
+ import { dirname as dirname6, resolve as resolve4 } from "node:path";
5711
5931
  function registryPath(workdir, sessionId) {
5712
5932
  return resolve4(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
5713
5933
  }
5714
5934
  function readRegistry(path13) {
5715
- if (!existsSync16(path13)) {
5935
+ if (!existsSync17(path13)) {
5716
5936
  return {};
5717
5937
  }
5718
5938
  try {
@@ -5733,7 +5953,7 @@ function readRegistry(path13) {
5733
5953
  return {};
5734
5954
  }
5735
5955
  function writeRegistry(path13, registry) {
5736
- mkdirSync8(dirname5(path13), { recursive: true });
5956
+ mkdirSync8(dirname6(path13), { recursive: true });
5737
5957
  writeFileSync13(path13, `${JSON.stringify(registry, null, 2)}
5738
5958
  `, "utf8");
5739
5959
  }
@@ -6184,15 +6404,15 @@ async function ensureMessageHasReply(cfg, sessionId, messageId, fallback) {
6184
6404
  }
6185
6405
 
6186
6406
  // src/commands/connect/cli-version-sync.ts
6187
- import { existsSync as existsSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "fs";
6188
- import { join as join16 } from "path";
6407
+ import { existsSync as existsSync18, readFileSync as readFileSync15, writeFileSync as writeFileSync14 } from "fs";
6408
+ import { join as join17 } from "path";
6189
6409
  var CLI_VERSION_FILE = ".cli-version.json";
6190
6410
  function manifestPath(apmDir) {
6191
- return join16(apmDir, CLI_VERSION_FILE);
6411
+ return join17(apmDir, CLI_VERSION_FILE);
6192
6412
  }
6193
6413
  function loadManifest4(apmDir) {
6194
6414
  const path13 = toFsPath(manifestPath(apmDir));
6195
- if (!existsSync17(path13)) {
6415
+ if (!existsSync18(path13)) {
6196
6416
  return null;
6197
6417
  }
6198
6418
  try {
@@ -6260,23 +6480,53 @@ function markPullDone(sessionId, workdir) {
6260
6480
 
6261
6481
  // src/commands/connect/run-slot-pool.ts
6262
6482
  var DEFAULT_MAX_CONCURRENT = 5;
6263
- function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT) {
6483
+ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {}) {
6484
+ const label = options.label ?? "task";
6485
+ const isDeployPool = label === "deploy";
6264
6486
  let active = 0;
6265
6487
  const waiters = [];
6266
- const acquire = () => {
6488
+ const logDeploy = (message) => {
6489
+ if (isDeployPool) {
6490
+ console.error(`[apm] deploy \u4E32\u884C\u9650\u6D41\uFF1A${message}`);
6491
+ }
6492
+ };
6493
+ const acquire = (meta) => {
6267
6494
  if (active < maxConcurrent) {
6268
6495
  active += 1;
6496
+ if (isDeployPool) {
6497
+ logDeploy(
6498
+ `\u5F00\u59CB\u6267\u884C${meta ? `\uFF08${meta}\uFF09` : ""}\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`
6499
+ );
6500
+ }
6269
6501
  return Promise.resolve();
6270
6502
  }
6503
+ const queueIndex = waiters.length + 1;
6504
+ if (isDeployPool) {
6505
+ logDeploy(
6506
+ `\u5E76\u53D1\u5DF2\u6EE1\uFF08${maxConcurrent}/${maxConcurrent}\uFF09\uFF0C${meta ? `${meta} ` : ""}\u8FDB\u5165\u6392\u961F\uFF0C\u524D\u65B9 ${queueIndex} \u4E2A`
6507
+ );
6508
+ }
6509
+ const queuedAt = Date.now();
6271
6510
  return new Promise((resolve5) => {
6272
6511
  waiters.push(() => {
6273
6512
  active += 1;
6513
+ const waitedMs = Date.now() - queuedAt;
6514
+ if (isDeployPool) {
6515
+ logDeploy(
6516
+ `\u6392\u961F\u7ED3\u675F\uFF0C\u5F00\u59CB\u6267\u884C${meta ? `\uFF08${meta}\uFF09` : ""}\uFF0C\u7B49\u5F85 ${Math.ceil(
6517
+ waitedMs / 1e3
6518
+ )}s\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`
6519
+ );
6520
+ }
6274
6521
  resolve5();
6275
6522
  });
6276
6523
  });
6277
6524
  };
6278
6525
  const release = () => {
6279
6526
  active = Math.max(0, active - 1);
6527
+ if (isDeployPool) {
6528
+ logDeploy(`\u6267\u884C\u69FD\u91CA\u653E\uFF0C\u5F53\u524D\u5360\u7528 ${active}/${maxConcurrent}`);
6529
+ }
6280
6530
  const next = waiters.shift();
6281
6531
  if (next) {
6282
6532
  next();
@@ -6473,6 +6723,7 @@ function attachWsHandlers(ws, ctx, onOpen) {
6473
6723
  clientMachineId,
6474
6724
  shutdownAbort,
6475
6725
  runSlots,
6726
+ deployRunSlots,
6476
6727
  activeTasks,
6477
6728
  activeRuns,
6478
6729
  pendingCancels,
@@ -6511,12 +6762,13 @@ function attachWsHandlers(ws, ctx, onOpen) {
6511
6762
  shutdownAbort.signal,
6512
6763
  perDeployController.signal
6513
6764
  ]);
6765
+ const deploySlotMeta = `deploymentRunId=${msg2.deploymentRunId} env=${msg2.environment} workdir=${msg2.workdir}`;
6514
6766
  const task2 = (async () => {
6515
- await runSlots.acquire();
6767
+ await deployRunSlots.acquire(deploySlotMeta);
6516
6768
  try {
6517
6769
  await handleInboundDeploy(cfg, msg2, signal2);
6518
6770
  } finally {
6519
- runSlots.release();
6771
+ deployRunSlots.release();
6520
6772
  }
6521
6773
  })();
6522
6774
  activeTasks.add(task2);
@@ -6674,6 +6926,7 @@ async function runConnect(options) {
6674
6926
  const lifecycleAbort = new AbortController();
6675
6927
  const shutdownAbort = new AbortController();
6676
6928
  const runSlots = createRunSlotPool();
6929
+ const deployRunSlots = createRunSlotPool(1, { label: "deploy" });
6677
6930
  const activeTasks = /* @__PURE__ */ new Set();
6678
6931
  const activeRuns = /* @__PURE__ */ new Map();
6679
6932
  const pendingCancels = /* @__PURE__ */ new Set();
@@ -6683,6 +6936,7 @@ async function runConnect(options) {
6683
6936
  clientMachineId,
6684
6937
  shutdownAbort,
6685
6938
  runSlots,
6939
+ deployRunSlots,
6686
6940
  activeTasks,
6687
6941
  activeRuns,
6688
6942
  pendingCancels,
@@ -6921,7 +7175,7 @@ async function runDeployWithBackendTracking(options) {
6921
7175
  const run = await api.cli.createTaskDeployment({
6922
7176
  sessionId: options.sessionId,
6923
7177
  environment,
6924
- workdirPath: options.cwd ?? process.cwd()
7178
+ workdirPath: options.cwd
6925
7179
  });
6926
7180
  deploymentRunId = run.id;
6927
7181
  console.log(
@@ -6957,7 +7211,11 @@ async function runDeployWithBackendTracking(options) {
6957
7211
  originalError.apply(console, args);
6958
7212
  };
6959
7213
  try {
6960
- const output = await executeDeploy({ ...options, captureOutput: true });
7214
+ const output = await executeDeploy({
7215
+ ...options,
7216
+ captureOutput: true,
7217
+ archiveDeployArtifact: true
7218
+ });
6961
7219
  if (output.trim()) {
6962
7220
  appendLog(output);
6963
7221
  }
@@ -7000,8 +7258,8 @@ async function runDeployWithBackendTracking(options) {
7000
7258
  // src/commands/deploy/deploy.ts
7001
7259
  function registerDeployMainCommand(program) {
7002
7260
  program.command("deploy").description(
7003
- "\u7EDF\u4E00\u90E8\u7F72\uFF08\u6267\u884C\u524D\u81EA\u52A8\u540C\u6B65\u90E8\u7F72\u914D\u7F6E\u5E76\u5408\u5E76\u57FA\u7EBF\u5206\u652F\uFF09\uFF1A\u533B\u52A1\u5B58\u91CF\u81EA\u52A8\u8BC6\u522B\u524D\u540E\u7AEF\uFF1B\u5176\u4ED6\u9879\u76EE\u6309 deploy.<\u73AF\u5883> \u6267\u884C shell \u547D\u4EE4"
7004
- ).argument("<env>", "\u90E8\u7F72\u73AF\u5883\u540D\uFF08\u5982 test\u3001online\uFF09").option(
7261
+ "\u533B\u52A1\u90E8\u7F72\uFF1AVue build + SFTP / Java Maven + SSH\uFF08\u9700 apm.config.json wisdomDeploy\uFF09"
7262
+ ).argument("<env>", "\u90E8\u7F72\u73AF\u5883\u540D\uFF08\u5982 test\u3001online\uFF1BVue \u5BF9\u5E94 build:<env>\uFF09").option(
7005
7263
  "--config <path>",
7006
7264
  "apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
7007
7265
  ).option(
@@ -7009,7 +7267,7 @@ function registerDeployMainCommand(program) {
7009
7267
  "\u6C9F\u901A\u7FA4 ID\uFF1B\u4F20\u5165\u65F6\u5728\u5E73\u53F0\u521B\u5EFA\u90E8\u7F72\u8BB0\u5F55\u5E76\u540C\u6B65\u65E5\u5FD7"
7010
7268
  ).option(
7011
7269
  "--pack-only",
7012
- "\u4EC5\u6784\u5EFA/\u6253\u5305\u5E76\u4E0A\u4F20 MinIO \u5F52\u6863\uFF0C\u4E0D\u4E0A\u4F20\u8FDC\u7A0B\u670D\u52A1\u5668\uFF08\u524D\u7AEF build:<env>\uFF0C\u540E\u7AEF Maven \u6784\u5EFA\uFF09"
7270
+ "\u4EC5\u6784\u5EFA/\u6253\u5305\uFF0C\u4E0D\u4E0A\u4F20\u8FDC\u7A0B SFTP/SSH\uFF1B\u53EF\u5F52\u6863\u5E73\u53F0\u90E8\u7F72\u4EA7\u7269"
7013
7271
  ).action(
7014
7272
  async (env, opts) => {
7015
7273
  const cwd = process.cwd();
@@ -7022,11 +7280,18 @@ function registerDeployMainCommand(program) {
7022
7280
  cwd,
7023
7281
  configPath: opts.config,
7024
7282
  sessionId,
7025
- packOnly
7283
+ packOnly,
7284
+ deployTrigger: "session"
7026
7285
  });
7027
7286
  return;
7028
7287
  }
7029
- await executeDeploy({ env, cwd, configPath: opts.config, packOnly });
7288
+ await executeDeploy({
7289
+ env,
7290
+ cwd,
7291
+ configPath: opts.config,
7292
+ packOnly,
7293
+ deployTrigger: "cli"
7294
+ });
7030
7295
  } catch (error) {
7031
7296
  if (error instanceof DeployExecutionError) {
7032
7297
  printDeployExecutionError(error);
@@ -7048,7 +7313,7 @@ import path9 from "node:path";
7048
7313
  import Docker from "dockerode";
7049
7314
 
7050
7315
  // src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
7051
- import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
7316
+ import { existsSync as existsSync19, readFileSync as readFileSync16 } from "node:fs";
7052
7317
  import path6 from "node:path";
7053
7318
  function asOptionalTlsBuffer(value) {
7054
7319
  if (typeof value !== "string") {
@@ -7060,7 +7325,7 @@ function asOptionalTlsBuffer(value) {
7060
7325
  if (normalized === "") {
7061
7326
  return void 0;
7062
7327
  }
7063
- if (existsSync18(normalized)) {
7328
+ if (existsSync19(normalized)) {
7064
7329
  return readFileSync16(normalized);
7065
7330
  }
7066
7331
  const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
@@ -7271,7 +7536,7 @@ var DockerodeClient = class {
7271
7536
  var createDockerodeClient = (config) => new DockerodeClient(config);
7272
7537
 
7273
7538
  // src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
7274
- import { existsSync as existsSync19, readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
7539
+ import { existsSync as existsSync20, readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
7275
7540
  import path7 from "node:path";
7276
7541
  function stripSurroundingQuotes(value) {
7277
7542
  const t = value.trim();
@@ -7288,7 +7553,7 @@ function loadEnvFromFile(envFilePath) {
7288
7553
  return {};
7289
7554
  }
7290
7555
  const targetPath = path7.resolve(envFilePath);
7291
- if (!existsSync19(targetPath) || !statSync8(targetPath).isFile()) {
7556
+ if (!existsSync20(targetPath) || !statSync8(targetPath).isFile()) {
7292
7557
  return {};
7293
7558
  }
7294
7559
  const raw = readFileSync17(targetPath, "utf-8");
@@ -7462,12 +7727,12 @@ function dockerPushImage(params, cwd) {
7462
7727
  }
7463
7728
 
7464
7729
  // src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
7465
- import { existsSync as existsSync20 } from "node:fs";
7730
+ import { existsSync as existsSync21 } from "node:fs";
7466
7731
  import path8 from "node:path";
7467
7732
  function resolveDockerBuildPaths(cwd) {
7468
7733
  const dockerfilePath = path8.join(cwd, "Dockerfile");
7469
7734
  Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
7470
- if (!existsSync20(dockerfilePath)) {
7735
+ if (!existsSync21(dockerfilePath)) {
7471
7736
  throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
7472
7737
  }
7473
7738
  Logger.info("\u2713 Dockerfile \u5B58\u5728");