ai-project-manage-cli 8.0.15 → 8.0.17
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.
|
@@ -1858,6 +1858,334 @@ function createMysqlExecuteTool(options) {
|
|
|
1858
1858
|
};
|
|
1859
1859
|
}
|
|
1860
1860
|
|
|
1861
|
+
// src/commands/connect/tools/package-sql-tool.ts
|
|
1862
|
+
import { existsSync as existsSync4, statSync as statSync4 } from "node:fs";
|
|
1863
|
+
import { isAbsolute as isAbsolute2, relative as relative3, resolve as resolve5 } from "node:path";
|
|
1864
|
+
|
|
1865
|
+
// src/commands/connect/sync-package-sql.ts
|
|
1866
|
+
import { createHash } from "node:crypto";
|
|
1867
|
+
import fs from "node:fs";
|
|
1868
|
+
import path from "node:path";
|
|
1869
|
+
|
|
1870
|
+
// src/utils/minio.ts
|
|
1871
|
+
import * as Minio from "minio";
|
|
1872
|
+
var MinioClient = class {
|
|
1873
|
+
inner;
|
|
1874
|
+
constructor(opts) {
|
|
1875
|
+
const endPoint = opts.endPoint.replace(/^https?:\/\//i, "").split("/")[0] ?? opts.endPoint;
|
|
1876
|
+
this.inner = new Minio.Client({
|
|
1877
|
+
endPoint,
|
|
1878
|
+
port: opts.port,
|
|
1879
|
+
useSSL: opts.useSSL,
|
|
1880
|
+
accessKey: opts.accessKey,
|
|
1881
|
+
secretKey: opts.secretKey
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
async ensureBucket(bucket) {
|
|
1885
|
+
const exists = await this.inner.bucketExists(bucket);
|
|
1886
|
+
if (!exists) {
|
|
1887
|
+
await this.inner.makeBucket(bucket);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
async putObject(bucket, objectKey, body, meta) {
|
|
1891
|
+
await this.inner.putObject(bucket, objectKey, body, body.length, meta);
|
|
1892
|
+
}
|
|
1893
|
+
/** 大文件:从本地路径流式上传,避免整包读入内存 */
|
|
1894
|
+
async fPutObject(bucket, objectKey, filePath, meta) {
|
|
1895
|
+
await this.inner.fPutObject(bucket, objectKey, filePath, meta);
|
|
1896
|
+
}
|
|
1897
|
+
async listObjects(bucket, prefix) {
|
|
1898
|
+
const objects = [];
|
|
1899
|
+
const stream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
1900
|
+
await new Promise((resolve8, reject) => {
|
|
1901
|
+
stream.on("data", (obj) => {
|
|
1902
|
+
if (!obj.name) return;
|
|
1903
|
+
objects.push({
|
|
1904
|
+
name: obj.name,
|
|
1905
|
+
size: typeof obj.size === "number" ? obj.size : 0,
|
|
1906
|
+
lastModified: obj.lastModified ?? null,
|
|
1907
|
+
...typeof obj.etag === "string" ? { etag: obj.etag } : {}
|
|
1908
|
+
});
|
|
1909
|
+
});
|
|
1910
|
+
stream.on("error", reject);
|
|
1911
|
+
stream.on("end", () => resolve8());
|
|
1912
|
+
});
|
|
1913
|
+
return objects;
|
|
1914
|
+
}
|
|
1915
|
+
async statObject(bucket, objectKey) {
|
|
1916
|
+
const stat = await this.inner.statObject(bucket, objectKey);
|
|
1917
|
+
return {
|
|
1918
|
+
size: typeof stat.size === "number" ? stat.size : 0,
|
|
1919
|
+
metaData: stat.metaData
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
async removeObject(bucket, objectKey) {
|
|
1923
|
+
await this.inner.removeObject(bucket, objectKey);
|
|
1924
|
+
}
|
|
1925
|
+
};
|
|
1926
|
+
|
|
1927
|
+
// src/commands/connect/apm-log-minio.ts
|
|
1928
|
+
async function fetchApmLogStorage(cfg) {
|
|
1929
|
+
const api = createApmApiClient(cfg);
|
|
1930
|
+
return api.cli.getApmLogStorage(void 0);
|
|
1931
|
+
}
|
|
1932
|
+
async function createApmLogMinioClient(cfg) {
|
|
1933
|
+
const storage = await fetchApmLogStorage(cfg);
|
|
1934
|
+
return {
|
|
1935
|
+
client: new MinioClient({
|
|
1936
|
+
endPoint: storage.endpoint,
|
|
1937
|
+
port: storage.port,
|
|
1938
|
+
useSSL: storage.useSsl,
|
|
1939
|
+
accessKey: storage.accessKey,
|
|
1940
|
+
secretKey: storage.secretKey
|
|
1941
|
+
}),
|
|
1942
|
+
bucket: storage.bucket,
|
|
1943
|
+
...storage.publicEndpoint ? { publicEndpoint: storage.publicEndpoint } : {}
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
// src/commands/connect/sync-package-sql.ts
|
|
1948
|
+
var SKIP_DIR_NAMES2 = /* @__PURE__ */ new Set([
|
|
1949
|
+
".apm",
|
|
1950
|
+
".git",
|
|
1951
|
+
".idea",
|
|
1952
|
+
".vscode",
|
|
1953
|
+
"node_modules",
|
|
1954
|
+
"target",
|
|
1955
|
+
"dist",
|
|
1956
|
+
"build",
|
|
1957
|
+
"out",
|
|
1958
|
+
"coverage",
|
|
1959
|
+
"__pycache__"
|
|
1960
|
+
]);
|
|
1961
|
+
function isSqlFileName(name) {
|
|
1962
|
+
return name.toLowerCase().endsWith(".sql");
|
|
1963
|
+
}
|
|
1964
|
+
function sha256File(absPath) {
|
|
1965
|
+
const hash = createHash("sha256");
|
|
1966
|
+
hash.update(fs.readFileSync(absPath));
|
|
1967
|
+
return hash.digest("hex");
|
|
1968
|
+
}
|
|
1969
|
+
function normalizeSqlRepoName(repo) {
|
|
1970
|
+
const trimmed = repo.trim().replace(/\\/g, "/");
|
|
1971
|
+
if (!trimmed) {
|
|
1972
|
+
throw new Error("repo \u4E0D\u80FD\u4E3A\u7A7A");
|
|
1973
|
+
}
|
|
1974
|
+
if (trimmed.includes("/") || trimmed.includes("..") || trimmed === "." || trimmed.startsWith(".")) {
|
|
1975
|
+
throw new Error(`\u65E0\u6548\u7684 repo \u540D: ${repo}`);
|
|
1976
|
+
}
|
|
1977
|
+
return trimmed;
|
|
1978
|
+
}
|
|
1979
|
+
function scanSqlFilesUnderDir(localDir) {
|
|
1980
|
+
const root = path.resolve(toFsPath(localDir));
|
|
1981
|
+
if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {
|
|
1982
|
+
throw new Error(`localDir \u4E0D\u5B58\u5728\u6216\u4E0D\u662F\u76EE\u5F55: ${localDir}`);
|
|
1983
|
+
}
|
|
1984
|
+
const byRelative = /* @__PURE__ */ new Map();
|
|
1985
|
+
const walk = (dir) => {
|
|
1986
|
+
let entries;
|
|
1987
|
+
try {
|
|
1988
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1989
|
+
} catch {
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
for (const entry of entries) {
|
|
1993
|
+
const name = entry.name;
|
|
1994
|
+
if (entry.isDirectory()) {
|
|
1995
|
+
if (SKIP_DIR_NAMES2.has(name) || name.startsWith(".")) continue;
|
|
1996
|
+
walk(path.join(dir, name));
|
|
1997
|
+
continue;
|
|
1998
|
+
}
|
|
1999
|
+
if (!entry.isFile() || !isSqlFileName(name)) continue;
|
|
2000
|
+
const absPath = path.join(dir, name);
|
|
2001
|
+
const relativePath = path.relative(root, absPath).replace(/\\/g, "/");
|
|
2002
|
+
if (!relativePath || relativePath.includes("..")) continue;
|
|
2003
|
+
const stat = fs.statSync(absPath);
|
|
2004
|
+
if (!stat.isFile() || stat.size <= 0) continue;
|
|
2005
|
+
byRelative.set(relativePath, {
|
|
2006
|
+
absPath,
|
|
2007
|
+
relativePath,
|
|
2008
|
+
size: stat.size,
|
|
2009
|
+
sha256: sha256File(absPath)
|
|
2010
|
+
});
|
|
2011
|
+
}
|
|
2012
|
+
};
|
|
2013
|
+
walk(root);
|
|
2014
|
+
return [...byRelative.values()].sort(
|
|
2015
|
+
(a, b) => a.relativePath.localeCompare(b.relativePath)
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
function packageSqlObjectKey(projectId, repo, relativePath) {
|
|
2019
|
+
return `packages/${projectId}/${repo}/${relativePath}`;
|
|
2020
|
+
}
|
|
2021
|
+
function packageSqlRepoPrefix(projectId, repo) {
|
|
2022
|
+
return `packages/${projectId}/${repo}/`;
|
|
2023
|
+
}
|
|
2024
|
+
async function syncPackageSqlToMinio(params) {
|
|
2025
|
+
const id = params.projectId.trim();
|
|
2026
|
+
if (!id) {
|
|
2027
|
+
throw new Error("projectId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
2028
|
+
}
|
|
2029
|
+
const repo = normalizeSqlRepoName(params.repo);
|
|
2030
|
+
const localFiles = scanSqlFilesUnderDir(params.localDir);
|
|
2031
|
+
const { client, bucket } = await createApmLogMinioClient(params.cfg);
|
|
2032
|
+
await client.ensureBucket(bucket);
|
|
2033
|
+
const prefix = packageSqlRepoPrefix(id, repo);
|
|
2034
|
+
const remoteObjects = await client.listObjects(bucket, prefix);
|
|
2035
|
+
const remoteByRelative = /* @__PURE__ */ new Map();
|
|
2036
|
+
for (const obj of remoteObjects) {
|
|
2037
|
+
if (!obj.name.startsWith(prefix) || obj.name.endsWith("/")) continue;
|
|
2038
|
+
if (!obj.name.toLowerCase().endsWith(".sql")) continue;
|
|
2039
|
+
if (obj.name.includes("..")) continue;
|
|
2040
|
+
const relativePath = obj.name.slice(prefix.length);
|
|
2041
|
+
if (!relativePath) continue;
|
|
2042
|
+
remoteByRelative.set(relativePath, {
|
|
2043
|
+
objectKey: obj.name,
|
|
2044
|
+
size: obj.size
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
2047
|
+
for (const [relativePath, remote] of remoteByRelative) {
|
|
2048
|
+
const local = localFiles.find((f) => f.relativePath === relativePath);
|
|
2049
|
+
if (!local) continue;
|
|
2050
|
+
if (local.size !== remote.size) continue;
|
|
2051
|
+
try {
|
|
2052
|
+
const stat = await client.statObject(bucket, remote.objectKey);
|
|
2053
|
+
const meta = stat.metaData ?? {};
|
|
2054
|
+
const sha = meta["sha256"] || meta["x-amz-meta-sha256"] || meta["Sha256"] || void 0;
|
|
2055
|
+
if (typeof sha === "string" && sha.trim()) {
|
|
2056
|
+
remote.sha256 = sha.trim().toLowerCase();
|
|
2057
|
+
}
|
|
2058
|
+
} catch {
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
let uploaded = 0;
|
|
2062
|
+
let skipped = 0;
|
|
2063
|
+
const localRelativeSet = new Set(localFiles.map((f) => f.relativePath));
|
|
2064
|
+
for (const file of localFiles) {
|
|
2065
|
+
const objectKey = packageSqlObjectKey(id, repo, file.relativePath);
|
|
2066
|
+
const remote = remoteByRelative.get(file.relativePath);
|
|
2067
|
+
if (remote?.sha256 && remote.sha256 === file.sha256) {
|
|
2068
|
+
skipped += 1;
|
|
2069
|
+
continue;
|
|
2070
|
+
}
|
|
2071
|
+
await client.fPutObject(bucket, objectKey, file.absPath, {
|
|
2072
|
+
"Content-Type": "application/sql",
|
|
2073
|
+
sha256: file.sha256
|
|
2074
|
+
});
|
|
2075
|
+
uploaded += 1;
|
|
2076
|
+
}
|
|
2077
|
+
let deleted = 0;
|
|
2078
|
+
for (const [relativePath, remote] of remoteByRelative) {
|
|
2079
|
+
if (localRelativeSet.has(relativePath)) continue;
|
|
2080
|
+
await client.removeObject(bucket, remote.objectKey);
|
|
2081
|
+
deleted += 1;
|
|
2082
|
+
}
|
|
2083
|
+
return {
|
|
2084
|
+
scanned: localFiles.length,
|
|
2085
|
+
uploaded,
|
|
2086
|
+
skipped,
|
|
2087
|
+
deleted
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// src/commands/connect/tools/package-sql-tool.ts
|
|
2092
|
+
function asString4(value) {
|
|
2093
|
+
return typeof value === "string" ? value.trim() : "";
|
|
2094
|
+
}
|
|
2095
|
+
function resolveLocalSqlDir(workdir, localDirArg) {
|
|
2096
|
+
if (!isAbsolute2(localDirArg)) {
|
|
2097
|
+
return { ok: false, error: "localDir \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84" };
|
|
2098
|
+
}
|
|
2099
|
+
const workdirAbs = resolve5(toFsPath(workdir));
|
|
2100
|
+
const targetAbs = resolve5(toFsPath(localDirArg));
|
|
2101
|
+
const rel = relative3(workdirAbs, targetAbs);
|
|
2102
|
+
if (!rel || rel.startsWith("..") || isAbsolute2(rel)) {
|
|
2103
|
+
return { ok: false, error: "localDir \u5FC5\u987B\u4F4D\u4E8E\u5F53\u524D\u5DE5\u4F5C\u533A\u5185" };
|
|
2104
|
+
}
|
|
2105
|
+
const fsPath = toFsPath(targetAbs);
|
|
2106
|
+
if (!existsSync4(fsPath)) {
|
|
2107
|
+
return { ok: false, error: `\u76EE\u5F55\u4E0D\u5B58\u5728: ${localDirArg}` };
|
|
2108
|
+
}
|
|
2109
|
+
try {
|
|
2110
|
+
if (!statSync4(fsPath).isDirectory()) {
|
|
2111
|
+
return { ok: false, error: "localDir \u5FC5\u987B\u662F\u76EE\u5F55" };
|
|
2112
|
+
}
|
|
2113
|
+
} catch {
|
|
2114
|
+
return { ok: false, error: `\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55: ${localDirArg}` };
|
|
2115
|
+
}
|
|
2116
|
+
return { ok: true, absPath: targetAbs };
|
|
2117
|
+
}
|
|
2118
|
+
function createUploadPackageSqlTool(options) {
|
|
2119
|
+
const { cfg, workdir, projectId } = options;
|
|
2120
|
+
return {
|
|
2121
|
+
UploadPackageSql: {
|
|
2122
|
+
description: "Upload SQL scripts from a local directory to project MinIO mirror. Call after reading deploy docs: pass repo (directory name from\u300C\u8FDB\u5165 xxx \u76EE\u5F55\u300D) and localDir (absolute path to the SQL script directory). Syncs **/*.sql under localDir to packages/{projectId}/{repo}/.... Do not put SQL into jars.zip.",
|
|
2123
|
+
inputSchema: {
|
|
2124
|
+
type: "object",
|
|
2125
|
+
properties: {
|
|
2126
|
+
repo: {
|
|
2127
|
+
type: "string",
|
|
2128
|
+
description: "Backend repo root directory name, e.g. mmis-java (from deploy\u300C\u8FDB\u5165 xxx \u76EE\u5F55\u300D)"
|
|
2129
|
+
},
|
|
2130
|
+
localDir: {
|
|
2131
|
+
type: "string",
|
|
2132
|
+
description: "Absolute path to the SQL script root directory under the workspace (deploy\u300CSQL\u811A\u672C\u76EE\u5F55\u300Dwithout the /**/*.sql suffix)"
|
|
2133
|
+
}
|
|
2134
|
+
},
|
|
2135
|
+
required: ["repo", "localDir"]
|
|
2136
|
+
},
|
|
2137
|
+
execute: async (args) => {
|
|
2138
|
+
const repoRaw = asString4(args.repo);
|
|
2139
|
+
const localDirRaw = asString4(args.localDir);
|
|
2140
|
+
if (!repoRaw) {
|
|
2141
|
+
return {
|
|
2142
|
+
content: [{ type: "text", text: "repo \u4E0D\u80FD\u4E3A\u7A7A" }],
|
|
2143
|
+
isError: true
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
if (!localDirRaw) {
|
|
2147
|
+
return {
|
|
2148
|
+
content: [{ type: "text", text: "localDir \u4E0D\u80FD\u4E3A\u7A7A" }],
|
|
2149
|
+
isError: true
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
let repo;
|
|
2153
|
+
try {
|
|
2154
|
+
repo = normalizeSqlRepoName(repoRaw);
|
|
2155
|
+
} catch (err) {
|
|
2156
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
2157
|
+
return {
|
|
2158
|
+
content: [{ type: "text", text: detail }],
|
|
2159
|
+
isError: true
|
|
2160
|
+
};
|
|
2161
|
+
}
|
|
2162
|
+
const resolved = resolveLocalSqlDir(workdir, localDirRaw);
|
|
2163
|
+
if (!resolved.ok) {
|
|
2164
|
+
return {
|
|
2165
|
+
content: [{ type: "text", text: resolved.error }],
|
|
2166
|
+
isError: true
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
try {
|
|
2170
|
+
const result = await syncPackageSqlToMinio({
|
|
2171
|
+
cfg,
|
|
2172
|
+
projectId,
|
|
2173
|
+
repo,
|
|
2174
|
+
localDir: resolved.absPath
|
|
2175
|
+
});
|
|
2176
|
+
return `SQL \u5DF2\u540C\u6B65 repo=${repo} scanned=${result.scanned} uploaded=${result.uploaded} skipped=${result.skipped} deleted=${result.deleted}`;
|
|
2177
|
+
} catch (err) {
|
|
2178
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
2179
|
+
return {
|
|
2180
|
+
content: [{ type: "text", text: `\u4E0A\u4F20 SQL \u5931\u8D25: ${detail}` }],
|
|
2181
|
+
isError: true
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
|
|
1861
2189
|
// src/commands/connect/tools/package-status-tool.ts
|
|
1862
2190
|
function createSetPackageFailedTool(options) {
|
|
1863
2191
|
const { packageId, setFailed } = options;
|
|
@@ -1964,6 +2292,17 @@ function createCursorCustomTools(cfg, options) {
|
|
|
1964
2292
|
}
|
|
1965
2293
|
})
|
|
1966
2294
|
);
|
|
2295
|
+
const projectId = options.projectId?.trim();
|
|
2296
|
+
if (projectId && options.workdir) {
|
|
2297
|
+
Object.assign(
|
|
2298
|
+
tools,
|
|
2299
|
+
createUploadPackageSqlTool({
|
|
2300
|
+
cfg,
|
|
2301
|
+
workdir: options.workdir,
|
|
2302
|
+
projectId
|
|
2303
|
+
})
|
|
2304
|
+
);
|
|
2305
|
+
}
|
|
1967
2306
|
}
|
|
1968
2307
|
return tools;
|
|
1969
2308
|
}
|
|
@@ -2088,6 +2427,7 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2088
2427
|
workdir,
|
|
2089
2428
|
enablePackageStatusTools: options.enablePackageStatusTools,
|
|
2090
2429
|
packageId: options.packageId,
|
|
2430
|
+
projectId: options.projectId,
|
|
2091
2431
|
onPackageFailed: options.onPackageFailed
|
|
2092
2432
|
});
|
|
2093
2433
|
const enableSandbox = Boolean(options.enableSandbox);
|
|
@@ -2221,13 +2561,13 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2221
2561
|
}
|
|
2222
2562
|
|
|
2223
2563
|
// src/commands/connect/webide-agent-registry.ts
|
|
2224
|
-
import { existsSync as
|
|
2225
|
-
import { dirname as dirname3, resolve as
|
|
2564
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2565
|
+
import { dirname as dirname3, resolve as resolve6 } from "node:path";
|
|
2226
2566
|
function registryPath(workdir, taskId) {
|
|
2227
|
-
return
|
|
2567
|
+
return resolve6(workdir, ".apm", "webide", taskId, "cursor-agent.json");
|
|
2228
2568
|
}
|
|
2229
2569
|
function readRegistry(path3) {
|
|
2230
|
-
if (!
|
|
2570
|
+
if (!existsSync5(path3)) {
|
|
2231
2571
|
return {};
|
|
2232
2572
|
}
|
|
2233
2573
|
try {
|
|
@@ -2302,20 +2642,20 @@ function saveWebIdeAgentId(workdir, taskId, agentId) {
|
|
|
2302
2642
|
}
|
|
2303
2643
|
function clearWebIdeAgentId(workdir, taskId) {
|
|
2304
2644
|
const path3 = registryPath(workdir, taskId);
|
|
2305
|
-
if (!
|
|
2645
|
+
if (!existsSync5(path3)) return;
|
|
2306
2646
|
syncWebIdeTaskState(workdir, taskId, { agentId: "" });
|
|
2307
2647
|
}
|
|
2308
2648
|
|
|
2309
2649
|
// src/commands/clean-webide-cache.ts
|
|
2310
|
-
import { existsSync as
|
|
2311
|
-
import { resolve as
|
|
2650
|
+
import { existsSync as existsSync6, rmSync } from "node:fs";
|
|
2651
|
+
import { resolve as resolve7 } from "node:path";
|
|
2312
2652
|
import { getDefaultSdkStateRoot } from "@cursor/sdk";
|
|
2313
2653
|
async function purgeCursorAgentStoreForAgent(workdir, agentId) {
|
|
2314
2654
|
const trimmedAgentId = agentId.trim();
|
|
2315
2655
|
const trimmedWorkdir = workdir.trim();
|
|
2316
2656
|
if (!trimmedAgentId || !trimmedWorkdir) return false;
|
|
2317
2657
|
const stateRoot = getDefaultSdkStateRoot(trimmedWorkdir);
|
|
2318
|
-
if (!
|
|
2658
|
+
if (!existsSync6(stateRoot)) return false;
|
|
2319
2659
|
const { SqliteLocalAgentStore } = await import(
|
|
2320
2660
|
/* @vite-ignore */
|
|
2321
2661
|
"@cursor/sdk/sqlite"
|
|
@@ -2379,8 +2719,8 @@ async function cleanWebIdeWorkspaceCache(taskId, workdir) {
|
|
|
2379
2719
|
`[apm] \u65E0 WebIDE agentId\uFF0C\u8DF3\u8FC7 agent store \u6E05\u7406 taskId=${trimmedTaskId}`
|
|
2380
2720
|
);
|
|
2381
2721
|
}
|
|
2382
|
-
const dir =
|
|
2383
|
-
if (
|
|
2722
|
+
const dir = resolve7(trimmedWorkdir, ".apm", "webide", trimmedTaskId);
|
|
2723
|
+
if (existsSync6(dir)) {
|
|
2384
2724
|
rmSync(dir, { recursive: true, force: true });
|
|
2385
2725
|
console.log(`[apm] \u5DF2\u6E05\u7406 WebIDE \u7F13\u5B58 ${dir}`);
|
|
2386
2726
|
} else {
|
|
@@ -2391,11 +2731,11 @@ async function cleanWebIdeWorkspaceCache(taskId, workdir) {
|
|
|
2391
2731
|
// src/commands/connect/webide-ask-question.ts
|
|
2392
2732
|
import { setTimeout as delay } from "node:timers/promises";
|
|
2393
2733
|
var POLL_INTERVAL_MS = 2e3;
|
|
2394
|
-
function
|
|
2734
|
+
function asString5(value) {
|
|
2395
2735
|
return typeof value === "string" ? value.trim() : "";
|
|
2396
2736
|
}
|
|
2397
2737
|
function parseQuestions(args) {
|
|
2398
|
-
const title =
|
|
2738
|
+
const title = asString5(args.title) || void 0;
|
|
2399
2739
|
const raw = args.questions;
|
|
2400
2740
|
if (!Array.isArray(raw) || raw.length === 0) {
|
|
2401
2741
|
throw new Error("AskQuestion \u7F3A\u5C11 questions");
|
|
@@ -2404,16 +2744,16 @@ function parseQuestions(args) {
|
|
|
2404
2744
|
for (const item of raw) {
|
|
2405
2745
|
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
2406
2746
|
const row = item;
|
|
2407
|
-
const id =
|
|
2408
|
-
const prompt =
|
|
2747
|
+
const id = asString5(row.id);
|
|
2748
|
+
const prompt = asString5(row.prompt);
|
|
2409
2749
|
const optionsRaw = row.options;
|
|
2410
2750
|
if (!id || !prompt || !Array.isArray(optionsRaw)) continue;
|
|
2411
2751
|
const options = [];
|
|
2412
2752
|
for (const opt of optionsRaw) {
|
|
2413
2753
|
if (!opt || typeof opt !== "object" || Array.isArray(opt)) continue;
|
|
2414
2754
|
const o = opt;
|
|
2415
|
-
const oid =
|
|
2416
|
-
const label =
|
|
2755
|
+
const oid = asString5(o.id);
|
|
2756
|
+
const label = asString5(o.label);
|
|
2417
2757
|
if (oid && label) options.push({ id: oid, label });
|
|
2418
2758
|
}
|
|
2419
2759
|
if (options.length < 2) {
|
|
@@ -2479,83 +2819,6 @@ function createWebIdeAskQuestionExecute(options) {
|
|
|
2479
2819
|
};
|
|
2480
2820
|
}
|
|
2481
2821
|
|
|
2482
|
-
// src/utils/minio.ts
|
|
2483
|
-
import * as Minio from "minio";
|
|
2484
|
-
var MinioClient = class {
|
|
2485
|
-
inner;
|
|
2486
|
-
constructor(opts) {
|
|
2487
|
-
const endPoint = opts.endPoint.replace(/^https?:\/\//i, "").split("/")[0] ?? opts.endPoint;
|
|
2488
|
-
this.inner = new Minio.Client({
|
|
2489
|
-
endPoint,
|
|
2490
|
-
port: opts.port,
|
|
2491
|
-
useSSL: opts.useSSL,
|
|
2492
|
-
accessKey: opts.accessKey,
|
|
2493
|
-
secretKey: opts.secretKey
|
|
2494
|
-
});
|
|
2495
|
-
}
|
|
2496
|
-
async ensureBucket(bucket) {
|
|
2497
|
-
const exists = await this.inner.bucketExists(bucket);
|
|
2498
|
-
if (!exists) {
|
|
2499
|
-
await this.inner.makeBucket(bucket);
|
|
2500
|
-
}
|
|
2501
|
-
}
|
|
2502
|
-
async putObject(bucket, objectKey, body, meta) {
|
|
2503
|
-
await this.inner.putObject(bucket, objectKey, body, body.length, meta);
|
|
2504
|
-
}
|
|
2505
|
-
/** 大文件:从本地路径流式上传,避免整包读入内存 */
|
|
2506
|
-
async fPutObject(bucket, objectKey, filePath, meta) {
|
|
2507
|
-
await this.inner.fPutObject(bucket, objectKey, filePath, meta);
|
|
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
|
-
}
|
|
2537
|
-
};
|
|
2538
|
-
|
|
2539
|
-
// src/commands/connect/apm-log-minio.ts
|
|
2540
|
-
async function fetchApmLogStorage(cfg) {
|
|
2541
|
-
const api = createApmApiClient(cfg);
|
|
2542
|
-
return api.cli.getApmLogStorage(void 0);
|
|
2543
|
-
}
|
|
2544
|
-
async function createApmLogMinioClient(cfg) {
|
|
2545
|
-
const storage = await fetchApmLogStorage(cfg);
|
|
2546
|
-
return {
|
|
2547
|
-
client: new MinioClient({
|
|
2548
|
-
endPoint: storage.endpoint,
|
|
2549
|
-
port: storage.port,
|
|
2550
|
-
useSSL: storage.useSsl,
|
|
2551
|
-
accessKey: storage.accessKey,
|
|
2552
|
-
secretKey: storage.secretKey
|
|
2553
|
-
}),
|
|
2554
|
-
bucket: storage.bucket,
|
|
2555
|
-
...storage.publicEndpoint ? { publicEndpoint: storage.publicEndpoint } : {}
|
|
2556
|
-
};
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
2822
|
// src/commands/connect/webide-message-log.ts
|
|
2560
2823
|
var SYNC_INTERVAL_MS = 2e3;
|
|
2561
2824
|
function webIdeEventsObjectPrefix(taskId, messageId) {
|
|
@@ -2965,7 +3228,7 @@ function readCliVersion() {
|
|
|
2965
3228
|
}
|
|
2966
3229
|
|
|
2967
3230
|
// src/commands/sync-webide-attachments.ts
|
|
2968
|
-
import { existsSync as
|
|
3231
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
2969
3232
|
import { join as join5 } from "path";
|
|
2970
3233
|
var MANIFEST_FILE = ".sync-manifest.json";
|
|
2971
3234
|
async function downloadAttachment(cfg, attachmentId) {
|
|
@@ -2983,7 +3246,7 @@ async function downloadAttachment(cfg, attachmentId) {
|
|
|
2983
3246
|
}
|
|
2984
3247
|
function loadManifest(dir) {
|
|
2985
3248
|
const path3 = join5(dir, MANIFEST_FILE);
|
|
2986
|
-
if (!
|
|
3249
|
+
if (!existsSync7(path3)) {
|
|
2987
3250
|
return { version: 1, attachments: {} };
|
|
2988
3251
|
}
|
|
2989
3252
|
try {
|
|
@@ -3006,7 +3269,7 @@ function saveManifest(dir, manifest) {
|
|
|
3006
3269
|
);
|
|
3007
3270
|
}
|
|
3008
3271
|
function isAttachmentUpToDate(entry, item, dest) {
|
|
3009
|
-
if (!entry || !
|
|
3272
|
+
if (!entry || !existsSync7(dest)) return false;
|
|
3010
3273
|
if (entry.name !== item.name) return false;
|
|
3011
3274
|
const createdAt = item.createdAt ?? "";
|
|
3012
3275
|
return entry.createdAt === createdAt;
|
|
@@ -3053,14 +3316,14 @@ async function syncWebIdeAttachments(cfg, taskId, workdir, attachments) {
|
|
|
3053
3316
|
|
|
3054
3317
|
// src/utils/project-documents.ts
|
|
3055
3318
|
import {
|
|
3056
|
-
existsSync as
|
|
3319
|
+
existsSync as existsSync8,
|
|
3057
3320
|
readdirSync as readdirSync3,
|
|
3058
3321
|
readFileSync as readFileSync7,
|
|
3059
3322
|
rmSync as rmSync2,
|
|
3060
3323
|
writeFileSync as writeFileSync5
|
|
3061
3324
|
} from "fs";
|
|
3062
|
-
import { createHash } from "crypto";
|
|
3063
|
-
import { dirname as dirname5, join as join6, relative as
|
|
3325
|
+
import { createHash as createHash2 } from "crypto";
|
|
3326
|
+
import { dirname as dirname5, join as join6, relative as relative4, sep } from "path";
|
|
3064
3327
|
var MANIFEST_FILE2 = "manifest.json";
|
|
3065
3328
|
function normalizeProjectIdForPath(projectId) {
|
|
3066
3329
|
const id = projectId.trim();
|
|
@@ -3095,14 +3358,14 @@ function normalizeLocalDocumentPath(path3) {
|
|
|
3095
3358
|
return segments.join("/");
|
|
3096
3359
|
}
|
|
3097
3360
|
function hashLocalFileContent(content) {
|
|
3098
|
-
return
|
|
3361
|
+
return createHash2("sha256").update(content, "utf8").digest("hex");
|
|
3099
3362
|
}
|
|
3100
3363
|
function readLocalManifest(apmRoot, projectId) {
|
|
3101
3364
|
const manifestPath3 = join6(
|
|
3102
3365
|
projectDocumentsDir(apmRoot, projectId),
|
|
3103
3366
|
MANIFEST_FILE2
|
|
3104
3367
|
);
|
|
3105
|
-
if (!
|
|
3368
|
+
if (!existsSync8(manifestPath3)) {
|
|
3106
3369
|
return null;
|
|
3107
3370
|
}
|
|
3108
3371
|
try {
|
|
@@ -3115,7 +3378,7 @@ function readLocalManifest(apmRoot, projectId) {
|
|
|
3115
3378
|
}
|
|
3116
3379
|
function listLocalDocumentPaths(apmRoot, projectId) {
|
|
3117
3380
|
const root = projectDocumentsDir(apmRoot, projectId);
|
|
3118
|
-
if (!
|
|
3381
|
+
if (!existsSync8(root)) {
|
|
3119
3382
|
return [];
|
|
3120
3383
|
}
|
|
3121
3384
|
const paths = [];
|
|
@@ -3129,7 +3392,7 @@ function listLocalDocumentPaths(apmRoot, projectId) {
|
|
|
3129
3392
|
if (entry.isFile() && entry.name === MANIFEST_FILE2) {
|
|
3130
3393
|
continue;
|
|
3131
3394
|
}
|
|
3132
|
-
const rel =
|
|
3395
|
+
const rel = relative4(root, abs).split(sep).join("/");
|
|
3133
3396
|
paths.push(rel);
|
|
3134
3397
|
}
|
|
3135
3398
|
};
|
|
@@ -3250,7 +3513,7 @@ ${diagnostic ?? ""}`);
|
|
|
3250
3513
|
const absPath = toFsPath(
|
|
3251
3514
|
projectDocumentLocalPath(targetApmDir, projectId, path3)
|
|
3252
3515
|
);
|
|
3253
|
-
if (
|
|
3516
|
+
if (existsSync8(absPath)) {
|
|
3254
3517
|
rmSync2(absPath, { force: true });
|
|
3255
3518
|
deleted += 1;
|
|
3256
3519
|
}
|
|
@@ -3320,7 +3583,7 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
3320
3583
|
}
|
|
3321
3584
|
|
|
3322
3585
|
// src/commands/connect/cli-version-sync.ts
|
|
3323
|
-
import { existsSync as
|
|
3586
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
3324
3587
|
import { join as join7 } from "path";
|
|
3325
3588
|
var CLI_VERSION_FILE = ".cli-version.json";
|
|
3326
3589
|
function manifestPath2(apmDir) {
|
|
@@ -3328,7 +3591,7 @@ function manifestPath2(apmDir) {
|
|
|
3328
3591
|
}
|
|
3329
3592
|
function loadManifest2(apmDir) {
|
|
3330
3593
|
const path3 = toFsPath(manifestPath2(apmDir));
|
|
3331
|
-
if (!
|
|
3594
|
+
if (!existsSync9(path3)) {
|
|
3332
3595
|
return null;
|
|
3333
3596
|
}
|
|
3334
3597
|
try {
|
|
@@ -4016,14 +4279,14 @@ async function handleStartProject(cfg, msg, signal) {
|
|
|
4016
4279
|
}
|
|
4017
4280
|
|
|
4018
4281
|
// src/commands/connect/upload-package-artifact.ts
|
|
4019
|
-
import
|
|
4020
|
-
import
|
|
4282
|
+
import fs2 from "node:fs";
|
|
4283
|
+
import path2 from "node:path";
|
|
4021
4284
|
function packageTmpDir(packageId) {
|
|
4022
4285
|
return `/data/package-tmp/${packageId}`;
|
|
4023
4286
|
}
|
|
4024
4287
|
function expectedLocalArtifactPath(target, packageId) {
|
|
4025
4288
|
const fileName = target === "frontend" ? "dist.zip" : "jars.zip";
|
|
4026
|
-
return
|
|
4289
|
+
return path2.join(packageTmpDir(packageId), fileName);
|
|
4027
4290
|
}
|
|
4028
4291
|
function packageArtifactObjectKey(target, projectId, timestampMs = Date.now()) {
|
|
4029
4292
|
const folder = target === "frontend" ? "vue" : "java";
|
|
@@ -4033,7 +4296,7 @@ function packageArtifactObjectKey(target, projectId, timestampMs = Date.now()) {
|
|
|
4033
4296
|
function removePackageTmpDir(packageId) {
|
|
4034
4297
|
const dir = packageTmpDir(packageId);
|
|
4035
4298
|
try {
|
|
4036
|
-
|
|
4299
|
+
fs2.rmSync(dir, { recursive: true, force: true });
|
|
4037
4300
|
} catch (err) {
|
|
4038
4301
|
console.warn(
|
|
4039
4302
|
`[apm] \u6E05\u7406\u6253\u5305\u4E34\u65F6\u76EE\u5F55\u5931\u8D25 ${dir}:`,
|
|
@@ -4043,10 +4306,10 @@ function removePackageTmpDir(packageId) {
|
|
|
4043
4306
|
}
|
|
4044
4307
|
async function uploadPackageArtifact(cfg, target, packageId, projectId) {
|
|
4045
4308
|
const localPath = expectedLocalArtifactPath(target, packageId);
|
|
4046
|
-
if (!
|
|
4309
|
+
if (!fs2.existsSync(localPath)) {
|
|
4047
4310
|
throw new Error(`\u6253\u5305\u4EA7\u7269\u4E0D\u5B58\u5728: ${localPath}`);
|
|
4048
4311
|
}
|
|
4049
|
-
const stat =
|
|
4312
|
+
const stat = fs2.statSync(localPath);
|
|
4050
4313
|
if (!stat.isFile() || stat.size <= 0) {
|
|
4051
4314
|
throw new Error(`\u6253\u5305\u4EA7\u7269\u65E0\u6548\u6216\u4E3A\u7A7A: ${localPath}`);
|
|
4052
4315
|
}
|
|
@@ -4062,151 +4325,6 @@ async function uploadPackageArtifact(cfg, target, packageId, projectId) {
|
|
|
4062
4325
|
return { artifactPath: objectKey, artifactUrl };
|
|
4063
4326
|
}
|
|
4064
4327
|
|
|
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
|
-
|
|
4210
4328
|
// src/commands/connect/handle-package.ts
|
|
4211
4329
|
async function updatePackageStatus(cfg, packageId, status, extra) {
|
|
4212
4330
|
const api = createApmApiClient(cfg);
|
|
@@ -4337,21 +4455,6 @@ async function handleWebIdePackage(cfg, msg, signal) {
|
|
|
4337
4455
|
return `downloaded=${result.downloaded} deleted=${result.deleted}`;
|
|
4338
4456
|
}
|
|
4339
4457
|
);
|
|
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
|
-
}
|
|
4355
4458
|
eventSession.addCliStep("\u542F\u52A8\u6253\u5305 Agent", "\u51C6\u5907 create\u2026", "running");
|
|
4356
4459
|
await syncPrepLog();
|
|
4357
4460
|
let failedByTool = false;
|
|
@@ -4376,6 +4479,7 @@ async function handleWebIdePackage(cfg, msg, signal) {
|
|
|
4376
4479
|
enableSandbox: false,
|
|
4377
4480
|
enablePackageStatusTools: true,
|
|
4378
4481
|
packageId,
|
|
4482
|
+
projectId,
|
|
4379
4483
|
onPackageFailed: async () => {
|
|
4380
4484
|
failedByTool = true;
|
|
4381
4485
|
},
|
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`、**禁止**把 SQL 打进 jars.zip、**禁止**在规则或命令里写死具体 jar 名。
|
|
43
|
+
2. **只**收集 deploy 文档标明的交付 jar(路径/文件名/glob 以文档为准)。**禁止**全量收集 `target/lib`、**禁止**把 SQL 打进 jars.zip、**禁止**在规则或命令里写死具体 jar 名。
|
|
44
44
|
3. 确认文档列出的每个 jar 均已生成;缺任一文件 → SetPackageFailed。
|
|
45
45
|
4. 在临时目录将上述 jar **打成一个 zip**(勿在工作区生成交付 zip),落到:
|
|
46
46
|
|
|
@@ -57,7 +57,11 @@
|
|
|
57
57
|
zip /data/package-tmp/<packageId>/jars.zip ./*.jar
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
5.
|
|
60
|
+
5. **SQL 镜像上传**(deploy 打包章节写有「SQL脚本目录」时必须做;无则跳过):
|
|
61
|
+
- 从「进入 `xxx` 目录」取 `repo`(如 `mmis-java`)
|
|
62
|
+
- 从「SQL脚本目录」取相对路径(去掉末尾 `/**/*.sql`),拼成工作区内 **绝对路径** `localDir`
|
|
63
|
+
- 调用 **UploadPackageSql**(`repo` + `localDir`);工具会同步该目录下全部 `**/*.sql` 到 MinIO `packages/{projectId}/{repo}/...`
|
|
64
|
+
- **禁止**猜测路径;**禁止**把 SQL 打进 jars.zip
|
|
61
65
|
6. 构建或落盘失败 → 调用 **SetPackageFailed**(传入失败原因)后结束。
|
|
62
66
|
|
|
63
67
|
### 结束
|