ai-project-manage-cli 8.0.13 → 8.0.15
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 +0 -4
- package/dist/webide-message-worker.js +243 -79
- package/package.json +1 -1
- package/template/rules/webide_package.md +1 -1
package/dist/index.js
CHANGED
|
@@ -196,10 +196,6 @@ var init_request_config = __esm({
|
|
|
196
196
|
method: "GET",
|
|
197
197
|
path: "/cli/apm-log-storage"
|
|
198
198
|
}),
|
|
199
|
-
getDeployArtifactStorage: defineEndpoint({
|
|
200
|
-
method: "GET",
|
|
201
|
-
path: "/cli/deploy-artifact-storage"
|
|
202
|
-
}),
|
|
203
199
|
projectPackageUpdateStatus: defineEndpoint({
|
|
204
200
|
method: "PUT",
|
|
205
201
|
path: "/cli/project-packages/status"
|
|
@@ -100,10 +100,6 @@ var requestConfig = {
|
|
|
100
100
|
method: "GET",
|
|
101
101
|
path: "/cli/apm-log-storage"
|
|
102
102
|
}),
|
|
103
|
-
getDeployArtifactStorage: defineEndpoint({
|
|
104
|
-
method: "GET",
|
|
105
|
-
path: "/cli/deploy-artifact-storage"
|
|
106
|
-
}),
|
|
107
103
|
projectPackageUpdateStatus: defineEndpoint({
|
|
108
104
|
method: "PUT",
|
|
109
105
|
path: "/cli/project-packages/status"
|
|
@@ -209,8 +205,8 @@ function toFsPath(inputPath) {
|
|
|
209
205
|
}
|
|
210
206
|
return `\\\\?\\${normalized}`;
|
|
211
207
|
}
|
|
212
|
-
function normalizeWorkdirPath(
|
|
213
|
-
let normalized =
|
|
208
|
+
function normalizeWorkdirPath(path3) {
|
|
209
|
+
let normalized = path3.trim().replace(/\\/g, "/").normalize("NFC");
|
|
214
210
|
if (normalized.startsWith("//?/")) {
|
|
215
211
|
normalized = normalized.slice(4);
|
|
216
212
|
}
|
|
@@ -332,9 +328,9 @@ function listWebIdeRuleFileNames(rulesDir) {
|
|
|
332
328
|
function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
|
|
333
329
|
const required = ["AGENTS.md", "rules"];
|
|
334
330
|
for (const item of required) {
|
|
335
|
-
const
|
|
336
|
-
if (!existsSync(toFsPath(
|
|
337
|
-
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${
|
|
331
|
+
const path3 = join2(apmDir, item);
|
|
332
|
+
if (!existsSync(toFsPath(path3))) {
|
|
333
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path3}`);
|
|
338
334
|
}
|
|
339
335
|
}
|
|
340
336
|
const rulesDir = join2(apmDir, "rules");
|
|
@@ -618,13 +614,13 @@ function normalizeRepoEntry(raw) {
|
|
|
618
614
|
return entry;
|
|
619
615
|
}
|
|
620
616
|
function readManifest(workdir) {
|
|
621
|
-
const
|
|
622
|
-
if (!existsSync2(
|
|
617
|
+
const path3 = toFsPath(manifestPath(workdir));
|
|
618
|
+
if (!existsSync2(path3)) {
|
|
623
619
|
return null;
|
|
624
620
|
}
|
|
625
621
|
try {
|
|
626
622
|
const raw = JSON.parse(
|
|
627
|
-
readFileSync2(
|
|
623
|
+
readFileSync2(path3, "utf8")
|
|
628
624
|
);
|
|
629
625
|
if (raw?.version !== WORKSPACE_REPOS_VERSION) {
|
|
630
626
|
return null;
|
|
@@ -656,8 +652,8 @@ function readManifest(workdir) {
|
|
|
656
652
|
function writeManifest(workdir, manifest) {
|
|
657
653
|
const apmDir = toFsPath(workspaceApmDir(workdir));
|
|
658
654
|
mkdirSync3(apmDir, { recursive: true });
|
|
659
|
-
const
|
|
660
|
-
writeFileSync2(
|
|
655
|
+
const path3 = toFsPath(manifestPath(workdir));
|
|
656
|
+
writeFileSync2(path3, `${JSON.stringify(manifest, null, 2)}
|
|
661
657
|
`, "utf8");
|
|
662
658
|
}
|
|
663
659
|
function manifestStillValid(workdir, manifest) {
|
|
@@ -2230,12 +2226,12 @@ import { dirname as dirname3, resolve as resolve5 } from "node:path";
|
|
|
2230
2226
|
function registryPath(workdir, taskId) {
|
|
2231
2227
|
return resolve5(workdir, ".apm", "webide", taskId, "cursor-agent.json");
|
|
2232
2228
|
}
|
|
2233
|
-
function readRegistry(
|
|
2234
|
-
if (!existsSync4(
|
|
2229
|
+
function readRegistry(path3) {
|
|
2230
|
+
if (!existsSync4(path3)) {
|
|
2235
2231
|
return {};
|
|
2236
2232
|
}
|
|
2237
2233
|
try {
|
|
2238
|
-
const parsed = JSON.parse(readFileSync4(
|
|
2234
|
+
const parsed = JSON.parse(readFileSync4(path3, "utf8"));
|
|
2239
2235
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2240
2236
|
const raw = parsed;
|
|
2241
2237
|
const state = {};
|
|
@@ -2263,16 +2259,16 @@ function readRegistry(path2) {
|
|
|
2263
2259
|
}
|
|
2264
2260
|
return {};
|
|
2265
2261
|
}
|
|
2266
|
-
function writeRegistry(
|
|
2267
|
-
mkdirSync4(dirname3(
|
|
2268
|
-
writeFileSync3(
|
|
2262
|
+
function writeRegistry(path3, registry) {
|
|
2263
|
+
mkdirSync4(dirname3(path3), { recursive: true });
|
|
2264
|
+
writeFileSync3(path3, `${JSON.stringify(registry, null, 2)}
|
|
2269
2265
|
`, "utf8");
|
|
2270
2266
|
}
|
|
2271
2267
|
function syncWebIdeTaskState(workdir, taskId, patch) {
|
|
2272
2268
|
const trimmedTaskId = taskId.trim();
|
|
2273
2269
|
if (!trimmedTaskId) return;
|
|
2274
|
-
const
|
|
2275
|
-
const current = readRegistry(
|
|
2270
|
+
const path3 = registryPath(workdir, trimmedTaskId);
|
|
2271
|
+
const current = readRegistry(path3);
|
|
2276
2272
|
const next = {
|
|
2277
2273
|
...current,
|
|
2278
2274
|
taskId: trimmedTaskId,
|
|
@@ -2296,7 +2292,7 @@ function syncWebIdeTaskState(workdir, taskId, patch) {
|
|
|
2296
2292
|
if (patch.status !== void 0) {
|
|
2297
2293
|
next.status = patch.status;
|
|
2298
2294
|
}
|
|
2299
|
-
writeRegistry(
|
|
2295
|
+
writeRegistry(path3, next);
|
|
2300
2296
|
}
|
|
2301
2297
|
function loadWebIdeAgentId(workdir, taskId) {
|
|
2302
2298
|
return readRegistry(registryPath(workdir, taskId)).agentId;
|
|
@@ -2305,8 +2301,8 @@ function saveWebIdeAgentId(workdir, taskId, agentId) {
|
|
|
2305
2301
|
syncWebIdeTaskState(workdir, taskId, { agentId });
|
|
2306
2302
|
}
|
|
2307
2303
|
function clearWebIdeAgentId(workdir, taskId) {
|
|
2308
|
-
const
|
|
2309
|
-
if (!existsSync4(
|
|
2304
|
+
const path3 = registryPath(workdir, taskId);
|
|
2305
|
+
if (!existsSync4(path3)) return;
|
|
2310
2306
|
syncWebIdeTaskState(workdir, taskId, { agentId: "" });
|
|
2311
2307
|
}
|
|
2312
2308
|
|
|
@@ -2510,6 +2506,34 @@ var MinioClient = class {
|
|
|
2510
2506
|
async fPutObject(bucket, objectKey, filePath, meta) {
|
|
2511
2507
|
await this.inner.fPutObject(bucket, objectKey, filePath, meta);
|
|
2512
2508
|
}
|
|
2509
|
+
async listObjects(bucket, prefix) {
|
|
2510
|
+
const objects = [];
|
|
2511
|
+
const stream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
2512
|
+
await new Promise((resolve7, reject) => {
|
|
2513
|
+
stream.on("data", (obj) => {
|
|
2514
|
+
if (!obj.name) return;
|
|
2515
|
+
objects.push({
|
|
2516
|
+
name: obj.name,
|
|
2517
|
+
size: typeof obj.size === "number" ? obj.size : 0,
|
|
2518
|
+
lastModified: obj.lastModified ?? null,
|
|
2519
|
+
...typeof obj.etag === "string" ? { etag: obj.etag } : {}
|
|
2520
|
+
});
|
|
2521
|
+
});
|
|
2522
|
+
stream.on("error", reject);
|
|
2523
|
+
stream.on("end", () => resolve7());
|
|
2524
|
+
});
|
|
2525
|
+
return objects;
|
|
2526
|
+
}
|
|
2527
|
+
async statObject(bucket, objectKey) {
|
|
2528
|
+
const stat = await this.inner.statObject(bucket, objectKey);
|
|
2529
|
+
return {
|
|
2530
|
+
size: typeof stat.size === "number" ? stat.size : 0,
|
|
2531
|
+
metaData: stat.metaData
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
async removeObject(bucket, objectKey) {
|
|
2535
|
+
await this.inner.removeObject(bucket, objectKey);
|
|
2536
|
+
}
|
|
2513
2537
|
};
|
|
2514
2538
|
|
|
2515
2539
|
// src/commands/connect/apm-log-minio.ts
|
|
@@ -2527,7 +2551,8 @@ async function createApmLogMinioClient(cfg) {
|
|
|
2527
2551
|
accessKey: storage.accessKey,
|
|
2528
2552
|
secretKey: storage.secretKey
|
|
2529
2553
|
}),
|
|
2530
|
-
bucket: storage.bucket
|
|
2554
|
+
bucket: storage.bucket,
|
|
2555
|
+
...storage.publicEndpoint ? { publicEndpoint: storage.publicEndpoint } : {}
|
|
2531
2556
|
};
|
|
2532
2557
|
}
|
|
2533
2558
|
|
|
@@ -2957,13 +2982,13 @@ async function downloadAttachment(cfg, attachmentId) {
|
|
|
2957
2982
|
return Buffer.from(await res.arrayBuffer());
|
|
2958
2983
|
}
|
|
2959
2984
|
function loadManifest(dir) {
|
|
2960
|
-
const
|
|
2961
|
-
if (!existsSync6(
|
|
2985
|
+
const path3 = join5(dir, MANIFEST_FILE);
|
|
2986
|
+
if (!existsSync6(path3)) {
|
|
2962
2987
|
return { version: 1, attachments: {} };
|
|
2963
2988
|
}
|
|
2964
2989
|
try {
|
|
2965
2990
|
const parsed = JSON.parse(
|
|
2966
|
-
readFileSync6(
|
|
2991
|
+
readFileSync6(path3, "utf8")
|
|
2967
2992
|
);
|
|
2968
2993
|
if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
|
|
2969
2994
|
return parsed;
|
|
@@ -3058,14 +3083,14 @@ function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
|
|
|
3058
3083
|
...normalized.split("/")
|
|
3059
3084
|
);
|
|
3060
3085
|
}
|
|
3061
|
-
function normalizeLocalDocumentPath(
|
|
3062
|
-
const trimmed =
|
|
3086
|
+
function normalizeLocalDocumentPath(path3) {
|
|
3087
|
+
const trimmed = path3.trim().replace(/\\/g, "/");
|
|
3063
3088
|
if (!trimmed || trimmed.startsWith("/") || /^[a-zA-Z]:/.test(trimmed)) {
|
|
3064
|
-
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${
|
|
3089
|
+
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path3}`);
|
|
3065
3090
|
}
|
|
3066
3091
|
const segments = trimmed.split("/").filter(Boolean);
|
|
3067
3092
|
if (segments.some((segment) => segment === ".." || segment === ".")) {
|
|
3068
|
-
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${
|
|
3093
|
+
throw new Error(`\u975E\u6CD5\u6587\u6863\u8DEF\u5F84: ${path3}`);
|
|
3069
3094
|
}
|
|
3070
3095
|
return segments.join("/");
|
|
3071
3096
|
}
|
|
@@ -3119,15 +3144,15 @@ function diffManifestPaths(remote, local) {
|
|
|
3119
3144
|
(local?.documents ?? []).map((doc) => [doc.path, doc.contentHash])
|
|
3120
3145
|
);
|
|
3121
3146
|
const download = [];
|
|
3122
|
-
for (const [
|
|
3123
|
-
if (localMap.get(
|
|
3124
|
-
download.push(
|
|
3147
|
+
for (const [path3, hash] of remoteMap) {
|
|
3148
|
+
if (localMap.get(path3) !== hash) {
|
|
3149
|
+
download.push(path3);
|
|
3125
3150
|
}
|
|
3126
3151
|
}
|
|
3127
3152
|
const deleteLocal = [];
|
|
3128
|
-
for (const
|
|
3129
|
-
if (!remoteMap.has(
|
|
3130
|
-
deleteLocal.push(
|
|
3153
|
+
for (const path3 of localMap.keys()) {
|
|
3154
|
+
if (!remoteMap.has(path3)) {
|
|
3155
|
+
deleteLocal.push(path3);
|
|
3131
3156
|
}
|
|
3132
3157
|
}
|
|
3133
3158
|
return { download, deleteLocal };
|
|
@@ -3221,9 +3246,9 @@ ${diagnostic ?? ""}`);
|
|
|
3221
3246
|
}
|
|
3222
3247
|
}
|
|
3223
3248
|
let deleted = 0;
|
|
3224
|
-
for (const
|
|
3249
|
+
for (const path3 of deleteLocal) {
|
|
3225
3250
|
const absPath = toFsPath(
|
|
3226
|
-
projectDocumentLocalPath(targetApmDir, projectId,
|
|
3251
|
+
projectDocumentLocalPath(targetApmDir, projectId, path3)
|
|
3227
3252
|
);
|
|
3228
3253
|
if (existsSync7(absPath)) {
|
|
3229
3254
|
rmSync2(absPath, { force: true });
|
|
@@ -3270,23 +3295,23 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
3270
3295
|
(remoteManifest?.documents ?? []).map((doc) => [doc.path, doc.description])
|
|
3271
3296
|
);
|
|
3272
3297
|
let synced = 0;
|
|
3273
|
-
for (const
|
|
3298
|
+
for (const path3 of localPaths) {
|
|
3274
3299
|
const absPath = toFsPath(
|
|
3275
|
-
projectDocumentLocalPath(targetApmDir, projectId,
|
|
3300
|
+
projectDocumentLocalPath(targetApmDir, projectId, path3)
|
|
3276
3301
|
);
|
|
3277
3302
|
const content = readFileSync7(absPath, "utf8");
|
|
3278
3303
|
const contentHash = hashLocalFileContent(content);
|
|
3279
|
-
if (remoteHashByPath.get(
|
|
3304
|
+
if (remoteHashByPath.get(path3) === contentHash) {
|
|
3280
3305
|
continue;
|
|
3281
3306
|
}
|
|
3282
3307
|
await api.cli.upsertProjectDocument({
|
|
3283
3308
|
projectId,
|
|
3284
|
-
path:
|
|
3309
|
+
path: path3,
|
|
3285
3310
|
content,
|
|
3286
|
-
description: remoteDescriptionByPath.get(
|
|
3311
|
+
description: remoteDescriptionByPath.get(path3) ?? void 0
|
|
3287
3312
|
});
|
|
3288
3313
|
synced += 1;
|
|
3289
|
-
console.log(`[apm] \u5DF2\u540C\u6B65\u9879\u76EE\u6587\u6863: ${
|
|
3314
|
+
console.log(`[apm] \u5DF2\u540C\u6B65\u9879\u76EE\u6587\u6863: ${path3}`);
|
|
3290
3315
|
}
|
|
3291
3316
|
if (synced === 0) {
|
|
3292
3317
|
console.log("[apm] \u9879\u76EE\u6587\u6863\u65E0\u53D8\u5316\uFF0C\u8DF3\u8FC7\u63A8\u9001");
|
|
@@ -3302,13 +3327,13 @@ function manifestPath2(apmDir) {
|
|
|
3302
3327
|
return join7(apmDir, CLI_VERSION_FILE);
|
|
3303
3328
|
}
|
|
3304
3329
|
function loadManifest2(apmDir) {
|
|
3305
|
-
const
|
|
3306
|
-
if (!existsSync8(
|
|
3330
|
+
const path3 = toFsPath(manifestPath2(apmDir));
|
|
3331
|
+
if (!existsSync8(path3)) {
|
|
3307
3332
|
return null;
|
|
3308
3333
|
}
|
|
3309
3334
|
try {
|
|
3310
3335
|
const parsed = JSON.parse(
|
|
3311
|
-
readFileSync8(
|
|
3336
|
+
readFileSync8(path3, "utf8")
|
|
3312
3337
|
);
|
|
3313
3338
|
if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
|
|
3314
3339
|
return parsed;
|
|
@@ -3993,28 +4018,6 @@ async function handleStartProject(cfg, msg, signal) {
|
|
|
3993
4018
|
// src/commands/connect/upload-package-artifact.ts
|
|
3994
4019
|
import fs from "node:fs";
|
|
3995
4020
|
import path from "node:path";
|
|
3996
|
-
|
|
3997
|
-
// src/commands/connect/deploy-artifact-minio.ts
|
|
3998
|
-
async function fetchDeployArtifactStorage(cfg) {
|
|
3999
|
-
const api = createApmApiClient(cfg);
|
|
4000
|
-
return api.cli.getDeployArtifactStorage(void 0);
|
|
4001
|
-
}
|
|
4002
|
-
async function createDeployArtifactMinioClient(cfg) {
|
|
4003
|
-
const storage = await fetchDeployArtifactStorage(cfg);
|
|
4004
|
-
return {
|
|
4005
|
-
client: new MinioClient({
|
|
4006
|
-
endPoint: storage.endpoint,
|
|
4007
|
-
port: storage.port,
|
|
4008
|
-
useSSL: storage.useSsl,
|
|
4009
|
-
accessKey: storage.accessKey,
|
|
4010
|
-
secretKey: storage.secretKey
|
|
4011
|
-
}),
|
|
4012
|
-
bucket: storage.bucket,
|
|
4013
|
-
...storage.publicEndpoint ? { publicEndpoint: storage.publicEndpoint } : {}
|
|
4014
|
-
};
|
|
4015
|
-
}
|
|
4016
|
-
|
|
4017
|
-
// src/commands/connect/upload-package-artifact.ts
|
|
4018
4021
|
function packageTmpDir(packageId) {
|
|
4019
4022
|
return `/data/package-tmp/${packageId}`;
|
|
4020
4023
|
}
|
|
@@ -4022,9 +4025,10 @@ function expectedLocalArtifactPath(target, packageId) {
|
|
|
4022
4025
|
const fileName = target === "frontend" ? "dist.zip" : "jars.zip";
|
|
4023
4026
|
return path.join(packageTmpDir(packageId), fileName);
|
|
4024
4027
|
}
|
|
4025
|
-
function packageArtifactObjectKey(target,
|
|
4026
|
-
const
|
|
4027
|
-
|
|
4028
|
+
function packageArtifactObjectKey(target, projectId, timestampMs = Date.now()) {
|
|
4029
|
+
const folder = target === "frontend" ? "vue" : "java";
|
|
4030
|
+
const suffix = target === "frontend" ? "dist.zip" : "jar.zip";
|
|
4031
|
+
return `packages/${projectId}/${folder}/${timestampMs}.${suffix}`;
|
|
4028
4032
|
}
|
|
4029
4033
|
function removePackageTmpDir(packageId) {
|
|
4030
4034
|
const dir = packageTmpDir(packageId);
|
|
@@ -4037,7 +4041,7 @@ function removePackageTmpDir(packageId) {
|
|
|
4037
4041
|
);
|
|
4038
4042
|
}
|
|
4039
4043
|
}
|
|
4040
|
-
async function uploadPackageArtifact(cfg, target, packageId) {
|
|
4044
|
+
async function uploadPackageArtifact(cfg, target, packageId, projectId) {
|
|
4041
4045
|
const localPath = expectedLocalArtifactPath(target, packageId);
|
|
4042
4046
|
if (!fs.existsSync(localPath)) {
|
|
4043
4047
|
throw new Error(`\u6253\u5305\u4EA7\u7269\u4E0D\u5B58\u5728: ${localPath}`);
|
|
@@ -4046,8 +4050,8 @@ async function uploadPackageArtifact(cfg, target, packageId) {
|
|
|
4046
4050
|
if (!stat.isFile() || stat.size <= 0) {
|
|
4047
4051
|
throw new Error(`\u6253\u5305\u4EA7\u7269\u65E0\u6548\u6216\u4E3A\u7A7A: ${localPath}`);
|
|
4048
4052
|
}
|
|
4049
|
-
const objectKey = packageArtifactObjectKey(target,
|
|
4050
|
-
const { client, bucket, publicEndpoint } = await
|
|
4053
|
+
const objectKey = packageArtifactObjectKey(target, projectId);
|
|
4054
|
+
const { client, bucket, publicEndpoint } = await createApmLogMinioClient(cfg);
|
|
4051
4055
|
await client.ensureBucket(bucket);
|
|
4052
4056
|
await client.fPutObject(bucket, objectKey, localPath, {
|
|
4053
4057
|
"Content-Type": "application/zip"
|
|
@@ -4058,6 +4062,151 @@ async function uploadPackageArtifact(cfg, target, packageId) {
|
|
|
4058
4062
|
return { artifactPath: objectKey, artifactUrl };
|
|
4059
4063
|
}
|
|
4060
4064
|
|
|
4065
|
+
// src/commands/connect/sync-package-sql.ts
|
|
4066
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
4067
|
+
import fs2 from "node:fs";
|
|
4068
|
+
import path2 from "node:path";
|
|
4069
|
+
var SKIP_DIR_NAMES2 = /* @__PURE__ */ new Set([
|
|
4070
|
+
".apm",
|
|
4071
|
+
".git",
|
|
4072
|
+
".idea",
|
|
4073
|
+
".vscode",
|
|
4074
|
+
"node_modules",
|
|
4075
|
+
"target",
|
|
4076
|
+
"dist",
|
|
4077
|
+
"build",
|
|
4078
|
+
"out",
|
|
4079
|
+
"coverage",
|
|
4080
|
+
"__pycache__"
|
|
4081
|
+
]);
|
|
4082
|
+
var MIGRATION_MARKER = "/db/migration/";
|
|
4083
|
+
function isSqlFileName(name) {
|
|
4084
|
+
return name.toLowerCase().endsWith(".sql");
|
|
4085
|
+
}
|
|
4086
|
+
function sha256File(absPath) {
|
|
4087
|
+
const hash = createHash2("sha256");
|
|
4088
|
+
hash.update(fs2.readFileSync(absPath));
|
|
4089
|
+
return hash.digest("hex");
|
|
4090
|
+
}
|
|
4091
|
+
function scanLocalMigrationSqlFiles(workdir) {
|
|
4092
|
+
const root = path2.resolve(workdir);
|
|
4093
|
+
const byRelative = /* @__PURE__ */ new Map();
|
|
4094
|
+
const walk = (dir) => {
|
|
4095
|
+
let entries;
|
|
4096
|
+
try {
|
|
4097
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
4098
|
+
} catch {
|
|
4099
|
+
return;
|
|
4100
|
+
}
|
|
4101
|
+
for (const entry of entries) {
|
|
4102
|
+
const name = entry.name;
|
|
4103
|
+
if (entry.isDirectory()) {
|
|
4104
|
+
if (SKIP_DIR_NAMES2.has(name) || name.startsWith(".")) continue;
|
|
4105
|
+
walk(path2.join(dir, name));
|
|
4106
|
+
continue;
|
|
4107
|
+
}
|
|
4108
|
+
if (!entry.isFile() || !isSqlFileName(name)) continue;
|
|
4109
|
+
const absPath = path2.join(dir, name);
|
|
4110
|
+
const normalized = absPath.replace(/\\/g, "/");
|
|
4111
|
+
const idx = normalized.toLowerCase().lastIndexOf(MIGRATION_MARKER);
|
|
4112
|
+
if (idx < 0) continue;
|
|
4113
|
+
const relativePath = normalized.slice(idx + MIGRATION_MARKER.length);
|
|
4114
|
+
if (!relativePath || relativePath.includes("..")) continue;
|
|
4115
|
+
const stat = fs2.statSync(absPath);
|
|
4116
|
+
if (!stat.isFile() || stat.size <= 0) continue;
|
|
4117
|
+
const item = {
|
|
4118
|
+
absPath,
|
|
4119
|
+
relativePath,
|
|
4120
|
+
size: stat.size,
|
|
4121
|
+
sha256: sha256File(absPath)
|
|
4122
|
+
};
|
|
4123
|
+
const prev = byRelative.get(relativePath);
|
|
4124
|
+
if (prev) {
|
|
4125
|
+
console.warn(
|
|
4126
|
+
`[apm] SQL relative path conflict, overwrite: ${relativePath}
|
|
4127
|
+
old: ${prev.absPath}
|
|
4128
|
+
new: ${absPath}`
|
|
4129
|
+
);
|
|
4130
|
+
}
|
|
4131
|
+
byRelative.set(relativePath, item);
|
|
4132
|
+
}
|
|
4133
|
+
};
|
|
4134
|
+
walk(root);
|
|
4135
|
+
return [...byRelative.values()].sort(
|
|
4136
|
+
(a, b) => a.relativePath.localeCompare(b.relativePath)
|
|
4137
|
+
);
|
|
4138
|
+
}
|
|
4139
|
+
function packageSqlObjectKey(projectId, relativePath) {
|
|
4140
|
+
return `packages/${projectId}/sql/${relativePath}`;
|
|
4141
|
+
}
|
|
4142
|
+
function packageSqlPrefix(projectId) {
|
|
4143
|
+
return `packages/${projectId}/sql/`;
|
|
4144
|
+
}
|
|
4145
|
+
async function syncPackageSqlToMinio(cfg, workdir, projectId) {
|
|
4146
|
+
const id = projectId.trim();
|
|
4147
|
+
if (!id) {
|
|
4148
|
+
throw new Error("projectId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
4149
|
+
}
|
|
4150
|
+
const localFiles = scanLocalMigrationSqlFiles(workdir);
|
|
4151
|
+
const { client, bucket } = await createApmLogMinioClient(cfg);
|
|
4152
|
+
await client.ensureBucket(bucket);
|
|
4153
|
+
const prefix = packageSqlPrefix(id);
|
|
4154
|
+
const remoteObjects = await client.listObjects(bucket, prefix);
|
|
4155
|
+
const remoteByRelative = /* @__PURE__ */ new Map();
|
|
4156
|
+
for (const obj of remoteObjects) {
|
|
4157
|
+
if (!obj.name.startsWith(prefix) || obj.name.endsWith("/")) continue;
|
|
4158
|
+
if (!obj.name.toLowerCase().endsWith(".sql")) continue;
|
|
4159
|
+
const relativePath = obj.name.slice(prefix.length);
|
|
4160
|
+
if (!relativePath) continue;
|
|
4161
|
+
remoteByRelative.set(relativePath, {
|
|
4162
|
+
objectKey: obj.name,
|
|
4163
|
+
size: obj.size
|
|
4164
|
+
});
|
|
4165
|
+
}
|
|
4166
|
+
for (const [relativePath, remote] of remoteByRelative) {
|
|
4167
|
+
const local = localFiles.find((f) => f.relativePath === relativePath);
|
|
4168
|
+
if (!local) continue;
|
|
4169
|
+
if (local.size !== remote.size) continue;
|
|
4170
|
+
try {
|
|
4171
|
+
const stat = await client.statObject(bucket, remote.objectKey);
|
|
4172
|
+
const meta = stat.metaData ?? {};
|
|
4173
|
+
const sha = meta["sha256"] || meta["x-amz-meta-sha256"] || meta["Sha256"] || void 0;
|
|
4174
|
+
if (typeof sha === "string" && sha.trim()) {
|
|
4175
|
+
remote.sha256 = sha.trim().toLowerCase();
|
|
4176
|
+
}
|
|
4177
|
+
} catch {
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4180
|
+
let uploaded = 0;
|
|
4181
|
+
let skipped = 0;
|
|
4182
|
+
const localRelativeSet = new Set(localFiles.map((f) => f.relativePath));
|
|
4183
|
+
for (const file of localFiles) {
|
|
4184
|
+
const objectKey = packageSqlObjectKey(id, file.relativePath);
|
|
4185
|
+
const remote = remoteByRelative.get(file.relativePath);
|
|
4186
|
+
if (remote?.sha256 && remote.sha256 === file.sha256) {
|
|
4187
|
+
skipped += 1;
|
|
4188
|
+
continue;
|
|
4189
|
+
}
|
|
4190
|
+
await client.fPutObject(bucket, objectKey, file.absPath, {
|
|
4191
|
+
"Content-Type": "application/sql",
|
|
4192
|
+
sha256: file.sha256
|
|
4193
|
+
});
|
|
4194
|
+
uploaded += 1;
|
|
4195
|
+
}
|
|
4196
|
+
let deleted = 0;
|
|
4197
|
+
for (const [relativePath, remote] of remoteByRelative) {
|
|
4198
|
+
if (localRelativeSet.has(relativePath)) continue;
|
|
4199
|
+
await client.removeObject(bucket, remote.objectKey);
|
|
4200
|
+
deleted += 1;
|
|
4201
|
+
}
|
|
4202
|
+
return {
|
|
4203
|
+
scanned: localFiles.length,
|
|
4204
|
+
uploaded,
|
|
4205
|
+
skipped,
|
|
4206
|
+
deleted
|
|
4207
|
+
};
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4061
4210
|
// src/commands/connect/handle-package.ts
|
|
4062
4211
|
async function updatePackageStatus(cfg, packageId, status, extra) {
|
|
4063
4212
|
const api = createApmApiClient(cfg);
|
|
@@ -4188,6 +4337,21 @@ async function handleWebIdePackage(cfg, msg, signal) {
|
|
|
4188
4337
|
return `downloaded=${result.downloaded} deleted=${result.deleted}`;
|
|
4189
4338
|
}
|
|
4190
4339
|
);
|
|
4340
|
+
if (msg.target === "backend") {
|
|
4341
|
+
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
4342
|
+
try {
|
|
4343
|
+
await runPrepStep(
|
|
4344
|
+
"\u540C\u6B65 SQL \u5230 MinIO",
|
|
4345
|
+
() => syncPackageSqlToMinio(cfg, workdir, projectId),
|
|
4346
|
+
(result) => `scanned=${result.scanned} uploaded=${result.uploaded} skipped=${result.skipped} deleted=${result.deleted}`
|
|
4347
|
+
);
|
|
4348
|
+
} catch (err) {
|
|
4349
|
+
console.warn(
|
|
4350
|
+
`[apm] \u540C\u6B65 SQL \u5230 MinIO \u5931\u8D25\uFF08\u4E0D\u963B\u65AD\u6253\u5305\uFF09:`,
|
|
4351
|
+
err instanceof Error ? err.message : err
|
|
4352
|
+
);
|
|
4353
|
+
}
|
|
4354
|
+
}
|
|
4191
4355
|
eventSession.addCliStep("\u542F\u52A8\u6253\u5305 Agent", "\u51C6\u5907 create\u2026", "running");
|
|
4192
4356
|
await syncPrepLog();
|
|
4193
4357
|
let failedByTool = false;
|
|
@@ -4298,7 +4462,7 @@ async function handleWebIdePackage(cfg, msg, signal) {
|
|
|
4298
4462
|
}
|
|
4299
4463
|
const uploaded = await runPrepStep(
|
|
4300
4464
|
"\u4E0A\u4F20\u6253\u5305\u4EA7\u7269\u5230 MinIO",
|
|
4301
|
-
() => uploadPackageArtifact(cfg, msg.target, packageId),
|
|
4465
|
+
() => uploadPackageArtifact(cfg, msg.target, packageId, projectId),
|
|
4302
4466
|
(result) => `objectKey=${result.artifactPath}${result.artifactUrl ? ` url=${result.artifactUrl}` : ""}`
|
|
4303
4467
|
);
|
|
4304
4468
|
await updatePackageStatus(cfg, packageId, "SUCCESS", {
|
package/package.json
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
### target=backend(SpringBoot)
|
|
41
41
|
|
|
42
42
|
1. 按 deploy 文档进入后端目录,执行文档写明的构建命令(通常 `mvn clean package`)。
|
|
43
|
-
2. **只**收集 deploy 文档标明的交付 jar(路径/文件名/glob 以文档为准)。**禁止**全量收集 `target/lib
|
|
43
|
+
2. **只**收集 deploy 文档标明的交付 jar(路径/文件名/glob 以文档为准)。**禁止**全量收集 `target/lib`、**禁止**把 SQL 打进 jars.zip、**禁止**在规则或命令里写死具体 jar 名。SQL 镜像由 CLI 自动扫描本地 `db/migration` 下的 `.sql` 同步到 MinIO,Agent **不要**上传 SQL。
|
|
44
44
|
3. 确认文档列出的每个 jar 均已生成;缺任一文件 → SetPackageFailed。
|
|
45
45
|
4. 在临时目录将上述 jar **打成一个 zip**(勿在工作区生成交付 zip),落到:
|
|
46
46
|
|