ai-project-manage-cli 8.0.2 → 8.0.3
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 +4 -18
- package/dist/index.js +467 -5215
- package/dist/webide-message-worker.js +370 -538
- package/package.json +3 -10
- package/template/AGENTS.webide.md +2 -2
- package/template/rules/webide_terminal.md +22 -18
- package/template/skills/webide-run-retro/SKILL.md +103 -0
- package/template/skills/webide-run-retro/attribution.md +26 -0
- package/template/skills/webide-run-retro/scripts/inspect-run.mjs +335 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/commands/connect/webide-message-worker.ts
|
|
2
|
-
import { parentPort
|
|
2
|
+
import { parentPort, workerData } from "node:worker_threads";
|
|
3
3
|
|
|
4
4
|
// src/api/client.ts
|
|
5
5
|
import { createApiClient } from "listpage-http";
|
|
@@ -58,32 +58,12 @@ var requestConfig = {
|
|
|
58
58
|
method: "PUT",
|
|
59
59
|
path: "/cli/webide/test-cases"
|
|
60
60
|
}),
|
|
61
|
-
webideListTerminals: defineEndpoint({
|
|
62
|
-
method: "GET",
|
|
63
|
-
path: "/cli/webide/terminals"
|
|
64
|
-
}),
|
|
65
|
-
webideUpsertTerminal: defineEndpoint({
|
|
66
|
-
method: "POST",
|
|
67
|
-
path: "/cli/webide/terminals"
|
|
68
|
-
}),
|
|
69
|
-
webideUpdateTerminalStatus: defineEndpoint({
|
|
70
|
-
method: "PUT",
|
|
71
|
-
path: "/cli/webide/terminals/status"
|
|
72
|
-
}),
|
|
73
|
-
webideUpdateTerminalMeta: defineEndpoint({
|
|
74
|
-
method: "PUT",
|
|
75
|
-
path: "/cli/webide/terminals/meta"
|
|
76
|
-
}),
|
|
77
61
|
projectBaseBranch: defineEndpoint(
|
|
78
62
|
{
|
|
79
63
|
method: "GET",
|
|
80
64
|
path: "/cli/tasks/project-base-branch"
|
|
81
65
|
}
|
|
82
66
|
),
|
|
83
|
-
workspaceBaseline: defineEndpoint({
|
|
84
|
-
method: "GET",
|
|
85
|
-
path: "/cli/workspaces/baseline"
|
|
86
|
-
}),
|
|
87
67
|
createWebIdeDraftPullRequest: defineEndpoint({
|
|
88
68
|
method: "POST",
|
|
89
69
|
path: "/cli/webide/draft-pull-requests"
|
|
@@ -108,12 +88,6 @@ var requestConfig = {
|
|
|
108
88
|
method: "DELETE",
|
|
109
89
|
path: "/cli/project-documents"
|
|
110
90
|
}),
|
|
111
|
-
getDeployArtifactStorage: defineEndpoint(
|
|
112
|
-
{
|
|
113
|
-
method: "GET",
|
|
114
|
-
path: "/cli/deploy-artifact-storage"
|
|
115
|
-
}
|
|
116
|
-
),
|
|
117
91
|
getApmLogStorage: defineEndpoint({
|
|
118
92
|
method: "GET",
|
|
119
93
|
path: "/cli/apm-log-storage"
|
|
@@ -197,7 +171,7 @@ function createApmApiClient(cfg) {
|
|
|
197
171
|
});
|
|
198
172
|
}
|
|
199
173
|
|
|
200
|
-
// src/
|
|
174
|
+
// src/utils/path.ts
|
|
201
175
|
import { realpathSync } from "fs";
|
|
202
176
|
import { platform } from "os";
|
|
203
177
|
import { resolve } from "path";
|
|
@@ -244,7 +218,7 @@ function requireRemoteWorkdir(workdir) {
|
|
|
244
218
|
return resolveWorkdirPath(trimmed);
|
|
245
219
|
}
|
|
246
220
|
|
|
247
|
-
// src/
|
|
221
|
+
// src/utils/workspace.ts
|
|
248
222
|
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
|
|
249
223
|
import { dirname, join as join2, resolve as resolve2 } from "path";
|
|
250
224
|
import { fileURLToPath } from "url";
|
|
@@ -381,11 +355,11 @@ async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()
|
|
|
381
355
|
assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
382
356
|
}
|
|
383
357
|
|
|
384
|
-
// src/git
|
|
358
|
+
// src/utils/git.ts
|
|
385
359
|
import { execFile as execFile2 } from "child_process";
|
|
386
360
|
import { promisify as promisify2 } from "util";
|
|
387
361
|
|
|
388
|
-
// src/git-remote.ts
|
|
362
|
+
// src/utils/git-remote.ts
|
|
389
363
|
import { execFile } from "child_process";
|
|
390
364
|
import { promisify } from "util";
|
|
391
365
|
var execFileAsync = promisify(execFile);
|
|
@@ -438,7 +412,7 @@ async function tryReadHttpsGitOriginUrl(cwd) {
|
|
|
438
412
|
return toHttpsGitRemoteUrl(raw);
|
|
439
413
|
}
|
|
440
414
|
|
|
441
|
-
// src/git
|
|
415
|
+
// src/utils/git.ts
|
|
442
416
|
var execFileAsync2 = promisify2(execFile2);
|
|
443
417
|
function gitExecEnv() {
|
|
444
418
|
const existing = process.env.GIT_SSH_COMMAND?.trim();
|
|
@@ -536,10 +510,16 @@ async function branchHasChangesAgainstBase(cwd, baseBranch, headBranch) {
|
|
|
536
510
|
return true;
|
|
537
511
|
}
|
|
538
512
|
}
|
|
539
|
-
var FEATURE_BRANCH_RE = /^feat\/task
|
|
513
|
+
var FEATURE_BRANCH_RE = /^feat\/task-(.+)$/;
|
|
540
514
|
function isFeatureBranchName(branch) {
|
|
541
515
|
return FEATURE_BRANCH_RE.test(branch.trim().replace(/^origin\//, ""));
|
|
542
516
|
}
|
|
517
|
+
function taskIdFromFeatureBranch(branch) {
|
|
518
|
+
const name = branch.trim().replace(/^origin\//, "");
|
|
519
|
+
const match = name.match(FEATURE_BRANCH_RE);
|
|
520
|
+
const id = match?.[1]?.trim() ?? "";
|
|
521
|
+
return id || null;
|
|
522
|
+
}
|
|
543
523
|
async function hasUpstream(cwd) {
|
|
544
524
|
try {
|
|
545
525
|
await execGit(cwd, ["rev-parse", "--abbrev-ref", "@{upstream}"], true);
|
|
@@ -565,7 +545,7 @@ async function pushCurrentBranch(cwd) {
|
|
|
565
545
|
return true;
|
|
566
546
|
}
|
|
567
547
|
|
|
568
|
-
// src/workspace-repos.ts
|
|
548
|
+
// src/utils/workspace-repos.ts
|
|
569
549
|
import {
|
|
570
550
|
existsSync as existsSync2,
|
|
571
551
|
mkdirSync as mkdirSync3,
|
|
@@ -947,7 +927,12 @@ async function runTaskBranch(taskId, options = {}) {
|
|
|
947
927
|
cwd: gitRoot
|
|
948
928
|
});
|
|
949
929
|
}
|
|
950
|
-
return {
|
|
930
|
+
return {
|
|
931
|
+
branch,
|
|
932
|
+
baseline: baselineBranch,
|
|
933
|
+
kind: manifest.kind,
|
|
934
|
+
repos: repoRoots
|
|
935
|
+
};
|
|
951
936
|
}
|
|
952
937
|
|
|
953
938
|
// src/commands/connect/cursor-agent.ts
|
|
@@ -955,9 +940,8 @@ import {
|
|
|
955
940
|
Agent,
|
|
956
941
|
CursorAgentError
|
|
957
942
|
} from "@cursor/sdk";
|
|
958
|
-
import { setMaxListeners as setMaxListeners2 } from "node:events";
|
|
959
943
|
|
|
960
|
-
// src/plan-format.ts
|
|
944
|
+
// src/utils/plan-format.ts
|
|
961
945
|
function formatPlanMarkdown(raw) {
|
|
962
946
|
let text = raw.trim();
|
|
963
947
|
if (!text) {
|
|
@@ -978,7 +962,7 @@ function formatPlanMarkdown(raw) {
|
|
|
978
962
|
return text.replace(/\r\n/g, "\n").trimEnd() + "\n";
|
|
979
963
|
}
|
|
980
964
|
|
|
981
|
-
// src/session
|
|
965
|
+
// src/utils/session.ts
|
|
982
966
|
function serializeTokenUsage(usage) {
|
|
983
967
|
return {
|
|
984
968
|
inputTokens: usage.inputTokens,
|
|
@@ -1260,71 +1244,9 @@ ${JSON.stringify(event, null, 2)}
|
|
|
1260
1244
|
\`\`\``;
|
|
1261
1245
|
}
|
|
1262
1246
|
|
|
1263
|
-
// src/commands/connect/
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
getMaxListeners,
|
|
1267
|
-
setMaxListeners
|
|
1268
|
-
} from "node:events";
|
|
1269
|
-
function isAbortSignalDebugEnabled() {
|
|
1270
|
-
const v = process.env.APM_DEBUG_ABORT_SIGNAL?.trim().toLowerCase();
|
|
1271
|
-
return v === "1" || v === "true" || v === "yes";
|
|
1272
|
-
}
|
|
1273
|
-
function formatAbortSignalStats(signal, label) {
|
|
1274
|
-
if (!signal) {
|
|
1275
|
-
return `[apm:abort-debug] ${label}: (no signal)`;
|
|
1276
|
-
}
|
|
1277
|
-
const listeners = getEventListeners(signal, "abort");
|
|
1278
|
-
const max = getMaxListeners(signal);
|
|
1279
|
-
return `[apm:abort-debug] ${label}: abortListeners=${listeners.length} maxListeners=${max} aborted=${signal.aborted}`;
|
|
1280
|
-
}
|
|
1281
|
-
function logAbortSignalStats(signal, label) {
|
|
1282
|
-
if (!isAbortSignalDebugEnabled()) return;
|
|
1283
|
-
console.log(formatAbortSignalStats(signal, label));
|
|
1284
|
-
}
|
|
1285
|
-
var installed = false;
|
|
1286
|
-
function installAbortSignalDebug() {
|
|
1287
|
-
if (!isAbortSignalDebugEnabled() || installed) return;
|
|
1288
|
-
installed = true;
|
|
1289
|
-
const maxFromEnv = Number.parseInt(
|
|
1290
|
-
process.env.APM_ABORT_SIGNAL_MAX_LISTENERS ?? "",
|
|
1291
|
-
10
|
|
1292
|
-
);
|
|
1293
|
-
if (Number.isFinite(maxFromEnv) && maxFromEnv > 0) {
|
|
1294
|
-
setMaxListeners(maxFromEnv);
|
|
1295
|
-
console.log(
|
|
1296
|
-
`[apm:abort-debug] setMaxListeners(${maxFromEnv}) via APM_ABORT_SIGNAL_MAX_LISTENERS`
|
|
1297
|
-
);
|
|
1298
|
-
}
|
|
1299
|
-
process.on("warning", (warning) => {
|
|
1300
|
-
if (warning.name !== "MaxListenersExceededWarning") return;
|
|
1301
|
-
console.warn(`[apm:abort-debug] ${warning.name}: ${warning.message}`);
|
|
1302
|
-
if (warning.stack) {
|
|
1303
|
-
console.warn(warning.stack);
|
|
1304
|
-
}
|
|
1305
|
-
});
|
|
1306
|
-
const proto = AbortSignal.prototype;
|
|
1307
|
-
const original = proto.addEventListener;
|
|
1308
|
-
proto.addEventListener = function(type, listener, options) {
|
|
1309
|
-
if (type === "abort") {
|
|
1310
|
-
const sig = this;
|
|
1311
|
-
const before = getEventListeners(sig, "abort").length;
|
|
1312
|
-
const max = getMaxListeners(sig);
|
|
1313
|
-
const stack = new Error("[apm:abort-debug] addEventListener stack").stack?.split("\n").slice(2, 8).join("\n") ?? "";
|
|
1314
|
-
console.log(
|
|
1315
|
-
`[apm:abort-debug] addEventListener("abort") before=${before} max=${max}
|
|
1316
|
-
${stack}`
|
|
1317
|
-
);
|
|
1318
|
-
}
|
|
1319
|
-
return original.call(this, type, listener, options);
|
|
1320
|
-
};
|
|
1321
|
-
console.log(
|
|
1322
|
-
"[apm:abort-debug] \u5DF2\u542F\u7528 AbortSignal \u8C03\u8BD5\uFF08APM_DEBUG_ABORT_SIGNAL\uFF09"
|
|
1323
|
-
);
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
// src/commands/connect/append-message-tool.ts
|
|
1327
|
-
function createAppendMessageCustomTools(messageId, appendContent2) {
|
|
1247
|
+
// src/commands/connect/tools/append-message-tool.ts
|
|
1248
|
+
function createAppendMessageCustomTools(options) {
|
|
1249
|
+
const { appendContent: appendContent2 } = options;
|
|
1328
1250
|
return {
|
|
1329
1251
|
AppendMessage: {
|
|
1330
1252
|
description: "\u5411\u5F53\u524D WebIDE \u6D88\u606F\u8FFD\u52A0\u7528\u6237\u53EF\u89C1\u56DE\u590D\u3002\u53EF\u591A\u6B21\u8C03\u7528\u8865\u5145\u8FDB\u5C55\uFF1B\u88AB @ \u65F6\u6536\u5230\u540E\u5E94\u5148\u7B80\u77ED\u786E\u8BA4\u518D\u6267\u884C\u4EFB\u52A1\u3002\u7ED3\u8BBA\u4E0E\u8FDB\u5C55\u5E94\u5199\u5728\u672C\u5DE5\u5177\u4E2D\uFF1B\u6700\u7EC8\u81EA\u7136\u8BED\u8A00\u6536\u5C3E\u52FF\u518D\u590D\u8FF0\u6B64\u5904\u5185\u5BB9\u3002",
|
|
@@ -1348,7 +1270,6 @@ function createAppendMessageCustomTools(messageId, appendContent2) {
|
|
|
1348
1270
|
}
|
|
1349
1271
|
try {
|
|
1350
1272
|
await appendContent2(content);
|
|
1351
|
-
console.log(`[apm] AppendMessage \u5DF2\u8FFD\u52A0: messageId=${messageId}`);
|
|
1352
1273
|
return "\u5DF2\u8FFD\u52A0\u6D88\u606F\u5185\u5BB9";
|
|
1353
1274
|
} catch (err) {
|
|
1354
1275
|
const detail = err instanceof Error ? err.message : String(err);
|
|
@@ -1362,7 +1283,7 @@ function createAppendMessageCustomTools(messageId, appendContent2) {
|
|
|
1362
1283
|
};
|
|
1363
1284
|
}
|
|
1364
1285
|
|
|
1365
|
-
// src/commands/connect/ask-question-tool.ts
|
|
1286
|
+
// src/commands/connect/tools/ask-question-tool.ts
|
|
1366
1287
|
var INPUT_SCHEMA = {
|
|
1367
1288
|
type: "object",
|
|
1368
1289
|
properties: {
|
|
@@ -1400,121 +1321,118 @@ var INPUT_SCHEMA = {
|
|
|
1400
1321
|
};
|
|
1401
1322
|
function createAskQuestionTool(options) {
|
|
1402
1323
|
return {
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1324
|
+
AskQuestion: {
|
|
1325
|
+
description: "Collect structured multiple-choice answers from the user. Use when blocked on a decision that is genuinely the user's to make.",
|
|
1326
|
+
inputSchema: INPUT_SCHEMA,
|
|
1327
|
+
execute: async (args) => {
|
|
1328
|
+
options?.onInvoke?.(args);
|
|
1329
|
+
if (options?.execute) {
|
|
1330
|
+
return options.execute(args);
|
|
1331
|
+
}
|
|
1332
|
+
const payload = JSON.stringify(args, null, 2);
|
|
1333
|
+
console.log(`[apm] AskQuestion\uFF08\u672C\u5730\u5360\u4F4D\uFF0C\u672A\u7B49\u5F85\u7528\u6237\uFF09:
|
|
1412
1334
|
${payload}`);
|
|
1413
|
-
|
|
1335
|
+
return `[local] AskQuestion \u5DF2\u8BB0\u5F55\uFF08\u672A\u521B\u5EFA\u4EFB\u52A1\u95EE\u9898\u3001\u672A\u7B49\u5F85\u7528\u6237\u56DE\u7B54\uFF09\u3002\u53C2\u6570:
|
|
1414
1336
|
${payload}`;
|
|
1337
|
+
}
|
|
1415
1338
|
}
|
|
1416
1339
|
};
|
|
1417
1340
|
}
|
|
1418
1341
|
|
|
1419
|
-
// src/commands/connect/webide-merge-tools.ts
|
|
1342
|
+
// src/commands/connect/tools/webide-merge-tools.ts
|
|
1420
1343
|
function createMergeWebIdePullRequestsTool(options) {
|
|
1421
|
-
const {
|
|
1344
|
+
const { webideMergePullRequests } = options;
|
|
1422
1345
|
return {
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1346
|
+
MergeWebIdePullRequests: {
|
|
1347
|
+
description: "Merge all open pull requests for this WebIDE task. Call once with confirmedConflictFree=true. No baseline sync or review is required before calling.",
|
|
1348
|
+
inputSchema: {
|
|
1349
|
+
type: "object",
|
|
1350
|
+
properties: {
|
|
1351
|
+
confirmedConflictFree: {
|
|
1352
|
+
type: "boolean",
|
|
1353
|
+
description: "Must be true to confirm you intend to merge this task's open PRs now."
|
|
1354
|
+
}
|
|
1355
|
+
},
|
|
1356
|
+
required: ["confirmedConflictFree"]
|
|
1431
1357
|
},
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
);
|
|
1358
|
+
execute: async (args) => {
|
|
1359
|
+
if (args.confirmedConflictFree !== true) {
|
|
1360
|
+
throw new Error(
|
|
1361
|
+
"MergeWebIdePullRequests \u8981\u6C42 confirmedConflictFree=true\u3002"
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
const result = await webideMergePullRequests();
|
|
1365
|
+
return JSON.stringify(result, null, 2);
|
|
1439
1366
|
}
|
|
1440
|
-
const api = createApmApiClient(cfg);
|
|
1441
|
-
console.log(`[apm] MergeWebIdePullRequests taskId=${taskId}`);
|
|
1442
|
-
const result = await api.cli.webideMergePullRequests({ taskId });
|
|
1443
|
-
return JSON.stringify(result, null, 2);
|
|
1444
1367
|
}
|
|
1445
1368
|
};
|
|
1446
1369
|
}
|
|
1447
1370
|
|
|
1448
|
-
// src/commands/connect/webide-plan-tools.ts
|
|
1371
|
+
// src/commands/connect/tools/webide-plan-tools.ts
|
|
1449
1372
|
function asString(value) {
|
|
1450
1373
|
return typeof value === "string" ? value.trim() : "";
|
|
1451
1374
|
}
|
|
1452
1375
|
function createRecommendPlanTool(options) {
|
|
1453
|
-
const {
|
|
1376
|
+
const { webideRecommendPlan } = options;
|
|
1454
1377
|
return {
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1378
|
+
RecommendPlan: {
|
|
1379
|
+
description: "Recommend whether the human should write an implementation plan or skip it. Does not change workflow phase; the human decides in the WebIDE UI.",
|
|
1380
|
+
inputSchema: {
|
|
1381
|
+
type: "object",
|
|
1382
|
+
properties: {
|
|
1383
|
+
recommendation: {
|
|
1384
|
+
type: "string",
|
|
1385
|
+
enum: ["write", "skip", "unknown"],
|
|
1386
|
+
description: "write = suggest generating a plan; skip = plan optional/unnecessary; unknown = unsure"
|
|
1387
|
+
},
|
|
1388
|
+
reason: {
|
|
1389
|
+
type: "string",
|
|
1390
|
+
description: "Short Chinese reason for the recommendation"
|
|
1391
|
+
}
|
|
1463
1392
|
},
|
|
1464
|
-
|
|
1465
|
-
type: "string",
|
|
1466
|
-
description: "Short Chinese reason for the recommendation"
|
|
1467
|
-
}
|
|
1393
|
+
required: ["recommendation"]
|
|
1468
1394
|
},
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
reason
|
|
1480
|
-
});
|
|
1481
|
-
console.log(
|
|
1482
|
-
`[apm] RecommendPlan taskId=${taskId} recommendation=${recommendation}`
|
|
1483
|
-
);
|
|
1484
|
-
return JSON.stringify({ ok: true, recommendation, reason }, null, 2);
|
|
1395
|
+
execute: async (args) => {
|
|
1396
|
+
const raw = asString(args.recommendation);
|
|
1397
|
+
const recommendation = raw === "write" || raw === "skip" || raw === "unknown" ? raw : "unknown";
|
|
1398
|
+
const reason = asString(args.reason) || void 0;
|
|
1399
|
+
await webideRecommendPlan({
|
|
1400
|
+
recommendation,
|
|
1401
|
+
reason
|
|
1402
|
+
});
|
|
1403
|
+
return JSON.stringify({ ok: true, recommendation, reason }, null, 2);
|
|
1404
|
+
}
|
|
1485
1405
|
}
|
|
1486
1406
|
};
|
|
1487
1407
|
}
|
|
1488
1408
|
function createUpsertWebIdePlanTool(options) {
|
|
1489
|
-
const {
|
|
1409
|
+
const { webideUpsertPlan } = options;
|
|
1490
1410
|
return {
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1411
|
+
UpsertWebIdePlan: {
|
|
1412
|
+
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.",
|
|
1413
|
+
inputSchema: {
|
|
1414
|
+
type: "object",
|
|
1415
|
+
properties: {
|
|
1416
|
+
content: {
|
|
1417
|
+
type: "string",
|
|
1418
|
+
description: "Full implementation plan in Markdown (Chinese)"
|
|
1419
|
+
}
|
|
1420
|
+
},
|
|
1421
|
+
required: ["content"]
|
|
1499
1422
|
},
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1423
|
+
execute: async (args) => {
|
|
1424
|
+
const content = asString(args.content);
|
|
1425
|
+
if (!content) {
|
|
1426
|
+
throw new Error("UpsertWebIdePlan \u7F3A\u5C11 content");
|
|
1427
|
+
}
|
|
1428
|
+
await webideUpsertPlan({ content });
|
|
1429
|
+
return JSON.stringify({ ok: true, chars: content.length }, null, 2);
|
|
1506
1430
|
}
|
|
1507
|
-
const api = createApmApiClient(cfg);
|
|
1508
|
-
await api.cli.webideUpsertPlan({ taskId, content });
|
|
1509
|
-
console.log(
|
|
1510
|
-
`[apm] UpsertWebIdePlan taskId=${taskId} chars=${content.length}`
|
|
1511
|
-
);
|
|
1512
|
-
return JSON.stringify({ ok: true, chars: content.length }, null, 2);
|
|
1513
1431
|
}
|
|
1514
1432
|
};
|
|
1515
1433
|
}
|
|
1516
1434
|
|
|
1517
|
-
// src/commands/connect/webide-test-case-tools.ts
|
|
1435
|
+
// src/commands/connect/tools/webide-test-case-tools.ts
|
|
1518
1436
|
function asString2(value) {
|
|
1519
1437
|
return typeof value === "string" ? value.trim() : "";
|
|
1520
1438
|
}
|
|
@@ -1542,222 +1460,62 @@ function parseCases(raw) {
|
|
|
1542
1460
|
return cases;
|
|
1543
1461
|
}
|
|
1544
1462
|
function createUpsertWebIdeTestCasesTool(options) {
|
|
1545
|
-
const {
|
|
1463
|
+
const { webideReplaceTestCases } = options;
|
|
1546
1464
|
return {
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1465
|
+
UpsertWebIdeTestCases: {
|
|
1466
|
+
description: "Persist generated automated test cases for this WebIDE task (full replace) and mark the workflow TEST_READY. Call once with the complete case list after reviewing the task and code changes.",
|
|
1467
|
+
inputSchema: {
|
|
1468
|
+
type: "object",
|
|
1469
|
+
properties: {
|
|
1470
|
+
cases: {
|
|
1471
|
+
type: "array",
|
|
1472
|
+
description: "Complete list of test cases to store on the platform",
|
|
1473
|
+
items: {
|
|
1474
|
+
type: "object",
|
|
1475
|
+
properties: {
|
|
1476
|
+
name: {
|
|
1477
|
+
type: "string",
|
|
1478
|
+
description: "Short stable case id / name"
|
|
1479
|
+
},
|
|
1480
|
+
description: {
|
|
1481
|
+
type: "string",
|
|
1482
|
+
description: "What this case verifies (Chinese ok)"
|
|
1483
|
+
},
|
|
1484
|
+
steps: {
|
|
1485
|
+
type: "array",
|
|
1486
|
+
items: { type: "string" },
|
|
1487
|
+
description: "Ordered human-readable steps"
|
|
1488
|
+
},
|
|
1489
|
+
sortOrder: {
|
|
1490
|
+
type: "number",
|
|
1491
|
+
description: "Optional display order (0-based)"
|
|
1492
|
+
}
|
|
1569
1493
|
},
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
description: "Optional display order (0-based)"
|
|
1573
|
-
}
|
|
1574
|
-
},
|
|
1575
|
-
required: ["name", "description", "steps"]
|
|
1494
|
+
required: ["name", "description", "steps"]
|
|
1495
|
+
}
|
|
1576
1496
|
}
|
|
1577
|
-
}
|
|
1578
|
-
},
|
|
1579
|
-
required: ["cases"]
|
|
1580
|
-
},
|
|
1581
|
-
execute: async (args) => {
|
|
1582
|
-
const cases = parseCases(args.cases);
|
|
1583
|
-
if (cases.length === 0) {
|
|
1584
|
-
throw new Error(
|
|
1585
|
-
"UpsertWebIdeTestCases \u7F3A\u5C11\u6709\u6548 cases\uFF08\u6BCF\u6761\u9700 name \u4E0E\u975E\u7A7A steps\uFF09"
|
|
1586
|
-
);
|
|
1587
|
-
}
|
|
1588
|
-
const api = createApmApiClient(cfg);
|
|
1589
|
-
const result = await api.cli.webideReplaceTestCases({ taskId, cases });
|
|
1590
|
-
console.log(
|
|
1591
|
-
`[apm] UpsertWebIdeTestCases taskId=${taskId} count=${cases.length}`
|
|
1592
|
-
);
|
|
1593
|
-
return JSON.stringify(
|
|
1594
|
-
{ ok: true, count: result.count ?? cases.length },
|
|
1595
|
-
null,
|
|
1596
|
-
2
|
|
1597
|
-
);
|
|
1598
|
-
}
|
|
1599
|
-
};
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
// src/commands/connect/webide-terminal-tools.ts
|
|
1603
|
-
function asString3(value) {
|
|
1604
|
-
return typeof value === "string" ? value.trim() : "";
|
|
1605
|
-
}
|
|
1606
|
-
function asPorts(value) {
|
|
1607
|
-
if (!Array.isArray(value)) return void 0;
|
|
1608
|
-
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));
|
|
1609
|
-
return ports.length ? ports : void 0;
|
|
1610
|
-
}
|
|
1611
|
-
function createWebIdeTerminalTools(options) {
|
|
1612
|
-
const { cfg, taskId, workdir, rpc } = options;
|
|
1613
|
-
const StartWebIdeTerminal = {
|
|
1614
|
-
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.",
|
|
1615
|
-
inputSchema: {
|
|
1616
|
-
type: "object",
|
|
1617
|
-
properties: {
|
|
1618
|
-
key: {
|
|
1619
|
-
type: "string",
|
|
1620
|
-
description: "Stable key, e.g. frontend / backend"
|
|
1621
|
-
},
|
|
1622
|
-
name: { type: "string", description: "Display name" },
|
|
1623
|
-
cwd: {
|
|
1624
|
-
type: "string",
|
|
1625
|
-
description: "Working directory (absolute or under workspace)"
|
|
1626
|
-
},
|
|
1627
|
-
command: {
|
|
1628
|
-
type: "string",
|
|
1629
|
-
description: "Shell command to run, e.g. pnpm dev"
|
|
1630
1497
|
},
|
|
1631
|
-
|
|
1632
|
-
type: "string",
|
|
1633
|
-
description: "Optional regex; when matched in logs, status becomes READY"
|
|
1634
|
-
},
|
|
1635
|
-
portsHint: {
|
|
1636
|
-
type: "array",
|
|
1637
|
-
items: { type: "number" },
|
|
1638
|
-
description: "Optional expected listen ports"
|
|
1639
|
-
}
|
|
1498
|
+
required: ["cases"]
|
|
1640
1499
|
},
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
if (!key || !command) {
|
|
1648
|
-
return {
|
|
1649
|
-
content: [{ type: "text", text: "key / command \u4E0D\u80FD\u4E3A\u7A7A" }],
|
|
1650
|
-
isError: true
|
|
1651
|
-
};
|
|
1652
|
-
}
|
|
1653
|
-
try {
|
|
1654
|
-
const result = rpc ? await rpc.start({
|
|
1655
|
-
taskId,
|
|
1656
|
-
key,
|
|
1657
|
-
name: asString3(args.name) || void 0,
|
|
1658
|
-
cwd,
|
|
1659
|
-
command,
|
|
1660
|
-
readyPattern: asString3(args.readyPattern) || void 0,
|
|
1661
|
-
portsHint: asPorts(args.portsHint)
|
|
1662
|
-
}) : await (async () => {
|
|
1663
|
-
throw new Error("Terminal RPC \u4E0D\u53EF\u7528\uFF08\u9700\u5728 connect \u4E3B\u8FDB\u7A0B\uFF09");
|
|
1664
|
-
})();
|
|
1665
|
-
return JSON.stringify(result, null, 2);
|
|
1666
|
-
} catch (err) {
|
|
1667
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
1668
|
-
return {
|
|
1669
|
-
content: [{ type: "text", text: `\u542F\u52A8\u7EC8\u7AEF\u5931\u8D25: ${detail}` }],
|
|
1670
|
-
isError: true
|
|
1671
|
-
};
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
};
|
|
1675
|
-
const StopWebIdeTerminal = {
|
|
1676
|
-
description: "Stop a WebIDE terminal and kill its process tree. Soft-terminates (status EXITED, record kept).",
|
|
1677
|
-
inputSchema: {
|
|
1678
|
-
type: "object",
|
|
1679
|
-
properties: {
|
|
1680
|
-
key: { type: "string", description: "Terminal key" },
|
|
1681
|
-
terminalId: { type: "string", description: "Server terminal id" }
|
|
1682
|
-
}
|
|
1683
|
-
},
|
|
1684
|
-
execute: async (args) => {
|
|
1685
|
-
const key = asString3(args.key) || void 0;
|
|
1686
|
-
const terminalId = asString3(args.terminalId) || void 0;
|
|
1687
|
-
if (!key && !terminalId) {
|
|
1688
|
-
return {
|
|
1689
|
-
content: [{ type: "text", text: "\u9700\u8981 key \u6216 terminalId" }],
|
|
1690
|
-
isError: true
|
|
1691
|
-
};
|
|
1692
|
-
}
|
|
1693
|
-
try {
|
|
1694
|
-
const result = rpc ? await rpc.stop({ taskId, key, terminalId }) : await (async () => {
|
|
1695
|
-
throw new Error("Terminal RPC \u4E0D\u53EF\u7528\uFF08\u9700\u5728 connect \u4E3B\u8FDB\u7A0B\uFF09");
|
|
1696
|
-
})();
|
|
1697
|
-
return JSON.stringify(result, null, 2);
|
|
1698
|
-
} catch (err) {
|
|
1699
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
1700
|
-
return {
|
|
1701
|
-
content: [{ type: "text", text: `\u505C\u6B62\u7EC8\u7AEF\u5931\u8D25: ${detail}` }],
|
|
1702
|
-
isError: true
|
|
1703
|
-
};
|
|
1704
|
-
}
|
|
1705
|
-
}
|
|
1706
|
-
};
|
|
1707
|
-
const StopAllWebIdeTerminals = {
|
|
1708
|
-
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.",
|
|
1709
|
-
inputSchema: {
|
|
1710
|
-
type: "object",
|
|
1711
|
-
properties: {}
|
|
1712
|
-
},
|
|
1713
|
-
execute: async () => {
|
|
1714
|
-
try {
|
|
1715
|
-
const result = rpc ? await rpc.stopAll({ taskId }) : await (async () => {
|
|
1716
|
-
throw new Error("Terminal RPC \u4E0D\u53EF\u7528\uFF08\u9700\u5728 connect \u4E3B\u8FDB\u7A0B\uFF09");
|
|
1717
|
-
})();
|
|
1718
|
-
return JSON.stringify(result, null, 2);
|
|
1719
|
-
} catch (err) {
|
|
1720
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
1721
|
-
return {
|
|
1722
|
-
content: [{ type: "text", text: `\u5168\u90E8\u505C\u6B62\u5931\u8D25: ${detail}` }],
|
|
1723
|
-
isError: true
|
|
1724
|
-
};
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
};
|
|
1728
|
-
const ListWebIdeTerminals = {
|
|
1729
|
-
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.",
|
|
1730
|
-
inputSchema: {
|
|
1731
|
-
type: "object",
|
|
1732
|
-
properties: {}
|
|
1733
|
-
},
|
|
1734
|
-
execute: async () => {
|
|
1735
|
-
try {
|
|
1736
|
-
if (rpc) {
|
|
1737
|
-
const result2 = await rpc.list({ taskId });
|
|
1738
|
-
return JSON.stringify(result2, null, 2);
|
|
1500
|
+
execute: async (args) => {
|
|
1501
|
+
const cases = parseCases(args.cases);
|
|
1502
|
+
if (cases.length === 0) {
|
|
1503
|
+
throw new Error(
|
|
1504
|
+
"UpsertWebIdeTestCases \u7F3A\u5C11\u6709\u6548 cases\uFF08\u6BCF\u6761\u9700 name \u4E0E\u975E\u7A7A steps\uFF09"
|
|
1505
|
+
);
|
|
1739
1506
|
}
|
|
1740
|
-
const
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
content: [{ type: "text", text: `\u5217\u51FA\u7EC8\u7AEF\u5931\u8D25: ${detail}` }],
|
|
1747
|
-
isError: true
|
|
1748
|
-
};
|
|
1507
|
+
const result = await webideReplaceTestCases({ cases });
|
|
1508
|
+
return JSON.stringify(
|
|
1509
|
+
{ ok: true, count: result.count ?? cases.length },
|
|
1510
|
+
null,
|
|
1511
|
+
2
|
|
1512
|
+
);
|
|
1749
1513
|
}
|
|
1750
1514
|
}
|
|
1751
1515
|
};
|
|
1752
|
-
return {
|
|
1753
|
-
StartWebIdeTerminal,
|
|
1754
|
-
StopWebIdeTerminal,
|
|
1755
|
-
StopAllWebIdeTerminals,
|
|
1756
|
-
ListWebIdeTerminals
|
|
1757
|
-
};
|
|
1758
1516
|
}
|
|
1759
1517
|
|
|
1760
|
-
// src/commands/connect/
|
|
1518
|
+
// src/commands/connect/tools/index.ts
|
|
1761
1519
|
var PLAN_MODE_ASK_QUESTION_HINT = `[SDK \u73AF\u5883\u8BF4\u660E]
|
|
1762
1520
|
AskQuestion \u5DF2\u901A\u8FC7 MCP \u670D\u52A1\u5668 custom-user-tools \u6CE8\u518C\uFF0C\u5DE5\u5177\u540D\u4E3A AskQuestion\u3002
|
|
1763
1521
|
\u9700\u8981\u5411\u7528\u6237\u786E\u8BA4\u65F6\uFF0C\u8BF7\u8C03\u7528 AskQuestion\uFF08\u7ECF CallMcpTool / custom-user-tools\uFF09\uFF0C\u4E0D\u8981\u5047\u8BBE IDE \u5185\u7F6E AskQuestion \u4E0D\u53EF\u7528\u3002
|
|
@@ -1765,39 +1523,33 @@ AskQuestion \u5DF2\u901A\u8FC7 MCP \u670D\u52A1\u5668 custom-user-tools \u6CE8\u
|
|
|
1765
1523
|
var WORKSPACE_BOUNDARY_HINT = `[\u5DE5\u4F5C\u533A\u8FB9\u754C]
|
|
1766
1524
|
\u6240\u6709\u6587\u4EF6\u8BFB\u5199\u3001\u641C\u7D22\uFF08Grep/Glob/Read\uFF09\u3001Shell \u5FC5\u987B\u4E25\u683C\u9650\u5236\u5728\u5F53\u524D\u5DE5\u4F5C\u533A cwd \u5185\u3002
|
|
1767
1525
|
\u7981\u6B62\u8BBF\u95EE\u5DE5\u4F5C\u533A\u5916\u8DEF\u5F84\uFF08\u5982\u5176\u5B83\u9879\u76EE\u3001~/.cursor\u3001agent-transcripts\u3001\u7CFB\u7EDF\u76EE\u5F55\u7B49\uFF09\u3002`;
|
|
1768
|
-
function createCursorCustomTools(cfg,
|
|
1526
|
+
function createCursorCustomTools(cfg, options) {
|
|
1769
1527
|
const tools = {
|
|
1770
|
-
...
|
|
1771
|
-
|
|
1528
|
+
...options.enableAppendMessage !== false && options.appendMessageContent ? createAppendMessageCustomTools({
|
|
1529
|
+
appendContent: options.appendMessageContent
|
|
1530
|
+
}) : {},
|
|
1531
|
+
...createAskQuestionTool({
|
|
1772
1532
|
onInvoke: options?.onAskQuestion,
|
|
1773
1533
|
execute: options?.askQuestionExecute
|
|
1774
1534
|
})
|
|
1775
1535
|
};
|
|
1776
|
-
if (options?.
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
});
|
|
1781
|
-
tools.UpsertWebIdePlan = createUpsertWebIdePlanTool({
|
|
1782
|
-
cfg,
|
|
1783
|
-
taskId: options.taskId
|
|
1784
|
-
});
|
|
1785
|
-
tools.UpsertWebIdeTestCases = createUpsertWebIdeTestCasesTool({
|
|
1786
|
-
cfg,
|
|
1787
|
-
taskId: options.taskId
|
|
1788
|
-
});
|
|
1789
|
-
tools.MergeWebIdePullRequests = createMergeWebIdePullRequestsTool({
|
|
1790
|
-
cfg,
|
|
1791
|
-
taskId: options.taskId
|
|
1792
|
-
});
|
|
1793
|
-
if (options.workdir) {
|
|
1536
|
+
if (options?.taskId && options.workdir) {
|
|
1537
|
+
const { cli } = createApmApiClient(cfg);
|
|
1538
|
+
const taskId = options.taskId;
|
|
1539
|
+
if (options.enableWebIdePlanTools) {
|
|
1794
1540
|
Object.assign(
|
|
1795
1541
|
tools,
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1542
|
+
createRecommendPlanTool({
|
|
1543
|
+
webideRecommendPlan: (args) => cli.webideRecommendPlan({ taskId, ...args })
|
|
1544
|
+
}),
|
|
1545
|
+
createUpsertWebIdePlanTool({
|
|
1546
|
+
webideUpsertPlan: (args) => cli.webideUpsertPlan({ taskId, ...args })
|
|
1547
|
+
}),
|
|
1548
|
+
createUpsertWebIdeTestCasesTool({
|
|
1549
|
+
webideReplaceTestCases: (args) => cli.webideReplaceTestCases({ taskId, ...args })
|
|
1550
|
+
}),
|
|
1551
|
+
createMergeWebIdePullRequestsTool({
|
|
1552
|
+
webideMergePullRequests: () => cli.webideMergePullRequests({ taskId })
|
|
1801
1553
|
})
|
|
1802
1554
|
);
|
|
1803
1555
|
}
|
|
@@ -1818,9 +1570,30 @@ function withWorkspaceBoundaryHint(prompt) {
|
|
|
1818
1570
|
${WORKSPACE_BOUNDARY_HINT}`;
|
|
1819
1571
|
}
|
|
1820
1572
|
|
|
1573
|
+
// src/commands/connect/pty-session-mcp.ts
|
|
1574
|
+
var PTY_SESSION_MCP_NAME = "pty-session";
|
|
1575
|
+
var DEFAULT_PTY_SESSION_PORT = "7788";
|
|
1576
|
+
function resolvePtySessionBaseUrl(env = process.env) {
|
|
1577
|
+
const explicit = env.LOCAL_TERMINAL_URL?.trim();
|
|
1578
|
+
if (explicit) return explicit.replace(/\/+$/, "");
|
|
1579
|
+
const port = env.LOCAL_TERMINAL_PORT?.trim() || DEFAULT_PTY_SESSION_PORT;
|
|
1580
|
+
return `http://127.0.0.1:${port}`;
|
|
1581
|
+
}
|
|
1582
|
+
function createPtySessionMcpServers(cfg) {
|
|
1583
|
+
const token = resolveApiKey(cfg);
|
|
1584
|
+
if (!token) return void 0;
|
|
1585
|
+
return {
|
|
1586
|
+
[PTY_SESSION_MCP_NAME]: {
|
|
1587
|
+
type: "http",
|
|
1588
|
+
url: `${resolvePtySessionBaseUrl()}/mcp`,
|
|
1589
|
+
headers: {
|
|
1590
|
+
Authorization: `Bearer ${token}`
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1821
1596
|
// src/commands/connect/cursor-agent.ts
|
|
1822
|
-
setMaxListeners2(100);
|
|
1823
|
-
installAbortSignalDebug();
|
|
1824
1597
|
var noopRemoteLogSync = {
|
|
1825
1598
|
schedule(_session) {
|
|
1826
1599
|
},
|
|
@@ -1883,7 +1656,6 @@ async function obtainAgent(ctx) {
|
|
|
1883
1656
|
}
|
|
1884
1657
|
async function runCursorAgent(cfg, ctx, options) {
|
|
1885
1658
|
const signal = options.signal;
|
|
1886
|
-
logAbortSignalStats(signal, "runCursorAgent:start");
|
|
1887
1659
|
if (signal?.aborted) {
|
|
1888
1660
|
throw new Error("\u8FDE\u63A5\u5DF2\u5173\u95ED\uFF0C\u4EFB\u52A1\u4E2D\u65AD");
|
|
1889
1661
|
}
|
|
@@ -1892,16 +1664,17 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
1892
1664
|
throw new Error("\u7F3A\u5C11 apiKey\uFF0C\u65E0\u6CD5\u8C03\u7528 Cursor SDK");
|
|
1893
1665
|
}
|
|
1894
1666
|
const workdir = resolveWorkdirPath(ctx.workdir);
|
|
1895
|
-
const customTools = createCursorCustomTools(cfg,
|
|
1667
|
+
const customTools = createCursorCustomTools(cfg, {
|
|
1896
1668
|
onAskQuestion: options.onAskQuestion,
|
|
1897
1669
|
appendMessageContent: options.appendMessageContent,
|
|
1670
|
+
enableAppendMessage: options.enableAppendMessage,
|
|
1898
1671
|
askQuestionExecute: options.askQuestionExecute,
|
|
1899
1672
|
enableWebIdePlanTools: options.enableWebIdePlanTools,
|
|
1900
1673
|
taskId: options.taskId,
|
|
1901
|
-
workdir
|
|
1902
|
-
terminalRpc: options.terminalRpc
|
|
1674
|
+
workdir
|
|
1903
1675
|
});
|
|
1904
1676
|
const enableSandbox = Boolean(options.enableSandbox);
|
|
1677
|
+
const mcpServers = options.enablePtySessionMcp ? createPtySessionMcpServers(cfg) : void 0;
|
|
1905
1678
|
let prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
|
|
1906
1679
|
prompt = withWorkspaceBoundaryHint(prompt);
|
|
1907
1680
|
console.log(
|
|
@@ -1916,6 +1689,7 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
1916
1689
|
resumeAgentId: ctx.resumeAgentId,
|
|
1917
1690
|
customTools,
|
|
1918
1691
|
enableSandbox,
|
|
1692
|
+
mcpServers,
|
|
1919
1693
|
onInvalidatePersistedAgentId: options.onInvalidatePersistedAgentId
|
|
1920
1694
|
});
|
|
1921
1695
|
const invalidateAgentMapping = () => {
|
|
@@ -1929,7 +1703,6 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
1929
1703
|
void activeRun.cancel().catch(() => void 0);
|
|
1930
1704
|
};
|
|
1931
1705
|
signal?.addEventListener("abort", abortRun, { once: true });
|
|
1932
|
-
logAbortSignalStats(signal, "runCursorAgent:after-addListener");
|
|
1933
1706
|
try {
|
|
1934
1707
|
const run = await agent.send(prompt, {
|
|
1935
1708
|
...ctx.mode ? { mode: ctx.mode } : {},
|
|
@@ -1939,7 +1712,6 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
1939
1712
|
}
|
|
1940
1713
|
});
|
|
1941
1714
|
activeRun = run;
|
|
1942
|
-
logAbortSignalStats(signal, "runCursorAgent:after-send");
|
|
1943
1715
|
console.log(`[apm] Cursor run id=${run.id} agentId=${agent.agentId}`);
|
|
1944
1716
|
await options.onRunStarted?.({ agentId: agent.agentId, runId: run.id });
|
|
1945
1717
|
let lastRunErrorStatus;
|
|
@@ -2026,9 +1798,7 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2026
1798
|
}
|
|
2027
1799
|
throw err;
|
|
2028
1800
|
} finally {
|
|
2029
|
-
logAbortSignalStats(signal, "runCursorAgent:finally-before-cleanup");
|
|
2030
1801
|
signal?.removeEventListener("abort", abortRun);
|
|
2031
|
-
logAbortSignalStats(signal, "runCursorAgent:finally-after-cleanup");
|
|
2032
1802
|
await agent[Symbol.asyncDispose]();
|
|
2033
1803
|
}
|
|
2034
1804
|
}
|
|
@@ -2204,11 +1974,11 @@ async function cleanWebIdeWorkspaceCache(taskId, workdir) {
|
|
|
2204
1974
|
// src/commands/connect/webide-ask-question.ts
|
|
2205
1975
|
import { setTimeout as delay } from "node:timers/promises";
|
|
2206
1976
|
var POLL_INTERVAL_MS = 2e3;
|
|
2207
|
-
function
|
|
1977
|
+
function asString3(value) {
|
|
2208
1978
|
return typeof value === "string" ? value.trim() : "";
|
|
2209
1979
|
}
|
|
2210
1980
|
function parseQuestions(args) {
|
|
2211
|
-
const title =
|
|
1981
|
+
const title = asString3(args.title) || void 0;
|
|
2212
1982
|
const raw = args.questions;
|
|
2213
1983
|
if (!Array.isArray(raw) || raw.length === 0) {
|
|
2214
1984
|
throw new Error("AskQuestion \u7F3A\u5C11 questions");
|
|
@@ -2217,16 +1987,16 @@ function parseQuestions(args) {
|
|
|
2217
1987
|
for (const item of raw) {
|
|
2218
1988
|
if (!item || typeof item !== "object" || Array.isArray(item)) continue;
|
|
2219
1989
|
const row = item;
|
|
2220
|
-
const id =
|
|
2221
|
-
const prompt =
|
|
1990
|
+
const id = asString3(row.id);
|
|
1991
|
+
const prompt = asString3(row.prompt);
|
|
2222
1992
|
const optionsRaw = row.options;
|
|
2223
1993
|
if (!id || !prompt || !Array.isArray(optionsRaw)) continue;
|
|
2224
1994
|
const options = [];
|
|
2225
1995
|
for (const opt of optionsRaw) {
|
|
2226
1996
|
if (!opt || typeof opt !== "object" || Array.isArray(opt)) continue;
|
|
2227
1997
|
const o = opt;
|
|
2228
|
-
const oid =
|
|
2229
|
-
const label =
|
|
1998
|
+
const oid = asString3(o.id);
|
|
1999
|
+
const label = asString3(o.label);
|
|
2230
2000
|
if (oid && label) options.push({ id: oid, label });
|
|
2231
2001
|
}
|
|
2232
2002
|
if (options.length < 2) {
|
|
@@ -2260,11 +2030,11 @@ function createWebIdeAskQuestionExecute(options) {
|
|
|
2260
2030
|
const byId = new Map(
|
|
2261
2031
|
list.assumptions.map((a) => [a.questionId, a])
|
|
2262
2032
|
);
|
|
2263
|
-
const
|
|
2033
|
+
const pending = parsed.questions.filter((q) => {
|
|
2264
2034
|
const row = byId.get(q.id);
|
|
2265
2035
|
return !row || row.status !== "RESOLVED";
|
|
2266
2036
|
});
|
|
2267
|
-
if (
|
|
2037
|
+
if (pending.length === 0) {
|
|
2268
2038
|
const answers = parsed.questions.map((q) => {
|
|
2269
2039
|
const row = byId.get(q.id);
|
|
2270
2040
|
return {
|
|
@@ -2292,7 +2062,7 @@ function createWebIdeAskQuestionExecute(options) {
|
|
|
2292
2062
|
};
|
|
2293
2063
|
}
|
|
2294
2064
|
|
|
2295
|
-
// src/
|
|
2065
|
+
// src/utils/minio.ts
|
|
2296
2066
|
import * as Minio from "minio";
|
|
2297
2067
|
var MinioClient = class {
|
|
2298
2068
|
inner;
|
|
@@ -2312,45 +2082,9 @@ var MinioClient = class {
|
|
|
2312
2082
|
await this.inner.makeBucket(bucket);
|
|
2313
2083
|
}
|
|
2314
2084
|
}
|
|
2315
|
-
async deleteObjectsByPrefix(bucket, prefix) {
|
|
2316
|
-
const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
2317
|
-
const keys = [];
|
|
2318
|
-
await new Promise((resolve6, reject) => {
|
|
2319
|
-
objectsStream.on("data", (obj) => {
|
|
2320
|
-
if (obj.name) {
|
|
2321
|
-
keys.push(obj.name);
|
|
2322
|
-
}
|
|
2323
|
-
});
|
|
2324
|
-
objectsStream.on("error", reject);
|
|
2325
|
-
objectsStream.on("end", resolve6);
|
|
2326
|
-
});
|
|
2327
|
-
const chunkSize = 500;
|
|
2328
|
-
for (let i = 0; i < keys.length; i += chunkSize) {
|
|
2329
|
-
const chunk = keys.slice(i, i + chunkSize);
|
|
2330
|
-
await this.inner.removeObjects(
|
|
2331
|
-
bucket,
|
|
2332
|
-
chunk.map((name) => name)
|
|
2333
|
-
);
|
|
2334
|
-
}
|
|
2335
|
-
}
|
|
2336
2085
|
async putObject(bucket, objectKey, body, meta) {
|
|
2337
2086
|
await this.inner.putObject(bucket, objectKey, body, body.length, meta);
|
|
2338
2087
|
}
|
|
2339
|
-
/** 匿名可读当前桶全部对象(便于静态站点直链) */
|
|
2340
|
-
async setBucketPublicRead(bucket) {
|
|
2341
|
-
const policy = {
|
|
2342
|
-
Version: "2012-10-17",
|
|
2343
|
-
Statement: [
|
|
2344
|
-
{
|
|
2345
|
-
Effect: "Allow",
|
|
2346
|
-
Principal: { AWS: ["*"] },
|
|
2347
|
-
Action: ["s3:GetObject"],
|
|
2348
|
-
Resource: [`arn:aws:s3:::${bucket}/*`]
|
|
2349
|
-
}
|
|
2350
|
-
]
|
|
2351
|
-
};
|
|
2352
|
-
await this.inner.setBucketPolicy(bucket, JSON.stringify(policy));
|
|
2353
|
-
}
|
|
2354
2088
|
};
|
|
2355
2089
|
|
|
2356
2090
|
// src/commands/connect/apm-log-minio.ts
|
|
@@ -2856,7 +2590,7 @@ async function syncWebIdeAttachments(cfg, taskId, workdir, attachments) {
|
|
|
2856
2590
|
);
|
|
2857
2591
|
}
|
|
2858
2592
|
|
|
2859
|
-
// src/project-documents
|
|
2593
|
+
// src/utils/project-documents.ts
|
|
2860
2594
|
import {
|
|
2861
2595
|
existsSync as existsSync6,
|
|
2862
2596
|
readdirSync as readdirSync3,
|
|
@@ -2968,24 +2702,25 @@ async function resolveProjectIdForSync(api, workdirPath, options) {
|
|
|
2968
2702
|
return { projectId: explicit, diagnostic: null };
|
|
2969
2703
|
}
|
|
2970
2704
|
try {
|
|
2971
|
-
const
|
|
2972
|
-
const
|
|
2973
|
-
|
|
2974
|
-
|
|
2705
|
+
const gitRoot = await resolveGitRepoRoot(workdirPath);
|
|
2706
|
+
const current = await getCurrentBranch(gitRoot);
|
|
2707
|
+
const taskId = taskIdFromFeatureBranch(current);
|
|
2708
|
+
if (!taskId) {
|
|
2709
|
+
return {
|
|
2710
|
+
projectId: null,
|
|
2711
|
+
diagnostic: `\u5F53\u524D\u5206\u652F ${current} \u4E0D\u662F feat/task-*\uFF0C\u65E0\u6CD5\u89E3\u6790\u6240\u5C5E\u9879\u76EE\u3002
|
|
2712
|
+
\u8BF7\u5728\u7279\u6027\u5206\u652F\u4E0A\u6267\u884C\uFF0C\u6216\u663E\u5F0F\u6307\u5B9A projectId\u3002`
|
|
2713
|
+
};
|
|
2975
2714
|
}
|
|
2976
|
-
const
|
|
2977
|
-
|
|
2715
|
+
const baseline = await api.cli.projectBaseBranch({ taskId });
|
|
2716
|
+
const projectId = baseline.projectId?.trim() || null;
|
|
2717
|
+
if (!projectId) {
|
|
2978
2718
|
return {
|
|
2979
2719
|
projectId: null,
|
|
2980
|
-
diagnostic:
|
|
2981
|
-
\u8BF7\u5728\u5E73\u53F0\u5C06\u5DE5\u4F5C\u7A7A\u95F4\u5173\u8054\u5230\u552F\u4E00\u9879\u76EE\u3002`
|
|
2720
|
+
diagnostic: `\u4EFB\u52A1 ${taskId} \u672A\u5173\u8054\u9879\u76EE\uFF0C\u65E0\u6CD5\u540C\u6B65\u9879\u76EE\u6587\u6863\u3002`
|
|
2982
2721
|
};
|
|
2983
2722
|
}
|
|
2984
|
-
return {
|
|
2985
|
-
projectId: null,
|
|
2986
|
-
diagnostic: `\u5DE5\u4F5C\u7A7A\u95F4\u5173\u8054\u4E86 ${projectIds.length} \u4E2A\u9879\u76EE\uFF0C\u65E0\u6CD5\u786E\u5B9A\u540C\u6B65\u76EE\u6807\u3002
|
|
2987
|
-
\u8BF7\u786E\u4FDD\u8BE5\u5DE5\u4F5C\u7A7A\u95F4\u53EA\u5173\u8054\u4E00\u4E2A\u9879\u76EE\u540E\u518D\u540C\u6B65\u9879\u76EE\u6587\u6863\u3002`
|
|
2988
|
-
};
|
|
2723
|
+
return { projectId, diagnostic: null };
|
|
2989
2724
|
} catch (err) {
|
|
2990
2725
|
const detail = err instanceof Error ? err.message : String(err);
|
|
2991
2726
|
return {
|
|
@@ -3204,7 +2939,7 @@ async function appendContent(cfg, messageId, content) {
|
|
|
3204
2939
|
const api = createApmApiClient(cfg);
|
|
3205
2940
|
await api.cli.webideAppendMessageContent({ id: messageId, content });
|
|
3206
2941
|
}
|
|
3207
|
-
async function handleWebIdeInboundMessage(cfg, msg, signal
|
|
2942
|
+
async function handleWebIdeInboundMessage(cfg, msg, signal) {
|
|
3208
2943
|
const workdir = requireRemoteWorkdir(msg.workdir);
|
|
3209
2944
|
const messageId = msg.messageId;
|
|
3210
2945
|
const taskId = msg.taskId;
|
|
@@ -3302,7 +3037,7 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3302
3037
|
async () => runTaskBranch(taskId, { cwd: workdir }),
|
|
3303
3038
|
(branchResult) => {
|
|
3304
3039
|
markBranchDone(branchCacheKey, workdir);
|
|
3305
|
-
return `kind=${branchResult.kind} branch=${branchResult.branch} repos=${branchResult.repos.length}`;
|
|
3040
|
+
return `kind=${branchResult.kind} branch=${branchResult.branch} baseline=${branchResult.baseline} repos=${branchResult.repos.length}`;
|
|
3306
3041
|
}
|
|
3307
3042
|
);
|
|
3308
3043
|
} else {
|
|
@@ -3419,7 +3154,6 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3419
3154
|
enableSandbox: false,
|
|
3420
3155
|
onInvalidatePersistedAgentId: () => clearWebIdeAgentId(workdir, taskId),
|
|
3421
3156
|
taskId,
|
|
3422
|
-
terminalRpc: options?.terminalRpc,
|
|
3423
3157
|
createRemoteLogSync: (agentId) => {
|
|
3424
3158
|
saveWebIdeAgentId(workdir, taskId, agentId);
|
|
3425
3159
|
logSyncRef.current = createThrottledWebIdeMessageLogSync(
|
|
@@ -3611,68 +3345,166 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3611
3345
|
}
|
|
3612
3346
|
}
|
|
3613
3347
|
|
|
3614
|
-
// src/commands/connect/
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
function installTerminalRpcListener() {
|
|
3619
|
-
parentPort?.on("message", (raw) => {
|
|
3620
|
-
if (!raw || raw.type !== "terminal-rpc-result") return;
|
|
3621
|
-
const p = pending.get(raw.id);
|
|
3622
|
-
if (!p) return;
|
|
3623
|
-
pending.delete(raw.id);
|
|
3624
|
-
if (raw.ok) p.resolve(raw.result);
|
|
3625
|
-
else p.reject(new Error(raw.error || "terminal rpc failed"));
|
|
3626
|
-
});
|
|
3348
|
+
// src/commands/connect/handle-start-project.ts
|
|
3349
|
+
async function updateStatus2(cfg, messageId, status) {
|
|
3350
|
+
const api = createApmApiClient(cfg);
|
|
3351
|
+
await api.cli.webideUpdateMessageStatus({ id: messageId, status });
|
|
3627
3352
|
}
|
|
3628
|
-
function
|
|
3629
|
-
const
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3353
|
+
async function setError2(cfg, messageId, error) {
|
|
3354
|
+
const api = createApmApiClient(cfg);
|
|
3355
|
+
await api.cli.webideSetMessageError({ id: messageId, error });
|
|
3356
|
+
}
|
|
3357
|
+
async function handleStartProject(cfg, msg, signal) {
|
|
3358
|
+
const workdir = requireRemoteWorkdir(msg.workdir);
|
|
3359
|
+
const messageId = msg.messageId;
|
|
3360
|
+
const taskId = msg.taskId;
|
|
3361
|
+
console.log(
|
|
3362
|
+
`[apm] webide-start-project target=${msg.target} restart=${msg.restart} taskId=${taskId} messageId=${messageId}`
|
|
3363
|
+
);
|
|
3364
|
+
await updateStatus2(cfg, messageId, "TYPING");
|
|
3365
|
+
const eventSession = new EventSession(msg.content);
|
|
3366
|
+
const logSyncRef = {
|
|
3367
|
+
current: createThrottledWebIdeMessageLogSync(
|
|
3368
|
+
cfg,
|
|
3369
|
+
{ taskId, messageId, agentId: "webide-start-project" },
|
|
3370
|
+
(err) => {
|
|
3371
|
+
console.warn(
|
|
3372
|
+
"[apm] WebIDE \u542F\u52A8\u9879\u76EE\u65E5\u5FD7\u540C\u6B65\u5931\u8D25:",
|
|
3373
|
+
err instanceof Error ? err.message : err
|
|
3374
|
+
);
|
|
3375
|
+
}
|
|
3376
|
+
)
|
|
3377
|
+
};
|
|
3378
|
+
try {
|
|
3379
|
+
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
3380
|
+
await ensureWorkspaceInitialized(workdir);
|
|
3381
|
+
const api = createApmApiClient(cfg);
|
|
3382
|
+
const outcome = await runCursorAgent(
|
|
3383
|
+
cfg,
|
|
3384
|
+
{
|
|
3385
|
+
messageId,
|
|
3386
|
+
prompt: msg.content,
|
|
3387
|
+
model: msg.model,
|
|
3388
|
+
apiKey: msg.apiKey,
|
|
3389
|
+
workdir,
|
|
3390
|
+
user: msg.user || "webide"
|
|
3391
|
+
},
|
|
3392
|
+
{
|
|
3393
|
+
signal,
|
|
3394
|
+
forceSend: true,
|
|
3395
|
+
eventSession,
|
|
3396
|
+
enableAppendMessage: false,
|
|
3397
|
+
askQuestionExecute: async () => "\u8FD9\u662F\u65E0\u4EBA\u503C\u5B88\u7684\u542F\u52A8\u4EFB\u52A1\uFF0C\u8BF7\u6839\u636E deploy.md \u81EA\u884C\u51B3\u5B9A\uFF0C\u4E0D\u8981\u7B49\u5F85\u7528\u6237\u3002",
|
|
3398
|
+
enableWebIdePlanTools: false,
|
|
3399
|
+
enablePtySessionMcp: true,
|
|
3400
|
+
enableSandbox: false,
|
|
3401
|
+
taskId,
|
|
3402
|
+
createRemoteLogSync: (agentId) => {
|
|
3403
|
+
logSyncRef.current = createThrottledWebIdeMessageLogSync(
|
|
3404
|
+
cfg,
|
|
3405
|
+
{ taskId, messageId, agentId },
|
|
3406
|
+
(err) => {
|
|
3407
|
+
console.warn(
|
|
3408
|
+
"[apm] WebIDE \u542F\u52A8\u9879\u76EE\u65E5\u5FD7\u540C\u6B65\u5931\u8D25:",
|
|
3409
|
+
err instanceof Error ? err.message : err
|
|
3410
|
+
);
|
|
3411
|
+
}
|
|
3412
|
+
);
|
|
3413
|
+
return logSyncRef.current;
|
|
3414
|
+
},
|
|
3415
|
+
onRunStarted: async ({ agentId, runId }) => {
|
|
3416
|
+
eventSession.addCliStep(
|
|
3417
|
+
"\u542F\u52A8\u72EC\u7ACB Agent",
|
|
3418
|
+
`agentId=${agentId} runId=${runId}`,
|
|
3419
|
+
"ok"
|
|
3420
|
+
);
|
|
3421
|
+
logSyncRef.current?.schedule(eventSession);
|
|
3422
|
+
await logSyncRef.current?.markRun(runId, "running");
|
|
3423
|
+
await logSyncRef.current?.flush(eventSession);
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
);
|
|
3427
|
+
const tokenUsage = outcome.usage != null ? {
|
|
3428
|
+
modelId: outcome.modelId ?? (msg.model?.trim() || void 0),
|
|
3429
|
+
inputTokens: outcome.usage.inputTokens,
|
|
3430
|
+
outputTokens: outcome.usage.outputTokens,
|
|
3431
|
+
cacheReadTokens: outcome.usage.cacheReadTokens,
|
|
3432
|
+
cacheWriteTokens: outcome.usage.cacheWriteTokens,
|
|
3433
|
+
totalTokens: outcome.usage.totalTokens,
|
|
3434
|
+
...outcome.usage.reasoningTokens != null ? { reasoningTokens: outcome.usage.reasoningTokens } : {}
|
|
3435
|
+
} : void 0;
|
|
3436
|
+
if (outcome.status === "error") {
|
|
3437
|
+
const detail = formatCursorRunFailure(outcome.runId, {
|
|
3438
|
+
resultText: outcome.result
|
|
3439
|
+
});
|
|
3440
|
+
await logSyncRef.current?.markRun(
|
|
3441
|
+
outcome.runId,
|
|
3442
|
+
"error",
|
|
3443
|
+
detail,
|
|
3444
|
+
tokenUsage
|
|
3445
|
+
);
|
|
3446
|
+
await setError2(cfg, messageId, detail);
|
|
3633
3447
|
return;
|
|
3634
3448
|
}
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3449
|
+
if (outcome.status === "cancelled" || signal.aborted) {
|
|
3450
|
+
await logSyncRef.current?.markRun(
|
|
3451
|
+
outcome.runId,
|
|
3452
|
+
"cancelled",
|
|
3453
|
+
"\u5DF2\u53D6\u6D88",
|
|
3454
|
+
tokenUsage
|
|
3455
|
+
);
|
|
3456
|
+
await updateStatus2(cfg, messageId, "CANCELLED");
|
|
3457
|
+
return;
|
|
3458
|
+
}
|
|
3459
|
+
const fallback = resolveMessageReplyFallback({
|
|
3460
|
+
assistantText: outcome.assistantText,
|
|
3461
|
+
result: outcome.result
|
|
3641
3462
|
});
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
}
|
|
3463
|
+
await api.cli.webideEnsureMessageContent({
|
|
3464
|
+
id: messageId,
|
|
3465
|
+
content: fallback
|
|
3466
|
+
});
|
|
3467
|
+
await logSyncRef.current?.markRun(
|
|
3468
|
+
outcome.runId,
|
|
3469
|
+
"finished",
|
|
3470
|
+
null,
|
|
3471
|
+
tokenUsage
|
|
3472
|
+
);
|
|
3473
|
+
await updateStatus2(cfg, messageId, "SUCCESS");
|
|
3474
|
+
console.log(
|
|
3475
|
+
`[apm] webide-start-project \u5B8C\u6210 target=${msg.target} messageId=${messageId} agentId=${outcome.agentId}`
|
|
3476
|
+
);
|
|
3477
|
+
} catch (err) {
|
|
3478
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
3479
|
+
console.error(`[apm] webide-start-project \u5931\u8D25: ${detail}`);
|
|
3480
|
+
try {
|
|
3481
|
+
await setError2(cfg, messageId, detail);
|
|
3482
|
+
} catch (statusErr) {
|
|
3483
|
+
console.error(
|
|
3484
|
+
"[apm] \u5199\u5165\u542F\u52A8\u9879\u76EE FAILED \u5931\u8D25:",
|
|
3485
|
+
statusErr instanceof Error ? statusErr.message : statusErr
|
|
3486
|
+
);
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3657
3489
|
}
|
|
3658
3490
|
|
|
3659
3491
|
// src/commands/connect/webide-message-worker.ts
|
|
3660
3492
|
var controllers = /* @__PURE__ */ new Map();
|
|
3661
|
-
installTerminalRpcListener();
|
|
3662
|
-
var terminalRpc = createWorkerTerminalRpc();
|
|
3663
3493
|
async function runJob(cfg, msg) {
|
|
3664
3494
|
const controller = new AbortController();
|
|
3665
3495
|
controllers.set(msg.messageId, controller);
|
|
3666
3496
|
try {
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
}
|
|
3670
|
-
|
|
3497
|
+
if (msg.type === "webide-start-project") {
|
|
3498
|
+
await handleStartProject(cfg, msg, controller.signal);
|
|
3499
|
+
} else {
|
|
3500
|
+
await handleWebIdeInboundMessage(cfg, msg, controller.signal);
|
|
3501
|
+
}
|
|
3502
|
+
parentPort?.postMessage({
|
|
3671
3503
|
type: "done",
|
|
3672
3504
|
messageId: msg.messageId
|
|
3673
3505
|
});
|
|
3674
3506
|
} catch (err) {
|
|
3675
|
-
|
|
3507
|
+
parentPort?.postMessage({
|
|
3676
3508
|
type: "error",
|
|
3677
3509
|
messageId: msg.messageId,
|
|
3678
3510
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -3681,7 +3513,7 @@ async function runJob(cfg, msg) {
|
|
|
3681
3513
|
controllers.delete(msg.messageId);
|
|
3682
3514
|
}
|
|
3683
3515
|
}
|
|
3684
|
-
|
|
3516
|
+
parentPort?.on("message", (raw) => {
|
|
3685
3517
|
if (raw.type === "cancel") {
|
|
3686
3518
|
controllers.get(raw.messageId)?.abort();
|
|
3687
3519
|
return;
|