ai-project-manage-cli 7.1.12 → 7.1.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/README.md +1 -1
- package/dist/index.js +1531 -607
- package/dist/webide-message-worker.js +382 -160
- package/package.json +1 -1
- package/template/AGENTS.md +4 -4
- package/template/rules/webide_merge.md +5 -28
- package/template/rules/webide_terminal.md +37 -0
package/dist/index.js
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res, err) => function __init() {
|
|
5
|
+
if (err) throw err[0];
|
|
6
|
+
try {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
} catch (e) {
|
|
9
|
+
throw err = [e], e;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
5
16
|
|
|
6
17
|
// src/config.ts
|
|
7
18
|
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
8
19
|
import { homedir } from "os";
|
|
9
20
|
import { join } from "path";
|
|
10
|
-
var APM_CONFIG_DIR = join(homedir(), ".config", "apm");
|
|
11
|
-
var APM_CONFIG_PATH = join(APM_CONFIG_DIR, "config.json");
|
|
12
|
-
var DEFAULT_BASE_URL = "http://127.0.0.1:3000";
|
|
13
21
|
function resolveClientMachineId(cfg) {
|
|
14
22
|
return (cfg.clientMachineId ?? cfg.userId ?? "").trim();
|
|
15
23
|
}
|
|
@@ -78,12 +86,1018 @@ function buildAgentWsUrl(httpBase, apiKey) {
|
|
|
78
86
|
const q = new URLSearchParams({ apiKey });
|
|
79
87
|
return `${origin}/ws/agent?${q.toString()}`;
|
|
80
88
|
}
|
|
89
|
+
var APM_CONFIG_DIR, APM_CONFIG_PATH, DEFAULT_BASE_URL;
|
|
90
|
+
var init_config = __esm({
|
|
91
|
+
"src/config.ts"() {
|
|
92
|
+
"use strict";
|
|
93
|
+
APM_CONFIG_DIR = join(homedir(), ".config", "apm");
|
|
94
|
+
APM_CONFIG_PATH = join(APM_CONFIG_DIR, "config.json");
|
|
95
|
+
DEFAULT_BASE_URL = "http://127.0.0.1:3000";
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// src/api/request-config.ts
|
|
100
|
+
import { defineEndpoint } from "listpage-http";
|
|
101
|
+
var requestConfig;
|
|
102
|
+
var init_request_config = __esm({
|
|
103
|
+
"src/api/request-config.ts"() {
|
|
104
|
+
"use strict";
|
|
105
|
+
requestConfig = {
|
|
106
|
+
cli: {
|
|
107
|
+
me: defineEndpoint(
|
|
108
|
+
{
|
|
109
|
+
method: "GET",
|
|
110
|
+
path: "/cli/me"
|
|
111
|
+
}
|
|
112
|
+
),
|
|
113
|
+
sessionDetail: defineEndpoint({
|
|
114
|
+
method: "GET",
|
|
115
|
+
path: "/cli/sessions/detail"
|
|
116
|
+
}),
|
|
117
|
+
sessionMembers: defineEndpoint({
|
|
118
|
+
method: "GET",
|
|
119
|
+
path: "/cli/sessions/members"
|
|
120
|
+
}),
|
|
121
|
+
listSessionMessages: defineEndpoint({
|
|
122
|
+
method: "GET",
|
|
123
|
+
path: "/cli/messages"
|
|
124
|
+
}),
|
|
125
|
+
listDocuments: defineEndpoint({
|
|
126
|
+
method: "GET",
|
|
127
|
+
path: "/cli/documents"
|
|
128
|
+
}),
|
|
129
|
+
getDevGate: defineEndpoint({
|
|
130
|
+
method: "GET",
|
|
131
|
+
path: "/cli/dev-gate"
|
|
132
|
+
}),
|
|
133
|
+
listAttachments: defineEndpoint(
|
|
134
|
+
{
|
|
135
|
+
method: "GET",
|
|
136
|
+
path: "/cli/attachments"
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
upsertDocument: defineEndpoint({
|
|
140
|
+
method: "PUT",
|
|
141
|
+
path: "/cli/documents/upsert"
|
|
142
|
+
}),
|
|
143
|
+
appendMessageContent: defineEndpoint({
|
|
144
|
+
method: "PUT",
|
|
145
|
+
path: "/cli/messages/content"
|
|
146
|
+
}),
|
|
147
|
+
setMessageError: defineEndpoint({
|
|
148
|
+
method: "PUT",
|
|
149
|
+
path: "/cli/messages/error"
|
|
150
|
+
}),
|
|
151
|
+
upsertCursorMessageLog: defineEndpoint({
|
|
152
|
+
method: "PUT",
|
|
153
|
+
path: "/cli/cursor-message-logs"
|
|
154
|
+
}),
|
|
155
|
+
updateMessageStatus: defineEndpoint({
|
|
156
|
+
method: "PUT",
|
|
157
|
+
path: "/cli/messages/status"
|
|
158
|
+
}),
|
|
159
|
+
webideAppendMessageContent: defineEndpoint({
|
|
160
|
+
method: "PUT",
|
|
161
|
+
path: "/cli/webide/messages/content"
|
|
162
|
+
}),
|
|
163
|
+
webideEnsureMessageContent: defineEndpoint({
|
|
164
|
+
method: "PUT",
|
|
165
|
+
path: "/cli/webide/messages/ensure-content"
|
|
166
|
+
}),
|
|
167
|
+
webideSetMessageError: defineEndpoint({
|
|
168
|
+
method: "PUT",
|
|
169
|
+
path: "/cli/webide/messages/error"
|
|
170
|
+
}),
|
|
171
|
+
webideUpdateMessageStatus: defineEndpoint({
|
|
172
|
+
method: "PUT",
|
|
173
|
+
path: "/cli/webide/messages/status"
|
|
174
|
+
}),
|
|
175
|
+
webideUpsertMessageLog: defineEndpoint({
|
|
176
|
+
method: "PUT",
|
|
177
|
+
path: "/cli/webide/message-logs"
|
|
178
|
+
}),
|
|
179
|
+
webideReplaceAssumptions: defineEndpoint({
|
|
180
|
+
method: "PUT",
|
|
181
|
+
path: "/cli/webide/assumptions"
|
|
182
|
+
}),
|
|
183
|
+
webideListAssumptions: defineEndpoint({
|
|
184
|
+
method: "GET",
|
|
185
|
+
path: "/cli/webide/assumptions"
|
|
186
|
+
}),
|
|
187
|
+
webideRecommendPlan: defineEndpoint({
|
|
188
|
+
method: "PUT",
|
|
189
|
+
path: "/cli/webide/plan-recommendation"
|
|
190
|
+
}),
|
|
191
|
+
webideUpsertPlan: defineEndpoint({
|
|
192
|
+
method: "PUT",
|
|
193
|
+
path: "/cli/webide/plan"
|
|
194
|
+
}),
|
|
195
|
+
webideReplaceTestCases: defineEndpoint({
|
|
196
|
+
method: "PUT",
|
|
197
|
+
path: "/cli/webide/test-cases"
|
|
198
|
+
}),
|
|
199
|
+
webideListTerminals: defineEndpoint({
|
|
200
|
+
method: "GET",
|
|
201
|
+
path: "/cli/webide/terminals"
|
|
202
|
+
}),
|
|
203
|
+
webideUpsertTerminal: defineEndpoint({
|
|
204
|
+
method: "POST",
|
|
205
|
+
path: "/cli/webide/terminals"
|
|
206
|
+
}),
|
|
207
|
+
webideUpdateTerminalStatus: defineEndpoint({
|
|
208
|
+
method: "PUT",
|
|
209
|
+
path: "/cli/webide/terminals/status"
|
|
210
|
+
}),
|
|
211
|
+
webideUpdateTerminalMeta: defineEndpoint({
|
|
212
|
+
method: "PUT",
|
|
213
|
+
path: "/cli/webide/terminals/meta"
|
|
214
|
+
}),
|
|
215
|
+
acquireSteelBrowser: defineEndpoint({
|
|
216
|
+
method: "POST",
|
|
217
|
+
path: "/cli/steel-browser/acquire"
|
|
218
|
+
}),
|
|
219
|
+
branchBaseline: defineEndpoint({
|
|
220
|
+
method: "GET",
|
|
221
|
+
path: "/cli/tasks/branch-baseline"
|
|
222
|
+
}),
|
|
223
|
+
projectBaseBranch: defineEndpoint({
|
|
224
|
+
method: "GET",
|
|
225
|
+
path: "/cli/tasks/project-base-branch"
|
|
226
|
+
}),
|
|
227
|
+
listSessionsForBranchCleanup: defineEndpoint({
|
|
228
|
+
method: "GET",
|
|
229
|
+
path: "/cli/sessions/branch-cleanup"
|
|
230
|
+
}),
|
|
231
|
+
workspaceBaseline: defineEndpoint({
|
|
232
|
+
method: "GET",
|
|
233
|
+
path: "/cli/workspaces/baseline"
|
|
234
|
+
}),
|
|
235
|
+
getDeploymentConfiguration: defineEndpoint({
|
|
236
|
+
method: "GET",
|
|
237
|
+
path: "/cli/deployment-configurations"
|
|
238
|
+
}),
|
|
239
|
+
matchRepository: defineEndpoint({
|
|
240
|
+
method: "GET",
|
|
241
|
+
path: "/cli/repositories/match"
|
|
242
|
+
}),
|
|
243
|
+
listSkills: defineEndpoint({
|
|
244
|
+
method: "GET",
|
|
245
|
+
path: "/cli/skills"
|
|
246
|
+
}),
|
|
247
|
+
listRules: defineEndpoint({
|
|
248
|
+
method: "GET",
|
|
249
|
+
path: "/cli/rules"
|
|
250
|
+
}),
|
|
251
|
+
createPullRequest: defineEndpoint({
|
|
252
|
+
method: "POST",
|
|
253
|
+
path: "/cli/pull-requests"
|
|
254
|
+
}),
|
|
255
|
+
createWebIdeDraftPullRequest: defineEndpoint({
|
|
256
|
+
method: "POST",
|
|
257
|
+
path: "/cli/webide/draft-pull-requests"
|
|
258
|
+
}),
|
|
259
|
+
webideMergePullRequests: defineEndpoint({
|
|
260
|
+
method: "POST",
|
|
261
|
+
path: "/cli/webide/pull-requests/merge"
|
|
262
|
+
}),
|
|
263
|
+
getProjectDocumentManifest: defineEndpoint({
|
|
264
|
+
method: "GET",
|
|
265
|
+
path: "/cli/project-documents/manifest"
|
|
266
|
+
}),
|
|
267
|
+
listProjectDocuments: defineEndpoint({
|
|
268
|
+
method: "GET",
|
|
269
|
+
path: "/cli/project-documents"
|
|
270
|
+
}),
|
|
271
|
+
upsertProjectDocument: defineEndpoint({
|
|
272
|
+
method: "PUT",
|
|
273
|
+
path: "/cli/project-documents/upsert"
|
|
274
|
+
}),
|
|
275
|
+
removeProjectDocument: defineEndpoint({
|
|
276
|
+
method: "DELETE",
|
|
277
|
+
path: "/cli/project-documents"
|
|
278
|
+
}),
|
|
279
|
+
createTaskDeployment: defineEndpoint({
|
|
280
|
+
method: "POST",
|
|
281
|
+
path: "/cli/task-deployments"
|
|
282
|
+
}),
|
|
283
|
+
updateTaskDeploymentStatus: defineEndpoint({
|
|
284
|
+
method: "PUT",
|
|
285
|
+
path: "/cli/task-deployments/status"
|
|
286
|
+
}),
|
|
287
|
+
syncTaskDeploymentLog: defineEndpoint({
|
|
288
|
+
method: "PUT",
|
|
289
|
+
path: "/cli/task-deployments/log"
|
|
290
|
+
}),
|
|
291
|
+
completeTaskDeployment: defineEndpoint({
|
|
292
|
+
method: "PUT",
|
|
293
|
+
path: "/cli/task-deployments/complete"
|
|
294
|
+
}),
|
|
295
|
+
getDeployArtifactStorage: defineEndpoint(
|
|
296
|
+
{
|
|
297
|
+
method: "GET",
|
|
298
|
+
path: "/cli/deploy-artifact-storage"
|
|
299
|
+
}
|
|
300
|
+
),
|
|
301
|
+
attachTaskDeploymentArtifact: defineEndpoint({
|
|
302
|
+
method: "PUT",
|
|
303
|
+
path: "/cli/task-deployments/artifact"
|
|
304
|
+
})
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// src/api/client.ts
|
|
311
|
+
import { createApiClient } from "listpage-http";
|
|
312
|
+
function createApmApiClient(cfg) {
|
|
313
|
+
const baseURL = `${cfg.baseUrl.trim().replace(/\/+$/, "")}/api/v1`;
|
|
314
|
+
return createApiClient(requestConfig, {
|
|
315
|
+
baseURL,
|
|
316
|
+
getToken: () => resolveApiKey(cfg) || void 0,
|
|
317
|
+
successCodes: [0],
|
|
318
|
+
unauthorizedCodes: [401]
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
var init_client = __esm({
|
|
322
|
+
"src/api/client.ts"() {
|
|
323
|
+
"use strict";
|
|
324
|
+
init_request_config();
|
|
325
|
+
init_config();
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// src/commands/deploy/internal/minio.ts
|
|
330
|
+
import { statSync as statSync5 } from "node:fs";
|
|
331
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
332
|
+
import path from "node:path";
|
|
333
|
+
import * as Minio from "minio";
|
|
334
|
+
async function isDirectoryPath(dir) {
|
|
335
|
+
try {
|
|
336
|
+
const st = statSync5(dir);
|
|
337
|
+
return st.isDirectory();
|
|
338
|
+
} catch {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function sanitizeRelativePath(rel) {
|
|
343
|
+
const norm = rel.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
344
|
+
const segments = norm.split("/").filter(Boolean);
|
|
345
|
+
for (const s of segments) {
|
|
346
|
+
if (s === "." || s === "..") {
|
|
347
|
+
throw new Error(`\u975E\u6CD5\u76F8\u5BF9\u8DEF\u5F84\u7247\u6BB5\uFF1A${s}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return segments.join("/");
|
|
351
|
+
}
|
|
352
|
+
async function collectFiles(root) {
|
|
353
|
+
const out = [];
|
|
354
|
+
async function walk(dir, prefix) {
|
|
355
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
356
|
+
for (const e of entries) {
|
|
357
|
+
const name = e.name;
|
|
358
|
+
if (name === "." || name === "..") {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const abs = path.join(dir, name);
|
|
362
|
+
const rel = prefix ? `${prefix}/${name}` : name;
|
|
363
|
+
if (e.isDirectory()) {
|
|
364
|
+
await walk(abs, rel);
|
|
365
|
+
} else if (e.isFile()) {
|
|
366
|
+
const st = statSync5(abs);
|
|
367
|
+
out.push({
|
|
368
|
+
absPath: abs,
|
|
369
|
+
relativePath: rel.replace(/\\/g, "/"),
|
|
370
|
+
size: st.size
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
await walk(root, "");
|
|
376
|
+
out.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
377
|
+
return out;
|
|
378
|
+
}
|
|
379
|
+
async function readArtifactFile(absPath) {
|
|
380
|
+
return readFile(absPath);
|
|
381
|
+
}
|
|
382
|
+
function toMB(bytes) {
|
|
383
|
+
return Math.round(bytes / (1024 * 1024) * 1e3) / 1e3;
|
|
384
|
+
}
|
|
385
|
+
function detectMimeType(filePath) {
|
|
386
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
387
|
+
return MIME[ext] ?? "";
|
|
388
|
+
}
|
|
389
|
+
var DEFAULT_MAX_FILE_SIZE_MB, MIME, MinioClient;
|
|
390
|
+
var init_minio = __esm({
|
|
391
|
+
"src/commands/deploy/internal/minio.ts"() {
|
|
392
|
+
"use strict";
|
|
393
|
+
DEFAULT_MAX_FILE_SIZE_MB = 50;
|
|
394
|
+
MIME = {
|
|
395
|
+
".html": "text/html; charset=utf-8",
|
|
396
|
+
".css": "text/css; charset=utf-8",
|
|
397
|
+
".js": "application/javascript; charset=utf-8",
|
|
398
|
+
".json": "application/json; charset=utf-8",
|
|
399
|
+
".svg": "image/svg+xml",
|
|
400
|
+
".png": "image/png",
|
|
401
|
+
".jpg": "image/jpeg",
|
|
402
|
+
".jpeg": "image/jpeg",
|
|
403
|
+
".gif": "image/gif",
|
|
404
|
+
".webp": "image/webp",
|
|
405
|
+
".woff": "font/woff",
|
|
406
|
+
".woff2": "font/woff2",
|
|
407
|
+
".ttf": "font/ttf",
|
|
408
|
+
".ico": "image/x-icon",
|
|
409
|
+
".txt": "text/plain; charset=utf-8",
|
|
410
|
+
".map": "application/json"
|
|
411
|
+
};
|
|
412
|
+
MinioClient = class {
|
|
413
|
+
inner;
|
|
414
|
+
constructor(opts) {
|
|
415
|
+
const endPoint = opts.endPoint.replace(/^https?:\/\//i, "").split("/")[0] ?? opts.endPoint;
|
|
416
|
+
this.inner = new Minio.Client({
|
|
417
|
+
endPoint,
|
|
418
|
+
port: opts.port,
|
|
419
|
+
useSSL: opts.useSSL,
|
|
420
|
+
accessKey: opts.accessKey,
|
|
421
|
+
secretKey: opts.secretKey
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
async ensureBucket(bucket) {
|
|
425
|
+
const exists = await this.inner.bucketExists(bucket);
|
|
426
|
+
if (!exists) {
|
|
427
|
+
await this.inner.makeBucket(bucket);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
async deleteObjectsByPrefix(bucket, prefix) {
|
|
431
|
+
const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
432
|
+
const keys = [];
|
|
433
|
+
await new Promise((resolve7, reject) => {
|
|
434
|
+
objectsStream.on("data", (obj) => {
|
|
435
|
+
if (obj.name) {
|
|
436
|
+
keys.push(obj.name);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
objectsStream.on("error", reject);
|
|
440
|
+
objectsStream.on("end", resolve7);
|
|
441
|
+
});
|
|
442
|
+
const chunkSize = 500;
|
|
443
|
+
for (let i = 0; i < keys.length; i += chunkSize) {
|
|
444
|
+
const chunk = keys.slice(i, i + chunkSize);
|
|
445
|
+
await this.inner.removeObjects(
|
|
446
|
+
bucket,
|
|
447
|
+
chunk.map((name) => name)
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
async putObject(bucket, objectKey, body, meta) {
|
|
452
|
+
await this.inner.putObject(bucket, objectKey, body, body.length, meta);
|
|
453
|
+
}
|
|
454
|
+
/** 匿名可读当前桶全部对象(便于静态站点直链) */
|
|
455
|
+
async setBucketPublicRead(bucket) {
|
|
456
|
+
const policy = {
|
|
457
|
+
Version: "2012-10-17",
|
|
458
|
+
Statement: [
|
|
459
|
+
{
|
|
460
|
+
Effect: "Allow",
|
|
461
|
+
Principal: { AWS: ["*"] },
|
|
462
|
+
Action: ["s3:GetObject"],
|
|
463
|
+
Resource: [`arn:aws:s3:::${bucket}/*`]
|
|
464
|
+
}
|
|
465
|
+
]
|
|
466
|
+
};
|
|
467
|
+
await this.inner.setBucketPolicy(bucket, JSON.stringify(policy));
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// src/commands/deploy/internal/deploy-artifact-minio.ts
|
|
474
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
475
|
+
function formatDeployArtifactTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
476
|
+
const pad2 = (n) => String(n).padStart(2, "0");
|
|
477
|
+
return `${date.getFullYear()}${pad2(date.getMonth() + 1)}${pad2(date.getDate())}${pad2(date.getHours())}${pad2(date.getMinutes())}${pad2(date.getSeconds())}`;
|
|
478
|
+
}
|
|
479
|
+
function sanitizeDeployProjectName(name) {
|
|
480
|
+
const trimmed = name.trim().replace(/\\/g, "/");
|
|
481
|
+
const base = trimmed.split("/").filter(Boolean).pop() ?? trimmed;
|
|
482
|
+
try {
|
|
483
|
+
return sanitizeRelativePath(base.replace(/[/\\:*?"<>|]/g, "_"));
|
|
484
|
+
} catch {
|
|
485
|
+
return "project";
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function buildDeployArtifactFileName(kind, projectName, timestamp = formatDeployArtifactTimestamp()) {
|
|
489
|
+
const safeName = sanitizeDeployProjectName(projectName);
|
|
490
|
+
const suffix = kind === "frontend" ? "dist.zip" : "jar.zip";
|
|
491
|
+
return `${timestamp}-${safeName}.${suffix}`;
|
|
492
|
+
}
|
|
493
|
+
function buildDeployArtifactObjectKey(projectName, fileName) {
|
|
494
|
+
const safeProject = sanitizeDeployProjectName(projectName);
|
|
495
|
+
return `deploy/${safeProject}/${fileName}`;
|
|
496
|
+
}
|
|
497
|
+
function resolveDeploymentRunIdFromEnv() {
|
|
498
|
+
const raw = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim();
|
|
499
|
+
return raw || null;
|
|
500
|
+
}
|
|
501
|
+
async function fetchDeployArtifactStorage(api) {
|
|
502
|
+
return api.cli.getDeployArtifactStorage(void 0);
|
|
503
|
+
}
|
|
504
|
+
async function uploadDeployArtifactZip(options) {
|
|
505
|
+
const deploymentRunId = options.deploymentRunId ?? resolveDeploymentRunIdFromEnv();
|
|
506
|
+
if (!deploymentRunId && !options.uploadWithoutRunId) {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
const cfg = await tryReadApmConfig();
|
|
510
|
+
if (!cfg || !resolveApiKey(cfg)) {
|
|
511
|
+
console.warn("[apm] \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7 MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863");
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
const api = options.api ?? createApmApiClient(cfg);
|
|
515
|
+
let storage;
|
|
516
|
+
try {
|
|
517
|
+
storage = await fetchDeployArtifactStorage(api);
|
|
518
|
+
} catch (error) {
|
|
519
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
520
|
+
console.warn(`[apm] \u83B7\u53D6 MinIO \u914D\u7F6E\u5931\u8D25\uFF0C\u8DF3\u8FC7\u90E8\u7F72\u4EA7\u7269\u5F52\u6863: ${detail}`);
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
const fileName = buildDeployArtifactFileName(
|
|
524
|
+
options.kind,
|
|
525
|
+
options.projectName,
|
|
526
|
+
options.timestamp
|
|
527
|
+
);
|
|
528
|
+
const objectKey = buildDeployArtifactObjectKey(options.projectName, fileName);
|
|
529
|
+
let body;
|
|
530
|
+
try {
|
|
531
|
+
body = await readFile2(options.zipPath);
|
|
532
|
+
} catch (error) {
|
|
533
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
534
|
+
console.warn(`[apm] \u8BFB\u53D6\u90E8\u7F72\u4EA7\u7269 zip \u5931\u8D25\uFF0C\u8DF3\u8FC7 MinIO \u5F52\u6863: ${detail}`);
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
try {
|
|
538
|
+
const client = new MinioClient({
|
|
539
|
+
endPoint: storage.endpoint,
|
|
540
|
+
port: storage.port,
|
|
541
|
+
useSSL: storage.useSsl,
|
|
542
|
+
accessKey: storage.accessKey,
|
|
543
|
+
secretKey: storage.secretKey
|
|
544
|
+
});
|
|
545
|
+
await client.ensureBucket(storage.bucket);
|
|
546
|
+
await client.putObject(storage.bucket, objectKey, body, {
|
|
547
|
+
"Content-Type": "application/zip"
|
|
548
|
+
});
|
|
549
|
+
console.error(
|
|
550
|
+
`[apm] \u672C\u5730\u76F4\u4F20 MinIO\uFF08\u4E0D\u7ECF\u5E73\u53F0\u670D\u52A1\u5668\uFF09: ${storage.endpoint}:${storage.port}/${storage.bucket}/${objectKey} (${(body.length / 1024 / 1024).toFixed(
|
|
551
|
+
2
|
|
552
|
+
)} MB)`
|
|
553
|
+
);
|
|
554
|
+
} catch (error) {
|
|
555
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
556
|
+
console.warn(`[apm] MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863\u5931\u8D25: ${detail}`);
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
if (deploymentRunId) {
|
|
560
|
+
try {
|
|
561
|
+
await api.cli.attachTaskDeploymentArtifact({
|
|
562
|
+
id: deploymentRunId,
|
|
563
|
+
artifactObjectKey: objectKey,
|
|
564
|
+
artifactFileName: fileName
|
|
565
|
+
});
|
|
566
|
+
console.error(
|
|
567
|
+
`[apm] \u5DF2\u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55 id=${deploymentRunId} file=${fileName}`
|
|
568
|
+
);
|
|
569
|
+
} catch (error) {
|
|
570
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
571
|
+
console.warn(`[apm] \u7ED1\u5B9A\u90E8\u7F72\u4EA7\u7269\u5230\u8BB0\u5F55\u5931\u8D25: ${detail}`);
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return {
|
|
576
|
+
objectKey,
|
|
577
|
+
fileName,
|
|
578
|
+
bucket: storage.bucket
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
var APM_DEPLOYMENT_RUN_ID_ENV;
|
|
582
|
+
var init_deploy_artifact_minio = __esm({
|
|
583
|
+
"src/commands/deploy/internal/deploy-artifact-minio.ts"() {
|
|
584
|
+
"use strict";
|
|
585
|
+
init_client();
|
|
586
|
+
init_config();
|
|
587
|
+
init_minio();
|
|
588
|
+
init_minio();
|
|
589
|
+
APM_DEPLOYMENT_RUN_ID_ENV = "APM_DEPLOYMENT_RUN_ID";
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
// src/commands/connect/webide-terminal-registry.ts
|
|
594
|
+
var webide_terminal_registry_exports = {};
|
|
595
|
+
__export(webide_terminal_registry_exports, {
|
|
596
|
+
WEBIDE_TERMINAL_LINES_PER_CHUNK: () => WEBIDE_TERMINAL_LINES_PER_CHUNK,
|
|
597
|
+
WebIdeTerminalRegistry: () => WebIdeTerminalRegistry,
|
|
598
|
+
getWebIdeTerminalRegistry: () => getWebIdeTerminalRegistry
|
|
599
|
+
});
|
|
600
|
+
import { spawn } from "node:child_process";
|
|
601
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
602
|
+
import { promisify as promisify3 } from "node:util";
|
|
603
|
+
function taskKey(taskId, key) {
|
|
604
|
+
return `${taskId}\0${key}`;
|
|
605
|
+
}
|
|
606
|
+
function chunkKey(prefix, chunkIndex) {
|
|
607
|
+
return `${prefix}chunks/${String(chunkIndex).padStart(6, "0")}.json`;
|
|
608
|
+
}
|
|
609
|
+
function extractPortsAndUrl(text) {
|
|
610
|
+
const ports = /* @__PURE__ */ new Set();
|
|
611
|
+
let primaryUrl = null;
|
|
612
|
+
let m;
|
|
613
|
+
const re = new RegExp(PORT_URL_RE.source, "gi");
|
|
614
|
+
while ((m = re.exec(text)) !== null) {
|
|
615
|
+
const urlCandidate = m[2];
|
|
616
|
+
if (urlCandidate) {
|
|
617
|
+
primaryUrl = primaryUrl ?? urlCandidate.replace(/[),.;]+$/, "");
|
|
618
|
+
try {
|
|
619
|
+
const u = new URL(primaryUrl);
|
|
620
|
+
if (u.port) ports.add(Number(u.port));
|
|
621
|
+
else if (u.protocol === "https:") ports.add(443);
|
|
622
|
+
else ports.add(80);
|
|
623
|
+
} catch {
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
for (const g of [m[1], m[3], m[4]]) {
|
|
627
|
+
if (g) {
|
|
628
|
+
const p = Number(g);
|
|
629
|
+
if (p > 0 && p < 65536) ports.add(p);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const httpMatch = text.match(/https?:\/\/[^\s)'"]+/i);
|
|
634
|
+
if (httpMatch && !primaryUrl) {
|
|
635
|
+
primaryUrl = httpMatch[0].replace(/[),.;]+$/, "");
|
|
636
|
+
}
|
|
637
|
+
return { ports: [...ports].sort((a, b) => a - b), primaryUrl };
|
|
638
|
+
}
|
|
639
|
+
function killProcessTree(pid) {
|
|
640
|
+
try {
|
|
641
|
+
process.kill(-pid, "SIGTERM");
|
|
642
|
+
} catch {
|
|
643
|
+
try {
|
|
644
|
+
process.kill(pid, "SIGTERM");
|
|
645
|
+
} catch {
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
function forceKillProcessTree(pid) {
|
|
650
|
+
try {
|
|
651
|
+
process.kill(-pid, "SIGKILL");
|
|
652
|
+
} catch {
|
|
653
|
+
try {
|
|
654
|
+
process.kill(pid, "SIGKILL");
|
|
655
|
+
} catch {
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async function listProcessTreePids(rootPid) {
|
|
660
|
+
const pids = [rootPid];
|
|
661
|
+
const queue = [rootPid];
|
|
662
|
+
while (queue.length > 0) {
|
|
663
|
+
const parent = queue.shift();
|
|
664
|
+
try {
|
|
665
|
+
const { stdout } = await execFileAsync3("pgrep", ["-P", String(parent)], {
|
|
666
|
+
timeout: 2e3
|
|
667
|
+
});
|
|
668
|
+
for (const line of stdout.split("\n")) {
|
|
669
|
+
const child = Number(line.trim());
|
|
670
|
+
if (child > 0 && !pids.includes(child)) {
|
|
671
|
+
pids.push(child);
|
|
672
|
+
queue.push(child);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
} catch {
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return pids;
|
|
679
|
+
}
|
|
680
|
+
async function probeListenPorts(pid) {
|
|
681
|
+
try {
|
|
682
|
+
const treePids = await listProcessTreePids(pid);
|
|
683
|
+
const { stdout } = await execFileAsync3(
|
|
684
|
+
"lsof",
|
|
685
|
+
["-nP", "-a", `-p${treePids.join(",")}`, "-iTCP", "-sTCP:LISTEN"],
|
|
686
|
+
{ timeout: 3e3, maxBuffer: 1024 * 1024 }
|
|
687
|
+
);
|
|
688
|
+
const ports = /* @__PURE__ */ new Set();
|
|
689
|
+
for (const line of stdout.split("\n")) {
|
|
690
|
+
const m = line.match(/:(\d+)\s+\(LISTEN\)/);
|
|
691
|
+
if (m) {
|
|
692
|
+
const p = Number(m[1]);
|
|
693
|
+
if (p > 0 && p < 65536) ports.add(p);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return [...ports].sort((a, b) => a - b);
|
|
697
|
+
} catch {
|
|
698
|
+
return [];
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
function getWebIdeTerminalRegistry(cfg) {
|
|
702
|
+
if (!registrySingleton) {
|
|
703
|
+
registrySingleton = new WebIdeTerminalRegistry(cfg);
|
|
704
|
+
}
|
|
705
|
+
return registrySingleton;
|
|
706
|
+
}
|
|
707
|
+
var execFileAsync3, WEBIDE_TERMINAL_LINES_PER_CHUNK, SYNC_INTERVAL_MS, PORT_PROBE_INTERVAL_MS, STOP_SIGKILL_MS, PORT_URL_RE, WebIdeTerminalRegistry, registrySingleton;
|
|
708
|
+
var init_webide_terminal_registry = __esm({
|
|
709
|
+
"src/commands/connect/webide-terminal-registry.ts"() {
|
|
710
|
+
"use strict";
|
|
711
|
+
init_client();
|
|
712
|
+
init_deploy_artifact_minio();
|
|
713
|
+
init_minio();
|
|
714
|
+
execFileAsync3 = promisify3(execFile3);
|
|
715
|
+
WEBIDE_TERMINAL_LINES_PER_CHUNK = 50;
|
|
716
|
+
SYNC_INTERVAL_MS = 400;
|
|
717
|
+
PORT_PROBE_INTERVAL_MS = 2e3;
|
|
718
|
+
STOP_SIGKILL_MS = 5e3;
|
|
719
|
+
PORT_URL_RE = /(?:https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::(\d+))?|(?:Local|Network):\s*(https?:\/\/\S+)|listening\s+(?:on\s+)?(?:port\s+)?(\d+)|(?:port|PORT)\s*[:=]\s*(\d+))/gi;
|
|
720
|
+
WebIdeTerminalRegistry = class {
|
|
721
|
+
constructor(cfg) {
|
|
722
|
+
this.cfg = cfg;
|
|
723
|
+
}
|
|
724
|
+
cfg;
|
|
725
|
+
byId = /* @__PURE__ */ new Map();
|
|
726
|
+
byTaskKey = /* @__PURE__ */ new Map();
|
|
727
|
+
minio;
|
|
728
|
+
bucket = "";
|
|
729
|
+
async ensureMinio() {
|
|
730
|
+
if (this.minio) return;
|
|
731
|
+
const storage = await fetchDeployArtifactStorage(
|
|
732
|
+
createApmApiClient(this.cfg)
|
|
733
|
+
);
|
|
734
|
+
this.minio = new MinioClient({
|
|
735
|
+
endPoint: storage.endpoint,
|
|
736
|
+
port: storage.port,
|
|
737
|
+
useSSL: storage.useSsl,
|
|
738
|
+
accessKey: storage.accessKey,
|
|
739
|
+
secretKey: storage.secretKey
|
|
740
|
+
});
|
|
741
|
+
this.bucket = storage.bucket;
|
|
742
|
+
await this.minio.ensureBucket(this.bucket);
|
|
743
|
+
}
|
|
744
|
+
listLocal(taskId) {
|
|
745
|
+
const alive = [
|
|
746
|
+
"STARTING",
|
|
747
|
+
"RUNNING",
|
|
748
|
+
"READY",
|
|
749
|
+
"STOPPING"
|
|
750
|
+
];
|
|
751
|
+
const sessions = [...this.byId.values()].filter(
|
|
752
|
+
(s) => alive.includes(s.status)
|
|
753
|
+
);
|
|
754
|
+
return (taskId ? sessions.filter((s) => s.taskId === taskId) : sessions).map((s) => ({
|
|
755
|
+
id: s.id,
|
|
756
|
+
taskId: s.taskId,
|
|
757
|
+
key: s.key,
|
|
758
|
+
name: s.name,
|
|
759
|
+
status: s.status,
|
|
760
|
+
pid: s.pid,
|
|
761
|
+
ports: s.ports,
|
|
762
|
+
primaryUrl: s.primaryUrl,
|
|
763
|
+
nextSeq: s.nextSeq,
|
|
764
|
+
command: s.command,
|
|
765
|
+
cwd: s.cwd
|
|
766
|
+
}));
|
|
767
|
+
}
|
|
768
|
+
async start(opts) {
|
|
769
|
+
const key = opts.key.trim();
|
|
770
|
+
const existingId = this.byTaskKey.get(taskKey(opts.taskId, key));
|
|
771
|
+
const existing = existingId ? this.byId.get(existingId) : void 0;
|
|
772
|
+
if (existing?.child && (existing.status === "RUNNING" || existing.status === "READY" || existing.status === "STARTING")) {
|
|
773
|
+
return {
|
|
774
|
+
ok: true,
|
|
775
|
+
idempotent: true,
|
|
776
|
+
terminalId: existing.id,
|
|
777
|
+
status: existing.status,
|
|
778
|
+
pid: existing.pid,
|
|
779
|
+
ports: existing.ports,
|
|
780
|
+
primaryUrl: existing.primaryUrl
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
const api = createApmApiClient(this.cfg);
|
|
784
|
+
const upserted = await api.cli.webideUpsertTerminal({
|
|
785
|
+
taskId: opts.taskId,
|
|
786
|
+
key,
|
|
787
|
+
name: opts.name ?? key,
|
|
788
|
+
cwd: opts.cwd,
|
|
789
|
+
command: opts.command,
|
|
790
|
+
readyPattern: opts.readyPattern,
|
|
791
|
+
portsHint: opts.portsHint
|
|
792
|
+
});
|
|
793
|
+
const terminalId = upserted.id;
|
|
794
|
+
const objectPrefix = upserted.objectPrefix?.trim() || `terminals/${opts.taskId}/${terminalId}/`;
|
|
795
|
+
if (existing?.child) {
|
|
796
|
+
await this.stop(terminalId, { reason: "restart" });
|
|
797
|
+
}
|
|
798
|
+
const session = {
|
|
799
|
+
id: terminalId,
|
|
800
|
+
taskId: opts.taskId,
|
|
801
|
+
key,
|
|
802
|
+
name: (opts.name ?? key).trim() || key,
|
|
803
|
+
cwd: opts.cwd,
|
|
804
|
+
command: opts.command,
|
|
805
|
+
readyPattern: opts.readyPattern?.trim() || null,
|
|
806
|
+
status: "STARTING",
|
|
807
|
+
pid: null,
|
|
808
|
+
ports: opts.portsHint ? [...opts.portsHint] : [],
|
|
809
|
+
primaryUrl: null,
|
|
810
|
+
nextSeq: typeof upserted.nextSeq === "number" ? upserted.nextSeq : 0,
|
|
811
|
+
chunkCount: typeof upserted.chunkCount === "number" ? upserted.chunkCount : 0,
|
|
812
|
+
objectPrefix,
|
|
813
|
+
child: null,
|
|
814
|
+
stopping: false,
|
|
815
|
+
pendingLines: [],
|
|
816
|
+
syncChain: Promise.resolve()
|
|
817
|
+
};
|
|
818
|
+
this.byId.set(terminalId, session);
|
|
819
|
+
this.byTaskKey.set(taskKey(opts.taskId, key), terminalId);
|
|
820
|
+
this.pushSystemLine(
|
|
821
|
+
session,
|
|
822
|
+
`[apm] starting: ${opts.command} (cwd=${opts.cwd})`
|
|
823
|
+
);
|
|
824
|
+
const child = spawn(opts.command, {
|
|
825
|
+
cwd: opts.cwd,
|
|
826
|
+
shell: true,
|
|
827
|
+
detached: true,
|
|
828
|
+
env: process.env,
|
|
829
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
830
|
+
});
|
|
831
|
+
session.child = child;
|
|
832
|
+
session.pid = child.pid ?? null;
|
|
833
|
+
session.status = "RUNNING";
|
|
834
|
+
await api.cli.webideUpdateTerminalStatus({
|
|
835
|
+
id: terminalId,
|
|
836
|
+
status: "RUNNING",
|
|
837
|
+
pid: session.pid,
|
|
838
|
+
ports: session.ports,
|
|
839
|
+
primaryUrl: null
|
|
840
|
+
});
|
|
841
|
+
const onData = (stream) => (buf) => {
|
|
842
|
+
const text = buf.toString("utf8");
|
|
843
|
+
for (const line of text.split(/\r?\n/)) {
|
|
844
|
+
if (!line.length && text.endsWith("\n") === false) continue;
|
|
845
|
+
if (line.length === 0) continue;
|
|
846
|
+
this.pushLine(session, stream, line);
|
|
847
|
+
}
|
|
848
|
+
this.scheduleSync(session);
|
|
849
|
+
this.maybeUpdatePortsFromText(session, text);
|
|
850
|
+
};
|
|
851
|
+
child.stdout?.on("data", onData("stdout"));
|
|
852
|
+
child.stderr?.on("data", onData("stderr"));
|
|
853
|
+
child.on("exit", (code, signal) => {
|
|
854
|
+
void this.onExit(session, code, signal);
|
|
855
|
+
});
|
|
856
|
+
session.portTimer = setInterval(() => {
|
|
857
|
+
void this.probePorts(session);
|
|
858
|
+
}, PORT_PROBE_INTERVAL_MS);
|
|
859
|
+
this.scheduleSync(session);
|
|
860
|
+
return {
|
|
861
|
+
ok: true,
|
|
862
|
+
idempotent: false,
|
|
863
|
+
terminalId,
|
|
864
|
+
status: session.status,
|
|
865
|
+
pid: session.pid,
|
|
866
|
+
ports: session.ports,
|
|
867
|
+
primaryUrl: session.primaryUrl
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
async stop(terminalId, opts) {
|
|
871
|
+
const session = this.byId.get(terminalId);
|
|
872
|
+
const api = createApmApiClient(this.cfg);
|
|
873
|
+
if (!session) {
|
|
874
|
+
const pid2 = opts?.pid;
|
|
875
|
+
if (typeof pid2 === "number" && pid2 > 0) {
|
|
876
|
+
killProcessTree(pid2);
|
|
877
|
+
setTimeout(() => forceKillProcessTree(pid2), STOP_SIGKILL_MS);
|
|
878
|
+
}
|
|
879
|
+
try {
|
|
880
|
+
await api.cli.webideUpdateTerminalStatus({
|
|
881
|
+
id: terminalId,
|
|
882
|
+
status: "EXITED",
|
|
883
|
+
lastError: opts?.reason ?? "stopped"
|
|
884
|
+
});
|
|
885
|
+
} catch {
|
|
886
|
+
}
|
|
887
|
+
return { ok: true, terminalId, status: "EXITED" };
|
|
888
|
+
}
|
|
889
|
+
if (session.status === "EXITED" || session.status === "FAILED" || session.stopping) {
|
|
890
|
+
return { ok: true, terminalId, status: session.status };
|
|
891
|
+
}
|
|
892
|
+
session.stopping = true;
|
|
893
|
+
session.status = "STOPPING";
|
|
894
|
+
this.pushSystemLine(
|
|
895
|
+
session,
|
|
896
|
+
`[apm] stopping${opts?.reason ? `: ${opts.reason}` : ""}`
|
|
897
|
+
);
|
|
898
|
+
this.scheduleSync(session);
|
|
899
|
+
try {
|
|
900
|
+
await api.cli.webideUpdateTerminalStatus({
|
|
901
|
+
id: terminalId,
|
|
902
|
+
status: "STOPPING",
|
|
903
|
+
pid: session.pid
|
|
904
|
+
});
|
|
905
|
+
} catch {
|
|
906
|
+
}
|
|
907
|
+
const pid = session.pid ?? opts?.pid ?? null;
|
|
908
|
+
if (session.child && !session.child.killed) {
|
|
909
|
+
try {
|
|
910
|
+
if (session.child.pid) killProcessTree(session.child.pid);
|
|
911
|
+
} catch {
|
|
912
|
+
}
|
|
913
|
+
} else if (typeof pid === "number" && pid > 0) {
|
|
914
|
+
killProcessTree(pid);
|
|
915
|
+
}
|
|
916
|
+
const killPid = session.child?.pid ?? pid;
|
|
917
|
+
if (typeof killPid === "number" && killPid > 0) {
|
|
918
|
+
setTimeout(() => {
|
|
919
|
+
if (session.child && !session.child.killed) {
|
|
920
|
+
forceKillProcessTree(killPid);
|
|
921
|
+
}
|
|
922
|
+
}, STOP_SIGKILL_MS);
|
|
923
|
+
}
|
|
924
|
+
return { ok: true, terminalId, status: "STOPPING" };
|
|
925
|
+
}
|
|
926
|
+
async stopAllForTask(taskId, reason = "cache-cleanup") {
|
|
927
|
+
const ids = [...this.byId.values()].filter((s) => s.taskId === taskId).map((s) => s.id);
|
|
928
|
+
for (const id of ids) {
|
|
929
|
+
await this.stop(id, { reason });
|
|
930
|
+
}
|
|
931
|
+
return { ok: true, stopped: ids.length };
|
|
932
|
+
}
|
|
933
|
+
pushSystemLine(session, text) {
|
|
934
|
+
this.pushLine(session, "system", text);
|
|
935
|
+
}
|
|
936
|
+
pushLine(session, stream, text) {
|
|
937
|
+
session.nextSeq += 1;
|
|
938
|
+
session.pendingLines.push({
|
|
939
|
+
seq: session.nextSeq,
|
|
940
|
+
stream,
|
|
941
|
+
text,
|
|
942
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
maybeUpdatePortsFromText(session, text) {
|
|
946
|
+
const { ports, primaryUrl } = extractPortsAndUrl(text);
|
|
947
|
+
let changed = false;
|
|
948
|
+
for (const p of ports) {
|
|
949
|
+
if (!session.ports.includes(p)) {
|
|
950
|
+
session.ports.push(p);
|
|
951
|
+
changed = true;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
session.ports.sort((a, b) => a - b);
|
|
955
|
+
if (primaryUrl && !session.primaryUrl) {
|
|
956
|
+
session.primaryUrl = primaryUrl;
|
|
957
|
+
changed = true;
|
|
958
|
+
}
|
|
959
|
+
if (changed) {
|
|
960
|
+
void this.syncStatus(session);
|
|
961
|
+
}
|
|
962
|
+
if (session.readyPattern && session.status === "RUNNING" && new RegExp(session.readyPattern).test(text)) {
|
|
963
|
+
session.status = "READY";
|
|
964
|
+
void this.syncStatus(session);
|
|
965
|
+
} else if (session.status === "RUNNING" && (session.ports.length > 0 || session.primaryUrl)) {
|
|
966
|
+
session.status = "READY";
|
|
967
|
+
void this.syncStatus(session);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
async probePorts(session) {
|
|
971
|
+
if (session.status !== "RUNNING" && session.status !== "STARTING" && session.status !== "READY") {
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
if (!session.pid) return;
|
|
975
|
+
const ports = await probeListenPorts(session.pid);
|
|
976
|
+
if (ports.length === 0) return;
|
|
977
|
+
const same = ports.length === session.ports.length && ports.every((p, i) => p === session.ports[i]);
|
|
978
|
+
if (same) return;
|
|
979
|
+
session.ports = ports;
|
|
980
|
+
if (!session.primaryUrl && session.ports[0]) {
|
|
981
|
+
session.primaryUrl = `http://127.0.0.1:${session.ports[0]}`;
|
|
982
|
+
}
|
|
983
|
+
if (session.status === "RUNNING" || session.status === "STARTING") {
|
|
984
|
+
session.status = "READY";
|
|
985
|
+
}
|
|
986
|
+
void this.syncStatus(session);
|
|
987
|
+
}
|
|
988
|
+
async syncStatus(session) {
|
|
989
|
+
const api = createApmApiClient(this.cfg);
|
|
990
|
+
try {
|
|
991
|
+
await api.cli.webideUpdateTerminalStatus({
|
|
992
|
+
id: session.id,
|
|
993
|
+
status: session.status,
|
|
994
|
+
pid: session.pid,
|
|
995
|
+
ports: session.ports,
|
|
996
|
+
primaryUrl: session.primaryUrl
|
|
997
|
+
});
|
|
998
|
+
} catch (err) {
|
|
999
|
+
console.warn(
|
|
1000
|
+
"[apm] terminal status sync failed:",
|
|
1001
|
+
err instanceof Error ? err.message : err
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
scheduleSync(session) {
|
|
1006
|
+
if (session.syncTimer) return;
|
|
1007
|
+
session.syncTimer = setTimeout(() => {
|
|
1008
|
+
session.syncTimer = void 0;
|
|
1009
|
+
session.syncChain = session.syncChain.then(() => this.flushPending(session)).catch((err) => {
|
|
1010
|
+
console.warn(
|
|
1011
|
+
"[apm] terminal log flush failed:",
|
|
1012
|
+
err instanceof Error ? err.message : err
|
|
1013
|
+
);
|
|
1014
|
+
});
|
|
1015
|
+
}, SYNC_INTERVAL_MS);
|
|
1016
|
+
}
|
|
1017
|
+
async flushPending(session) {
|
|
1018
|
+
if (session.pendingLines.length === 0) return;
|
|
1019
|
+
const batch = session.pendingLines.splice(0, session.pendingLines.length);
|
|
1020
|
+
await this.ensureMinio();
|
|
1021
|
+
const seqStart = batch[0].seq;
|
|
1022
|
+
const seqEnd = batch.at(-1).seq;
|
|
1023
|
+
const ci = session.chunkCount;
|
|
1024
|
+
const key = chunkKey(session.objectPrefix, ci);
|
|
1025
|
+
const body = Buffer.from(
|
|
1026
|
+
JSON.stringify({ seqStart, seqEnd, lines: batch }),
|
|
1027
|
+
"utf8"
|
|
1028
|
+
);
|
|
1029
|
+
await this.minio.putObject(this.bucket, key, body, {
|
|
1030
|
+
"Content-Type": "application/json"
|
|
1031
|
+
});
|
|
1032
|
+
session.chunkCount = ci + 1;
|
|
1033
|
+
const api = createApmApiClient(this.cfg);
|
|
1034
|
+
await api.cli.webideUpdateTerminalMeta({
|
|
1035
|
+
id: session.id,
|
|
1036
|
+
nextSeq: session.nextSeq,
|
|
1037
|
+
chunkCount: session.chunkCount
|
|
1038
|
+
});
|
|
1039
|
+
if (!session.stopping && (session.status === "RUNNING" || session.status === "READY")) {
|
|
1040
|
+
try {
|
|
1041
|
+
const listed = await api.cli.webideListTerminals({
|
|
1042
|
+
taskId: session.taskId
|
|
1043
|
+
});
|
|
1044
|
+
const remote = listed.terminals?.find((t) => t.id === session.id);
|
|
1045
|
+
if (remote?.status === "STOPPING") {
|
|
1046
|
+
await this.stop(session.id, {
|
|
1047
|
+
pid: remote.pid ?? session.pid,
|
|
1048
|
+
reason: "server STOPPING"
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
} catch {
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
async onExit(session, code, signal) {
|
|
1056
|
+
if (session.portTimer) {
|
|
1057
|
+
clearInterval(session.portTimer);
|
|
1058
|
+
session.portTimer = void 0;
|
|
1059
|
+
}
|
|
1060
|
+
session.child = null;
|
|
1061
|
+
const exitCode = code ?? (signal ? 1 : 0);
|
|
1062
|
+
session.status = session.stopping || exitCode === 0 ? "EXITED" : "FAILED";
|
|
1063
|
+
this.pushSystemLine(
|
|
1064
|
+
session,
|
|
1065
|
+
`[apm] exited code=${exitCode}${signal ? ` signal=${signal}` : ""}`
|
|
1066
|
+
);
|
|
1067
|
+
await session.syncChain;
|
|
1068
|
+
await this.flushPending(session);
|
|
1069
|
+
const api = createApmApiClient(this.cfg);
|
|
1070
|
+
try {
|
|
1071
|
+
await api.cli.webideUpdateTerminalStatus({
|
|
1072
|
+
id: session.id,
|
|
1073
|
+
status: session.status,
|
|
1074
|
+
pid: session.pid,
|
|
1075
|
+
exitCode,
|
|
1076
|
+
ports: session.ports,
|
|
1077
|
+
primaryUrl: session.primaryUrl
|
|
1078
|
+
});
|
|
1079
|
+
} catch (err) {
|
|
1080
|
+
console.warn(
|
|
1081
|
+
"[apm] terminal exit status sync failed:",
|
|
1082
|
+
err instanceof Error ? err.message : err
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
registrySingleton = null;
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
// src/index.ts
|
|
1092
|
+
import { Command } from "commander";
|
|
1093
|
+
init_config();
|
|
81
1094
|
|
|
82
1095
|
// src/commands/init.ts
|
|
83
1096
|
import { join as join5 } from "path";
|
|
84
1097
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
85
1098
|
|
|
86
1099
|
// src/command-utils.ts
|
|
1100
|
+
init_config();
|
|
87
1101
|
import {
|
|
88
1102
|
copyFileSync,
|
|
89
1103
|
existsSync,
|
|
@@ -367,204 +1381,10 @@ async function copyTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
|
367
1381
|
}
|
|
368
1382
|
|
|
369
1383
|
// src/deployment-config-sync.ts
|
|
1384
|
+
init_client();
|
|
370
1385
|
import { join as join3 } from "path";
|
|
371
1386
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
372
1387
|
|
|
373
|
-
// src/api/client.ts
|
|
374
|
-
import { createApiClient } from "listpage-http";
|
|
375
|
-
|
|
376
|
-
// src/api/request-config.ts
|
|
377
|
-
import { defineEndpoint } from "listpage-http";
|
|
378
|
-
var requestConfig = {
|
|
379
|
-
cli: {
|
|
380
|
-
me: defineEndpoint(
|
|
381
|
-
{
|
|
382
|
-
method: "GET",
|
|
383
|
-
path: "/cli/me"
|
|
384
|
-
}
|
|
385
|
-
),
|
|
386
|
-
sessionDetail: defineEndpoint({
|
|
387
|
-
method: "GET",
|
|
388
|
-
path: "/cli/sessions/detail"
|
|
389
|
-
}),
|
|
390
|
-
sessionMembers: defineEndpoint({
|
|
391
|
-
method: "GET",
|
|
392
|
-
path: "/cli/sessions/members"
|
|
393
|
-
}),
|
|
394
|
-
listSessionMessages: defineEndpoint({
|
|
395
|
-
method: "GET",
|
|
396
|
-
path: "/cli/messages"
|
|
397
|
-
}),
|
|
398
|
-
listDocuments: defineEndpoint({
|
|
399
|
-
method: "GET",
|
|
400
|
-
path: "/cli/documents"
|
|
401
|
-
}),
|
|
402
|
-
getDevGate: defineEndpoint({
|
|
403
|
-
method: "GET",
|
|
404
|
-
path: "/cli/dev-gate"
|
|
405
|
-
}),
|
|
406
|
-
listAttachments: defineEndpoint(
|
|
407
|
-
{
|
|
408
|
-
method: "GET",
|
|
409
|
-
path: "/cli/attachments"
|
|
410
|
-
}
|
|
411
|
-
),
|
|
412
|
-
upsertDocument: defineEndpoint({
|
|
413
|
-
method: "PUT",
|
|
414
|
-
path: "/cli/documents/upsert"
|
|
415
|
-
}),
|
|
416
|
-
appendMessageContent: defineEndpoint({
|
|
417
|
-
method: "PUT",
|
|
418
|
-
path: "/cli/messages/content"
|
|
419
|
-
}),
|
|
420
|
-
setMessageError: defineEndpoint({
|
|
421
|
-
method: "PUT",
|
|
422
|
-
path: "/cli/messages/error"
|
|
423
|
-
}),
|
|
424
|
-
upsertCursorMessageLog: defineEndpoint({
|
|
425
|
-
method: "PUT",
|
|
426
|
-
path: "/cli/cursor-message-logs"
|
|
427
|
-
}),
|
|
428
|
-
updateMessageStatus: defineEndpoint({
|
|
429
|
-
method: "PUT",
|
|
430
|
-
path: "/cli/messages/status"
|
|
431
|
-
}),
|
|
432
|
-
webideAppendMessageContent: defineEndpoint({
|
|
433
|
-
method: "PUT",
|
|
434
|
-
path: "/cli/webide/messages/content"
|
|
435
|
-
}),
|
|
436
|
-
webideEnsureMessageContent: defineEndpoint({
|
|
437
|
-
method: "PUT",
|
|
438
|
-
path: "/cli/webide/messages/ensure-content"
|
|
439
|
-
}),
|
|
440
|
-
webideSetMessageError: defineEndpoint({
|
|
441
|
-
method: "PUT",
|
|
442
|
-
path: "/cli/webide/messages/error"
|
|
443
|
-
}),
|
|
444
|
-
webideUpdateMessageStatus: defineEndpoint({
|
|
445
|
-
method: "PUT",
|
|
446
|
-
path: "/cli/webide/messages/status"
|
|
447
|
-
}),
|
|
448
|
-
webideUpsertMessageLog: defineEndpoint({
|
|
449
|
-
method: "PUT",
|
|
450
|
-
path: "/cli/webide/message-logs"
|
|
451
|
-
}),
|
|
452
|
-
webideReplaceAssumptions: defineEndpoint({
|
|
453
|
-
method: "PUT",
|
|
454
|
-
path: "/cli/webide/assumptions"
|
|
455
|
-
}),
|
|
456
|
-
webideListAssumptions: defineEndpoint({
|
|
457
|
-
method: "GET",
|
|
458
|
-
path: "/cli/webide/assumptions"
|
|
459
|
-
}),
|
|
460
|
-
webideRecommendPlan: defineEndpoint({
|
|
461
|
-
method: "PUT",
|
|
462
|
-
path: "/cli/webide/plan-recommendation"
|
|
463
|
-
}),
|
|
464
|
-
webideUpsertPlan: defineEndpoint({
|
|
465
|
-
method: "PUT",
|
|
466
|
-
path: "/cli/webide/plan"
|
|
467
|
-
}),
|
|
468
|
-
webideReplaceTestCases: defineEndpoint({
|
|
469
|
-
method: "PUT",
|
|
470
|
-
path: "/cli/webide/test-cases"
|
|
471
|
-
}),
|
|
472
|
-
branchBaseline: defineEndpoint({
|
|
473
|
-
method: "GET",
|
|
474
|
-
path: "/cli/tasks/branch-baseline"
|
|
475
|
-
}),
|
|
476
|
-
listSessionsForBranchCleanup: defineEndpoint({
|
|
477
|
-
method: "GET",
|
|
478
|
-
path: "/cli/sessions/branch-cleanup"
|
|
479
|
-
}),
|
|
480
|
-
workspaceBaseline: defineEndpoint({
|
|
481
|
-
method: "GET",
|
|
482
|
-
path: "/cli/workspaces/baseline"
|
|
483
|
-
}),
|
|
484
|
-
getDeploymentConfiguration: defineEndpoint({
|
|
485
|
-
method: "GET",
|
|
486
|
-
path: "/cli/deployment-configurations"
|
|
487
|
-
}),
|
|
488
|
-
matchRepository: defineEndpoint({
|
|
489
|
-
method: "GET",
|
|
490
|
-
path: "/cli/repositories/match"
|
|
491
|
-
}),
|
|
492
|
-
listSkills: defineEndpoint({
|
|
493
|
-
method: "GET",
|
|
494
|
-
path: "/cli/skills"
|
|
495
|
-
}),
|
|
496
|
-
listRules: defineEndpoint({
|
|
497
|
-
method: "GET",
|
|
498
|
-
path: "/cli/rules"
|
|
499
|
-
}),
|
|
500
|
-
createPullRequest: defineEndpoint({
|
|
501
|
-
method: "POST",
|
|
502
|
-
path: "/cli/pull-requests"
|
|
503
|
-
}),
|
|
504
|
-
createWebIdeDraftPullRequest: defineEndpoint({
|
|
505
|
-
method: "POST",
|
|
506
|
-
path: "/cli/webide/draft-pull-requests"
|
|
507
|
-
}),
|
|
508
|
-
webideMergePullRequests: defineEndpoint({
|
|
509
|
-
method: "POST",
|
|
510
|
-
path: "/cli/webide/pull-requests/merge"
|
|
511
|
-
}),
|
|
512
|
-
getRepositoryProjectDocumentManifest: defineEndpoint({
|
|
513
|
-
method: "GET",
|
|
514
|
-
path: "/cli/repository-project-documents/manifest"
|
|
515
|
-
}),
|
|
516
|
-
listRepositoryProjectDocuments: defineEndpoint({
|
|
517
|
-
method: "GET",
|
|
518
|
-
path: "/cli/repository-project-documents"
|
|
519
|
-
}),
|
|
520
|
-
upsertRepositoryProjectDocument: defineEndpoint({
|
|
521
|
-
method: "PUT",
|
|
522
|
-
path: "/cli/repository-project-documents/upsert"
|
|
523
|
-
}),
|
|
524
|
-
removeRepositoryProjectDocument: defineEndpoint({
|
|
525
|
-
method: "DELETE",
|
|
526
|
-
path: "/cli/repository-project-documents"
|
|
527
|
-
}),
|
|
528
|
-
createTaskDeployment: defineEndpoint({
|
|
529
|
-
method: "POST",
|
|
530
|
-
path: "/cli/task-deployments"
|
|
531
|
-
}),
|
|
532
|
-
updateTaskDeploymentStatus: defineEndpoint({
|
|
533
|
-
method: "PUT",
|
|
534
|
-
path: "/cli/task-deployments/status"
|
|
535
|
-
}),
|
|
536
|
-
syncTaskDeploymentLog: defineEndpoint({
|
|
537
|
-
method: "PUT",
|
|
538
|
-
path: "/cli/task-deployments/log"
|
|
539
|
-
}),
|
|
540
|
-
completeTaskDeployment: defineEndpoint({
|
|
541
|
-
method: "PUT",
|
|
542
|
-
path: "/cli/task-deployments/complete"
|
|
543
|
-
}),
|
|
544
|
-
getDeployArtifactStorage: defineEndpoint(
|
|
545
|
-
{
|
|
546
|
-
method: "GET",
|
|
547
|
-
path: "/cli/deploy-artifact-storage"
|
|
548
|
-
}
|
|
549
|
-
),
|
|
550
|
-
attachTaskDeploymentArtifact: defineEndpoint({
|
|
551
|
-
method: "PUT",
|
|
552
|
-
path: "/cli/task-deployments/artifact"
|
|
553
|
-
})
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
|
|
557
|
-
// src/api/client.ts
|
|
558
|
-
function createApmApiClient(cfg) {
|
|
559
|
-
const baseURL = `${cfg.baseUrl.trim().replace(/\/+$/, "")}/api/v1`;
|
|
560
|
-
return createApiClient(requestConfig, {
|
|
561
|
-
baseURL,
|
|
562
|
-
getToken: () => resolveApiKey(cfg) || void 0,
|
|
563
|
-
successCodes: [0],
|
|
564
|
-
unauthorizedCodes: [401]
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
|
|
568
1388
|
// src/git-remote.ts
|
|
569
1389
|
import { execFile } from "child_process";
|
|
570
1390
|
import { promisify } from "util";
|
|
@@ -769,6 +1589,7 @@ async function resolveBranchBaseline(api, sessionId, workdirPath) {
|
|
|
769
1589
|
}
|
|
770
1590
|
|
|
771
1591
|
// src/deployment-config-sync.ts
|
|
1592
|
+
init_config();
|
|
772
1593
|
var TEMPLATE_HINT = "\u4FDD\u7559\u6A21\u677F .apm/apm.config.json";
|
|
773
1594
|
var SYNC_HINT = "\u767B\u8BB0\u5DE5\u4F5C\u7A7A\u95F4\u8DEF\u5F84\u3001\u7ED1\u5B9A\u4ED3\u5E93\u540E\uFF0C\u53EF\u6267\u884C: apm sync-deploy-config";
|
|
774
1595
|
async function resolveRepositoryIdForSync(api, workdirPath) {
|
|
@@ -831,7 +1652,9 @@ ${diagnostic ?? ""}
|
|
|
831
1652
|
return { synced: true, repositoryId, configName: config.name };
|
|
832
1653
|
}
|
|
833
1654
|
|
|
834
|
-
// src/
|
|
1655
|
+
// src/project-documents-sync.ts
|
|
1656
|
+
init_client();
|
|
1657
|
+
init_config();
|
|
835
1658
|
import {
|
|
836
1659
|
existsSync as existsSync2,
|
|
837
1660
|
readdirSync as readdirSync2,
|
|
@@ -843,7 +1666,7 @@ import { createHash } from "crypto";
|
|
|
843
1666
|
import { dirname as dirname2, join as join4, relative, sep } from "path";
|
|
844
1667
|
var MANIFEST_FILE = "manifest.json";
|
|
845
1668
|
function projectDocumentsDir(apmRoot) {
|
|
846
|
-
return join4(apmRoot ?? workspaceApmDir(), "
|
|
1669
|
+
return join4(apmRoot ?? workspaceApmDir(), "docs");
|
|
847
1670
|
}
|
|
848
1671
|
function projectDocumentLocalPath(apmRoot, documentPath) {
|
|
849
1672
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
@@ -918,43 +1741,67 @@ function diffManifestPaths(remote, local) {
|
|
|
918
1741
|
deleteLocal.push(path19);
|
|
919
1742
|
}
|
|
920
1743
|
}
|
|
921
|
-
return { download, deleteLocal };
|
|
1744
|
+
return { download, deleteLocal };
|
|
1745
|
+
}
|
|
1746
|
+
async function resolveProjectIdForSync(api, workdirPath) {
|
|
1747
|
+
try {
|
|
1748
|
+
const baseline = await api.cli.workspaceBaseline({ workdirPath });
|
|
1749
|
+
const projectId = baseline.projectId?.trim() || null;
|
|
1750
|
+
if (projectId) {
|
|
1751
|
+
return { projectId, diagnostic: null };
|
|
1752
|
+
}
|
|
1753
|
+
const projectIds = baseline.projectIds ?? [];
|
|
1754
|
+
if (projectIds.length === 0) {
|
|
1755
|
+
return {
|
|
1756
|
+
projectId: null,
|
|
1757
|
+
diagnostic: baseline.diagnostic?.message ?? `\u5DE5\u4F5C\u7A7A\u95F4\u672A\u5173\u8054\u9879\u76EE\uFF0C\u65E0\u6CD5\u540C\u6B65\u9879\u76EE\u6587\u6863\uFF08\u76EE\u5F55\uFF1A${workdirPath}\uFF09\u3002
|
|
1758
|
+
\u8BF7\u5728\u5E73\u53F0\u5C06\u5DE5\u4F5C\u7A7A\u95F4\u5173\u8054\u5230\u552F\u4E00\u9879\u76EE\u3002`
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
return {
|
|
1762
|
+
projectId: null,
|
|
1763
|
+
diagnostic: `\u5DE5\u4F5C\u7A7A\u95F4\u5173\u8054\u4E86 ${projectIds.length} \u4E2A\u9879\u76EE\uFF0C\u65E0\u6CD5\u786E\u5B9A\u540C\u6B65\u76EE\u6807\u3002
|
|
1764
|
+
\u8BF7\u786E\u4FDD\u8BE5\u5DE5\u4F5C\u7A7A\u95F4\u53EA\u5173\u8054\u4E00\u4E2A\u9879\u76EE\u540E\u518D\u540C\u6B65\u9879\u76EE\u6587\u6863\u3002`
|
|
1765
|
+
};
|
|
1766
|
+
} catch (err) {
|
|
1767
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
1768
|
+
return {
|
|
1769
|
+
projectId: null,
|
|
1770
|
+
diagnostic: detail.replace(/^\[apm\]\s*/, "")
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
922
1773
|
}
|
|
923
|
-
async function
|
|
1774
|
+
async function syncProjectDocumentsPull(workdirPath, apmDir) {
|
|
924
1775
|
const empty = {
|
|
925
1776
|
synced: false,
|
|
926
|
-
|
|
1777
|
+
projectId: null,
|
|
927
1778
|
downloaded: 0,
|
|
928
1779
|
deleted: 0
|
|
929
1780
|
};
|
|
930
1781
|
const cfg = await tryReadApmConfig();
|
|
931
1782
|
if (!cfg || !resolveApiKey(cfg)) {
|
|
932
1783
|
console.log(
|
|
933
|
-
"[apm] \u672A\u68C0\u6D4B\u5230\u767B\u5F55\u4FE1\u606F\uFF0C\u8DF3\u8FC7\
|
|
1784
|
+
"[apm] \u672A\u68C0\u6D4B\u5230\u767B\u5F55\u4FE1\u606F\uFF0C\u8DF3\u8FC7\u9879\u76EE\u6587\u6863\u540C\u6B65\u3002\n[apm] \u8BF7\u5148\u6267\u884C apm login\u3002"
|
|
934
1785
|
);
|
|
935
1786
|
return empty;
|
|
936
1787
|
}
|
|
937
1788
|
const api = createApmApiClient(cfg);
|
|
938
|
-
const {
|
|
1789
|
+
const { projectId, diagnostic } = await resolveProjectIdForSync(
|
|
939
1790
|
api,
|
|
940
1791
|
workdirPath
|
|
941
1792
|
);
|
|
942
|
-
if (!
|
|
943
|
-
console.log(
|
|
944
|
-
|
|
945
|
-
${diagnostic ?? ""}`
|
|
946
|
-
);
|
|
1793
|
+
if (!projectId) {
|
|
1794
|
+
console.log(`[apm] \u672A\u80FD\u540C\u6B65\u9879\u76EE\u6587\u6863\u3002
|
|
1795
|
+
${diagnostic ?? ""}`);
|
|
947
1796
|
return empty;
|
|
948
1797
|
}
|
|
949
1798
|
const targetApmDir = apmDir ?? workspaceApmDir(workdirPath);
|
|
950
|
-
const
|
|
951
|
-
await ensureDirExists(
|
|
952
|
-
const { manifest: remoteManifest } = await api.cli.
|
|
1799
|
+
const docsDir = projectDocumentsDir(targetApmDir);
|
|
1800
|
+
await ensureDirExists(docsDir);
|
|
1801
|
+
const { manifest: remoteManifest } = await api.cli.getProjectDocumentManifest({ projectId });
|
|
953
1802
|
if (!remoteManifest) {
|
|
954
|
-
console.log(
|
|
955
|
-
|
|
956
|
-
);
|
|
957
|
-
return { ...empty, repositoryId };
|
|
1803
|
+
console.log(`[apm] \u9879\u76EE ${projectId} \u65E0\u9879\u76EE\u6587\u6863 manifest\uFF0C\u8DF3\u8FC7\u540C\u6B65\u3002`);
|
|
1804
|
+
return { ...empty, projectId };
|
|
958
1805
|
}
|
|
959
1806
|
const localManifest = readLocalManifest(targetApmDir);
|
|
960
1807
|
const { download, deleteLocal } = diffManifestPaths(
|
|
@@ -963,12 +1810,14 @@ ${diagnostic ?? ""}`
|
|
|
963
1810
|
);
|
|
964
1811
|
let downloaded = 0;
|
|
965
1812
|
if (download.length > 0) {
|
|
966
|
-
const { list } = await api.cli.
|
|
967
|
-
|
|
1813
|
+
const { list } = await api.cli.listProjectDocuments({
|
|
1814
|
+
projectId,
|
|
968
1815
|
paths: download.join(",")
|
|
969
1816
|
});
|
|
970
1817
|
for (const doc of list) {
|
|
971
|
-
const absPath = toFsPath(
|
|
1818
|
+
const absPath = toFsPath(
|
|
1819
|
+
projectDocumentLocalPath(targetApmDir, doc.path)
|
|
1820
|
+
);
|
|
972
1821
|
await ensureDirExists(dirname2(absPath));
|
|
973
1822
|
writeFileSync4(absPath, doc.content, "utf8");
|
|
974
1823
|
downloaded += 1;
|
|
@@ -983,34 +1832,34 @@ ${diagnostic ?? ""}`
|
|
|
983
1832
|
}
|
|
984
1833
|
}
|
|
985
1834
|
writeFileSync4(
|
|
986
|
-
toFsPath(join4(
|
|
1835
|
+
toFsPath(join4(docsDir, MANIFEST_FILE)),
|
|
987
1836
|
`${JSON.stringify(remoteManifest, null, 2)}
|
|
988
1837
|
`,
|
|
989
1838
|
"utf8"
|
|
990
1839
|
);
|
|
991
1840
|
console.log(
|
|
992
|
-
`[apm] \u5DF2\u540C\u6B65\
|
|
1841
|
+
`[apm] \u5DF2\u540C\u6B65\u9879\u76EE\u6587\u6863: \u4E0B\u8F7D ${downloaded}\uFF0C\u5220\u9664\u672C\u5730 ${deleted}`
|
|
993
1842
|
);
|
|
994
1843
|
return {
|
|
995
1844
|
synced: true,
|
|
996
|
-
|
|
1845
|
+
projectId,
|
|
997
1846
|
downloaded,
|
|
998
1847
|
deleted
|
|
999
1848
|
};
|
|
1000
1849
|
}
|
|
1001
|
-
async function
|
|
1850
|
+
async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot) {
|
|
1002
1851
|
const api = createApmApiClient(cfg);
|
|
1003
|
-
const {
|
|
1004
|
-
if (!
|
|
1852
|
+
const { projectId } = await resolveProjectIdForSync(api, workdirPath);
|
|
1853
|
+
if (!projectId) {
|
|
1005
1854
|
return 0;
|
|
1006
1855
|
}
|
|
1007
1856
|
const targetApmDir = apmRoot ?? workspaceApmDir(workdirPath);
|
|
1008
1857
|
const localPaths = listLocalDocumentPaths(targetApmDir);
|
|
1009
1858
|
if (localPaths.length === 0) {
|
|
1010
|
-
console.log("[apm] \
|
|
1859
|
+
console.log("[apm] \u9879\u76EE\u6587\u6863\u65E0\u672C\u5730\u6587\u4EF6\uFF0C\u8DF3\u8FC7\u63A8\u9001");
|
|
1011
1860
|
return 0;
|
|
1012
1861
|
}
|
|
1013
|
-
const remoteManifest = (await api.cli.
|
|
1862
|
+
const remoteManifest = (await api.cli.getProjectDocumentManifest({ projectId })).manifest ?? null;
|
|
1014
1863
|
const remoteHashByPath = new Map(
|
|
1015
1864
|
(remoteManifest?.documents ?? []).map((doc) => [doc.path, doc.contentHash])
|
|
1016
1865
|
);
|
|
@@ -1028,17 +1877,17 @@ async function syncRepositoryProjectDocumentsPush(cfg, workdirPath, apmRoot) {
|
|
|
1028
1877
|
if (remoteHashByPath.get(path19) === contentHash) {
|
|
1029
1878
|
continue;
|
|
1030
1879
|
}
|
|
1031
|
-
await api.cli.
|
|
1032
|
-
|
|
1880
|
+
await api.cli.upsertProjectDocument({
|
|
1881
|
+
projectId,
|
|
1033
1882
|
path: path19,
|
|
1034
1883
|
content,
|
|
1035
1884
|
description: remoteDescriptionByPath.get(path19) ?? void 0
|
|
1036
1885
|
});
|
|
1037
1886
|
synced += 1;
|
|
1038
|
-
console.log(`[apm] \u5DF2\u540C\u6B65\
|
|
1887
|
+
console.log(`[apm] \u5DF2\u540C\u6B65\u9879\u76EE\u6587\u6863: ${path19}`);
|
|
1039
1888
|
}
|
|
1040
1889
|
if (synced === 0) {
|
|
1041
|
-
console.log("[apm] \
|
|
1890
|
+
console.log("[apm] \u9879\u76EE\u6587\u6863\u65E0\u53D8\u5316\uFF0C\u8DF3\u8FC7\u63A8\u9001");
|
|
1042
1891
|
}
|
|
1043
1892
|
return synced;
|
|
1044
1893
|
}
|
|
@@ -1059,7 +1908,7 @@ async function ensureWorkspaceInitialized(workdir, options) {
|
|
|
1059
1908
|
const apmDir = workspaceApmDir(workdir);
|
|
1060
1909
|
await copyTemplateFiles(apmDir, workdir);
|
|
1061
1910
|
const syncResult = await syncRemoteDeploymentConfig(workdir, apmDir);
|
|
1062
|
-
await
|
|
1911
|
+
await syncProjectDocumentsPull(workdir, apmDir);
|
|
1063
1912
|
const trimmedName = options?.name?.trim();
|
|
1064
1913
|
if (trimmedName) {
|
|
1065
1914
|
const apmConfigPath = toFsPath(join5(apmDir, "apm.config.json"));
|
|
@@ -1097,6 +1946,8 @@ async function runInit(name) {
|
|
|
1097
1946
|
}
|
|
1098
1947
|
|
|
1099
1948
|
// src/commands/login.ts
|
|
1949
|
+
init_config();
|
|
1950
|
+
init_client();
|
|
1100
1951
|
import { existsSync as existsSync3 } from "fs";
|
|
1101
1952
|
import { ApiError } from "listpage-http";
|
|
1102
1953
|
async function runLogin(opts) {
|
|
@@ -1158,6 +2009,7 @@ async function runLogin(opts) {
|
|
|
1158
2009
|
}
|
|
1159
2010
|
|
|
1160
2011
|
// src/commands/branch.ts
|
|
2012
|
+
init_client();
|
|
1161
2013
|
var SESSION_BRANCH_PREFIX = "feat/session-";
|
|
1162
2014
|
function branchNameForSession(sessionId) {
|
|
1163
2015
|
const id = sessionId.trim();
|
|
@@ -1281,6 +2133,9 @@ async function runBranch(sessionId, options = {}) {
|
|
|
1281
2133
|
return ensureFeatureBranch(branch, baseline.defaultBranch, options);
|
|
1282
2134
|
}
|
|
1283
2135
|
|
|
2136
|
+
// src/commands/clean-branches.ts
|
|
2137
|
+
init_client();
|
|
2138
|
+
|
|
1284
2139
|
// src/commands/session-branch-prune.ts
|
|
1285
2140
|
var TASK_STATUS_LABEL = {
|
|
1286
2141
|
OPEN: "\u5F85\u5F00\u59CB",
|
|
@@ -1603,6 +2458,7 @@ async function runCleanBranches(options = {}) {
|
|
|
1603
2458
|
}
|
|
1604
2459
|
|
|
1605
2460
|
// src/commands/pull.ts
|
|
2461
|
+
init_client();
|
|
1606
2462
|
import { writeFileSync as writeFileSync9 } from "fs";
|
|
1607
2463
|
import { join as join9 } from "path";
|
|
1608
2464
|
import { stringify as yamlStringify } from "yaml";
|
|
@@ -1713,6 +2569,7 @@ async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
|
|
|
1713
2569
|
}
|
|
1714
2570
|
|
|
1715
2571
|
// src/rules-sync.ts
|
|
2572
|
+
init_client();
|
|
1716
2573
|
import { basename as basename2, extname as extname2, join as join8 } from "path";
|
|
1717
2574
|
import { existsSync as existsSync6, readFileSync as readFileSync6, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
1718
2575
|
|
|
@@ -1965,7 +2822,7 @@ async function runPull(sessionId, remoteWorkdir) {
|
|
|
1965
2822
|
await syncSessionAttachments(cfg, trimmedId, attachments, apmRoot);
|
|
1966
2823
|
await syncPlatformRules(cfg, trimmedId, workdir, apmRoot);
|
|
1967
2824
|
await syncRemoteDeploymentConfig(workdir, apmRoot);
|
|
1968
|
-
await
|
|
2825
|
+
await syncProjectDocumentsPull(workdir, apmRoot);
|
|
1969
2826
|
console.log(`[apm] \u5DF2\u540C\u6B65\u4F1A\u8BDD\u5DE5\u4F5C\u533A: ${dir}`);
|
|
1970
2827
|
return dir;
|
|
1971
2828
|
}
|
|
@@ -2135,6 +2992,7 @@ async function runUpdate(options = {}) {
|
|
|
2135
2992
|
}
|
|
2136
2993
|
|
|
2137
2994
|
// src/commands/update-skills.ts
|
|
2995
|
+
init_client();
|
|
2138
2996
|
import { existsSync as existsSync7, mkdirSync as mkdirSync4, statSync as statSync3 } from "fs";
|
|
2139
2997
|
import { join as join11 } from "path";
|
|
2140
2998
|
async function syncWorkspaceSkills(cfg, workdir) {
|
|
@@ -2217,17 +3075,21 @@ async function runSyncDeployConfig() {
|
|
|
2217
3075
|
}
|
|
2218
3076
|
|
|
2219
3077
|
// src/commands/sync-project-documents.ts
|
|
3078
|
+
init_config();
|
|
2220
3079
|
async function runSyncProjectDocuments(options) {
|
|
2221
|
-
const pull = options?.pull ?? !options?.push;
|
|
2222
|
-
const push = options?.push ?? false;
|
|
2223
3080
|
const workdir = resolveWorkdirPath();
|
|
2224
3081
|
const apmRoot = workspaceApmDir(workdir);
|
|
2225
|
-
|
|
2226
|
-
|
|
3082
|
+
const doPush = Boolean(options.push);
|
|
3083
|
+
const doPull = Boolean(options.pull) || !doPush;
|
|
3084
|
+
if (doPull) {
|
|
3085
|
+
await syncProjectDocumentsPull(workdir, apmRoot);
|
|
2227
3086
|
}
|
|
2228
|
-
if (
|
|
2229
|
-
const cfg = await
|
|
2230
|
-
|
|
3087
|
+
if (doPush) {
|
|
3088
|
+
const cfg = await tryReadApmConfig();
|
|
3089
|
+
if (!cfg) {
|
|
3090
|
+
throw new Error("[apm] \u672A\u68C0\u6D4B\u5230\u767B\u5F55\u4FE1\u606F\uFF0C\u8BF7\u5148\u6267\u884C apm login");
|
|
3091
|
+
}
|
|
3092
|
+
await syncProjectDocumentsPush(cfg, workdir, apmRoot);
|
|
2231
3093
|
}
|
|
2232
3094
|
}
|
|
2233
3095
|
|
|
@@ -2398,7 +3260,11 @@ function validateAssumptionsMarkdown(markdown, source) {
|
|
|
2398
3260
|
};
|
|
2399
3261
|
}
|
|
2400
3262
|
|
|
3263
|
+
// src/commands/sync-document.ts
|
|
3264
|
+
init_client();
|
|
3265
|
+
|
|
2401
3266
|
// src/commands/sync-session-documents.ts
|
|
3267
|
+
init_client();
|
|
2402
3268
|
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync8 } from "fs";
|
|
2403
3269
|
import { join as join12 } from "path";
|
|
2404
3270
|
function listLocalMarkdownFiles(docsDir) {
|
|
@@ -2519,6 +3385,7 @@ async function runSyncDocument(sessionId, options) {
|
|
|
2519
3385
|
}
|
|
2520
3386
|
|
|
2521
3387
|
// src/commands/dev-gate.ts
|
|
3388
|
+
init_client();
|
|
2522
3389
|
async function runDevGate(sessionId, source) {
|
|
2523
3390
|
const trimmedId = sessionId.trim();
|
|
2524
3391
|
if (!trimmedId) {
|
|
@@ -2538,6 +3405,7 @@ async function runDevGate(sessionId, source) {
|
|
|
2538
3405
|
}
|
|
2539
3406
|
|
|
2540
3407
|
// src/commands/append-message.ts
|
|
3408
|
+
init_client();
|
|
2541
3409
|
async function appendMessageContent(cfg, messageId, content) {
|
|
2542
3410
|
const trimmedId = messageId.trim();
|
|
2543
3411
|
if (!trimmedId) {
|
|
@@ -2566,6 +3434,7 @@ async function runAppendMessage(options) {
|
|
|
2566
3434
|
}
|
|
2567
3435
|
|
|
2568
3436
|
// src/commands/update-message-status.ts
|
|
3437
|
+
init_client();
|
|
2569
3438
|
var VALID_STATUSES = [
|
|
2570
3439
|
"CREATED",
|
|
2571
3440
|
"QUEUED",
|
|
@@ -2594,8 +3463,10 @@ async function runUpdateMessageStatus(options) {
|
|
|
2594
3463
|
}
|
|
2595
3464
|
|
|
2596
3465
|
// src/commands/connect.ts
|
|
3466
|
+
init_client();
|
|
2597
3467
|
import WebSocket from "ws";
|
|
2598
3468
|
import { setTimeout as delay3 } from "node:timers/promises";
|
|
3469
|
+
init_config();
|
|
2599
3470
|
|
|
2600
3471
|
// src/ws/protocol.ts
|
|
2601
3472
|
function nonEmptyString(v) {
|
|
@@ -2777,13 +3648,38 @@ function validateWebIdeCacheCleanupPush(o) {
|
|
|
2777
3648
|
}
|
|
2778
3649
|
};
|
|
2779
3650
|
}
|
|
3651
|
+
function validateWebIdeTerminalStopPush(o) {
|
|
3652
|
+
if (o.type !== "webide-terminal-stop") {
|
|
3653
|
+
return { ok: false, reason: "\u671F\u671B webide-terminal-stop" };
|
|
3654
|
+
}
|
|
3655
|
+
if (!nonEmptyString(o.taskId)) {
|
|
3656
|
+
return { ok: false, reason: "webide-terminal-stop \u7F3A\u5C11 taskId" };
|
|
3657
|
+
}
|
|
3658
|
+
if (!nonEmptyString(o.terminalId)) {
|
|
3659
|
+
return { ok: false, reason: "webide-terminal-stop \u7F3A\u5C11 terminalId" };
|
|
3660
|
+
}
|
|
3661
|
+
if (!nonEmptyString(o.key)) {
|
|
3662
|
+
return { ok: false, reason: "webide-terminal-stop \u7F3A\u5C11 key" };
|
|
3663
|
+
}
|
|
3664
|
+
const pid = typeof o.pid === "number" && Number.isFinite(o.pid) ? Math.trunc(o.pid) : o.pid === null ? null : void 0;
|
|
3665
|
+
return {
|
|
3666
|
+
ok: true,
|
|
3667
|
+
data: {
|
|
3668
|
+
type: "webide-terminal-stop",
|
|
3669
|
+
taskId: o.taskId.trim(),
|
|
3670
|
+
terminalId: o.terminalId.trim(),
|
|
3671
|
+
key: o.key.trim(),
|
|
3672
|
+
...pid !== void 0 ? { pid } : {}
|
|
3673
|
+
}
|
|
3674
|
+
};
|
|
3675
|
+
}
|
|
2780
3676
|
function validateAgentWsMessage(value, kind) {
|
|
2781
3677
|
if (typeof value !== "object" || value === null) {
|
|
2782
3678
|
return { ok: false, reason: "\u6D88\u606F\u4F53\u4E0D\u662F JSON \u5BF9\u8C61" };
|
|
2783
3679
|
}
|
|
2784
3680
|
const o = value;
|
|
2785
3681
|
const type = o.type;
|
|
2786
|
-
if (type !== "heartbeat" && type !== "message" && type !== "webide-message" && type !== "cancel" && type !== "deploy" && type !== "session-cache-cleanup" && type !== "webide-cache-cleanup") {
|
|
3682
|
+
if (type !== "heartbeat" && type !== "message" && type !== "webide-message" && type !== "cancel" && type !== "deploy" && type !== "session-cache-cleanup" && type !== "webide-cache-cleanup" && type !== "webide-terminal-stop") {
|
|
2787
3683
|
return { ok: false, reason: `\u672A\u77E5 type: ${String(type)}` };
|
|
2788
3684
|
}
|
|
2789
3685
|
if (kind === "heartbeat" || type === "heartbeat") {
|
|
@@ -2801,12 +3697,18 @@ function validateAgentWsMessage(value, kind) {
|
|
|
2801
3697
|
if (type === "webide-cache-cleanup") {
|
|
2802
3698
|
return validateWebIdeCacheCleanupPush(o);
|
|
2803
3699
|
}
|
|
3700
|
+
if (type === "webide-terminal-stop") {
|
|
3701
|
+
return validateWebIdeTerminalStopPush(o);
|
|
3702
|
+
}
|
|
2804
3703
|
if (type === "webide-message") {
|
|
2805
3704
|
return validateWebIdeMessagePush(o);
|
|
2806
3705
|
}
|
|
2807
3706
|
return validateMessagePush(o);
|
|
2808
3707
|
}
|
|
2809
3708
|
|
|
3709
|
+
// src/commands/connect/deploy-run.ts
|
|
3710
|
+
init_client();
|
|
3711
|
+
|
|
2810
3712
|
// src/commands/deploy/deploy-execute.ts
|
|
2811
3713
|
import path11 from "node:path";
|
|
2812
3714
|
|
|
@@ -3054,366 +3956,119 @@ function resolveWisdomBackendPackOnlyFromApmConfig(cfg) {
|
|
|
3054
3956
|
mavenLocalRepoSourceDetail: mavenLocalRepo.sourceDetail,
|
|
3055
3957
|
mode: resolveWisdomDeployMode(w.mode)
|
|
3056
3958
|
};
|
|
3057
|
-
}
|
|
3058
|
-
function resolveWisdomBackendDeployFromApmConfig(cfg) {
|
|
3059
|
-
const projectName = reqTopLevelName(cfg);
|
|
3060
|
-
const w = cfg.wisdomDeploy ?? {};
|
|
3061
|
-
const h = cfg.healthCheck ?? {};
|
|
3062
|
-
const jarPath = req(w.jarPath, "jarPath", "wisdomDeploy").trim();
|
|
3063
|
-
const remoteAppDir = posixDirname(jarPath);
|
|
3064
|
-
const healthPort = Number(req(h.port, "port", "healthCheck"));
|
|
3065
|
-
const healthTimeout = Number(req(h.timeout, "timeout", "healthCheck"));
|
|
3066
|
-
if (!Number.isFinite(healthPort) || !Number.isInteger(healthPort) || healthPort < 1) {
|
|
3067
|
-
console.error("apm.config.json \u4E2D healthCheck.port \u987B\u4E3A\u6B63\u6574\u6570");
|
|
3068
|
-
process.exit(1);
|
|
3069
|
-
}
|
|
3070
|
-
if (!Number.isFinite(healthTimeout) || !Number.isInteger(healthTimeout) || healthTimeout < 1) {
|
|
3071
|
-
console.error("apm.config.json \u4E2D healthCheck.timeout \u987B\u4E3A\u6B63\u6574\u6570");
|
|
3072
|
-
process.exit(1);
|
|
3073
|
-
}
|
|
3074
|
-
const mavenLocalRepo = resolveMavenLocalRepoWithSource();
|
|
3075
|
-
return {
|
|
3076
|
-
projectName,
|
|
3077
|
-
host: req(w.host, "host", "wisdomDeploy").trim(),
|
|
3078
|
-
port: reqPositiveInt(w.port, "port", "wisdomDeploy"),
|
|
3079
|
-
username: req(w.username, "username", "wisdomDeploy").trim(),
|
|
3080
|
-
password: req(w.password, "password", "wisdomDeploy").trim(),
|
|
3081
|
-
remoteVueDistDir: req(w.remotePath, "remotePath", "wisdomDeploy").trim(),
|
|
3082
|
-
remoteAppDir,
|
|
3083
|
-
remoteLibDir: `${remoteAppDir}/lib`,
|
|
3084
|
-
startupJar: posixBasename(jarPath),
|
|
3085
|
-
packageName: `${projectName}.jar.zip`,
|
|
3086
|
-
mavenLocalRepo: mavenLocalRepo.path,
|
|
3087
|
-
mavenLocalRepoSource: mavenLocalRepo.source,
|
|
3088
|
-
mavenLocalRepoSourceDetail: mavenLocalRepo.sourceDetail,
|
|
3089
|
-
healthCheckPort: healthPort,
|
|
3090
|
-
healthCheckContext: req(h.context, "context", "healthCheck").trim(),
|
|
3091
|
-
healthCheckTimeout: healthTimeout,
|
|
3092
|
-
mode: resolveWisdomDeployMode(w.mode)
|
|
3093
|
-
};
|
|
3094
|
-
}
|
|
3095
|
-
|
|
3096
|
-
// src/commands/deploy/internal/apm-config.ts
|
|
3097
|
-
function loadApmConfig(options) {
|
|
3098
|
-
const p = resolve4(
|
|
3099
|
-
process.cwd(),
|
|
3100
|
-
options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
|
|
3101
|
-
);
|
|
3102
|
-
if (!existsSync12(p)) {
|
|
3103
|
-
console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
|
|
3104
|
-
process.exit(1);
|
|
3105
|
-
}
|
|
3106
|
-
try {
|
|
3107
|
-
const raw = readFileSync11(p, "utf8");
|
|
3108
|
-
return JSON.parse(raw);
|
|
3109
|
-
} catch (e) {
|
|
3110
|
-
console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
|
|
3111
|
-
process.exit(1);
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
|
|
3115
|
-
// src/commands/deploy/internal/deploy-hints.ts
|
|
3116
|
-
function isProductionDeployEnv(env) {
|
|
3117
|
-
const normalized = env.trim().toLowerCase();
|
|
3118
|
-
return normalized === "online" || normalized === "production" || normalized === "prod";
|
|
3119
|
-
}
|
|
3120
|
-
function formatMissingWisdomDeployLines() {
|
|
3121
|
-
return [
|
|
3122
|
-
"[apm] \u65E0\u6CD5\u6267\u884C apm deploy\uFF1A\u8BF7\u5728 apm.config.json \u4E2D\u914D\u7F6E wisdomDeploy\uFF08host\u3001remotePath\uFF09"
|
|
3123
|
-
];
|
|
3124
|
-
}
|
|
3125
|
-
function formatWisdomFrontendBuildNotConfiguredLines(env, packageJsonPath) {
|
|
3126
|
-
if (isProductionDeployEnv(env)) {
|
|
3127
|
-
return [
|
|
3128
|
-
`[apm] \u65E0\u6CD5\u6267\u884C\u524D\u7AEF\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u6216 build \u811A\u672C`,
|
|
3129
|
-
"[apm] \u8BF7\u914D\u7F6E npm run build:online \u6216 npm run build \u540E\u518D\u8BD5"
|
|
3130
|
-
];
|
|
3131
|
-
}
|
|
3132
|
-
return [
|
|
3133
|
-
`[apm] \u65E0\u6CD5\u6267\u884C\u524D\u7AEF\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u811A\u672C`,
|
|
3134
|
-
"[apm] \u8BF7\u914D\u7F6E npm run build:test \u540E\u518D\u8BD5"
|
|
3135
|
-
];
|
|
3136
|
-
}
|
|
3137
|
-
|
|
3138
|
-
// src/commands/deploy/deploy-errors.ts
|
|
3139
|
-
var DeployExecutionError = class extends Error {
|
|
3140
|
-
exitCode;
|
|
3141
|
-
output;
|
|
3142
|
-
constructor(message, exitCode, output = "") {
|
|
3143
|
-
super(message);
|
|
3144
|
-
this.name = "DeployExecutionError";
|
|
3145
|
-
this.exitCode = exitCode;
|
|
3146
|
-
this.output = output;
|
|
3147
|
-
}
|
|
3148
|
-
};
|
|
3149
|
-
|
|
3150
|
-
// src/commands/deploy/deploy-debug-log.ts
|
|
3151
|
-
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
3152
|
-
import { existsSync as existsSync16 } from "node:fs";
|
|
3153
|
-
import { dirname as dirname5, join as join17 } from "node:path";
|
|
3154
|
-
|
|
3155
|
-
// src/commands/deploy/internal/deploy-artifact-minio.ts
|
|
3156
|
-
import { readFile as readFile2 } from "node:fs/promises";
|
|
3157
|
-
|
|
3158
|
-
// src/commands/deploy/internal/minio.ts
|
|
3159
|
-
import { statSync as statSync5 } from "node:fs";
|
|
3160
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
3161
|
-
import path from "node:path";
|
|
3162
|
-
import * as Minio from "minio";
|
|
3163
|
-
var DEFAULT_MAX_FILE_SIZE_MB = 50;
|
|
3164
|
-
async function isDirectoryPath(dir) {
|
|
3165
|
-
try {
|
|
3166
|
-
const st = statSync5(dir);
|
|
3167
|
-
return st.isDirectory();
|
|
3168
|
-
} catch {
|
|
3169
|
-
return false;
|
|
3170
|
-
}
|
|
3171
|
-
}
|
|
3172
|
-
function sanitizeRelativePath(rel) {
|
|
3173
|
-
const norm = rel.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3174
|
-
const segments = norm.split("/").filter(Boolean);
|
|
3175
|
-
for (const s of segments) {
|
|
3176
|
-
if (s === "." || s === "..") {
|
|
3177
|
-
throw new Error(`\u975E\u6CD5\u76F8\u5BF9\u8DEF\u5F84\u7247\u6BB5\uFF1A${s}`);
|
|
3178
|
-
}
|
|
3179
|
-
}
|
|
3180
|
-
return segments.join("/");
|
|
3181
|
-
}
|
|
3182
|
-
async function collectFiles(root) {
|
|
3183
|
-
const out = [];
|
|
3184
|
-
async function walk(dir, prefix) {
|
|
3185
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
3186
|
-
for (const e of entries) {
|
|
3187
|
-
const name = e.name;
|
|
3188
|
-
if (name === "." || name === "..") {
|
|
3189
|
-
continue;
|
|
3190
|
-
}
|
|
3191
|
-
const abs = path.join(dir, name);
|
|
3192
|
-
const rel = prefix ? `${prefix}/${name}` : name;
|
|
3193
|
-
if (e.isDirectory()) {
|
|
3194
|
-
await walk(abs, rel);
|
|
3195
|
-
} else if (e.isFile()) {
|
|
3196
|
-
const st = statSync5(abs);
|
|
3197
|
-
out.push({
|
|
3198
|
-
absPath: abs,
|
|
3199
|
-
relativePath: rel.replace(/\\/g, "/"),
|
|
3200
|
-
size: st.size
|
|
3201
|
-
});
|
|
3202
|
-
}
|
|
3203
|
-
}
|
|
3204
|
-
}
|
|
3205
|
-
await walk(root, "");
|
|
3206
|
-
out.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
3207
|
-
return out;
|
|
3208
|
-
}
|
|
3209
|
-
async function readArtifactFile(absPath) {
|
|
3210
|
-
return readFile(absPath);
|
|
3211
|
-
}
|
|
3212
|
-
function toMB(bytes) {
|
|
3213
|
-
return Math.round(bytes / (1024 * 1024) * 1e3) / 1e3;
|
|
3214
|
-
}
|
|
3215
|
-
var MIME = {
|
|
3216
|
-
".html": "text/html; charset=utf-8",
|
|
3217
|
-
".css": "text/css; charset=utf-8",
|
|
3218
|
-
".js": "application/javascript; charset=utf-8",
|
|
3219
|
-
".json": "application/json; charset=utf-8",
|
|
3220
|
-
".svg": "image/svg+xml",
|
|
3221
|
-
".png": "image/png",
|
|
3222
|
-
".jpg": "image/jpeg",
|
|
3223
|
-
".jpeg": "image/jpeg",
|
|
3224
|
-
".gif": "image/gif",
|
|
3225
|
-
".webp": "image/webp",
|
|
3226
|
-
".woff": "font/woff",
|
|
3227
|
-
".woff2": "font/woff2",
|
|
3228
|
-
".ttf": "font/ttf",
|
|
3229
|
-
".ico": "image/x-icon",
|
|
3230
|
-
".txt": "text/plain; charset=utf-8",
|
|
3231
|
-
".map": "application/json"
|
|
3232
|
-
};
|
|
3233
|
-
function detectMimeType(filePath) {
|
|
3234
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
3235
|
-
return MIME[ext] ?? "";
|
|
3236
|
-
}
|
|
3237
|
-
var MinioClient = class {
|
|
3238
|
-
inner;
|
|
3239
|
-
constructor(opts) {
|
|
3240
|
-
const endPoint = opts.endPoint.replace(/^https?:\/\//i, "").split("/")[0] ?? opts.endPoint;
|
|
3241
|
-
this.inner = new Minio.Client({
|
|
3242
|
-
endPoint,
|
|
3243
|
-
port: opts.port,
|
|
3244
|
-
useSSL: opts.useSSL,
|
|
3245
|
-
accessKey: opts.accessKey,
|
|
3246
|
-
secretKey: opts.secretKey
|
|
3247
|
-
});
|
|
3248
|
-
}
|
|
3249
|
-
async ensureBucket(bucket) {
|
|
3250
|
-
const exists = await this.inner.bucketExists(bucket);
|
|
3251
|
-
if (!exists) {
|
|
3252
|
-
await this.inner.makeBucket(bucket);
|
|
3253
|
-
}
|
|
3254
|
-
}
|
|
3255
|
-
async deleteObjectsByPrefix(bucket, prefix) {
|
|
3256
|
-
const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
3257
|
-
const keys = [];
|
|
3258
|
-
await new Promise((resolve7, reject) => {
|
|
3259
|
-
objectsStream.on("data", (obj) => {
|
|
3260
|
-
if (obj.name) {
|
|
3261
|
-
keys.push(obj.name);
|
|
3262
|
-
}
|
|
3263
|
-
});
|
|
3264
|
-
objectsStream.on("error", reject);
|
|
3265
|
-
objectsStream.on("end", resolve7);
|
|
3266
|
-
});
|
|
3267
|
-
const chunkSize = 500;
|
|
3268
|
-
for (let i = 0; i < keys.length; i += chunkSize) {
|
|
3269
|
-
const chunk = keys.slice(i, i + chunkSize);
|
|
3270
|
-
await this.inner.removeObjects(
|
|
3271
|
-
bucket,
|
|
3272
|
-
chunk.map((name) => name)
|
|
3273
|
-
);
|
|
3274
|
-
}
|
|
3275
|
-
}
|
|
3276
|
-
async putObject(bucket, objectKey, body, meta) {
|
|
3277
|
-
await this.inner.putObject(bucket, objectKey, body, body.length, meta);
|
|
3278
|
-
}
|
|
3279
|
-
/** 匿名可读当前桶全部对象(便于静态站点直链) */
|
|
3280
|
-
async setBucketPublicRead(bucket) {
|
|
3281
|
-
const policy = {
|
|
3282
|
-
Version: "2012-10-17",
|
|
3283
|
-
Statement: [
|
|
3284
|
-
{
|
|
3285
|
-
Effect: "Allow",
|
|
3286
|
-
Principal: { AWS: ["*"] },
|
|
3287
|
-
Action: ["s3:GetObject"],
|
|
3288
|
-
Resource: [`arn:aws:s3:::${bucket}/*`]
|
|
3289
|
-
}
|
|
3290
|
-
]
|
|
3291
|
-
};
|
|
3292
|
-
await this.inner.setBucketPolicy(bucket, JSON.stringify(policy));
|
|
3293
|
-
}
|
|
3294
|
-
};
|
|
3295
|
-
|
|
3296
|
-
// src/commands/deploy/internal/deploy-artifact-minio.ts
|
|
3297
|
-
var APM_DEPLOYMENT_RUN_ID_ENV = "APM_DEPLOYMENT_RUN_ID";
|
|
3298
|
-
function formatDeployArtifactTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
3299
|
-
const pad2 = (n) => String(n).padStart(2, "0");
|
|
3300
|
-
return `${date.getFullYear()}${pad2(date.getMonth() + 1)}${pad2(date.getDate())}${pad2(date.getHours())}${pad2(date.getMinutes())}${pad2(date.getSeconds())}`;
|
|
3301
|
-
}
|
|
3302
|
-
function sanitizeDeployProjectName(name) {
|
|
3303
|
-
const trimmed = name.trim().replace(/\\/g, "/");
|
|
3304
|
-
const base = trimmed.split("/").filter(Boolean).pop() ?? trimmed;
|
|
3305
|
-
try {
|
|
3306
|
-
return sanitizeRelativePath(base.replace(/[/\\:*?"<>|]/g, "_"));
|
|
3307
|
-
} catch {
|
|
3308
|
-
return "project";
|
|
3309
|
-
}
|
|
3310
|
-
}
|
|
3311
|
-
function buildDeployArtifactFileName(kind, projectName, timestamp = formatDeployArtifactTimestamp()) {
|
|
3312
|
-
const safeName = sanitizeDeployProjectName(projectName);
|
|
3313
|
-
const suffix = kind === "frontend" ? "dist.zip" : "jar.zip";
|
|
3314
|
-
return `${timestamp}-${safeName}.${suffix}`;
|
|
3315
|
-
}
|
|
3316
|
-
function buildDeployArtifactObjectKey(projectName, fileName) {
|
|
3317
|
-
const safeProject = sanitizeDeployProjectName(projectName);
|
|
3318
|
-
return `deploy/${safeProject}/${fileName}`;
|
|
3319
|
-
}
|
|
3320
|
-
function resolveDeploymentRunIdFromEnv() {
|
|
3321
|
-
const raw = process.env[APM_DEPLOYMENT_RUN_ID_ENV]?.trim();
|
|
3322
|
-
return raw || null;
|
|
3323
|
-
}
|
|
3324
|
-
async function fetchDeployArtifactStorage(api) {
|
|
3325
|
-
return api.cli.getDeployArtifactStorage(void 0);
|
|
3326
|
-
}
|
|
3327
|
-
async function uploadDeployArtifactZip(options) {
|
|
3328
|
-
const deploymentRunId = options.deploymentRunId ?? resolveDeploymentRunIdFromEnv();
|
|
3329
|
-
if (!deploymentRunId && !options.uploadWithoutRunId) {
|
|
3330
|
-
return null;
|
|
3331
|
-
}
|
|
3332
|
-
const cfg = await tryReadApmConfig();
|
|
3333
|
-
if (!cfg || !resolveApiKey(cfg)) {
|
|
3334
|
-
console.warn("[apm] \u672A\u767B\u5F55\uFF0C\u8DF3\u8FC7 MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863");
|
|
3335
|
-
return null;
|
|
3959
|
+
}
|
|
3960
|
+
function resolveWisdomBackendDeployFromApmConfig(cfg) {
|
|
3961
|
+
const projectName = reqTopLevelName(cfg);
|
|
3962
|
+
const w = cfg.wisdomDeploy ?? {};
|
|
3963
|
+
const h = cfg.healthCheck ?? {};
|
|
3964
|
+
const jarPath = req(w.jarPath, "jarPath", "wisdomDeploy").trim();
|
|
3965
|
+
const remoteAppDir = posixDirname(jarPath);
|
|
3966
|
+
const healthPort = Number(req(h.port, "port", "healthCheck"));
|
|
3967
|
+
const healthTimeout = Number(req(h.timeout, "timeout", "healthCheck"));
|
|
3968
|
+
if (!Number.isFinite(healthPort) || !Number.isInteger(healthPort) || healthPort < 1) {
|
|
3969
|
+
console.error("apm.config.json \u4E2D healthCheck.port \u987B\u4E3A\u6B63\u6574\u6570");
|
|
3970
|
+
process.exit(1);
|
|
3336
3971
|
}
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
storage = await fetchDeployArtifactStorage(api);
|
|
3341
|
-
} catch (error) {
|
|
3342
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
3343
|
-
console.warn(`[apm] \u83B7\u53D6 MinIO \u914D\u7F6E\u5931\u8D25\uFF0C\u8DF3\u8FC7\u90E8\u7F72\u4EA7\u7269\u5F52\u6863: ${detail}`);
|
|
3344
|
-
return null;
|
|
3972
|
+
if (!Number.isFinite(healthTimeout) || !Number.isInteger(healthTimeout) || healthTimeout < 1) {
|
|
3973
|
+
console.error("apm.config.json \u4E2D healthCheck.timeout \u987B\u4E3A\u6B63\u6574\u6570");
|
|
3974
|
+
process.exit(1);
|
|
3345
3975
|
}
|
|
3346
|
-
const
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3976
|
+
const mavenLocalRepo = resolveMavenLocalRepoWithSource();
|
|
3977
|
+
return {
|
|
3978
|
+
projectName,
|
|
3979
|
+
host: req(w.host, "host", "wisdomDeploy").trim(),
|
|
3980
|
+
port: reqPositiveInt(w.port, "port", "wisdomDeploy"),
|
|
3981
|
+
username: req(w.username, "username", "wisdomDeploy").trim(),
|
|
3982
|
+
password: req(w.password, "password", "wisdomDeploy").trim(),
|
|
3983
|
+
remoteVueDistDir: req(w.remotePath, "remotePath", "wisdomDeploy").trim(),
|
|
3984
|
+
remoteAppDir,
|
|
3985
|
+
remoteLibDir: `${remoteAppDir}/lib`,
|
|
3986
|
+
startupJar: posixBasename(jarPath),
|
|
3987
|
+
packageName: `${projectName}.jar.zip`,
|
|
3988
|
+
mavenLocalRepo: mavenLocalRepo.path,
|
|
3989
|
+
mavenLocalRepoSource: mavenLocalRepo.source,
|
|
3990
|
+
mavenLocalRepoSourceDetail: mavenLocalRepo.sourceDetail,
|
|
3991
|
+
healthCheckPort: healthPort,
|
|
3992
|
+
healthCheckContext: req(h.context, "context", "healthCheck").trim(),
|
|
3993
|
+
healthCheckTimeout: healthTimeout,
|
|
3994
|
+
mode: resolveWisdomDeployMode(w.mode)
|
|
3995
|
+
};
|
|
3996
|
+
}
|
|
3997
|
+
|
|
3998
|
+
// src/commands/deploy/internal/apm-config.ts
|
|
3999
|
+
function loadApmConfig(options) {
|
|
4000
|
+
const p = resolve4(
|
|
4001
|
+
process.cwd(),
|
|
4002
|
+
options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
|
|
3350
4003
|
);
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
body = await readFile2(options.zipPath);
|
|
3355
|
-
} catch (error) {
|
|
3356
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
3357
|
-
console.warn(`[apm] \u8BFB\u53D6\u90E8\u7F72\u4EA7\u7269 zip \u5931\u8D25\uFF0C\u8DF3\u8FC7 MinIO \u5F52\u6863: ${detail}`);
|
|
3358
|
-
return null;
|
|
4004
|
+
if (!existsSync12(p)) {
|
|
4005
|
+
console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
|
|
4006
|
+
process.exit(1);
|
|
3359
4007
|
}
|
|
3360
4008
|
try {
|
|
3361
|
-
const
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
secretKey: storage.secretKey
|
|
3367
|
-
});
|
|
3368
|
-
await client.ensureBucket(storage.bucket);
|
|
3369
|
-
await client.putObject(storage.bucket, objectKey, body, {
|
|
3370
|
-
"Content-Type": "application/zip"
|
|
3371
|
-
});
|
|
3372
|
-
console.error(
|
|
3373
|
-
`[apm] \u672C\u5730\u76F4\u4F20 MinIO\uFF08\u4E0D\u7ECF\u5E73\u53F0\u670D\u52A1\u5668\uFF09: ${storage.endpoint}:${storage.port}/${storage.bucket}/${objectKey} (${(body.length / 1024 / 1024).toFixed(
|
|
3374
|
-
2
|
|
3375
|
-
)} MB)`
|
|
3376
|
-
);
|
|
3377
|
-
} catch (error) {
|
|
3378
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
3379
|
-
console.warn(`[apm] MinIO \u90E8\u7F72\u4EA7\u7269\u5F52\u6863\u5931\u8D25: ${detail}`);
|
|
3380
|
-
return null;
|
|
4009
|
+
const raw = readFileSync11(p, "utf8");
|
|
4010
|
+
return JSON.parse(raw);
|
|
4011
|
+
} catch (e) {
|
|
4012
|
+
console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
|
|
4013
|
+
process.exit(1);
|
|
3381
4014
|
}
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
4015
|
+
}
|
|
4016
|
+
|
|
4017
|
+
// src/commands/deploy/internal/deploy-hints.ts
|
|
4018
|
+
function isProductionDeployEnv(env) {
|
|
4019
|
+
const normalized = env.trim().toLowerCase();
|
|
4020
|
+
return normalized === "online" || normalized === "production" || normalized === "prod";
|
|
4021
|
+
}
|
|
4022
|
+
function formatMissingWisdomDeployLines() {
|
|
4023
|
+
return [
|
|
4024
|
+
"[apm] \u65E0\u6CD5\u6267\u884C apm deploy\uFF1A\u8BF7\u5728 apm.config.json \u4E2D\u914D\u7F6E wisdomDeploy\uFF08host\u3001remotePath\uFF09"
|
|
4025
|
+
];
|
|
4026
|
+
}
|
|
4027
|
+
function formatWisdomFrontendBuildNotConfiguredLines(env, packageJsonPath) {
|
|
4028
|
+
if (isProductionDeployEnv(env)) {
|
|
4029
|
+
return [
|
|
4030
|
+
`[apm] \u65E0\u6CD5\u6267\u884C\u524D\u7AEF\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u6216 build \u811A\u672C`,
|
|
4031
|
+
"[apm] \u8BF7\u914D\u7F6E npm run build:online \u6216 npm run build \u540E\u518D\u8BD5"
|
|
4032
|
+
];
|
|
3397
4033
|
}
|
|
3398
|
-
return
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
};
|
|
4034
|
+
return [
|
|
4035
|
+
`[apm] \u65E0\u6CD5\u6267\u884C\u524D\u7AEF\u90E8\u7F72\uFF1A${packageJsonPath} \u4E2D\u672A\u627E\u5230 build:${env} \u811A\u672C`,
|
|
4036
|
+
"[apm] \u8BF7\u914D\u7F6E npm run build:test \u540E\u518D\u8BD5"
|
|
4037
|
+
];
|
|
3403
4038
|
}
|
|
3404
4039
|
|
|
4040
|
+
// src/commands/deploy/deploy-errors.ts
|
|
4041
|
+
var DeployExecutionError = class extends Error {
|
|
4042
|
+
exitCode;
|
|
4043
|
+
output;
|
|
4044
|
+
constructor(message, exitCode, output = "") {
|
|
4045
|
+
super(message);
|
|
4046
|
+
this.name = "DeployExecutionError";
|
|
4047
|
+
this.exitCode = exitCode;
|
|
4048
|
+
this.output = output;
|
|
4049
|
+
}
|
|
4050
|
+
};
|
|
4051
|
+
|
|
4052
|
+
// src/commands/deploy/deploy-debug-log.ts
|
|
4053
|
+
init_deploy_artifact_minio();
|
|
4054
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
4055
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
4056
|
+
import { dirname as dirname5, join as join17 } from "node:path";
|
|
4057
|
+
|
|
3405
4058
|
// src/commands/deploy/internal/deploy-shell-env.ts
|
|
3406
4059
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
3407
4060
|
import { existsSync as existsSync15 } from "node:fs";
|
|
3408
4061
|
import { dirname as dirname4, join as join16 } from "node:path";
|
|
3409
4062
|
|
|
3410
4063
|
// src/commands/daemon.ts
|
|
4064
|
+
init_config();
|
|
3411
4065
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
3412
4066
|
import { setTimeout as delay } from "node:timers/promises";
|
|
3413
4067
|
import { existsSync as existsSync14, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "fs";
|
|
3414
4068
|
import { join as join15 } from "path";
|
|
3415
4069
|
|
|
3416
4070
|
// src/commands/connect-lock.ts
|
|
4071
|
+
init_config();
|
|
3417
4072
|
import {
|
|
3418
4073
|
existsSync as existsSync13,
|
|
3419
4074
|
mkdirSync as mkdirSync5,
|
|
@@ -4548,6 +5203,7 @@ function runDeployShellCommand(command, cwd, captureOutput) {
|
|
|
4548
5203
|
|
|
4549
5204
|
// src/commands/deploy/internal/wisdom-backend/index.ts
|
|
4550
5205
|
import path9 from "node:path";
|
|
5206
|
+
init_deploy_artifact_minio();
|
|
4551
5207
|
|
|
4552
5208
|
// src/commands/deploy/internal/wisdom-backend/jar-incremental.ts
|
|
4553
5209
|
import {
|
|
@@ -4616,6 +5272,8 @@ import SftpClient from "ssh2-sftp-client";
|
|
|
4616
5272
|
import { readdir as readdir2, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
|
|
4617
5273
|
import path3 from "node:path";
|
|
4618
5274
|
import JSZip from "jszip";
|
|
5275
|
+
init_deploy_artifact_minio();
|
|
5276
|
+
init_minio();
|
|
4619
5277
|
async function addDirToZip(dir, zipFolder) {
|
|
4620
5278
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
4621
5279
|
for (const entry of entries) {
|
|
@@ -4704,6 +5362,7 @@ async function packDirectoryWithMinioArchive(input) {
|
|
|
4704
5362
|
}
|
|
4705
5363
|
|
|
4706
5364
|
// src/commands/deploy/internal/wisdom-sftp.ts
|
|
5365
|
+
init_deploy_artifact_minio();
|
|
4707
5366
|
var SFTP_UPLOAD_MAX_ATTEMPTS = 3;
|
|
4708
5367
|
var SFTP_FAST_PUT_OPTIONS = {
|
|
4709
5368
|
chunkSize: 64 * 1024,
|
|
@@ -5703,6 +6362,8 @@ async function executeWisdomDeploy(options) {
|
|
|
5703
6362
|
}
|
|
5704
6363
|
|
|
5705
6364
|
// src/commands/deploy/internal/deploy-baseline-sync.ts
|
|
6365
|
+
init_client();
|
|
6366
|
+
init_config();
|
|
5706
6367
|
var LOG_PREFIX2 = "[apm] \u90E8\u7F72\u524D\u57FA\u7EBF\u540C\u6B65:";
|
|
5707
6368
|
function formatGitError(error) {
|
|
5708
6369
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -5910,6 +6571,9 @@ function printDeployExecutionError(error) {
|
|
|
5910
6571
|
console.error(error.message);
|
|
5911
6572
|
}
|
|
5912
6573
|
|
|
6574
|
+
// src/commands/deploy/platform/deploy-run-coordinator.ts
|
|
6575
|
+
init_deploy_artifact_minio();
|
|
6576
|
+
|
|
5913
6577
|
// src/commands/deploy/platform/deploy-console-capture.ts
|
|
5914
6578
|
function captureDeployConsole(logSyncer) {
|
|
5915
6579
|
const chunks = [];
|
|
@@ -6638,6 +7302,7 @@ function clearSessionAgentId(workdir, sessionId, user) {
|
|
|
6638
7302
|
}
|
|
6639
7303
|
|
|
6640
7304
|
// src/commands/connect/cursor-message-log.ts
|
|
7305
|
+
init_client();
|
|
6641
7306
|
var CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS = 2e3;
|
|
6642
7307
|
function createThrottledCursorMessageLogSync(cfg, ctx, onError) {
|
|
6643
7308
|
let lastRunAt = 0;
|
|
@@ -6806,16 +7471,17 @@ ${payload}`;
|
|
|
6806
7471
|
}
|
|
6807
7472
|
|
|
6808
7473
|
// src/commands/connect/webide-merge-tools.ts
|
|
7474
|
+
init_client();
|
|
6809
7475
|
function createMergeWebIdePullRequestsTool(options) {
|
|
6810
7476
|
const { cfg, taskId } = options;
|
|
6811
7477
|
return {
|
|
6812
|
-
description: "Merge all open pull requests for this WebIDE task
|
|
7478
|
+
description: "Merge all open pull requests for this WebIDE task. Call once with confirmedConflictFree=true. No baseline sync or review is required before calling.",
|
|
6813
7479
|
inputSchema: {
|
|
6814
7480
|
type: "object",
|
|
6815
7481
|
properties: {
|
|
6816
7482
|
confirmedConflictFree: {
|
|
6817
7483
|
type: "boolean",
|
|
6818
|
-
description: "Must be true
|
|
7484
|
+
description: "Must be true to confirm you intend to merge this task's open PRs now."
|
|
6819
7485
|
}
|
|
6820
7486
|
},
|
|
6821
7487
|
required: ["confirmedConflictFree"]
|
|
@@ -6823,7 +7489,7 @@ function createMergeWebIdePullRequestsTool(options) {
|
|
|
6823
7489
|
execute: async (args) => {
|
|
6824
7490
|
if (args.confirmedConflictFree !== true) {
|
|
6825
7491
|
throw new Error(
|
|
6826
|
-
"MergeWebIdePullRequests \u8981\u6C42 confirmedConflictFree=true\u3002
|
|
7492
|
+
"MergeWebIdePullRequests \u8981\u6C42 confirmedConflictFree=true\u3002"
|
|
6827
7493
|
);
|
|
6828
7494
|
}
|
|
6829
7495
|
const api = createApmApiClient(cfg);
|
|
@@ -6835,6 +7501,7 @@ function createMergeWebIdePullRequestsTool(options) {
|
|
|
6835
7501
|
}
|
|
6836
7502
|
|
|
6837
7503
|
// src/commands/connect/webide-plan-tools.ts
|
|
7504
|
+
init_client();
|
|
6838
7505
|
function asString(value) {
|
|
6839
7506
|
return typeof value === "string" ? value.trim() : "";
|
|
6840
7507
|
}
|
|
@@ -6877,7 +7544,7 @@ function createRecommendPlanTool(options) {
|
|
|
6877
7544
|
function createUpsertWebIdePlanTool(options) {
|
|
6878
7545
|
const { cfg, taskId } = options;
|
|
6879
7546
|
return {
|
|
6880
|
-
description: "Persist the implementation plan markdown for this WebIDE task and mark
|
|
7547
|
+
description: "Persist or replace the implementation plan markdown for this WebIDE task and mark it ready for human confirmation. Call with the full plan document (not a diff). Use after generating or revising the plan.",
|
|
6881
7548
|
inputSchema: {
|
|
6882
7549
|
type: "object",
|
|
6883
7550
|
properties: {
|
|
@@ -6904,6 +7571,7 @@ function createUpsertWebIdePlanTool(options) {
|
|
|
6904
7571
|
}
|
|
6905
7572
|
|
|
6906
7573
|
// src/commands/connect/webide-test-case-tools.ts
|
|
7574
|
+
init_client();
|
|
6907
7575
|
function asString2(value) {
|
|
6908
7576
|
return typeof value === "string" ? value.trim() : "";
|
|
6909
7577
|
}
|
|
@@ -6988,6 +7656,165 @@ function createUpsertWebIdeTestCasesTool(options) {
|
|
|
6988
7656
|
};
|
|
6989
7657
|
}
|
|
6990
7658
|
|
|
7659
|
+
// src/commands/connect/webide-terminal-tools.ts
|
|
7660
|
+
init_client();
|
|
7661
|
+
function asString3(value) {
|
|
7662
|
+
return typeof value === "string" ? value.trim() : "";
|
|
7663
|
+
}
|
|
7664
|
+
function asPorts(value) {
|
|
7665
|
+
if (!Array.isArray(value)) return void 0;
|
|
7666
|
+
const ports = value.map((p) => typeof p === "number" ? p : Number(p)).filter((p) => Number.isFinite(p) && p > 0 && p < 65536).map((p) => Math.trunc(p));
|
|
7667
|
+
return ports.length ? ports : void 0;
|
|
7668
|
+
}
|
|
7669
|
+
function createWebIdeTerminalTools(options) {
|
|
7670
|
+
const { cfg, taskId, workdir, rpc } = options;
|
|
7671
|
+
const StartWebIdeTerminal = {
|
|
7672
|
+
description: "Start a long-running WebIDE terminal (e.g. frontend/backend dev server). Process outlives this message. Same key already RUNNING/READY returns idempotently. Do NOT use Shell for long-lived dev servers. Returns terminalId, pid, ports.",
|
|
7673
|
+
inputSchema: {
|
|
7674
|
+
type: "object",
|
|
7675
|
+
properties: {
|
|
7676
|
+
key: {
|
|
7677
|
+
type: "string",
|
|
7678
|
+
description: "Stable key, e.g. frontend / backend"
|
|
7679
|
+
},
|
|
7680
|
+
name: { type: "string", description: "Display name" },
|
|
7681
|
+
cwd: {
|
|
7682
|
+
type: "string",
|
|
7683
|
+
description: "Working directory (absolute or under workspace)"
|
|
7684
|
+
},
|
|
7685
|
+
command: {
|
|
7686
|
+
type: "string",
|
|
7687
|
+
description: "Shell command to run, e.g. pnpm dev"
|
|
7688
|
+
},
|
|
7689
|
+
readyPattern: {
|
|
7690
|
+
type: "string",
|
|
7691
|
+
description: "Optional regex; when matched in logs, status becomes READY"
|
|
7692
|
+
},
|
|
7693
|
+
portsHint: {
|
|
7694
|
+
type: "array",
|
|
7695
|
+
items: { type: "number" },
|
|
7696
|
+
description: "Optional expected listen ports"
|
|
7697
|
+
}
|
|
7698
|
+
},
|
|
7699
|
+
required: ["key", "cwd", "command"]
|
|
7700
|
+
},
|
|
7701
|
+
execute: async (args) => {
|
|
7702
|
+
const key = asString3(args.key);
|
|
7703
|
+
const cwd = asString3(args.cwd) || workdir;
|
|
7704
|
+
const command = asString3(args.command);
|
|
7705
|
+
if (!key || !command) {
|
|
7706
|
+
return {
|
|
7707
|
+
content: [{ type: "text", text: "key / command \u4E0D\u80FD\u4E3A\u7A7A" }],
|
|
7708
|
+
isError: true
|
|
7709
|
+
};
|
|
7710
|
+
}
|
|
7711
|
+
try {
|
|
7712
|
+
const result = rpc ? await rpc.start({
|
|
7713
|
+
taskId,
|
|
7714
|
+
key,
|
|
7715
|
+
name: asString3(args.name) || void 0,
|
|
7716
|
+
cwd,
|
|
7717
|
+
command,
|
|
7718
|
+
readyPattern: asString3(args.readyPattern) || void 0,
|
|
7719
|
+
portsHint: asPorts(args.portsHint)
|
|
7720
|
+
}) : await (async () => {
|
|
7721
|
+
throw new Error("Terminal RPC \u4E0D\u53EF\u7528\uFF08\u9700\u5728 connect \u4E3B\u8FDB\u7A0B\uFF09");
|
|
7722
|
+
})();
|
|
7723
|
+
return JSON.stringify(result, null, 2);
|
|
7724
|
+
} catch (err) {
|
|
7725
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
7726
|
+
return {
|
|
7727
|
+
content: [{ type: "text", text: `\u542F\u52A8\u7EC8\u7AEF\u5931\u8D25: ${detail}` }],
|
|
7728
|
+
isError: true
|
|
7729
|
+
};
|
|
7730
|
+
}
|
|
7731
|
+
}
|
|
7732
|
+
};
|
|
7733
|
+
const StopWebIdeTerminal = {
|
|
7734
|
+
description: "Stop a WebIDE terminal and kill its process tree. Soft-terminates (status EXITED, record kept).",
|
|
7735
|
+
inputSchema: {
|
|
7736
|
+
type: "object",
|
|
7737
|
+
properties: {
|
|
7738
|
+
key: { type: "string", description: "Terminal key" },
|
|
7739
|
+
terminalId: { type: "string", description: "Server terminal id" }
|
|
7740
|
+
}
|
|
7741
|
+
},
|
|
7742
|
+
execute: async (args) => {
|
|
7743
|
+
const key = asString3(args.key) || void 0;
|
|
7744
|
+
const terminalId = asString3(args.terminalId) || void 0;
|
|
7745
|
+
if (!key && !terminalId) {
|
|
7746
|
+
return {
|
|
7747
|
+
content: [{ type: "text", text: "\u9700\u8981 key \u6216 terminalId" }],
|
|
7748
|
+
isError: true
|
|
7749
|
+
};
|
|
7750
|
+
}
|
|
7751
|
+
try {
|
|
7752
|
+
const result = rpc ? await rpc.stop({ taskId, key, terminalId }) : await (async () => {
|
|
7753
|
+
throw new Error("Terminal RPC \u4E0D\u53EF\u7528\uFF08\u9700\u5728 connect \u4E3B\u8FDB\u7A0B\uFF09");
|
|
7754
|
+
})();
|
|
7755
|
+
return JSON.stringify(result, null, 2);
|
|
7756
|
+
} catch (err) {
|
|
7757
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
7758
|
+
return {
|
|
7759
|
+
content: [{ type: "text", text: `\u505C\u6B62\u7EC8\u7AEF\u5931\u8D25: ${detail}` }],
|
|
7760
|
+
isError: true
|
|
7761
|
+
};
|
|
7762
|
+
}
|
|
7763
|
+
}
|
|
7764
|
+
};
|
|
7765
|
+
const StopAllWebIdeTerminals = {
|
|
7766
|
+
description: "Stop all living WebIDE terminals for the current task (kill process trees). Use before re-running local dev to avoid port conflicts. Soft-terminates records.",
|
|
7767
|
+
inputSchema: {
|
|
7768
|
+
type: "object",
|
|
7769
|
+
properties: {}
|
|
7770
|
+
},
|
|
7771
|
+
execute: async () => {
|
|
7772
|
+
try {
|
|
7773
|
+
const result = rpc ? await rpc.stopAll({ taskId }) : await (async () => {
|
|
7774
|
+
throw new Error("Terminal RPC \u4E0D\u53EF\u7528\uFF08\u9700\u5728 connect \u4E3B\u8FDB\u7A0B\uFF09");
|
|
7775
|
+
})();
|
|
7776
|
+
return JSON.stringify(result, null, 2);
|
|
7777
|
+
} catch (err) {
|
|
7778
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
7779
|
+
return {
|
|
7780
|
+
content: [{ type: "text", text: `\u5168\u90E8\u505C\u6B62\u5931\u8D25: ${detail}` }],
|
|
7781
|
+
isError: true
|
|
7782
|
+
};
|
|
7783
|
+
}
|
|
7784
|
+
}
|
|
7785
|
+
};
|
|
7786
|
+
const ListWebIdeTerminals = {
|
|
7787
|
+
description: "List living WebIDE terminals for the current task (STARTING/RUNNING/READY/STOPPING only). Does NOT include EXITED/FAILED. Returns id, key, status, pid, ports.",
|
|
7788
|
+
inputSchema: {
|
|
7789
|
+
type: "object",
|
|
7790
|
+
properties: {}
|
|
7791
|
+
},
|
|
7792
|
+
execute: async () => {
|
|
7793
|
+
try {
|
|
7794
|
+
if (rpc) {
|
|
7795
|
+
const result2 = await rpc.list({ taskId });
|
|
7796
|
+
return JSON.stringify(result2, null, 2);
|
|
7797
|
+
}
|
|
7798
|
+
const api = createApmApiClient(cfg);
|
|
7799
|
+
const result = await api.cli.webideListTerminals({ taskId });
|
|
7800
|
+
return JSON.stringify(result, null, 2);
|
|
7801
|
+
} catch (err) {
|
|
7802
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
7803
|
+
return {
|
|
7804
|
+
content: [{ type: "text", text: `\u5217\u51FA\u7EC8\u7AEF\u5931\u8D25: ${detail}` }],
|
|
7805
|
+
isError: true
|
|
7806
|
+
};
|
|
7807
|
+
}
|
|
7808
|
+
}
|
|
7809
|
+
};
|
|
7810
|
+
return {
|
|
7811
|
+
StartWebIdeTerminal,
|
|
7812
|
+
StopWebIdeTerminal,
|
|
7813
|
+
StopAllWebIdeTerminals,
|
|
7814
|
+
ListWebIdeTerminals
|
|
7815
|
+
};
|
|
7816
|
+
}
|
|
7817
|
+
|
|
6991
7818
|
// src/commands/connect/cursor-custom-tools.ts
|
|
6992
7819
|
var PLAN_MODE_ASK_QUESTION_HINT = `[SDK \u73AF\u5883\u8BF4\u660E]
|
|
6993
7820
|
AskQuestion \u5DF2\u901A\u8FC7 MCP \u670D\u52A1\u5668 custom-user-tools \u6CE8\u518C\uFF0C\u5DE5\u5177\u540D\u4E3A AskQuestion\u3002
|
|
@@ -7025,6 +7852,17 @@ function createCursorCustomTools(cfg, messageId, options) {
|
|
|
7025
7852
|
cfg,
|
|
7026
7853
|
taskId: options.taskId
|
|
7027
7854
|
});
|
|
7855
|
+
if (options.workdir) {
|
|
7856
|
+
Object.assign(
|
|
7857
|
+
tools,
|
|
7858
|
+
createWebIdeTerminalTools({
|
|
7859
|
+
cfg,
|
|
7860
|
+
taskId: options.taskId,
|
|
7861
|
+
workdir: options.workdir,
|
|
7862
|
+
rpc: options.terminalRpc
|
|
7863
|
+
})
|
|
7864
|
+
);
|
|
7865
|
+
}
|
|
7028
7866
|
}
|
|
7029
7867
|
return tools;
|
|
7030
7868
|
}
|
|
@@ -7093,8 +7931,8 @@ async function obtainAgent(ctx) {
|
|
|
7093
7931
|
settingSources: ["project"]
|
|
7094
7932
|
} : {}
|
|
7095
7933
|
},
|
|
7096
|
-
...ctx.mode ? { mode: ctx.mode } : {}
|
|
7097
|
-
|
|
7934
|
+
...ctx.mode ? { mode: ctx.mode } : {},
|
|
7935
|
+
...ctx.mcpServers ? { mcpServers: ctx.mcpServers } : {}
|
|
7098
7936
|
};
|
|
7099
7937
|
const explicitAgentId = ctx.resumeAgentId?.trim();
|
|
7100
7938
|
const savedAgentId = explicitAgentId || (ctx.user ? loadSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user) : void 0);
|
|
@@ -7148,7 +7986,9 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
7148
7986
|
appendMessageContent: options?.appendMessageContent,
|
|
7149
7987
|
askQuestionExecute: options?.askQuestionExecute,
|
|
7150
7988
|
enableWebIdePlanTools: options?.enableWebIdePlanTools,
|
|
7151
|
-
taskId: options?.taskId
|
|
7989
|
+
taskId: options?.taskId,
|
|
7990
|
+
workdir,
|
|
7991
|
+
terminalRpc: options?.terminalRpc
|
|
7152
7992
|
});
|
|
7153
7993
|
const enableSandbox = Boolean(options?.enableSandbox);
|
|
7154
7994
|
let prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
|
|
@@ -7189,7 +8029,6 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
7189
8029
|
try {
|
|
7190
8030
|
const run = await agent.send(prompt, {
|
|
7191
8031
|
...ctx.mode ? { mode: ctx.mode } : {},
|
|
7192
|
-
// mcpServers: createPlaywrightMcpServers(),
|
|
7193
8032
|
local: {
|
|
7194
8033
|
...options?.forceSend ? { force: true } : {},
|
|
7195
8034
|
customTools
|
|
@@ -7290,6 +8129,7 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
7290
8129
|
}
|
|
7291
8130
|
|
|
7292
8131
|
// src/commands/connect/ensure-message-reply.ts
|
|
8132
|
+
init_client();
|
|
7293
8133
|
var DEFAULT_REPLY = "\u4EFB\u52A1\u5DF2\u5B8C\u6210\u3002";
|
|
7294
8134
|
function resolveMessageReplyFallback(fallback) {
|
|
7295
8135
|
for (const candidate of [
|
|
@@ -7433,6 +8273,7 @@ function createRunSlotPool(maxConcurrent = DEFAULT_MAX_CONCURRENT, options = {})
|
|
|
7433
8273
|
}
|
|
7434
8274
|
|
|
7435
8275
|
// src/commands/connect/webide-worker-pool.ts
|
|
8276
|
+
init_webide_terminal_registry();
|
|
7436
8277
|
import { Worker } from "node:worker_threads";
|
|
7437
8278
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
7438
8279
|
import { dirname as dirname7, join as join20 } from "node:path";
|
|
@@ -7444,23 +8285,78 @@ function spawnWebIdeMessageWorker(cfg, msg) {
|
|
|
7444
8285
|
const worker = new Worker(workerFile, {
|
|
7445
8286
|
workerData: { cfg, msg }
|
|
7446
8287
|
});
|
|
8288
|
+
const registry = getWebIdeTerminalRegistry(cfg);
|
|
7447
8289
|
let resolveDone;
|
|
7448
8290
|
const done = new Promise((resolve7) => {
|
|
7449
8291
|
resolveDone = resolve7;
|
|
7450
8292
|
});
|
|
7451
|
-
worker.on(
|
|
7452
|
-
"
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
8293
|
+
worker.on("message", (m) => {
|
|
8294
|
+
if (m?.type === "terminal-rpc") {
|
|
8295
|
+
const rpc = m;
|
|
8296
|
+
void (async () => {
|
|
8297
|
+
try {
|
|
8298
|
+
let result;
|
|
8299
|
+
if (rpc.op === "start") {
|
|
8300
|
+
result = await registry.start({
|
|
8301
|
+
taskId: String(rpc.args.taskId ?? msg.taskId),
|
|
8302
|
+
key: String(rpc.args.key ?? ""),
|
|
8303
|
+
name: typeof rpc.args.name === "string" ? rpc.args.name : void 0,
|
|
8304
|
+
cwd: String(rpc.args.cwd ?? msg.workdir),
|
|
8305
|
+
command: String(rpc.args.command ?? ""),
|
|
8306
|
+
readyPattern: typeof rpc.args.readyPattern === "string" ? rpc.args.readyPattern : void 0,
|
|
8307
|
+
portsHint: Array.isArray(rpc.args.portsHint) ? rpc.args.portsHint : void 0
|
|
8308
|
+
});
|
|
8309
|
+
} else if (rpc.op === "stop") {
|
|
8310
|
+
const terminalId = typeof rpc.args.terminalId === "string" ? rpc.args.terminalId : void 0;
|
|
8311
|
+
const key = typeof rpc.args.key === "string" ? rpc.args.key : void 0;
|
|
8312
|
+
const taskId = String(rpc.args.taskId ?? msg.taskId);
|
|
8313
|
+
let id = terminalId;
|
|
8314
|
+
if (!id && key) {
|
|
8315
|
+
const local = registry.listLocal(taskId).find((t) => t.key === key);
|
|
8316
|
+
id = local?.id;
|
|
8317
|
+
}
|
|
8318
|
+
if (!id) {
|
|
8319
|
+
throw new Error("\u672A\u627E\u5230\u7EC8\u7AEF");
|
|
8320
|
+
}
|
|
8321
|
+
result = await registry.stop(id, { reason: "ai-stop" });
|
|
8322
|
+
} else if (rpc.op === "stopAll") {
|
|
8323
|
+
result = await registry.stopAllForTask(
|
|
8324
|
+
String(rpc.args.taskId ?? msg.taskId),
|
|
8325
|
+
"ai-stop-all"
|
|
8326
|
+
);
|
|
8327
|
+
} else {
|
|
8328
|
+
result = {
|
|
8329
|
+
terminals: registry.listLocal(
|
|
8330
|
+
String(rpc.args.taskId ?? msg.taskId)
|
|
8331
|
+
)
|
|
8332
|
+
};
|
|
8333
|
+
}
|
|
8334
|
+
worker.postMessage({
|
|
8335
|
+
type: "terminal-rpc-result",
|
|
8336
|
+
id: rpc.id,
|
|
8337
|
+
ok: true,
|
|
8338
|
+
result
|
|
8339
|
+
});
|
|
8340
|
+
} catch (err) {
|
|
8341
|
+
worker.postMessage({
|
|
8342
|
+
type: "terminal-rpc-result",
|
|
8343
|
+
id: rpc.id,
|
|
8344
|
+
ok: false,
|
|
8345
|
+
error: err instanceof Error ? err.message : String(err)
|
|
8346
|
+
});
|
|
7459
8347
|
}
|
|
7460
|
-
|
|
8348
|
+
})();
|
|
8349
|
+
return;
|
|
8350
|
+
}
|
|
8351
|
+
if (m?.type === "done" || m?.type === "error") {
|
|
8352
|
+
if (m.type === "error") {
|
|
8353
|
+
console.error(
|
|
8354
|
+
`[apm] webide worker error messageId=${m.messageId}: ${m.error}`
|
|
8355
|
+
);
|
|
7461
8356
|
}
|
|
8357
|
+
void worker.terminate().finally(() => resolveDone());
|
|
7462
8358
|
}
|
|
7463
|
-
);
|
|
8359
|
+
});
|
|
7464
8360
|
worker.on("error", (err) => {
|
|
7465
8361
|
console.error("[apm] webide worker crashed:", err);
|
|
7466
8362
|
resolveDone();
|
|
@@ -7565,7 +8461,7 @@ async function handleInboundMessage(cfg, msg, signal, ctx) {
|
|
|
7565
8461
|
if (!pullRan) {
|
|
7566
8462
|
await runStep(
|
|
7567
8463
|
"sync-project-documents-pull",
|
|
7568
|
-
() =>
|
|
8464
|
+
() => syncProjectDocumentsPull(workdir, apmRoot)
|
|
7569
8465
|
);
|
|
7570
8466
|
}
|
|
7571
8467
|
const agentResult = await runStep(
|
|
@@ -7598,7 +8494,7 @@ async function handleInboundMessage(cfg, msg, signal, ctx) {
|
|
|
7598
8494
|
);
|
|
7599
8495
|
await runStep(
|
|
7600
8496
|
"sync-project-documents",
|
|
7601
|
-
() =>
|
|
8497
|
+
() => syncProjectDocumentsPush(cfg, workdir, apmRoot)
|
|
7602
8498
|
);
|
|
7603
8499
|
await runStep(
|
|
7604
8500
|
"commit-files",
|
|
@@ -7737,6 +8633,11 @@ function attachWsHandlers(ws, ctx, onOpen) {
|
|
|
7737
8633
|
const msg2 = validated.data;
|
|
7738
8634
|
const task2 = (async () => {
|
|
7739
8635
|
const workdir = requireRemoteWorkdir(msg2.workdir);
|
|
8636
|
+
const { getWebIdeTerminalRegistry: getWebIdeTerminalRegistry2 } = await Promise.resolve().then(() => (init_webide_terminal_registry(), webide_terminal_registry_exports));
|
|
8637
|
+
await getWebIdeTerminalRegistry2(cfg).stopAllForTask(
|
|
8638
|
+
msg2.taskId,
|
|
8639
|
+
"cache-cleanup"
|
|
8640
|
+
);
|
|
7740
8641
|
cleanWebIdeWorkspaceCache(msg2.taskId, workdir);
|
|
7741
8642
|
})();
|
|
7742
8643
|
activeTasks.add(task2);
|
|
@@ -7745,6 +8646,21 @@ function attachWsHandlers(ws, ctx, onOpen) {
|
|
|
7745
8646
|
});
|
|
7746
8647
|
return;
|
|
7747
8648
|
}
|
|
8649
|
+
if (validated.data.type === "webide-terminal-stop") {
|
|
8650
|
+
const msg2 = validated.data;
|
|
8651
|
+
const task2 = (async () => {
|
|
8652
|
+
const { getWebIdeTerminalRegistry: getWebIdeTerminalRegistry2 } = await Promise.resolve().then(() => (init_webide_terminal_registry(), webide_terminal_registry_exports));
|
|
8653
|
+
await getWebIdeTerminalRegistry2(cfg).stop(msg2.terminalId, {
|
|
8654
|
+
pid: msg2.pid,
|
|
8655
|
+
reason: "web-stop"
|
|
8656
|
+
});
|
|
8657
|
+
})();
|
|
8658
|
+
activeTasks.add(task2);
|
|
8659
|
+
void task2.finally(() => {
|
|
8660
|
+
activeTasks.delete(task2);
|
|
8661
|
+
});
|
|
8662
|
+
return;
|
|
8663
|
+
}
|
|
7748
8664
|
if (validated.data.type === "webide-message") {
|
|
7749
8665
|
const msg2 = validated.data;
|
|
7750
8666
|
const perMessageController2 = new AbortController();
|
|
@@ -8009,6 +8925,10 @@ async function runConnect(options) {
|
|
|
8009
8925
|
}
|
|
8010
8926
|
}
|
|
8011
8927
|
|
|
8928
|
+
// src/commands/create-pr.ts
|
|
8929
|
+
init_client();
|
|
8930
|
+
init_config();
|
|
8931
|
+
|
|
8012
8932
|
// src/commands/create-pr-errors.ts
|
|
8013
8933
|
import { ApiError as ApiError2 } from "listpage-http";
|
|
8014
8934
|
function extractMessage(error) {
|
|
@@ -8136,6 +9056,8 @@ async function runCreatePr(options) {
|
|
|
8136
9056
|
}
|
|
8137
9057
|
|
|
8138
9058
|
// src/commands/deploy/deploy-tracking.ts
|
|
9059
|
+
init_client();
|
|
9060
|
+
init_config();
|
|
8139
9061
|
function normalizeDeployEnvironment(env) {
|
|
8140
9062
|
const normalized = env.trim().toLowerCase();
|
|
8141
9063
|
if (normalized === "test") return "TEST";
|
|
@@ -8805,6 +9727,7 @@ function registerDeployBackendCommands(program) {
|
|
|
8805
9727
|
// src/commands/deploy/frontend.ts
|
|
8806
9728
|
import { copyFile, readdir as readdir3, stat } from "node:fs/promises";
|
|
8807
9729
|
import path17 from "node:path";
|
|
9730
|
+
init_minio();
|
|
8808
9731
|
function artifactObjectKey(namePrefix, branchSegment, relativePath) {
|
|
8809
9732
|
const base = sanitizeRelativePath(namePrefix);
|
|
8810
9733
|
const rel = sanitizeRelativePath(relativePath);
|
|
@@ -8982,6 +9905,7 @@ function registerDeployFrontendCommands(program) {
|
|
|
8982
9905
|
|
|
8983
9906
|
// src/commands/deploy/sftp.ts
|
|
8984
9907
|
import path18 from "node:path";
|
|
9908
|
+
init_minio();
|
|
8985
9909
|
function registerDeploySftpCommands(program) {
|
|
8986
9910
|
program.command("deploy-sftp").description(
|
|
8987
9911
|
"\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"
|
|
@@ -9107,12 +10031,12 @@ function buildProgram() {
|
|
|
9107
10031
|
await runSyncDeployConfig();
|
|
9108
10032
|
});
|
|
9109
10033
|
program.command("sync-project-documents").description(
|
|
9110
|
-
"\u540C\u6B65\
|
|
9111
|
-
).option("--push", "\u63A8\u9001\u672C\u5730 .apm/
|
|
10034
|
+
"\u540C\u6B65\u9879\u76EE\u6587\u6863\uFF1A\u9ED8\u8BA4 pull \u5230 .apm/docs/\uFF1B\u52A0 --push \u5C06\u672C\u5730\u53D8\u66F4\u63A8\u9001\u5230\u5E73\u53F0"
|
|
10035
|
+
).option("--push", "\u63A8\u9001\u672C\u5730 .apm/docs/ \u5230\u5E73\u53F0").option("--pull", "\u4ECE\u5E73\u53F0\u62C9\u53D6\u5230 .apm/docs/").action(async (opts) => {
|
|
9112
10036
|
await runSyncProjectDocuments(opts);
|
|
9113
10037
|
});
|
|
9114
10038
|
program.command("pull").description(
|
|
9115
|
-
"\u62C9\u53D6\u6C9F\u901A\u7FA4\u6570\u636E\u5230 .apm/sessions/<sessionId>/\uFF0C\u5E76\u540C\u6B65\u90E8\u7F72\u914D\u7F6E\u4E0E\
|
|
10039
|
+
"\u62C9\u53D6\u6C9F\u901A\u7FA4\u6570\u636E\u5230 .apm/sessions/<sessionId>/\uFF0C\u5E76\u540C\u6B65\u90E8\u7F72\u914D\u7F6E\u4E0E\u9879\u76EE\u6587\u6863\u5230 .apm/docs/"
|
|
9116
10040
|
).argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").action(async (sessionId) => {
|
|
9117
10041
|
await runPull(sessionId);
|
|
9118
10042
|
});
|