ai-project-manage-cli 6.0.82 → 6.0.83
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 +298 -114
- package/package.json +1 -1
- package/template/skills/apm-deploy/SKILL.md +5 -3
package/dist/index.js
CHANGED
|
@@ -110,8 +110,8 @@ function toFsPath(inputPath) {
|
|
|
110
110
|
}
|
|
111
111
|
return `\\\\?\\${normalized}`;
|
|
112
112
|
}
|
|
113
|
-
function normalizeWorkdirPath(
|
|
114
|
-
let normalized =
|
|
113
|
+
function normalizeWorkdirPath(path13) {
|
|
114
|
+
let normalized = path13.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
|
|
330
|
-
if (!existsSync(toFsPath(
|
|
331
|
-
throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${
|
|
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}`);
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
334
|
const leakedRules = join2(workdir, "rules");
|
|
@@ -473,6 +473,10 @@ var requestConfig = {
|
|
|
473
473
|
method: "DELETE",
|
|
474
474
|
path: "/cli/repository-project-documents"
|
|
475
475
|
}),
|
|
476
|
+
createTaskDeployment: defineEndpoint({
|
|
477
|
+
method: "POST",
|
|
478
|
+
path: "/cli/task-deployments"
|
|
479
|
+
}),
|
|
476
480
|
updateTaskDeploymentStatus: defineEndpoint({
|
|
477
481
|
method: "PUT",
|
|
478
482
|
path: "/cli/task-deployments/status"
|
|
@@ -606,14 +610,14 @@ function projectDocumentLocalPath(apmRoot, documentPath) {
|
|
|
606
610
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
607
611
|
return join4(projectDocumentsDir(apmRoot), ...normalized.split("/"));
|
|
608
612
|
}
|
|
609
|
-
function normalizeLocalDocumentPath(
|
|
610
|
-
const trimmed =
|
|
613
|
+
function normalizeLocalDocumentPath(path13) {
|
|
614
|
+
const trimmed = path13.trim().replace(/\\/g, "/");
|
|
611
615
|
if (!trimmed || trimmed.startsWith("/") || /^[a-zA-Z]:/.test(trimmed)) {
|
|
612
|
-
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${
|
|
616
|
+
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path13}`);
|
|
613
617
|
}
|
|
614
618
|
const segments = trimmed.split("/").filter(Boolean);
|
|
615
619
|
if (segments.some((segment) => segment === ".." || segment === ".")) {
|
|
616
|
-
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${
|
|
620
|
+
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path13}`);
|
|
617
621
|
}
|
|
618
622
|
return segments.join("/");
|
|
619
623
|
}
|
|
@@ -664,15 +668,15 @@ function diffManifestPaths(remote, local) {
|
|
|
664
668
|
(local?.documents ?? []).map((doc) => [doc.path, doc.contentHash])
|
|
665
669
|
);
|
|
666
670
|
const download = [];
|
|
667
|
-
for (const [
|
|
668
|
-
if (localMap.get(
|
|
669
|
-
download.push(
|
|
671
|
+
for (const [path13, hash] of remoteMap) {
|
|
672
|
+
if (localMap.get(path13) !== hash) {
|
|
673
|
+
download.push(path13);
|
|
670
674
|
}
|
|
671
675
|
}
|
|
672
676
|
const deleteLocal = [];
|
|
673
|
-
for (const
|
|
674
|
-
if (!remoteMap.has(
|
|
675
|
-
deleteLocal.push(
|
|
677
|
+
for (const path13 of localMap.keys()) {
|
|
678
|
+
if (!remoteMap.has(path13)) {
|
|
679
|
+
deleteLocal.push(path13);
|
|
676
680
|
}
|
|
677
681
|
}
|
|
678
682
|
return { download, deleteLocal };
|
|
@@ -732,8 +736,8 @@ ${diagnostic ?? ""}`
|
|
|
732
736
|
}
|
|
733
737
|
}
|
|
734
738
|
let deleted = 0;
|
|
735
|
-
for (const
|
|
736
|
-
const absPath = toFsPath(projectDocumentLocalPath(targetApmDir,
|
|
739
|
+
for (const path13 of deleteLocal) {
|
|
740
|
+
const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path13));
|
|
737
741
|
if (existsSync2(absPath)) {
|
|
738
742
|
rmSync(absPath, { force: true });
|
|
739
743
|
deleted += 1;
|
|
@@ -778,21 +782,21 @@ async function syncRepositoryProjectDocumentsPush(cfg, workdirPath, apmRoot) {
|
|
|
778
782
|
])
|
|
779
783
|
);
|
|
780
784
|
let synced = 0;
|
|
781
|
-
for (const
|
|
782
|
-
const absPath = toFsPath(projectDocumentLocalPath(targetApmDir,
|
|
785
|
+
for (const path13 of localPaths) {
|
|
786
|
+
const absPath = toFsPath(projectDocumentLocalPath(targetApmDir, path13));
|
|
783
787
|
const content = readFileSync3(absPath, "utf8");
|
|
784
788
|
const contentHash = hashLocalFileContent(content);
|
|
785
|
-
if (remoteHashByPath.get(
|
|
789
|
+
if (remoteHashByPath.get(path13) === contentHash) {
|
|
786
790
|
continue;
|
|
787
791
|
}
|
|
788
792
|
await api.cli.upsertRepositoryProjectDocument({
|
|
789
793
|
repositoryId,
|
|
790
|
-
path:
|
|
794
|
+
path: path13,
|
|
791
795
|
content,
|
|
792
|
-
description: remoteDescriptionByPath.get(
|
|
796
|
+
description: remoteDescriptionByPath.get(path13) ?? void 0
|
|
793
797
|
});
|
|
794
798
|
synced += 1;
|
|
795
|
-
console.log(`[apm] \u5DF2\u540C\u6B65\u4ED3\u5E93\u9879\u76EE\u6587\u6863: ${
|
|
799
|
+
console.log(`[apm] \u5DF2\u540C\u6B65\u4ED3\u5E93\u9879\u76EE\u6587\u6863: ${path13}`);
|
|
796
800
|
}
|
|
797
801
|
if (synced === 0) {
|
|
798
802
|
console.log("[apm] \u4ED3\u5E93\u9879\u76EE\u6587\u6863\u65E0\u53D8\u5316\uFF0C\u8DF3\u8FC7\u63A8\u9001");
|
|
@@ -1415,13 +1419,13 @@ async function downloadAttachment(cfg, attachmentId) {
|
|
|
1415
1419
|
return Buffer.from(await res.arrayBuffer());
|
|
1416
1420
|
}
|
|
1417
1421
|
function loadManifest(dir) {
|
|
1418
|
-
const
|
|
1419
|
-
if (!existsSync4(
|
|
1422
|
+
const path13 = join6(dir, MANIFEST_FILE2);
|
|
1423
|
+
if (!existsSync4(path13)) {
|
|
1420
1424
|
return { version: 1, attachments: {} };
|
|
1421
1425
|
}
|
|
1422
1426
|
try {
|
|
1423
1427
|
const parsed = JSON.parse(
|
|
1424
|
-
readFileSync5(
|
|
1428
|
+
readFileSync5(path13, "utf8")
|
|
1425
1429
|
);
|
|
1426
1430
|
if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
|
|
1427
1431
|
return parsed;
|
|
@@ -1502,8 +1506,8 @@ function sanitizeSkillDirName(name) {
|
|
|
1502
1506
|
function listBaseSkillDirNames() {
|
|
1503
1507
|
if (!existsSync5(BASE_SKILLS_TEMPLATE_DIR)) return [];
|
|
1504
1508
|
return readdirSync3(BASE_SKILLS_TEMPLATE_DIR).filter((name) => {
|
|
1505
|
-
const
|
|
1506
|
-
return statSync2(
|
|
1509
|
+
const path13 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
|
|
1510
|
+
return statSync2(path13).isDirectory();
|
|
1507
1511
|
});
|
|
1508
1512
|
}
|
|
1509
1513
|
function syncAgentsGuide(apmDir) {
|
|
@@ -1515,8 +1519,8 @@ function syncAgentsGuide(apmDir) {
|
|
|
1515
1519
|
function listBaseRuleFileNames() {
|
|
1516
1520
|
if (!existsSync5(BASE_RULES_TEMPLATE_DIR)) return [];
|
|
1517
1521
|
return readdirSync3(BASE_RULES_TEMPLATE_DIR).filter((name) => {
|
|
1518
|
-
const
|
|
1519
|
-
return statSync2(
|
|
1522
|
+
const path13 = join7(BASE_RULES_TEMPLATE_DIR, name);
|
|
1523
|
+
return statSync2(path13).isFile();
|
|
1520
1524
|
});
|
|
1521
1525
|
}
|
|
1522
1526
|
function syncBaseRules(rulesDir) {
|
|
@@ -1579,13 +1583,13 @@ function ruleLocalFileName(ruleName) {
|
|
|
1579
1583
|
return `${sanitized}.md`;
|
|
1580
1584
|
}
|
|
1581
1585
|
function loadManifest2(rulesDir) {
|
|
1582
|
-
const
|
|
1583
|
-
if (!existsSync6(toFsPath(
|
|
1586
|
+
const path13 = join8(rulesDir, MANIFEST_FILE3);
|
|
1587
|
+
if (!existsSync6(toFsPath(path13))) {
|
|
1584
1588
|
return { version: 1, rules: {} };
|
|
1585
1589
|
}
|
|
1586
1590
|
try {
|
|
1587
1591
|
const parsed = JSON.parse(
|
|
1588
|
-
readFileSync6(toFsPath(
|
|
1592
|
+
readFileSync6(toFsPath(path13), "utf8")
|
|
1589
1593
|
);
|
|
1590
1594
|
if (parsed?.version === 1 && parsed.rules && typeof parsed.rules === "object") {
|
|
1591
1595
|
return parsed;
|
|
@@ -2684,12 +2688,12 @@ import { dirname as dirname4, resolve as resolve3 } from "node:path";
|
|
|
2684
2688
|
function registryPath(workdir, sessionId) {
|
|
2685
2689
|
return resolve3(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
|
|
2686
2690
|
}
|
|
2687
|
-
function readRegistry(
|
|
2688
|
-
if (!existsSync11(
|
|
2691
|
+
function readRegistry(path13) {
|
|
2692
|
+
if (!existsSync11(path13)) {
|
|
2689
2693
|
return {};
|
|
2690
2694
|
}
|
|
2691
2695
|
try {
|
|
2692
|
-
const parsed = JSON.parse(readFileSync9(
|
|
2696
|
+
const parsed = JSON.parse(readFileSync9(path13, "utf8"));
|
|
2693
2697
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2694
2698
|
const result = {};
|
|
2695
2699
|
for (const [key, value] of Object.entries(
|
|
@@ -2705,9 +2709,9 @@ function readRegistry(path12) {
|
|
|
2705
2709
|
}
|
|
2706
2710
|
return {};
|
|
2707
2711
|
}
|
|
2708
|
-
function writeRegistry(
|
|
2709
|
-
mkdirSync5(dirname4(
|
|
2710
|
-
writeFileSync10(
|
|
2712
|
+
function writeRegistry(path13, registry) {
|
|
2713
|
+
mkdirSync5(dirname4(path13), { recursive: true });
|
|
2714
|
+
writeFileSync10(path13, `${JSON.stringify(registry, null, 2)}
|
|
2711
2715
|
`, "utf8");
|
|
2712
2716
|
}
|
|
2713
2717
|
function loadSessionAgentId(workdir, sessionId, user) {
|
|
@@ -2715,19 +2719,19 @@ function loadSessionAgentId(workdir, sessionId, user) {
|
|
|
2715
2719
|
return registry[user];
|
|
2716
2720
|
}
|
|
2717
2721
|
function saveSessionAgentId(workdir, sessionId, user, agentId) {
|
|
2718
|
-
const
|
|
2719
|
-
const registry = readRegistry(
|
|
2722
|
+
const path13 = registryPath(workdir, sessionId);
|
|
2723
|
+
const registry = readRegistry(path13);
|
|
2720
2724
|
registry[user] = agentId;
|
|
2721
|
-
writeRegistry(
|
|
2725
|
+
writeRegistry(path13, registry);
|
|
2722
2726
|
}
|
|
2723
2727
|
function clearSessionAgentId(workdir, sessionId, user) {
|
|
2724
|
-
const
|
|
2725
|
-
const registry = readRegistry(
|
|
2728
|
+
const path13 = registryPath(workdir, sessionId);
|
|
2729
|
+
const registry = readRegistry(path13);
|
|
2726
2730
|
if (!(user in registry)) {
|
|
2727
2731
|
return;
|
|
2728
2732
|
}
|
|
2729
2733
|
delete registry[user];
|
|
2730
|
-
writeRegistry(
|
|
2734
|
+
writeRegistry(path13, registry);
|
|
2731
2735
|
}
|
|
2732
2736
|
|
|
2733
2737
|
// src/commands/connect/cursor-message-log.ts
|
|
@@ -3164,13 +3168,13 @@ function manifestPath(apmDir) {
|
|
|
3164
3168
|
return join13(apmDir, CLI_VERSION_FILE);
|
|
3165
3169
|
}
|
|
3166
3170
|
function loadManifest3(apmDir) {
|
|
3167
|
-
const
|
|
3168
|
-
if (!existsSync12(
|
|
3171
|
+
const path13 = toFsPath(manifestPath(apmDir));
|
|
3172
|
+
if (!existsSync12(path13)) {
|
|
3169
3173
|
return null;
|
|
3170
3174
|
}
|
|
3171
3175
|
try {
|
|
3172
3176
|
const parsed = JSON.parse(
|
|
3173
|
-
readFileSync10(
|
|
3177
|
+
readFileSync10(path13, "utf8")
|
|
3174
3178
|
);
|
|
3175
3179
|
if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
|
|
3176
3180
|
return parsed;
|
|
@@ -3959,8 +3963,9 @@ async function runCreatePr(options) {
|
|
|
3959
3963
|
console.log(`[apm] PR \u5DF2\u5C31\u7EEA #${pr.number} (${pr.state}): ${pr.url}`);
|
|
3960
3964
|
}
|
|
3961
3965
|
|
|
3962
|
-
// src/commands/deploy/deploy.ts
|
|
3966
|
+
// src/commands/deploy/deploy-execute.ts
|
|
3963
3967
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
3968
|
+
import path4 from "node:path";
|
|
3964
3969
|
|
|
3965
3970
|
// src/commands/deploy/internal/apm-config.ts
|
|
3966
3971
|
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "node:fs";
|
|
@@ -4152,9 +4157,9 @@ function readMavenLocalRepoFromEnv(env = process.env) {
|
|
|
4152
4157
|
}
|
|
4153
4158
|
const mavenOpts = readEnvVar(env, "MAVEN_OPTS")?.trim();
|
|
4154
4159
|
if (mavenOpts) {
|
|
4155
|
-
const
|
|
4156
|
-
if (
|
|
4157
|
-
return { path:
|
|
4160
|
+
const path13 = readMavenLocalRepoFromMavenOpts(mavenOpts, env);
|
|
4161
|
+
if (path13) {
|
|
4162
|
+
return { path: path13, key: "MAVEN_OPTS" };
|
|
4158
4163
|
}
|
|
4159
4164
|
}
|
|
4160
4165
|
return null;
|
|
@@ -4287,19 +4292,18 @@ function formatWisdomFrontendDeployNotConfiguredLines(env, packageJsonPath) {
|
|
|
4287
4292
|
"[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"
|
|
4288
4293
|
];
|
|
4289
4294
|
}
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
console.error(line);
|
|
4295
|
+
|
|
4296
|
+
// src/commands/deploy/deploy-errors.ts
|
|
4297
|
+
var DeployExecutionError = class extends Error {
|
|
4298
|
+
exitCode;
|
|
4299
|
+
output;
|
|
4300
|
+
constructor(message, exitCode, output = "") {
|
|
4301
|
+
super(message);
|
|
4302
|
+
this.name = "DeployExecutionError";
|
|
4303
|
+
this.exitCode = exitCode;
|
|
4304
|
+
this.output = output;
|
|
4301
4305
|
}
|
|
4302
|
-
}
|
|
4306
|
+
};
|
|
4303
4307
|
|
|
4304
4308
|
// src/commands/deploy/internal/wisdom-auto-deploy.ts
|
|
4305
4309
|
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
|
|
@@ -5105,19 +5109,33 @@ function resolveFrontendDeployCommand(env, cwd) {
|
|
|
5105
5109
|
}
|
|
5106
5110
|
return null;
|
|
5107
5111
|
}
|
|
5108
|
-
function runShellCommand2(command, cwd) {
|
|
5112
|
+
function runShellCommand2(command, cwd, captureOutput) {
|
|
5109
5113
|
const result = spawnSync4(command, {
|
|
5110
5114
|
cwd,
|
|
5111
|
-
stdio: "inherit",
|
|
5112
5115
|
shell: true,
|
|
5113
|
-
env: process.env
|
|
5116
|
+
env: process.env,
|
|
5117
|
+
encoding: "utf8",
|
|
5118
|
+
stdio: captureOutput ? ["inherit", "pipe", "pipe"] : "inherit"
|
|
5114
5119
|
});
|
|
5120
|
+
const stdout = captureOutput ? String(result.stdout ?? "") : "";
|
|
5121
|
+
const stderr = captureOutput ? String(result.stderr ?? "") : "";
|
|
5122
|
+
const output = [stdout, stderr].filter(Boolean).join("\n");
|
|
5123
|
+
if (captureOutput) {
|
|
5124
|
+
if (stdout) process.stdout.write(stdout);
|
|
5125
|
+
if (stderr) process.stderr.write(stderr);
|
|
5126
|
+
}
|
|
5115
5127
|
if (result.status !== 0) {
|
|
5116
|
-
|
|
5128
|
+
throw new DeployExecutionError(
|
|
5129
|
+
`\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${result.status ?? "unknown"}: ${command}`,
|
|
5130
|
+
result.status ?? 1,
|
|
5131
|
+
output
|
|
5132
|
+
);
|
|
5117
5133
|
}
|
|
5134
|
+
return output;
|
|
5118
5135
|
}
|
|
5119
5136
|
async function runWisdomAutoDeploy(options) {
|
|
5120
5137
|
const cwd = path3.resolve(options.cwd ?? process.cwd());
|
|
5138
|
+
const captureOutput = options.captureOutput ?? false;
|
|
5121
5139
|
const projectType = detectWisdomProjectType(cwd);
|
|
5122
5140
|
console.error(
|
|
5123
5141
|
`[apm] \u533B\u52A1\u5B58\u91CF\u9879\u76EE\u81EA\u52A8\u8BC6\u522B: ${projectType === "frontend" ? "\u524D\u7AEF Vue" : "\u540E\u7AEF Java"}`
|
|
@@ -5125,13 +5143,13 @@ async function runWisdomAutoDeploy(options) {
|
|
|
5125
5143
|
if (projectType === "frontend") {
|
|
5126
5144
|
const deployCmd = resolveFrontendDeployCommand(options.env, cwd);
|
|
5127
5145
|
if (!deployCmd) {
|
|
5128
|
-
|
|
5146
|
+
const lines = formatWisdomFrontendDeployNotConfiguredLines(
|
|
5129
5147
|
options.env,
|
|
5130
5148
|
path3.join(cwd, "package.json")
|
|
5131
5149
|
);
|
|
5132
|
-
|
|
5150
|
+
throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
|
|
5133
5151
|
}
|
|
5134
|
-
runShellCommand2(deployCmd, cwd);
|
|
5152
|
+
runShellCommand2(deployCmd, cwd, captureOutput);
|
|
5135
5153
|
return { projectType };
|
|
5136
5154
|
}
|
|
5137
5155
|
const configPath = options.configPath ?? path3.join(workspaceApmDir(cwd), "apm.config.json");
|
|
@@ -5147,63 +5165,229 @@ async function runWisdomAutoDeploy(options) {
|
|
|
5147
5165
|
return { projectType };
|
|
5148
5166
|
}
|
|
5149
5167
|
|
|
5150
|
-
// src/commands/deploy/deploy.ts
|
|
5151
|
-
function runShellCommand3(command, cwd) {
|
|
5168
|
+
// src/commands/deploy/deploy-execute.ts
|
|
5169
|
+
function runShellCommand3(command, cwd, captureOutput) {
|
|
5152
5170
|
const result = spawnSync5(command, {
|
|
5153
5171
|
cwd,
|
|
5154
|
-
stdio: "inherit",
|
|
5155
5172
|
shell: true,
|
|
5156
|
-
env: process.env
|
|
5173
|
+
env: process.env,
|
|
5174
|
+
encoding: "utf8",
|
|
5175
|
+
stdio: captureOutput ? ["inherit", "pipe", "pipe"] : "inherit"
|
|
5157
5176
|
});
|
|
5177
|
+
const stdout = captureOutput ? String(result.stdout ?? "") : "";
|
|
5178
|
+
const stderr = captureOutput ? String(result.stderr ?? "") : "";
|
|
5179
|
+
const output = [stdout, stderr].filter(Boolean).join("\n");
|
|
5180
|
+
if (captureOutput) {
|
|
5181
|
+
if (stdout) process.stdout.write(stdout);
|
|
5182
|
+
if (stderr) process.stderr.write(stderr);
|
|
5183
|
+
}
|
|
5158
5184
|
if (result.status !== 0) {
|
|
5159
|
-
|
|
5185
|
+
throw new DeployExecutionError(
|
|
5186
|
+
`\u90E8\u7F72\u547D\u4EE4\u9000\u51FA\u7801 ${result.status ?? "unknown"}: ${command}`,
|
|
5187
|
+
result.status ?? 1,
|
|
5188
|
+
output
|
|
5189
|
+
);
|
|
5190
|
+
}
|
|
5191
|
+
return output;
|
|
5192
|
+
}
|
|
5193
|
+
async function executeDeploy(options) {
|
|
5194
|
+
const cwd = path4.resolve(options.cwd ?? process.cwd());
|
|
5195
|
+
const captureOutput = options.captureOutput ?? false;
|
|
5196
|
+
const cfg = loadApmConfig({ configPath: options.configPath });
|
|
5197
|
+
if (isWisdomLegacyDeploy(cfg)) {
|
|
5198
|
+
try {
|
|
5199
|
+
await runWisdomAutoDeploy({
|
|
5200
|
+
env: options.env,
|
|
5201
|
+
cwd,
|
|
5202
|
+
configPath: options.configPath,
|
|
5203
|
+
captureOutput
|
|
5204
|
+
});
|
|
5205
|
+
return "";
|
|
5206
|
+
} catch (error) {
|
|
5207
|
+
if (error instanceof DeployExecutionError) {
|
|
5208
|
+
throw error;
|
|
5209
|
+
}
|
|
5210
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
5211
|
+
throw new DeployExecutionError(detail, 1);
|
|
5212
|
+
}
|
|
5213
|
+
}
|
|
5214
|
+
const deployCommands = cfg.deploy ?? {};
|
|
5215
|
+
const command = deployCommands[options.env]?.trim();
|
|
5216
|
+
if (!command) {
|
|
5217
|
+
const lines = formatDeployNotConfiguredLines(options.env, deployCommands);
|
|
5218
|
+
throw new DeployExecutionError(lines.join("\n"), 1, lines.join("\n"));
|
|
5219
|
+
}
|
|
5220
|
+
return runShellCommand3(command, cwd, captureOutput);
|
|
5221
|
+
}
|
|
5222
|
+
function printDeployExecutionError(error) {
|
|
5223
|
+
if (error.output.trim()) {
|
|
5224
|
+
console.error(error.output);
|
|
5225
|
+
return;
|
|
5160
5226
|
}
|
|
5227
|
+
console.error(error.message);
|
|
5161
5228
|
}
|
|
5229
|
+
|
|
5230
|
+
// src/commands/deploy/deploy-tracking.ts
|
|
5231
|
+
function normalizeDeployEnvironment(env) {
|
|
5232
|
+
const normalized = env.trim().toLowerCase();
|
|
5233
|
+
if (normalized === "test") return "TEST";
|
|
5234
|
+
if (normalized === "online") return "ONLINE";
|
|
5235
|
+
return null;
|
|
5236
|
+
}
|
|
5237
|
+
async function completeTrackedDeploy(api, deploymentRunId, logSyncer, input) {
|
|
5238
|
+
logSyncer.updateLog(input.log);
|
|
5239
|
+
await logSyncer.flush();
|
|
5240
|
+
await api.cli.completeTaskDeployment({
|
|
5241
|
+
id: deploymentRunId,
|
|
5242
|
+
status: input.status,
|
|
5243
|
+
log: input.log,
|
|
5244
|
+
error: input.error
|
|
5245
|
+
});
|
|
5246
|
+
}
|
|
5247
|
+
async function runDeployWithBackendTracking(options) {
|
|
5248
|
+
const cfg = await tryReadApmConfig();
|
|
5249
|
+
if (!cfg || !resolveApiKey(cfg)) {
|
|
5250
|
+
console.warn("[apm] \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7\u540E\u7AEF\u90E8\u7F72\u8BB0\u5F55");
|
|
5251
|
+
await executeDeploy(options);
|
|
5252
|
+
return;
|
|
5253
|
+
}
|
|
5254
|
+
const environment = normalizeDeployEnvironment(options.env);
|
|
5255
|
+
if (!environment) {
|
|
5256
|
+
console.warn(
|
|
5257
|
+
`[apm] \u672A\u77E5\u90E8\u7F72\u73AF\u5883 ${options.env}\uFF0C\u8DF3\u8FC7\u540E\u7AEF\u90E8\u7F72\u8BB0\u5F55\uFF08\u4EC5\u652F\u6301 test/online\uFF09`
|
|
5258
|
+
);
|
|
5259
|
+
await executeDeploy(options);
|
|
5260
|
+
return;
|
|
5261
|
+
}
|
|
5262
|
+
const api = createApmApiClient(cfg);
|
|
5263
|
+
let deploymentRunId;
|
|
5264
|
+
try {
|
|
5265
|
+
const run = await api.cli.createTaskDeployment({
|
|
5266
|
+
sessionId: options.sessionId,
|
|
5267
|
+
environment,
|
|
5268
|
+
workdirPath: options.cwd ?? process.cwd()
|
|
5269
|
+
});
|
|
5270
|
+
deploymentRunId = run.id;
|
|
5271
|
+
console.log(
|
|
5272
|
+
`[apm] \u5DF2\u521B\u5EFA\u90E8\u7F72\u8BB0\u5F55 id=${deploymentRunId} env=${environment}`
|
|
5273
|
+
);
|
|
5274
|
+
} catch (error) {
|
|
5275
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
5276
|
+
console.warn(`[apm] \u521B\u5EFA\u90E8\u7F72\u8BB0\u5F55\u5931\u8D25\uFF0C\u7EE7\u7EED\u90E8\u7F72: ${detail}`);
|
|
5277
|
+
await executeDeploy(options);
|
|
5278
|
+
return;
|
|
5279
|
+
}
|
|
5280
|
+
await api.cli.updateTaskDeploymentStatus({
|
|
5281
|
+
id: deploymentRunId,
|
|
5282
|
+
status: "DEPLOYING"
|
|
5283
|
+
});
|
|
5284
|
+
const logSyncer = createDeployLogSyncer(api, deploymentRunId);
|
|
5285
|
+
const chunks = [];
|
|
5286
|
+
const appendLog = (line) => {
|
|
5287
|
+
if (!line) return;
|
|
5288
|
+
chunks.push(line);
|
|
5289
|
+
logSyncer.updateLog(chunks.join("\n"));
|
|
5290
|
+
};
|
|
5291
|
+
const originalLog = console.log;
|
|
5292
|
+
const originalError = console.error;
|
|
5293
|
+
console.log = (...args) => {
|
|
5294
|
+
appendLog(args.map(String).join(" "));
|
|
5295
|
+
originalLog.apply(console, args);
|
|
5296
|
+
};
|
|
5297
|
+
console.error = (...args) => {
|
|
5298
|
+
appendLog(args.map(String).join(" "));
|
|
5299
|
+
originalError.apply(console, args);
|
|
5300
|
+
};
|
|
5301
|
+
try {
|
|
5302
|
+
const output = await executeDeploy({ ...options, captureOutput: true });
|
|
5303
|
+
if (output.trim()) {
|
|
5304
|
+
appendLog(output);
|
|
5305
|
+
}
|
|
5306
|
+
const log2 = chunks.join("\n");
|
|
5307
|
+
await completeTrackedDeploy(api, deploymentRunId, logSyncer, {
|
|
5308
|
+
status: "SUCCESS",
|
|
5309
|
+
log: log2
|
|
5310
|
+
});
|
|
5311
|
+
console.log(`[apm] deploy success id=${deploymentRunId}`);
|
|
5312
|
+
} catch (error) {
|
|
5313
|
+
const deployError = error instanceof DeployExecutionError ? error : new DeployExecutionError(
|
|
5314
|
+
error instanceof Error ? error.message : String(error),
|
|
5315
|
+
1
|
|
5316
|
+
);
|
|
5317
|
+
if (deployError.output.trim()) {
|
|
5318
|
+
appendLog(deployError.output);
|
|
5319
|
+
} else {
|
|
5320
|
+
appendLog(deployError.message);
|
|
5321
|
+
}
|
|
5322
|
+
const log2 = chunks.join("\n");
|
|
5323
|
+
await completeTrackedDeploy(api, deploymentRunId, logSyncer, {
|
|
5324
|
+
status: "FAILED",
|
|
5325
|
+
log: log2,
|
|
5326
|
+
error: deployError.message
|
|
5327
|
+
});
|
|
5328
|
+
printDeployExecutionError(deployError);
|
|
5329
|
+
process.exit(deployError.exitCode);
|
|
5330
|
+
} finally {
|
|
5331
|
+
console.log = originalLog;
|
|
5332
|
+
console.error = originalError;
|
|
5333
|
+
logSyncer.dispose();
|
|
5334
|
+
}
|
|
5335
|
+
}
|
|
5336
|
+
|
|
5337
|
+
// src/commands/deploy/deploy.ts
|
|
5162
5338
|
function registerDeployMainCommand(program) {
|
|
5163
5339
|
program.command("deploy").description(
|
|
5164
5340
|
"\u7EDF\u4E00\u90E8\u7F72\uFF1A\u533B\u52A1\u5B58\u91CF\u81EA\u52A8\u8BC6\u522B\u524D\u540E\u7AEF\uFF08\u524D\u7AEF\u6309 deploy:<env> \u811A\u672C\uFF1B\u540E\u7AEF test/online \u540C\u4E00\u5957\uFF09\uFF1B\u5176\u4ED6\u9879\u76EE\u6309 deploy.<\u73AF\u5883> \u6267\u884C shell \u547D\u4EE4"
|
|
5165
5341
|
).argument("<env>", "\u90E8\u7F72\u73AF\u5883\u540D\uFF08\u5982 test\u3001online\uFF09").option(
|
|
5166
5342
|
"--config <path>",
|
|
5167
5343
|
"apm.config.json \u8DEF\u5F84\uFF08\u9ED8\u8BA4 .apm/apm.config.json\uFF09"
|
|
5168
|
-
).
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5344
|
+
).option(
|
|
5345
|
+
"--session <sessionId>",
|
|
5346
|
+
"\u6C9F\u901A\u7FA4 ID\uFF1B\u4F20\u5165\u65F6\u5728\u5E73\u53F0\u521B\u5EFA\u90E8\u7F72\u8BB0\u5F55\u5E76\u540C\u6B65\u65E5\u5FD7"
|
|
5347
|
+
).action(
|
|
5348
|
+
async (env, opts) => {
|
|
5349
|
+
const cwd = process.cwd();
|
|
5350
|
+
const sessionId = opts.session?.trim();
|
|
5351
|
+
try {
|
|
5352
|
+
if (sessionId) {
|
|
5353
|
+
await runDeployWithBackendTracking({
|
|
5354
|
+
env,
|
|
5355
|
+
cwd,
|
|
5356
|
+
configPath: opts.config,
|
|
5357
|
+
sessionId
|
|
5358
|
+
});
|
|
5359
|
+
return;
|
|
5360
|
+
}
|
|
5361
|
+
await executeDeploy({ env, cwd, configPath: opts.config });
|
|
5362
|
+
} catch (error) {
|
|
5363
|
+
if (error instanceof DeployExecutionError) {
|
|
5364
|
+
printDeployExecutionError(error);
|
|
5365
|
+
process.exit(error.exitCode);
|
|
5366
|
+
}
|
|
5367
|
+
throw error;
|
|
5368
|
+
}
|
|
5184
5369
|
}
|
|
5185
|
-
|
|
5186
|
-
});
|
|
5370
|
+
);
|
|
5187
5371
|
}
|
|
5188
5372
|
|
|
5189
5373
|
// src/commands/deploy/backend.ts
|
|
5190
|
-
import
|
|
5374
|
+
import path9 from "node:path";
|
|
5191
5375
|
|
|
5192
5376
|
// src/commands/deploy/internal/backend-deploy/backend-deploy-workflow.ts
|
|
5193
|
-
import
|
|
5377
|
+
import path8 from "node:path";
|
|
5194
5378
|
|
|
5195
5379
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/client.ts
|
|
5196
5380
|
import Docker from "dockerode";
|
|
5197
5381
|
|
|
5198
5382
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
|
|
5199
5383
|
import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
|
|
5200
|
-
import
|
|
5384
|
+
import path5 from "node:path";
|
|
5201
5385
|
function asOptionalTlsBuffer(value) {
|
|
5202
5386
|
if (typeof value !== "string") {
|
|
5203
5387
|
console.log("tls filepath not exist");
|
|
5204
5388
|
return void 0;
|
|
5205
5389
|
}
|
|
5206
|
-
console.log("tls filepath",
|
|
5390
|
+
console.log("tls filepath", path5.join(process.cwd(), value));
|
|
5207
5391
|
const normalized = value.trim();
|
|
5208
5392
|
if (normalized === "") {
|
|
5209
5393
|
return void 0;
|
|
@@ -5420,7 +5604,7 @@ var createDockerodeClient = (config) => new DockerodeClient(config);
|
|
|
5420
5604
|
|
|
5421
5605
|
// src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
|
|
5422
5606
|
import { existsSync as existsSync19, readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
|
|
5423
|
-
import
|
|
5607
|
+
import path6 from "node:path";
|
|
5424
5608
|
function stripSurroundingQuotes(value) {
|
|
5425
5609
|
const t = value.trim();
|
|
5426
5610
|
if (t.length >= 2) {
|
|
@@ -5435,7 +5619,7 @@ function loadEnvFromFile(envFilePath) {
|
|
|
5435
5619
|
if (!envFilePath) {
|
|
5436
5620
|
return {};
|
|
5437
5621
|
}
|
|
5438
|
-
const targetPath =
|
|
5622
|
+
const targetPath = path6.resolve(envFilePath);
|
|
5439
5623
|
if (!existsSync19(targetPath) || !statSync6(targetPath).isFile()) {
|
|
5440
5624
|
return {};
|
|
5441
5625
|
}
|
|
@@ -5611,9 +5795,9 @@ function dockerPushImage(params, cwd) {
|
|
|
5611
5795
|
|
|
5612
5796
|
// src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
|
|
5613
5797
|
import { existsSync as existsSync20 } from "node:fs";
|
|
5614
|
-
import
|
|
5798
|
+
import path7 from "node:path";
|
|
5615
5799
|
function resolveDockerBuildPaths(cwd) {
|
|
5616
|
-
const dockerfilePath =
|
|
5800
|
+
const dockerfilePath = path7.join(cwd, "Dockerfile");
|
|
5617
5801
|
Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
|
|
5618
5802
|
if (!existsSync20(dockerfilePath)) {
|
|
5619
5803
|
throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
|
|
@@ -5670,7 +5854,7 @@ var BackendDeployWorkflow = class {
|
|
|
5670
5854
|
serveraddress
|
|
5671
5855
|
});
|
|
5672
5856
|
Logger.success("\u8FDC\u7A0B\u62C9\u53D6\u955C\u50CF\u5B8C\u6210");
|
|
5673
|
-
const envFilePath =
|
|
5857
|
+
const envFilePath = path8.resolve(cwd, this.params.envFilePath || ".env");
|
|
5674
5858
|
const envObj = loadEnvFromFile(envFilePath);
|
|
5675
5859
|
if (this.params.dockerNetwork?.trim()) {
|
|
5676
5860
|
Logger.info(`\u8FDC\u7A0B\u5BB9\u5668\u5C06\u52A0\u5165 Docker \u7F51\u7EDC\uFF1A${this.params.dockerNetwork.trim()}`);
|
|
@@ -5710,7 +5894,7 @@ function registerDeployBackendCommands(program) {
|
|
|
5710
5894
|
assertDeployImageTag(tag);
|
|
5711
5895
|
const cfg = loadApmConfig({ configPath: opts.config });
|
|
5712
5896
|
const fromApm = resolveBackendDeployFromApmConfig(cfg);
|
|
5713
|
-
const dirAbs =
|
|
5897
|
+
const dirAbs = path9.resolve(process.cwd(), opts.dir || "servers/api");
|
|
5714
5898
|
const params = {
|
|
5715
5899
|
image: fromApm.name,
|
|
5716
5900
|
tag,
|
|
@@ -5741,12 +5925,12 @@ function registerDeployBackendCommands(program) {
|
|
|
5741
5925
|
|
|
5742
5926
|
// src/commands/deploy/frontend.ts
|
|
5743
5927
|
import { copyFile, readdir as readdir3, stat } from "node:fs/promises";
|
|
5744
|
-
import
|
|
5928
|
+
import path11 from "node:path";
|
|
5745
5929
|
|
|
5746
5930
|
// src/commands/deploy/internal/minio.ts
|
|
5747
5931
|
import { statSync as statSync7 } from "node:fs";
|
|
5748
5932
|
import { readdir as readdir2, readFile as readFile2 } from "node:fs/promises";
|
|
5749
|
-
import
|
|
5933
|
+
import path10 from "node:path";
|
|
5750
5934
|
import * as Minio from "minio";
|
|
5751
5935
|
var DEFAULT_MAX_FILE_SIZE_MB = 50;
|
|
5752
5936
|
async function isDirectoryPath(dir) {
|
|
@@ -5776,7 +5960,7 @@ async function collectFiles(root) {
|
|
|
5776
5960
|
if (name === "." || name === "..") {
|
|
5777
5961
|
continue;
|
|
5778
5962
|
}
|
|
5779
|
-
const abs =
|
|
5963
|
+
const abs = path10.join(dir, name);
|
|
5780
5964
|
const rel = prefix ? `${prefix}/${name}` : name;
|
|
5781
5965
|
if (e.isDirectory()) {
|
|
5782
5966
|
await walk(abs, rel);
|
|
@@ -5819,7 +6003,7 @@ var MIME = {
|
|
|
5819
6003
|
".map": "application/json"
|
|
5820
6004
|
};
|
|
5821
6005
|
function detectMimeType(filePath) {
|
|
5822
|
-
const ext =
|
|
6006
|
+
const ext = path10.extname(filePath).toLowerCase();
|
|
5823
6007
|
return MIME[ext] ?? "";
|
|
5824
6008
|
}
|
|
5825
6009
|
var MinioClient = class {
|
|
@@ -5907,7 +6091,7 @@ function artifactObjectKey(namePrefix, branchSegment, relativePath) {
|
|
|
5907
6091
|
return `${base}/${branchSegment}/dist/${rel}`;
|
|
5908
6092
|
}
|
|
5909
6093
|
async function ensureArtifactRootIndexHtml(root) {
|
|
5910
|
-
const indexHtmlPath =
|
|
6094
|
+
const indexHtmlPath = path11.join(root, "index.html");
|
|
5911
6095
|
try {
|
|
5912
6096
|
const st = await stat(indexHtmlPath);
|
|
5913
6097
|
if (st.isFile()) {
|
|
@@ -5924,7 +6108,7 @@ async function ensureArtifactRootIndexHtml(root) {
|
|
|
5924
6108
|
}
|
|
5925
6109
|
const dirNames = entries.filter((e) => e.isDirectory()).map((e) => String(e.name)).sort();
|
|
5926
6110
|
for (const name of dirNames) {
|
|
5927
|
-
const candidate =
|
|
6111
|
+
const candidate = path11.join(root, name, "index.html");
|
|
5928
6112
|
try {
|
|
5929
6113
|
const st = await stat(candidate);
|
|
5930
6114
|
if (!st.isFile()) {
|
|
@@ -5935,7 +6119,7 @@ async function ensureArtifactRootIndexHtml(root) {
|
|
|
5935
6119
|
}
|
|
5936
6120
|
await copyFile(candidate, indexHtmlPath);
|
|
5937
6121
|
console.error(
|
|
5938
|
-
`\u4EA7\u7269\u534F\u8BAE\uFF1A\u5DF2\u5C06 ${
|
|
6122
|
+
`\u4EA7\u7269\u534F\u8BAE\uFF1A\u5DF2\u5C06 ${path11.join(name, "index.html")} \u590D\u5236\u4E3A\u6839\u76EE\u5F55 index.html`
|
|
5939
6123
|
);
|
|
5940
6124
|
return;
|
|
5941
6125
|
}
|
|
@@ -5971,7 +6155,7 @@ function registerDeployFrontendCommands(program) {
|
|
|
5971
6155
|
secretKey: settings.secretKey
|
|
5972
6156
|
});
|
|
5973
6157
|
const bucket = settings.bucket;
|
|
5974
|
-
const root =
|
|
6158
|
+
const root = path11.resolve(process.cwd(), opts.dir || "apps/web/dist");
|
|
5975
6159
|
if (!await isDirectoryPath(root)) {
|
|
5976
6160
|
console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
|
|
5977
6161
|
process.exit(1);
|
|
@@ -6040,7 +6224,7 @@ function registerDeployFrontendCommands(program) {
|
|
|
6040
6224
|
}
|
|
6041
6225
|
|
|
6042
6226
|
// src/commands/deploy/sftp.ts
|
|
6043
|
-
import
|
|
6227
|
+
import path12 from "node:path";
|
|
6044
6228
|
function registerDeploySftpCommands(program) {
|
|
6045
6229
|
program.command("deploy-sftp").description(
|
|
6046
6230
|
"\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"
|
|
@@ -6055,7 +6239,7 @@ function registerDeploySftpCommands(program) {
|
|
|
6055
6239
|
async (opts) => {
|
|
6056
6240
|
const cfg = loadApmConfig({ configPath: opts.config });
|
|
6057
6241
|
const settings = resolveWisdomDeployFromApmConfig(cfg);
|
|
6058
|
-
const root =
|
|
6242
|
+
const root = path12.resolve(process.cwd(), opts.dir || "apps/web/dist");
|
|
6059
6243
|
if (!await isDirectoryPath(root)) {
|
|
6060
6244
|
console.error(`\u4EA7\u7269\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${root}`);
|
|
6061
6245
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## 工作流程
|
|
4
4
|
|
|
5
|
-
在项目根目录执行 `apm deploy
|
|
5
|
+
在项目根目录执行 `apm deploy <环境名称> --session <sessionId>`,**以命令执行结果为准**。
|
|
6
|
+
|
|
7
|
+
**sessionId**:从当前工作项目录 `.apm/sessions/<sessionId>/` 或 `session.yaml` 获取;必须传入 `--session`,平台才会记录部署。
|
|
6
8
|
|
|
7
9
|
- **成功**:部署完成,在回信中说明测试环境地址或部署结果。
|
|
8
10
|
- **失败且输出含「未配置自动化部署」或「可跳过部署」**:本项目不支持自动化部署,属正常情况;放弃部署,在回信说明已跳过即可,无需修复配置或重试。
|
|
@@ -10,5 +12,5 @@
|
|
|
10
12
|
|
|
11
13
|
## 示例
|
|
12
14
|
|
|
13
|
-
1. 部署测试环境:`apm deploy test
|
|
14
|
-
2. 部署正式环境:`apm deploy online
|
|
15
|
+
1. 部署测试环境:`apm deploy test --session <sessionId>`
|
|
16
|
+
2. 部署正式环境:`apm deploy online --session <sessionId>`
|