ai-project-manage-cli 7.1.39 → 8.0.1
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 +6 -8
- package/dist/index.js +3969 -7465
- package/dist/webide-message-worker.js +283 -632
- package/package.json +1 -2
- package/template/AGENTS.md +0 -56
- package/template/apm.config.json +0 -3
- package/template/project/.gitkeep +0 -0
- package/template/rules/reply.md +0 -16
- package/template/rules/write_doc.md +0 -39
- package/template/sessions/.gitkeep +0 -0
- package/template/skills/apm-apply-change/SKILL.md +0 -116
- package/template/skills/apm-confirm-assumptions/SKILL.md +0 -3
- package/template/skills/apm-dev/SKILL.md +0 -80
- package/template/skills/apm-diff-review/SKILL.md +0 -63
- package/template/skills/apm-propose/SKILL.md +0 -52
- package/template/skills/apm-propose/design.md +0 -37
- package/template/skills/apm-propose/proposal.md +0 -31
- package/template/skills/apm-propose/specs.md +0 -39
- package/template/skills/apm-propose/tasks.md +0 -16
- package/template/skills/apm-recap/SKILL.md +0 -77
- package/template/skills/apm-recap/recap-template.md +0 -121
- package/template/skills/apm-update-plan/SKILL.md +0 -26
- package/template/skills/apm-write-assumptions/SKILL.md +0 -78
- package/template/skills/apm-write-assumptions/assumptions-template.md +0 -18
- package/template/skills/apm-write-backend-api/SKILL.md +0 -40
- package/template/skills/apm-write-backend-api/api-template.md +0 -35
- package/template/skills/apm-write-backend-api/backend-template.md +0 -41
- package/template/skills/apm-write-checklist/SKILL.md +0 -42
- package/template/skills/apm-write-checklist/checklist-template.md +0 -34
- package/template/skills/apm-write-frontend-plan/SKILL.md +0 -27
- package/template/skills/apm-write-frontend-plan/plan-template.md +0 -40
- package/template/skills/apm-write-plan/SKILL.md +0 -51
- package/template/skills/apm-write-plan/api-template.md +0 -35
- package/template/skills/apm-write-plan/plan-template.md +0 -72
- package/template/skills/apm-write-prd/SKILL.md +0 -14
- package/template/skills/apm-write-prd/template.md +0 -134
|
@@ -14,52 +14,6 @@ var requestConfig = {
|
|
|
14
14
|
path: "/cli/me"
|
|
15
15
|
}
|
|
16
16
|
),
|
|
17
|
-
sessionDetail: defineEndpoint({
|
|
18
|
-
method: "GET",
|
|
19
|
-
path: "/cli/sessions/detail"
|
|
20
|
-
}),
|
|
21
|
-
sessionMembers: defineEndpoint({
|
|
22
|
-
method: "GET",
|
|
23
|
-
path: "/cli/sessions/members"
|
|
24
|
-
}),
|
|
25
|
-
listSessionMessages: defineEndpoint({
|
|
26
|
-
method: "GET",
|
|
27
|
-
path: "/cli/messages"
|
|
28
|
-
}),
|
|
29
|
-
listDocuments: defineEndpoint({
|
|
30
|
-
method: "GET",
|
|
31
|
-
path: "/cli/documents"
|
|
32
|
-
}),
|
|
33
|
-
getDevGate: defineEndpoint({
|
|
34
|
-
method: "GET",
|
|
35
|
-
path: "/cli/dev-gate"
|
|
36
|
-
}),
|
|
37
|
-
listAttachments: defineEndpoint(
|
|
38
|
-
{
|
|
39
|
-
method: "GET",
|
|
40
|
-
path: "/cli/attachments"
|
|
41
|
-
}
|
|
42
|
-
),
|
|
43
|
-
upsertDocument: defineEndpoint({
|
|
44
|
-
method: "PUT",
|
|
45
|
-
path: "/cli/documents/upsert"
|
|
46
|
-
}),
|
|
47
|
-
appendMessageContent: defineEndpoint({
|
|
48
|
-
method: "PUT",
|
|
49
|
-
path: "/cli/messages/content"
|
|
50
|
-
}),
|
|
51
|
-
setMessageError: defineEndpoint({
|
|
52
|
-
method: "PUT",
|
|
53
|
-
path: "/cli/messages/error"
|
|
54
|
-
}),
|
|
55
|
-
upsertCursorMessageLog: defineEndpoint({
|
|
56
|
-
method: "PUT",
|
|
57
|
-
path: "/cli/cursor-message-logs"
|
|
58
|
-
}),
|
|
59
|
-
updateMessageStatus: defineEndpoint({
|
|
60
|
-
method: "PUT",
|
|
61
|
-
path: "/cli/messages/status"
|
|
62
|
-
}),
|
|
63
17
|
webideAppendMessageContent: defineEndpoint({
|
|
64
18
|
method: "PUT",
|
|
65
19
|
path: "/cli/webide/messages/content"
|
|
@@ -120,44 +74,20 @@ var requestConfig = {
|
|
|
120
74
|
method: "PUT",
|
|
121
75
|
path: "/cli/webide/terminals/meta"
|
|
122
76
|
}),
|
|
123
|
-
branchBaseline: defineEndpoint({
|
|
124
|
-
method: "GET",
|
|
125
|
-
path: "/cli/tasks/branch-baseline"
|
|
126
|
-
}),
|
|
127
77
|
projectBaseBranch: defineEndpoint(
|
|
128
78
|
{
|
|
129
79
|
method: "GET",
|
|
130
80
|
path: "/cli/tasks/project-base-branch"
|
|
131
81
|
}
|
|
132
82
|
),
|
|
133
|
-
listSessionsForBranchCleanup: defineEndpoint({
|
|
134
|
-
method: "GET",
|
|
135
|
-
path: "/cli/sessions/branch-cleanup"
|
|
136
|
-
}),
|
|
137
83
|
workspaceBaseline: defineEndpoint({
|
|
138
84
|
method: "GET",
|
|
139
85
|
path: "/cli/workspaces/baseline"
|
|
140
86
|
}),
|
|
141
|
-
getDeploymentConfiguration: defineEndpoint({
|
|
142
|
-
method: "GET",
|
|
143
|
-
path: "/cli/deployment-configurations"
|
|
144
|
-
}),
|
|
145
87
|
matchRepository: defineEndpoint({
|
|
146
88
|
method: "GET",
|
|
147
89
|
path: "/cli/repositories/match"
|
|
148
90
|
}),
|
|
149
|
-
listSkills: defineEndpoint({
|
|
150
|
-
method: "GET",
|
|
151
|
-
path: "/cli/skills"
|
|
152
|
-
}),
|
|
153
|
-
listRules: defineEndpoint({
|
|
154
|
-
method: "GET",
|
|
155
|
-
path: "/cli/rules"
|
|
156
|
-
}),
|
|
157
|
-
createPullRequest: defineEndpoint({
|
|
158
|
-
method: "POST",
|
|
159
|
-
path: "/cli/pull-requests"
|
|
160
|
-
}),
|
|
161
91
|
createWebIdeDraftPullRequest: defineEndpoint({
|
|
162
92
|
method: "POST",
|
|
163
93
|
path: "/cli/webide/draft-pull-requests"
|
|
@@ -338,6 +268,147 @@ function requireRemoteWorkdir(workdir) {
|
|
|
338
268
|
return resolveWorkdirPath(trimmed);
|
|
339
269
|
}
|
|
340
270
|
|
|
271
|
+
// src/command-utils.ts
|
|
272
|
+
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
|
|
273
|
+
import { dirname, join as join2, resolve as resolve2 } from "path";
|
|
274
|
+
import { fileURLToPath } from "url";
|
|
275
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
276
|
+
var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
|
|
277
|
+
function workspaceApmDir(cwd = resolveWorkdirPath()) {
|
|
278
|
+
return resolve2(resolve2(cwd), ".apm");
|
|
279
|
+
}
|
|
280
|
+
function isWorkspaceApmInitialized(workdir) {
|
|
281
|
+
const apmDir = workspaceApmDir(workdir);
|
|
282
|
+
const fsApmDir = toFsPath(apmDir);
|
|
283
|
+
if (!existsSync(fsApmDir)) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
const st = statSync(fsApmDir);
|
|
287
|
+
if (!st.isDirectory()) {
|
|
288
|
+
throw new Error(
|
|
289
|
+
`\u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u4E0B\u7684 .apm \u4E0D\u662F\u76EE\u5F55\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730\u63A5\u5165\u72B6\u6001\u3002`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
return readdirSync(fsApmDir).length > 0;
|
|
293
|
+
}
|
|
294
|
+
var WEBIDE_SUBDIR = "webide";
|
|
295
|
+
var WEBIDE_ATTACHMENTS_SUBDIR = "attachments";
|
|
296
|
+
function webideTaskDir(taskId, workdir) {
|
|
297
|
+
return join2(workdir, ".apm", WEBIDE_SUBDIR, taskId);
|
|
298
|
+
}
|
|
299
|
+
function webideAttachmentsDir(taskId, workdir) {
|
|
300
|
+
return join2(webideTaskDir(taskId, workdir), WEBIDE_ATTACHMENTS_SUBDIR);
|
|
301
|
+
}
|
|
302
|
+
async function ensureLoggedConfig() {
|
|
303
|
+
const cfg = await ensureApmConfig();
|
|
304
|
+
if (!resolveApiKey(cfg)) {
|
|
305
|
+
console.error(
|
|
306
|
+
"[apm] \u672A\u68C0\u6D4B\u5230 API Key\uFF0C\u8BF7\u5148\u6267\u884C: apm login --api-key cm_xxx"
|
|
307
|
+
);
|
|
308
|
+
process.exit(1);
|
|
309
|
+
}
|
|
310
|
+
return cfg;
|
|
311
|
+
}
|
|
312
|
+
async function ensureDirExists(dir) {
|
|
313
|
+
mkdirSync2(dir, { recursive: true });
|
|
314
|
+
}
|
|
315
|
+
async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
|
|
316
|
+
const dir = workspaceApmDir(cwd);
|
|
317
|
+
const fsDir = toFsPath(dir);
|
|
318
|
+
if (existsSync(fsDir) && !statSync(fsDir).isDirectory()) {
|
|
319
|
+
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${dir}`);
|
|
320
|
+
}
|
|
321
|
+
mkdirSync2(fsDir, { recursive: true });
|
|
322
|
+
}
|
|
323
|
+
var WEBIDE_AGENTS_TEMPLATE_NAME = "AGENTS.webide.md";
|
|
324
|
+
function shouldSkipTemplateEntry(name) {
|
|
325
|
+
return name === ".DS_Store" || name === "Thumbs.db";
|
|
326
|
+
}
|
|
327
|
+
function isWebIdeRuleFileName(name) {
|
|
328
|
+
return name.startsWith("webide");
|
|
329
|
+
}
|
|
330
|
+
function copyTemplateEntry(src, dest) {
|
|
331
|
+
const fsSrc = toFsPath(src);
|
|
332
|
+
const fsDest = toFsPath(dest);
|
|
333
|
+
const st = statSync(fsSrc);
|
|
334
|
+
if (st.isDirectory()) {
|
|
335
|
+
mkdirSync2(fsDest, { recursive: true });
|
|
336
|
+
for (const name of readdirSync(fsSrc)) {
|
|
337
|
+
if (shouldSkipTemplateEntry(name)) continue;
|
|
338
|
+
copyTemplateEntry(join2(src, name), join2(dest, name));
|
|
339
|
+
}
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (!st.isFile()) return;
|
|
343
|
+
mkdirSync2(toFsPath(dirname(dest)), { recursive: true });
|
|
344
|
+
copyFileSync(fsSrc, fsDest);
|
|
345
|
+
}
|
|
346
|
+
function listWebIdeRuleFileNames(rulesDir) {
|
|
347
|
+
const fsRulesDir = toFsPath(rulesDir);
|
|
348
|
+
if (!existsSync(fsRulesDir) || !statSync(fsRulesDir).isDirectory()) {
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
return readdirSync(fsRulesDir).filter((name) => {
|
|
352
|
+
if (shouldSkipTemplateEntry(name) || !isWebIdeRuleFileName(name)) {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
return statSync(toFsPath(join2(rulesDir, name))).isFile();
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
|
|
359
|
+
const required = ["AGENTS.md", "rules"];
|
|
360
|
+
for (const item of required) {
|
|
361
|
+
const path = join2(apmDir, item);
|
|
362
|
+
if (!existsSync(toFsPath(path))) {
|
|
363
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const rulesDir = join2(apmDir, "rules");
|
|
367
|
+
const ruleNames = listWebIdeRuleFileNames(rulesDir);
|
|
368
|
+
if (ruleNames.length === 0) {
|
|
369
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 webide \u89C4\u5219: ${rulesDir}`);
|
|
370
|
+
}
|
|
371
|
+
const leakedRules = join2(workdir, "rules");
|
|
372
|
+
const apmRules = join2(apmDir, "rules");
|
|
373
|
+
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "webide_reply.md")))) {
|
|
374
|
+
throw new Error(
|
|
375
|
+
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
380
|
+
const resolvedTarget = resolve2(targetDir);
|
|
381
|
+
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
382
|
+
const fsTemplateDir = toFsPath(templateDir);
|
|
383
|
+
if (!existsSync(fsTemplateDir) || !statSync(fsTemplateDir).isDirectory()) {
|
|
384
|
+
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
385
|
+
}
|
|
386
|
+
const agentsSrc = join2(templateDir, WEBIDE_AGENTS_TEMPLATE_NAME);
|
|
387
|
+
if (!existsSync(toFsPath(agentsSrc))) {
|
|
388
|
+
throw new Error(`[apm] \u672A\u627E\u5230 WebIDE \u6307\u5357: ${agentsSrc}`);
|
|
389
|
+
}
|
|
390
|
+
const rulesSrc = join2(templateDir, "rules");
|
|
391
|
+
const ruleNames = listWebIdeRuleFileNames(rulesSrc);
|
|
392
|
+
if (ruleNames.length === 0) {
|
|
393
|
+
throw new Error(`[apm] CLI \u6A21\u677F\u4E2D\u6CA1\u6709 webide \u89C4\u5219: ${rulesSrc}`);
|
|
394
|
+
}
|
|
395
|
+
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
396
|
+
copyFileSync(
|
|
397
|
+
toFsPath(agentsSrc),
|
|
398
|
+
toFsPath(join2(resolvedTarget, "AGENTS.md"))
|
|
399
|
+
);
|
|
400
|
+
const rulesDest = join2(resolvedTarget, "rules");
|
|
401
|
+
mkdirSync2(toFsPath(rulesDest), { recursive: true });
|
|
402
|
+
for (const name of ruleNames) {
|
|
403
|
+
copyTemplateEntry(join2(rulesSrc, name), join2(rulesDest, name));
|
|
404
|
+
}
|
|
405
|
+
assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/git-utils.ts
|
|
409
|
+
import { execFile as execFile2 } from "child_process";
|
|
410
|
+
import { promisify as promisify2 } from "util";
|
|
411
|
+
|
|
341
412
|
// src/git-remote.ts
|
|
342
413
|
import { execFile } from "child_process";
|
|
343
414
|
import { promisify } from "util";
|
|
@@ -392,8 +463,6 @@ async function tryReadHttpsGitOriginUrl(cwd) {
|
|
|
392
463
|
}
|
|
393
464
|
|
|
394
465
|
// src/git-utils.ts
|
|
395
|
-
import { execFile as execFile2 } from "child_process";
|
|
396
|
-
import { promisify as promisify2 } from "util";
|
|
397
466
|
var execFileAsync2 = promisify2(execFile2);
|
|
398
467
|
function gitExecEnv() {
|
|
399
468
|
const existing = process.env.GIT_SSH_COMMAND?.trim();
|
|
@@ -491,7 +560,7 @@ async function branchHasChangesAgainstBase(cwd, baseBranch, headBranch) {
|
|
|
491
560
|
return true;
|
|
492
561
|
}
|
|
493
562
|
}
|
|
494
|
-
var FEATURE_BRANCH_RE = /^feat\/
|
|
563
|
+
var FEATURE_BRANCH_RE = /^feat\/task-.+/;
|
|
495
564
|
function isFeatureBranchName(branch) {
|
|
496
565
|
return FEATURE_BRANCH_RE.test(branch.trim().replace(/^origin\//, ""));
|
|
497
566
|
}
|
|
@@ -601,198 +670,6 @@ async function pushCurrentBranch(cwd) {
|
|
|
601
670
|
return true;
|
|
602
671
|
}
|
|
603
672
|
|
|
604
|
-
// src/command-utils.ts
|
|
605
|
-
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
|
|
606
|
-
import { basename, dirname, extname, join as join2, resolve as resolve2 } from "path";
|
|
607
|
-
import { fileURLToPath } from "url";
|
|
608
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
609
|
-
var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
|
|
610
|
-
function workspaceApmDir(cwd = resolveWorkdirPath()) {
|
|
611
|
-
return resolve2(resolve2(cwd), ".apm");
|
|
612
|
-
}
|
|
613
|
-
function isWorkspaceApmInitialized(workdir) {
|
|
614
|
-
const apmDir = workspaceApmDir(workdir);
|
|
615
|
-
const fsApmDir = toFsPath(apmDir);
|
|
616
|
-
if (!existsSync(fsApmDir)) {
|
|
617
|
-
return false;
|
|
618
|
-
}
|
|
619
|
-
const st = statSync(fsApmDir);
|
|
620
|
-
if (!st.isDirectory()) {
|
|
621
|
-
throw new Error(
|
|
622
|
-
`\u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u4E0B\u7684 .apm \u4E0D\u662F\u76EE\u5F55\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730\u63A5\u5165\u72B6\u6001\u3002`
|
|
623
|
-
);
|
|
624
|
-
}
|
|
625
|
-
return readdirSync(fsApmDir).length > 0;
|
|
626
|
-
}
|
|
627
|
-
var SESSION_ATTACHMENTS_SUBDIR = "attachments";
|
|
628
|
-
var WEBIDE_SUBDIR = "webide";
|
|
629
|
-
function webideTaskDir(taskId, workdir) {
|
|
630
|
-
return join2(workdir, ".apm", WEBIDE_SUBDIR, taskId);
|
|
631
|
-
}
|
|
632
|
-
function webideAttachmentsDir(taskId, workdir) {
|
|
633
|
-
return join2(webideTaskDir(taskId, workdir), SESSION_ATTACHMENTS_SUBDIR);
|
|
634
|
-
}
|
|
635
|
-
async function ensureLoggedConfig() {
|
|
636
|
-
const cfg = await ensureApmConfig();
|
|
637
|
-
if (!resolveApiKey(cfg)) {
|
|
638
|
-
console.error(
|
|
639
|
-
"[apm] \u672A\u68C0\u6D4B\u5230 API Key\uFF0C\u8BF7\u5148\u6267\u884C: apm login --api-key cm_xxx"
|
|
640
|
-
);
|
|
641
|
-
process.exit(1);
|
|
642
|
-
}
|
|
643
|
-
return cfg;
|
|
644
|
-
}
|
|
645
|
-
async function ensureDirExists(dir) {
|
|
646
|
-
mkdirSync2(dir, { recursive: true });
|
|
647
|
-
}
|
|
648
|
-
async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
|
|
649
|
-
const dir = workspaceApmDir(cwd);
|
|
650
|
-
const fsDir = toFsPath(dir);
|
|
651
|
-
if (existsSync(fsDir) && !statSync(fsDir).isDirectory()) {
|
|
652
|
-
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${dir}`);
|
|
653
|
-
}
|
|
654
|
-
mkdirSync2(fsDir, { recursive: true });
|
|
655
|
-
}
|
|
656
|
-
var WORKSPACE_TEMPLATE_SUBDIRS = [
|
|
657
|
-
"sessions",
|
|
658
|
-
"skills",
|
|
659
|
-
"rules",
|
|
660
|
-
"deploy"
|
|
661
|
-
];
|
|
662
|
-
var WEBIDE_AGENTS_TEMPLATE_NAME = "AGENTS.webide.md";
|
|
663
|
-
function shouldSkipTemplateEntry(name) {
|
|
664
|
-
return name === ".DS_Store" || name === "Thumbs.db" || name === WEBIDE_AGENTS_TEMPLATE_NAME;
|
|
665
|
-
}
|
|
666
|
-
function isWebIdeRuleFileName(name) {
|
|
667
|
-
return name.startsWith("webide");
|
|
668
|
-
}
|
|
669
|
-
function copyTemplateEntry(src, dest) {
|
|
670
|
-
const fsSrc = toFsPath(src);
|
|
671
|
-
const fsDest = toFsPath(dest);
|
|
672
|
-
const st = statSync(fsSrc);
|
|
673
|
-
if (st.isDirectory()) {
|
|
674
|
-
mkdirSync2(fsDest, { recursive: true });
|
|
675
|
-
for (const name of readdirSync(fsSrc)) {
|
|
676
|
-
if (shouldSkipTemplateEntry(name)) continue;
|
|
677
|
-
copyTemplateEntry(join2(src, name), join2(dest, name));
|
|
678
|
-
}
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
681
|
-
if (!st.isFile()) return;
|
|
682
|
-
mkdirSync2(toFsPath(dirname(dest)), { recursive: true });
|
|
683
|
-
copyFileSync(fsSrc, fsDest);
|
|
684
|
-
}
|
|
685
|
-
function assertTemplateCopiedToApm(apmDir, workdir) {
|
|
686
|
-
const required = [
|
|
687
|
-
"AGENTS.md",
|
|
688
|
-
"apm.config.json",
|
|
689
|
-
"rules",
|
|
690
|
-
"skills",
|
|
691
|
-
"sessions"
|
|
692
|
-
];
|
|
693
|
-
for (const item of required) {
|
|
694
|
-
const path = join2(apmDir, item);
|
|
695
|
-
if (!existsSync(toFsPath(path))) {
|
|
696
|
-
throw new Error(`[apm] \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path}`);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
const leakedRules = join2(workdir, "rules");
|
|
700
|
-
const apmRules = join2(apmDir, "rules");
|
|
701
|
-
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "reply.md")))) {
|
|
702
|
-
throw new Error(
|
|
703
|
-
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
704
|
-
);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
async function copyTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
708
|
-
const resolvedTarget = resolve2(targetDir);
|
|
709
|
-
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
710
|
-
const fsTemplateDir = toFsPath(templateDir);
|
|
711
|
-
if (!existsSync(fsTemplateDir)) {
|
|
712
|
-
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
713
|
-
}
|
|
714
|
-
const dirStat = statSync(fsTemplateDir);
|
|
715
|
-
if (!dirStat.isDirectory()) {
|
|
716
|
-
throw new Error(`[apm] CLI \u6A21\u677F\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55: ${templateDir}`);
|
|
717
|
-
}
|
|
718
|
-
const entries = readdirSync(fsTemplateDir).filter(
|
|
719
|
-
(name) => !shouldSkipTemplateEntry(name)
|
|
720
|
-
);
|
|
721
|
-
if (entries.length === 0) {
|
|
722
|
-
throw new Error(`[apm] CLI \u6A21\u677F\u76EE\u5F55\u4E3A\u7A7A: ${templateDir}`);
|
|
723
|
-
}
|
|
724
|
-
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
725
|
-
for (const name of entries) {
|
|
726
|
-
copyTemplateEntry(join2(templateDir, name), join2(resolvedTarget, name));
|
|
727
|
-
}
|
|
728
|
-
for (const subdir of WORKSPACE_TEMPLATE_SUBDIRS) {
|
|
729
|
-
mkdirSync2(toFsPath(join2(resolvedTarget, subdir)), { recursive: true });
|
|
730
|
-
}
|
|
731
|
-
assertTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
732
|
-
}
|
|
733
|
-
function listWebIdeRuleFileNames(rulesDir) {
|
|
734
|
-
const fsRulesDir = toFsPath(rulesDir);
|
|
735
|
-
if (!existsSync(fsRulesDir) || !statSync(fsRulesDir).isDirectory()) {
|
|
736
|
-
return [];
|
|
737
|
-
}
|
|
738
|
-
return readdirSync(fsRulesDir).filter((name) => {
|
|
739
|
-
if (shouldSkipTemplateEntry(name) || !isWebIdeRuleFileName(name)) {
|
|
740
|
-
return false;
|
|
741
|
-
}
|
|
742
|
-
return statSync(toFsPath(join2(rulesDir, name))).isFile();
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
|
|
746
|
-
const required = ["AGENTS.md", "apm.config.json", "rules"];
|
|
747
|
-
for (const item of required) {
|
|
748
|
-
const path = join2(apmDir, item);
|
|
749
|
-
if (!existsSync(toFsPath(path))) {
|
|
750
|
-
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path}`);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
const rulesDir = join2(apmDir, "rules");
|
|
754
|
-
const ruleNames = listWebIdeRuleFileNames(rulesDir);
|
|
755
|
-
if (ruleNames.length === 0) {
|
|
756
|
-
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 webide \u89C4\u5219: ${rulesDir}`);
|
|
757
|
-
}
|
|
758
|
-
const leakedRules = join2(workdir, "rules");
|
|
759
|
-
const apmRules = join2(apmDir, "rules");
|
|
760
|
-
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "webide_reply.md")))) {
|
|
761
|
-
throw new Error(
|
|
762
|
-
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
763
|
-
);
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
767
|
-
const resolvedTarget = resolve2(targetDir);
|
|
768
|
-
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
769
|
-
const fsTemplateDir = toFsPath(templateDir);
|
|
770
|
-
if (!existsSync(fsTemplateDir) || !statSync(fsTemplateDir).isDirectory()) {
|
|
771
|
-
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
772
|
-
}
|
|
773
|
-
const agentsSrc = join2(templateDir, WEBIDE_AGENTS_TEMPLATE_NAME);
|
|
774
|
-
if (!existsSync(toFsPath(agentsSrc))) {
|
|
775
|
-
throw new Error(`[apm] \u672A\u627E\u5230 WebIDE \u6307\u5357: ${agentsSrc}`);
|
|
776
|
-
}
|
|
777
|
-
const rulesSrc = join2(templateDir, "rules");
|
|
778
|
-
const ruleNames = listWebIdeRuleFileNames(rulesSrc);
|
|
779
|
-
if (ruleNames.length === 0) {
|
|
780
|
-
throw new Error(`[apm] CLI \u6A21\u677F\u4E2D\u6CA1\u6709 webide \u89C4\u5219: ${rulesSrc}`);
|
|
781
|
-
}
|
|
782
|
-
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
783
|
-
copyFileSync(toFsPath(agentsSrc), toFsPath(join2(resolvedTarget, "AGENTS.md")));
|
|
784
|
-
copyTemplateEntry(
|
|
785
|
-
join2(templateDir, "apm.config.json"),
|
|
786
|
-
join2(resolvedTarget, "apm.config.json")
|
|
787
|
-
);
|
|
788
|
-
const rulesDest = join2(resolvedTarget, "rules");
|
|
789
|
-
mkdirSync2(toFsPath(rulesDest), { recursive: true });
|
|
790
|
-
for (const name of ruleNames) {
|
|
791
|
-
copyTemplateEntry(join2(rulesSrc, name), join2(rulesDest, name));
|
|
792
|
-
}
|
|
793
|
-
assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
794
|
-
}
|
|
795
|
-
|
|
796
673
|
// src/workspace-repos.ts
|
|
797
674
|
import {
|
|
798
675
|
existsSync as existsSync2,
|
|
@@ -802,7 +679,7 @@ import {
|
|
|
802
679
|
statSync as statSync2,
|
|
803
680
|
writeFileSync as writeFileSync2
|
|
804
681
|
} from "fs";
|
|
805
|
-
import { basename
|
|
682
|
+
import { basename, dirname as dirname2, join as join3, relative, resolve as resolve3 } from "path";
|
|
806
683
|
var WORKSPACE_REPOS_MANIFEST = "workspace-repos.json";
|
|
807
684
|
var WORKSPACE_REPOS_VERSION = 1;
|
|
808
685
|
var SKIP_DIR_NAMES = /* @__PURE__ */ new Set([".apm", "node_modules"]);
|
|
@@ -1026,7 +903,7 @@ function resolveWorkspaceRepoAbsolutePaths(manifest) {
|
|
|
1026
903
|
}
|
|
1027
904
|
function formatRepoLabel(workdir, repoAbs) {
|
|
1028
905
|
const rel = toRelativeRepoPath(resolveWorkdirPath(workdir), repoAbs);
|
|
1029
|
-
return rel === "." ?
|
|
906
|
+
return rel === "." ? basename(repoAbs) || repoAbs : rel;
|
|
1030
907
|
}
|
|
1031
908
|
|
|
1032
909
|
// src/commands/branch.ts
|
|
@@ -1099,57 +976,47 @@ function branchNameForTask(taskId) {
|
|
|
1099
976
|
async function ensureFeatureBranch(branch, baselineBranch, options) {
|
|
1100
977
|
const cwd = options.cwd ?? process.cwd();
|
|
1101
978
|
const gitRoot = await resolveGitRepoRoot(cwd);
|
|
1102
|
-
const commitMessage = options.message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${branch})`;
|
|
1103
979
|
await ensureGitRepo(gitRoot);
|
|
1104
|
-
await ensureRemoteBaselineBranch(gitRoot, baselineBranch);
|
|
1105
980
|
const current = await getCurrentBranch(gitRoot);
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
await commitWorkingTreeIfDirty(gitRoot, commitMessage);
|
|
1110
|
-
} else {
|
|
1111
|
-
await execGit(gitRoot, [
|
|
1112
|
-
"stash",
|
|
1113
|
-
"push",
|
|
1114
|
-
"-u",
|
|
1115
|
-
"-m",
|
|
1116
|
-
`apm: switch to ${branch}`
|
|
1117
|
-
]);
|
|
1118
|
-
}
|
|
981
|
+
if (current === branch) {
|
|
982
|
+
console.log(`[apm] \u5DF2\u5728\u5206\u652F ${branch}\uFF0C\u8DF3\u8FC7`);
|
|
983
|
+
return branch;
|
|
1119
984
|
}
|
|
1120
|
-
|
|
1121
|
-
if (
|
|
1122
|
-
await execGit(gitRoot, [
|
|
1123
|
-
|
|
985
|
+
await ensureRemoteBaselineBranch(gitRoot, baselineBranch);
|
|
986
|
+
if (await isWorkingTreeDirty(gitRoot)) {
|
|
987
|
+
await execGit(gitRoot, [
|
|
988
|
+
"stash",
|
|
989
|
+
"push",
|
|
990
|
+
"-u",
|
|
991
|
+
"-m",
|
|
992
|
+
`apm: switch to ${branch}`
|
|
993
|
+
]);
|
|
994
|
+
}
|
|
995
|
+
const remoteExists = await remoteBranchExists(gitRoot, branch);
|
|
996
|
+
if (remoteExists) {
|
|
997
|
+
await execGit(gitRoot, ["fetch", "origin", branch]);
|
|
998
|
+
await execGit(gitRoot, ["checkout", "-B", branch, `origin/${branch}`]);
|
|
999
|
+
} else if (await localBranchExists(gitRoot, branch)) {
|
|
1000
|
+
await execGit(gitRoot, ["checkout", branch]);
|
|
1001
|
+
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
1124
1002
|
} else {
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
await execGit(gitRoot, [
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
}
|
|
1135
|
-
await
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
"checkout",
|
|
1139
|
-
"-b",
|
|
1140
|
-
branch,
|
|
1141
|
-
`origin/${baselineBranch}`
|
|
1142
|
-
]);
|
|
1143
|
-
await execGit(gitRoot, ["push", "-u", "origin", branch]);
|
|
1144
|
-
} catch (err) {
|
|
1145
|
-
if (await localBranchExists(gitRoot, branch)) {
|
|
1146
|
-
if (await getCurrentBranch(gitRoot) !== branch) {
|
|
1147
|
-
await execGit(gitRoot, ["checkout", branch]);
|
|
1148
|
-
}
|
|
1149
|
-
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
1150
|
-
} else {
|
|
1151
|
-
throw err;
|
|
1003
|
+
await execGit(gitRoot, ["fetch", "origin", baselineBranch]);
|
|
1004
|
+
try {
|
|
1005
|
+
await execGit(gitRoot, [
|
|
1006
|
+
"checkout",
|
|
1007
|
+
"-b",
|
|
1008
|
+
branch,
|
|
1009
|
+
`origin/${baselineBranch}`
|
|
1010
|
+
]);
|
|
1011
|
+
await execGit(gitRoot, ["push", "-u", "origin", branch]);
|
|
1012
|
+
} catch (err) {
|
|
1013
|
+
if (await localBranchExists(gitRoot, branch)) {
|
|
1014
|
+
if (await getCurrentBranch(gitRoot) !== branch) {
|
|
1015
|
+
await execGit(gitRoot, ["checkout", branch]);
|
|
1152
1016
|
}
|
|
1017
|
+
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
1018
|
+
} else {
|
|
1019
|
+
throw err;
|
|
1153
1020
|
}
|
|
1154
1021
|
}
|
|
1155
1022
|
}
|
|
@@ -1168,9 +1035,7 @@ async function runTaskBranch(taskId, options = {}) {
|
|
|
1168
1035
|
});
|
|
1169
1036
|
const baselineBranch = projectBaseline.baseBranch?.trim() ?? "";
|
|
1170
1037
|
if (!baselineBranch) {
|
|
1171
|
-
throw new Error(
|
|
1172
|
-
"[apm] \u9879\u76EE\u672A\u914D\u7F6E\u57FA\u7840\u5206\u652F\uFF0C\u65E0\u6CD5\u521B\u5EFA WebIDE \u7279\u6027\u5206\u652F"
|
|
1173
|
-
);
|
|
1038
|
+
throw new Error("[apm] \u9879\u76EE\u672A\u914D\u7F6E\u57FA\u7840\u5206\u652F\uFF0C\u65E0\u6CD5\u521B\u5EFA WebIDE \u7279\u6027\u5206\u652F");
|
|
1174
1039
|
}
|
|
1175
1040
|
const cwd = options.cwd ?? process.cwd();
|
|
1176
1041
|
const workdirPath = resolveWorkdirPath(cwd);
|
|
@@ -1500,132 +1365,6 @@ ${JSON.stringify(event, null, 2)}
|
|
|
1500
1365
|
\`\`\``;
|
|
1501
1366
|
}
|
|
1502
1367
|
|
|
1503
|
-
// src/commands/connect/agent-session-registry.ts
|
|
1504
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1505
|
-
import { dirname as dirname3, resolve as resolve4 } from "node:path";
|
|
1506
|
-
function registryPath(workdir, sessionId) {
|
|
1507
|
-
return resolve4(workdir, ".apm", "sessions", sessionId, "cursor-agents.json");
|
|
1508
|
-
}
|
|
1509
|
-
function readRegistry(path) {
|
|
1510
|
-
if (!existsSync3(path)) {
|
|
1511
|
-
return {};
|
|
1512
|
-
}
|
|
1513
|
-
try {
|
|
1514
|
-
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
1515
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1516
|
-
const result = {};
|
|
1517
|
-
for (const [key, value] of Object.entries(
|
|
1518
|
-
parsed
|
|
1519
|
-
)) {
|
|
1520
|
-
if (typeof value === "string" && value.trim()) {
|
|
1521
|
-
result[key] = value.trim();
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
return result;
|
|
1525
|
-
}
|
|
1526
|
-
} catch {
|
|
1527
|
-
}
|
|
1528
|
-
return {};
|
|
1529
|
-
}
|
|
1530
|
-
function writeRegistry(path, registry) {
|
|
1531
|
-
mkdirSync4(dirname3(path), { recursive: true });
|
|
1532
|
-
writeFileSync3(path, `${JSON.stringify(registry, null, 2)}
|
|
1533
|
-
`, "utf8");
|
|
1534
|
-
}
|
|
1535
|
-
function loadSessionAgentId(workdir, sessionId, user) {
|
|
1536
|
-
const registry = readRegistry(registryPath(workdir, sessionId));
|
|
1537
|
-
return registry[user];
|
|
1538
|
-
}
|
|
1539
|
-
function saveSessionAgentId(workdir, sessionId, user, agentId) {
|
|
1540
|
-
const path = registryPath(workdir, sessionId);
|
|
1541
|
-
const registry = readRegistry(path);
|
|
1542
|
-
registry[user] = agentId;
|
|
1543
|
-
writeRegistry(path, registry);
|
|
1544
|
-
}
|
|
1545
|
-
function clearSessionAgentId(workdir, sessionId, user) {
|
|
1546
|
-
const path = registryPath(workdir, sessionId);
|
|
1547
|
-
const registry = readRegistry(path);
|
|
1548
|
-
if (!(user in registry)) {
|
|
1549
|
-
return;
|
|
1550
|
-
}
|
|
1551
|
-
delete registry[user];
|
|
1552
|
-
writeRegistry(path, registry);
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
// src/commands/connect/cursor-message-log.ts
|
|
1556
|
-
var CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS = 2e3;
|
|
1557
|
-
function createThrottledCursorMessageLogSync(cfg, ctx, onError) {
|
|
1558
|
-
let lastRunAt = 0;
|
|
1559
|
-
let timer;
|
|
1560
|
-
let latestSession;
|
|
1561
|
-
let syncChain = Promise.resolve();
|
|
1562
|
-
const syncDirtyEventsOnce = async (session) => {
|
|
1563
|
-
const events = session.getDirtyEvents();
|
|
1564
|
-
if (events.length === 0) {
|
|
1565
|
-
return;
|
|
1566
|
-
}
|
|
1567
|
-
lastRunAt = Date.now();
|
|
1568
|
-
try {
|
|
1569
|
-
await syncCursorMessageLog(cfg, ctx, events);
|
|
1570
|
-
session.clearDirtyIfUnchanged(events);
|
|
1571
|
-
} catch (err) {
|
|
1572
|
-
onError(err);
|
|
1573
|
-
}
|
|
1574
|
-
};
|
|
1575
|
-
const drainDirtyEvents = async (session) => {
|
|
1576
|
-
while (session.getDirtyEvents().length > 0) {
|
|
1577
|
-
await syncDirtyEventsOnce(session);
|
|
1578
|
-
}
|
|
1579
|
-
};
|
|
1580
|
-
const enqueueSync = (session) => {
|
|
1581
|
-
syncChain = syncChain.then(() => drainDirtyEvents(session));
|
|
1582
|
-
};
|
|
1583
|
-
return {
|
|
1584
|
-
schedule(session) {
|
|
1585
|
-
latestSession = session;
|
|
1586
|
-
const now = Date.now();
|
|
1587
|
-
const elapsed = now - lastRunAt;
|
|
1588
|
-
if (elapsed >= CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS) {
|
|
1589
|
-
if (timer) {
|
|
1590
|
-
clearTimeout(timer);
|
|
1591
|
-
timer = void 0;
|
|
1592
|
-
}
|
|
1593
|
-
enqueueSync(session);
|
|
1594
|
-
return;
|
|
1595
|
-
}
|
|
1596
|
-
if (timer) {
|
|
1597
|
-
return;
|
|
1598
|
-
}
|
|
1599
|
-
timer = setTimeout(() => {
|
|
1600
|
-
timer = void 0;
|
|
1601
|
-
enqueueSync(latestSession);
|
|
1602
|
-
}, CURSOR_MESSAGE_LOG_SYNC_INTERVAL_MS - elapsed);
|
|
1603
|
-
},
|
|
1604
|
-
async flush(session) {
|
|
1605
|
-
latestSession = session;
|
|
1606
|
-
if (timer) {
|
|
1607
|
-
clearTimeout(timer);
|
|
1608
|
-
timer = void 0;
|
|
1609
|
-
}
|
|
1610
|
-
await syncChain;
|
|
1611
|
-
await drainDirtyEvents(session);
|
|
1612
|
-
}
|
|
1613
|
-
};
|
|
1614
|
-
}
|
|
1615
|
-
async function syncCursorMessageLog(cfg, ctx, events) {
|
|
1616
|
-
const agentId = ctx.agentId.trim();
|
|
1617
|
-
if (!agentId || events.length === 0) {
|
|
1618
|
-
return;
|
|
1619
|
-
}
|
|
1620
|
-
const api = createApmApiClient(cfg);
|
|
1621
|
-
await api.cli.upsertCursorMessageLog({
|
|
1622
|
-
sessionId: ctx.sessionId,
|
|
1623
|
-
messageId: ctx.messageId,
|
|
1624
|
-
agentId,
|
|
1625
|
-
events
|
|
1626
|
-
});
|
|
1627
|
-
}
|
|
1628
|
-
|
|
1629
1368
|
// src/commands/connect/abort-signal-debug.ts
|
|
1630
1369
|
import {
|
|
1631
1370
|
getEventListeners,
|
|
@@ -1689,25 +1428,11 @@ ${stack}`
|
|
|
1689
1428
|
);
|
|
1690
1429
|
}
|
|
1691
1430
|
|
|
1692
|
-
// src/commands/append-message.ts
|
|
1693
|
-
async function appendMessageContent(cfg, messageId, content) {
|
|
1694
|
-
const trimmedId = messageId.trim();
|
|
1695
|
-
if (!trimmedId) {
|
|
1696
|
-
throw new Error("messageId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
1697
|
-
}
|
|
1698
|
-
if (!content) {
|
|
1699
|
-
throw new Error("content \u4E0D\u80FD\u4E3A\u7A7A");
|
|
1700
|
-
}
|
|
1701
|
-
const api = createApmApiClient(cfg);
|
|
1702
|
-
await api.cli.appendMessageContent({ id: trimmedId, content });
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
1431
|
// src/commands/connect/append-message-tool.ts
|
|
1706
|
-
function createAppendMessageCustomTools(
|
|
1707
|
-
const doAppend = appendContent2 ?? ((content) => appendMessageContent(cfg, messageId, content));
|
|
1432
|
+
function createAppendMessageCustomTools(messageId, appendContent2) {
|
|
1708
1433
|
return {
|
|
1709
1434
|
AppendMessage: {
|
|
1710
|
-
description: "\u5411\u5F53\u524D
|
|
1435
|
+
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",
|
|
1711
1436
|
inputSchema: {
|
|
1712
1437
|
type: "object",
|
|
1713
1438
|
properties: {
|
|
@@ -1727,7 +1452,7 @@ function createAppendMessageCustomTools(cfg, messageId, appendContent2) {
|
|
|
1727
1452
|
};
|
|
1728
1453
|
}
|
|
1729
1454
|
try {
|
|
1730
|
-
await
|
|
1455
|
+
await appendContent2(content);
|
|
1731
1456
|
console.log(`[apm] AppendMessage \u5DF2\u8FFD\u52A0: messageId=${messageId}`);
|
|
1732
1457
|
return "\u5DF2\u8FFD\u52A0\u6D88\u606F\u5185\u5BB9";
|
|
1733
1458
|
} catch (err) {
|
|
@@ -2147,11 +1872,7 @@ var WORKSPACE_BOUNDARY_HINT = `[\u5DE5\u4F5C\u533A\u8FB9\u754C]
|
|
|
2147
1872
|
\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`;
|
|
2148
1873
|
function createCursorCustomTools(cfg, messageId, options) {
|
|
2149
1874
|
const tools = {
|
|
2150
|
-
...createAppendMessageCustomTools(
|
|
2151
|
-
cfg,
|
|
2152
|
-
messageId,
|
|
2153
|
-
options?.appendMessageContent
|
|
2154
|
-
),
|
|
1875
|
+
...createAppendMessageCustomTools(messageId, options.appendMessageContent),
|
|
2155
1876
|
AskQuestion: createAskQuestionTool({
|
|
2156
1877
|
onInvoke: options?.onAskQuestion,
|
|
2157
1878
|
execute: options?.askQuestionExecute
|
|
@@ -2211,11 +1932,6 @@ var noopRemoteLogSync = {
|
|
|
2211
1932
|
async flush(_session) {
|
|
2212
1933
|
}
|
|
2213
1934
|
};
|
|
2214
|
-
var logCtx = (ctx, agentId) => ({
|
|
2215
|
-
sessionId: ctx.sessionId,
|
|
2216
|
-
messageId: ctx.messageId,
|
|
2217
|
-
agentId
|
|
2218
|
-
});
|
|
2219
1935
|
function formatCursorRunFailure(runId, options) {
|
|
2220
1936
|
const details = [
|
|
2221
1937
|
options?.statusError?.trim(),
|
|
@@ -2229,19 +1945,6 @@ function formatCursorRunFailure(runId, options) {
|
|
|
2229
1945
|
}
|
|
2230
1946
|
return `Cursor run \u5931\u8D25: ${runId} \u2014 ${details.join("\uFF1B")}`;
|
|
2231
1947
|
}
|
|
2232
|
-
function persistSessionAgentId(ctx, agentId) {
|
|
2233
|
-
if (ctx.skipSessionAgentRegistry || !ctx.user) return;
|
|
2234
|
-
saveSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user, agentId);
|
|
2235
|
-
}
|
|
2236
|
-
function invalidatePersistedAgentId(ctx) {
|
|
2237
|
-
if (ctx.skipSessionAgentRegistry) {
|
|
2238
|
-
ctx.onInvalidatePersistedAgentId?.();
|
|
2239
|
-
return;
|
|
2240
|
-
}
|
|
2241
|
-
if (ctx.user) {
|
|
2242
|
-
clearSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user);
|
|
2243
|
-
}
|
|
2244
|
-
}
|
|
2245
1948
|
async function obtainAgent(ctx) {
|
|
2246
1949
|
const agentOptions = {
|
|
2247
1950
|
apiKey: ctx.apiKey,
|
|
@@ -2258,29 +1961,22 @@ async function obtainAgent(ctx) {
|
|
|
2258
1961
|
...ctx.mode ? { mode: ctx.mode } : {},
|
|
2259
1962
|
...ctx.mcpServers ? { mcpServers: ctx.mcpServers } : {}
|
|
2260
1963
|
};
|
|
2261
|
-
const
|
|
2262
|
-
const savedAgentId = explicitAgentId || (!ctx.skipSessionAgentRegistry && ctx.user ? loadSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user) : void 0);
|
|
1964
|
+
const savedAgentId = ctx.resumeAgentId?.trim();
|
|
2263
1965
|
if (savedAgentId) {
|
|
2264
1966
|
try {
|
|
2265
1967
|
const agent = await Agent.resume(savedAgentId, agentOptions);
|
|
2266
|
-
console.log(
|
|
2267
|
-
`[apm] \u590D\u7528 Agent user=${ctx.user} agentId=${savedAgentId}${explicitAgentId ? "\uFF08\u53C2\u6570\u6307\u5B9A\uFF09" : ""}`
|
|
2268
|
-
);
|
|
2269
|
-
persistSessionAgentId(ctx, agent.agentId);
|
|
1968
|
+
console.log(`[apm] \u590D\u7528 Agent user=${ctx.user} agentId=${savedAgentId}`);
|
|
2270
1969
|
return { agent, resumed: true };
|
|
2271
1970
|
} catch (err) {
|
|
2272
1971
|
console.warn(
|
|
2273
1972
|
`[apm] \u590D\u7528 Agent \u5931\u8D25\uFF08agentId=${savedAgentId}\uFF09\uFF0C\u56DE\u9000\u4E3A\u65B0\u5EFA:`,
|
|
2274
1973
|
err instanceof Error ? err.message : err
|
|
2275
1974
|
);
|
|
2276
|
-
|
|
2277
|
-
invalidatePersistedAgentId(ctx);
|
|
2278
|
-
}
|
|
1975
|
+
ctx.onInvalidatePersistedAgentId?.();
|
|
2279
1976
|
}
|
|
2280
1977
|
}
|
|
2281
1978
|
try {
|
|
2282
1979
|
const agent = await Agent.create(agentOptions);
|
|
2283
|
-
persistSessionAgentId(ctx, agent.agentId);
|
|
2284
1980
|
return { agent, resumed: false };
|
|
2285
1981
|
} catch (err) {
|
|
2286
1982
|
if (ctx.enableSandbox && err instanceof Error && /sandbox/i.test(err.message)) {
|
|
@@ -2291,7 +1987,7 @@ async function obtainAgent(ctx) {
|
|
|
2291
1987
|
}
|
|
2292
1988
|
}
|
|
2293
1989
|
async function runCursorAgent(cfg, ctx, options) {
|
|
2294
|
-
const signal = options
|
|
1990
|
+
const signal = options.signal;
|
|
2295
1991
|
logAbortSignalStats(signal, "runCursorAgent:start");
|
|
2296
1992
|
if (signal?.aborted) {
|
|
2297
1993
|
throw new Error("\u8FDE\u63A5\u5DF2\u5173\u95ED\uFF0C\u4EFB\u52A1\u4E2D\u65AD");
|
|
@@ -2302,54 +1998,36 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2302
1998
|
}
|
|
2303
1999
|
const workdir = resolveWorkdirPath(ctx.workdir);
|
|
2304
2000
|
const customTools = createCursorCustomTools(cfg, ctx.messageId, {
|
|
2305
|
-
onAskQuestion: options
|
|
2306
|
-
appendMessageContent: options
|
|
2307
|
-
askQuestionExecute: options
|
|
2308
|
-
enableWebIdePlanTools: options
|
|
2309
|
-
taskId: options
|
|
2001
|
+
onAskQuestion: options.onAskQuestion,
|
|
2002
|
+
appendMessageContent: options.appendMessageContent,
|
|
2003
|
+
askQuestionExecute: options.askQuestionExecute,
|
|
2004
|
+
enableWebIdePlanTools: options.enableWebIdePlanTools,
|
|
2005
|
+
taskId: options.taskId,
|
|
2310
2006
|
workdir,
|
|
2311
|
-
terminalRpc: options
|
|
2007
|
+
terminalRpc: options.terminalRpc
|
|
2312
2008
|
});
|
|
2313
|
-
const enableSandbox = Boolean(options
|
|
2009
|
+
const enableSandbox = Boolean(options.enableSandbox);
|
|
2314
2010
|
let prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
|
|
2315
2011
|
prompt = withWorkspaceBoundaryHint(prompt);
|
|
2316
2012
|
console.log(
|
|
2317
|
-
`[apm] Cursor Agent \u5F00\u59CB messageId=${ctx.messageId}
|
|
2013
|
+
`[apm] Cursor Agent \u5F00\u59CB messageId=${ctx.messageId} cwd=${workdir} sandbox=${enableSandbox}`
|
|
2318
2014
|
);
|
|
2319
2015
|
const { agent, resumed } = await obtainAgent({
|
|
2320
2016
|
apiKey,
|
|
2321
2017
|
model: ctx.model,
|
|
2322
2018
|
cwd: workdir,
|
|
2323
|
-
workdir,
|
|
2324
|
-
sessionId: ctx.sessionId,
|
|
2325
2019
|
user: ctx.user,
|
|
2326
2020
|
mode: ctx.mode,
|
|
2327
2021
|
resumeAgentId: ctx.resumeAgentId,
|
|
2328
2022
|
customTools,
|
|
2329
2023
|
enableSandbox,
|
|
2330
|
-
|
|
2331
|
-
onInvalidatePersistedAgentId: options?.onInvalidatePersistedAgentId
|
|
2024
|
+
onInvalidatePersistedAgentId: options.onInvalidatePersistedAgentId
|
|
2332
2025
|
});
|
|
2333
2026
|
const invalidateAgentMapping = () => {
|
|
2334
|
-
|
|
2335
|
-
workdir,
|
|
2336
|
-
sessionId: ctx.sessionId,
|
|
2337
|
-
user: ctx.user,
|
|
2338
|
-
skipSessionAgentRegistry: options?.skipSessionAgentRegistry,
|
|
2339
|
-
onInvalidatePersistedAgentId: options?.onInvalidatePersistedAgentId
|
|
2340
|
-
});
|
|
2027
|
+
options.onInvalidatePersistedAgentId?.();
|
|
2341
2028
|
};
|
|
2342
|
-
const eventSession = options
|
|
2343
|
-
const syncRemoteLog = options
|
|
2344
|
-
cfg,
|
|
2345
|
-
logCtx(ctx, agent.agentId),
|
|
2346
|
-
(err) => {
|
|
2347
|
-
console.warn(
|
|
2348
|
-
"[apm] \u540C\u6B65 Cursor \u6D88\u606F\u65E5\u5FD7\u5931\u8D25:",
|
|
2349
|
-
err instanceof Error ? err.message : err
|
|
2350
|
-
);
|
|
2351
|
-
}
|
|
2352
|
-
);
|
|
2029
|
+
const eventSession = options.eventSession ?? new EventSession(prompt);
|
|
2030
|
+
const syncRemoteLog = options.createRemoteLogSync ? options.createRemoteLogSync(agent.agentId) : noopRemoteLogSync;
|
|
2353
2031
|
let activeRun;
|
|
2354
2032
|
const abortRun = () => {
|
|
2355
2033
|
if (!activeRun?.supports("cancel")) return;
|
|
@@ -2361,14 +2039,14 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2361
2039
|
const run = await agent.send(prompt, {
|
|
2362
2040
|
...ctx.mode ? { mode: ctx.mode } : {},
|
|
2363
2041
|
local: {
|
|
2364
|
-
...options
|
|
2042
|
+
...options.forceSend ? { force: true } : {},
|
|
2365
2043
|
customTools
|
|
2366
2044
|
}
|
|
2367
2045
|
});
|
|
2368
2046
|
activeRun = run;
|
|
2369
2047
|
logAbortSignalStats(signal, "runCursorAgent:after-send");
|
|
2370
2048
|
console.log(`[apm] Cursor run id=${run.id} agentId=${agent.agentId}`);
|
|
2371
|
-
await options
|
|
2049
|
+
await options.onRunStarted?.({ agentId: agent.agentId, runId: run.id });
|
|
2372
2050
|
let lastRunErrorStatus;
|
|
2373
2051
|
for await (const event of run.stream()) {
|
|
2374
2052
|
if (signal?.aborted) {
|
|
@@ -2384,7 +2062,7 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2384
2062
|
);
|
|
2385
2063
|
}
|
|
2386
2064
|
}
|
|
2387
|
-
options
|
|
2065
|
+
options.onStreamEvent?.(event);
|
|
2388
2066
|
eventSession.addEvent(event);
|
|
2389
2067
|
syncRemoteLog.schedule(eventSession);
|
|
2390
2068
|
}
|
|
@@ -2461,17 +2139,17 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2461
2139
|
}
|
|
2462
2140
|
|
|
2463
2141
|
// src/commands/connect/webide-agent-registry.ts
|
|
2464
|
-
import { existsSync as
|
|
2465
|
-
import { dirname as
|
|
2466
|
-
function
|
|
2467
|
-
return
|
|
2142
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2143
|
+
import { dirname as dirname3, resolve as resolve4 } from "node:path";
|
|
2144
|
+
function registryPath(workdir, taskId) {
|
|
2145
|
+
return resolve4(workdir, ".apm", "webide", taskId, "cursor-agent.json");
|
|
2468
2146
|
}
|
|
2469
|
-
function
|
|
2470
|
-
if (!
|
|
2147
|
+
function readRegistry(path) {
|
|
2148
|
+
if (!existsSync3(path)) {
|
|
2471
2149
|
return {};
|
|
2472
2150
|
}
|
|
2473
2151
|
try {
|
|
2474
|
-
const parsed = JSON.parse(
|
|
2152
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
2475
2153
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2476
2154
|
const raw = parsed;
|
|
2477
2155
|
const state = {};
|
|
@@ -2499,16 +2177,16 @@ function readRegistry2(path) {
|
|
|
2499
2177
|
}
|
|
2500
2178
|
return {};
|
|
2501
2179
|
}
|
|
2502
|
-
function
|
|
2503
|
-
|
|
2504
|
-
|
|
2180
|
+
function writeRegistry(path, registry) {
|
|
2181
|
+
mkdirSync4(dirname3(path), { recursive: true });
|
|
2182
|
+
writeFileSync3(path, `${JSON.stringify(registry, null, 2)}
|
|
2505
2183
|
`, "utf8");
|
|
2506
2184
|
}
|
|
2507
2185
|
function syncWebIdeTaskState(workdir, taskId, patch) {
|
|
2508
2186
|
const trimmedTaskId = taskId.trim();
|
|
2509
2187
|
if (!trimmedTaskId) return;
|
|
2510
|
-
const path =
|
|
2511
|
-
const current =
|
|
2188
|
+
const path = registryPath(workdir, trimmedTaskId);
|
|
2189
|
+
const current = readRegistry(path);
|
|
2512
2190
|
const next = {
|
|
2513
2191
|
...current,
|
|
2514
2192
|
taskId: trimmedTaskId,
|
|
@@ -2532,30 +2210,30 @@ function syncWebIdeTaskState(workdir, taskId, patch) {
|
|
|
2532
2210
|
if (patch.status !== void 0) {
|
|
2533
2211
|
next.status = patch.status;
|
|
2534
2212
|
}
|
|
2535
|
-
|
|
2213
|
+
writeRegistry(path, next);
|
|
2536
2214
|
}
|
|
2537
2215
|
function loadWebIdeAgentId(workdir, taskId) {
|
|
2538
|
-
return
|
|
2216
|
+
return readRegistry(registryPath(workdir, taskId)).agentId;
|
|
2539
2217
|
}
|
|
2540
2218
|
function saveWebIdeAgentId(workdir, taskId, agentId) {
|
|
2541
2219
|
syncWebIdeTaskState(workdir, taskId, { agentId });
|
|
2542
2220
|
}
|
|
2543
2221
|
function clearWebIdeAgentId(workdir, taskId) {
|
|
2544
|
-
const path =
|
|
2545
|
-
if (!
|
|
2222
|
+
const path = registryPath(workdir, taskId);
|
|
2223
|
+
if (!existsSync3(path)) return;
|
|
2546
2224
|
syncWebIdeTaskState(workdir, taskId, { agentId: "" });
|
|
2547
2225
|
}
|
|
2548
2226
|
|
|
2549
2227
|
// src/commands/clean-webide-cache.ts
|
|
2550
|
-
import { existsSync as
|
|
2551
|
-
import { resolve as
|
|
2228
|
+
import { existsSync as existsSync4, rmSync } from "node:fs";
|
|
2229
|
+
import { resolve as resolve5 } from "node:path";
|
|
2552
2230
|
import { getDefaultSdkStateRoot } from "@cursor/sdk";
|
|
2553
2231
|
async function purgeCursorAgentStoreForAgent(workdir, agentId) {
|
|
2554
2232
|
const trimmedAgentId = agentId.trim();
|
|
2555
2233
|
const trimmedWorkdir = workdir.trim();
|
|
2556
2234
|
if (!trimmedAgentId || !trimmedWorkdir) return false;
|
|
2557
2235
|
const stateRoot = getDefaultSdkStateRoot(trimmedWorkdir);
|
|
2558
|
-
if (!
|
|
2236
|
+
if (!existsSync4(stateRoot)) return false;
|
|
2559
2237
|
const { SqliteLocalAgentStore } = await import(
|
|
2560
2238
|
/* @vite-ignore */
|
|
2561
2239
|
"@cursor/sdk/sqlite"
|
|
@@ -2619,8 +2297,8 @@ async function cleanWebIdeWorkspaceCache(taskId, workdir) {
|
|
|
2619
2297
|
`[apm] \u65E0 WebIDE agentId\uFF0C\u8DF3\u8FC7 agent store \u6E05\u7406 taskId=${trimmedTaskId}`
|
|
2620
2298
|
);
|
|
2621
2299
|
}
|
|
2622
|
-
const dir =
|
|
2623
|
-
if (
|
|
2300
|
+
const dir = resolve5(trimmedWorkdir, ".apm", "webide", trimmedTaskId);
|
|
2301
|
+
if (existsSync4(dir)) {
|
|
2624
2302
|
rmSync(dir, { recursive: true, force: true });
|
|
2625
2303
|
console.log(`[apm] \u5DF2\u6E05\u7406 WebIDE \u7F13\u5B58 ${dir}`);
|
|
2626
2304
|
} else {
|
|
@@ -2742,14 +2420,14 @@ var MinioClient = class {
|
|
|
2742
2420
|
async deleteObjectsByPrefix(bucket, prefix) {
|
|
2743
2421
|
const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
2744
2422
|
const keys = [];
|
|
2745
|
-
await new Promise((
|
|
2423
|
+
await new Promise((resolve6, reject) => {
|
|
2746
2424
|
objectsStream.on("data", (obj) => {
|
|
2747
2425
|
if (obj.name) {
|
|
2748
2426
|
keys.push(obj.name);
|
|
2749
2427
|
}
|
|
2750
2428
|
});
|
|
2751
2429
|
objectsStream.on("error", reject);
|
|
2752
|
-
objectsStream.on("end",
|
|
2430
|
+
objectsStream.on("end", resolve6);
|
|
2753
2431
|
});
|
|
2754
2432
|
const chunkSize = 500;
|
|
2755
2433
|
for (let i = 0; i < keys.length; i += chunkSize) {
|
|
@@ -2938,56 +2616,33 @@ function resolveMessageReplyFallback(fallback) {
|
|
|
2938
2616
|
}
|
|
2939
2617
|
|
|
2940
2618
|
// src/commands/init.ts
|
|
2941
|
-
|
|
2942
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
2943
|
-
function applyWorkspaceName(apmDir, name) {
|
|
2944
|
-
const trimmedName = name?.trim();
|
|
2945
|
-
if (!trimmedName) return;
|
|
2946
|
-
const apmConfigPath = toFsPath(join4(apmDir, "apm.config.json"));
|
|
2947
|
-
const config = readFileSync5(apmConfigPath, "utf8");
|
|
2948
|
-
const configJson = JSON.parse(config);
|
|
2949
|
-
configJson.name = trimmedName;
|
|
2950
|
-
writeFileSync5(
|
|
2951
|
-
apmConfigPath,
|
|
2952
|
-
`${JSON.stringify(configJson, null, 2)}
|
|
2953
|
-
`,
|
|
2954
|
-
"utf8"
|
|
2955
|
-
);
|
|
2956
|
-
}
|
|
2957
|
-
async function initializeWorkspace(workdir, options) {
|
|
2619
|
+
async function initializeWorkspace(workdir) {
|
|
2958
2620
|
await ensureWorkspaceApmDirForInit(workdir);
|
|
2959
2621
|
const apmDir = workspaceApmDir(workdir);
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
} else {
|
|
2963
|
-
await copyTemplateFiles(apmDir, workdir);
|
|
2964
|
-
}
|
|
2965
|
-
applyWorkspaceName(apmDir, options?.name);
|
|
2966
|
-
console.log(
|
|
2967
|
-
options?.webide ? `[apm] \u5DF2\u6309 WebIDE \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}` : `[apm] \u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`
|
|
2968
|
-
);
|
|
2622
|
+
await copyWebIdeTemplateFiles(apmDir, workdir);
|
|
2623
|
+
console.log(`[apm] \u5DF2\u6309 WebIDE \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
|
|
2969
2624
|
return { didInit: true };
|
|
2970
2625
|
}
|
|
2971
|
-
async function ensureWorkspaceInitialized(workdir
|
|
2626
|
+
async function ensureWorkspaceInitialized(workdir) {
|
|
2972
2627
|
if (isWorkspaceApmInitialized(workdir)) {
|
|
2973
2628
|
return { didInit: false };
|
|
2974
2629
|
}
|
|
2975
2630
|
console.log(
|
|
2976
|
-
|
|
2631
|
+
`[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u6309 WebIDE \u81EA\u52A8\u521D\u59CB\u5316\u2026`
|
|
2977
2632
|
);
|
|
2978
|
-
return initializeWorkspace(workdir
|
|
2633
|
+
return initializeWorkspace(workdir);
|
|
2979
2634
|
}
|
|
2980
2635
|
|
|
2981
2636
|
// src/commands/connect/pre-step-cache.ts
|
|
2982
|
-
function
|
|
2983
|
-
return `${
|
|
2637
|
+
function taskWorkdirKey(taskId, workdir) {
|
|
2638
|
+
return `${taskId}\0${workdir}`;
|
|
2984
2639
|
}
|
|
2985
2640
|
var lastBranchKey = null;
|
|
2986
|
-
function shouldRunBranch(
|
|
2987
|
-
return lastBranchKey !==
|
|
2641
|
+
function shouldRunBranch(taskId, workdir) {
|
|
2642
|
+
return lastBranchKey !== taskWorkdirKey(taskId, workdir);
|
|
2988
2643
|
}
|
|
2989
|
-
function markBranchDone(
|
|
2990
|
-
lastBranchKey =
|
|
2644
|
+
function markBranchDone(taskId, workdir) {
|
|
2645
|
+
lastBranchKey = taskWorkdirKey(taskId, workdir);
|
|
2991
2646
|
}
|
|
2992
2647
|
|
|
2993
2648
|
// src/commands/connect/webide-pull-requests.ts
|
|
@@ -3109,7 +2764,7 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3109
2764
|
try {
|
|
3110
2765
|
const current = await getCurrentBranch(gitRoot);
|
|
3111
2766
|
if (!isFeatureBranchName(current)) {
|
|
3112
|
-
const tip = `${label}\uFF1A\u5F53\u524D\u5206\u652F ${current} \u4E0D\u662F feat/task
|
|
2767
|
+
const tip = `${label}\uFF1A\u5F53\u524D\u5206\u652F ${current} \u4E0D\u662F feat/task-*\uFF0C\u4E0D\u7B26\u5408\u521B\u5EFA PR \u6761\u4EF6`;
|
|
3113
2768
|
console.warn(`[apm] WebIDE PR\uFF1A${tip}`);
|
|
3114
2769
|
tips.push(tip);
|
|
3115
2770
|
skipped += 1;
|
|
@@ -3227,23 +2882,23 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3227
2882
|
}
|
|
3228
2883
|
|
|
3229
2884
|
// src/version.ts
|
|
3230
|
-
import { readFileSync as
|
|
3231
|
-
import { dirname as
|
|
2885
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
2886
|
+
import { dirname as dirname4, join as join4 } from "path";
|
|
3232
2887
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3233
2888
|
function readCliVersion() {
|
|
3234
2889
|
try {
|
|
3235
|
-
const dir =
|
|
3236
|
-
const pkgPath =
|
|
3237
|
-
const pkg = JSON.parse(
|
|
2890
|
+
const dir = dirname4(fileURLToPath2(import.meta.url));
|
|
2891
|
+
const pkgPath = join4(dir, "..", "package.json");
|
|
2892
|
+
const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
|
|
3238
2893
|
return pkg.version ?? "0.0.0";
|
|
3239
2894
|
} catch {
|
|
3240
2895
|
return "0.0.0";
|
|
3241
2896
|
}
|
|
3242
2897
|
}
|
|
3243
2898
|
|
|
3244
|
-
// src/commands/sync-
|
|
3245
|
-
import { existsSync as
|
|
3246
|
-
import { join as
|
|
2899
|
+
// src/commands/sync-webide-attachments.ts
|
|
2900
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
2901
|
+
import { join as join5 } from "path";
|
|
3247
2902
|
var MANIFEST_FILE = ".sync-manifest.json";
|
|
3248
2903
|
async function downloadAttachment(cfg, attachmentId) {
|
|
3249
2904
|
const base = cfg.baseUrl.trim().replace(/\/+$/, "");
|
|
@@ -3259,13 +2914,13 @@ async function downloadAttachment(cfg, attachmentId) {
|
|
|
3259
2914
|
return Buffer.from(await res.arrayBuffer());
|
|
3260
2915
|
}
|
|
3261
2916
|
function loadManifest(dir) {
|
|
3262
|
-
const path =
|
|
3263
|
-
if (!
|
|
2917
|
+
const path = join5(dir, MANIFEST_FILE);
|
|
2918
|
+
if (!existsSync5(path)) {
|
|
3264
2919
|
return { version: 1, attachments: {} };
|
|
3265
2920
|
}
|
|
3266
2921
|
try {
|
|
3267
2922
|
const parsed = JSON.parse(
|
|
3268
|
-
|
|
2923
|
+
readFileSync5(path, "utf8")
|
|
3269
2924
|
);
|
|
3270
2925
|
if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
|
|
3271
2926
|
return parsed;
|
|
@@ -3275,15 +2930,15 @@ function loadManifest(dir) {
|
|
|
3275
2930
|
return { version: 1, attachments: {} };
|
|
3276
2931
|
}
|
|
3277
2932
|
function saveManifest(dir, manifest) {
|
|
3278
|
-
|
|
3279
|
-
|
|
2933
|
+
writeFileSync4(
|
|
2934
|
+
join5(dir, MANIFEST_FILE),
|
|
3280
2935
|
`${JSON.stringify(manifest, null, 2)}
|
|
3281
2936
|
`,
|
|
3282
2937
|
"utf8"
|
|
3283
2938
|
);
|
|
3284
2939
|
}
|
|
3285
2940
|
function isAttachmentUpToDate(entry, item, dest) {
|
|
3286
|
-
if (!entry || !
|
|
2941
|
+
if (!entry || !existsSync5(dest)) return false;
|
|
3287
2942
|
if (entry.name !== item.name) return false;
|
|
3288
2943
|
const createdAt = item.createdAt ?? "";
|
|
3289
2944
|
return entry.createdAt === createdAt;
|
|
@@ -3298,7 +2953,7 @@ async function syncAttachmentsToDirectory(cfg, attachments, dir, logLabel) {
|
|
|
3298
2953
|
const nextManifest = { version: 1, attachments: {} };
|
|
3299
2954
|
const names = [];
|
|
3300
2955
|
for (const item of attachments) {
|
|
3301
|
-
const dest =
|
|
2956
|
+
const dest = join5(dir, item.name);
|
|
3302
2957
|
const entry = manifest.attachments[item.id];
|
|
3303
2958
|
const createdAt = item.createdAt ?? "";
|
|
3304
2959
|
names.push(item.name);
|
|
@@ -3308,7 +2963,7 @@ async function syncAttachmentsToDirectory(cfg, attachments, dir, logLabel) {
|
|
|
3308
2963
|
continue;
|
|
3309
2964
|
}
|
|
3310
2965
|
const buffer = await downloadAttachment(cfg, item.id);
|
|
3311
|
-
|
|
2966
|
+
writeFileSync4(dest, buffer);
|
|
3312
2967
|
nextManifest.attachments[item.id] = {
|
|
3313
2968
|
name: item.name,
|
|
3314
2969
|
createdAt
|
|
@@ -3330,14 +2985,14 @@ async function syncWebIdeAttachments(cfg, taskId, workdir, attachments) {
|
|
|
3330
2985
|
|
|
3331
2986
|
// src/project-documents-sync.ts
|
|
3332
2987
|
import {
|
|
3333
|
-
existsSync as
|
|
2988
|
+
existsSync as existsSync6,
|
|
3334
2989
|
readdirSync as readdirSync3,
|
|
3335
|
-
readFileSync as
|
|
2990
|
+
readFileSync as readFileSync6,
|
|
3336
2991
|
rmSync as rmSync2,
|
|
3337
|
-
writeFileSync as
|
|
2992
|
+
writeFileSync as writeFileSync5
|
|
3338
2993
|
} from "fs";
|
|
3339
2994
|
import { createHash } from "crypto";
|
|
3340
|
-
import { dirname as
|
|
2995
|
+
import { dirname as dirname5, join as join6, relative as relative2, sep } from "path";
|
|
3341
2996
|
var MANIFEST_FILE2 = "manifest.json";
|
|
3342
2997
|
function normalizeProjectIdForPath(projectId) {
|
|
3343
2998
|
const id = projectId.trim();
|
|
@@ -3351,11 +3006,11 @@ function normalizeProjectIdForPath(projectId) {
|
|
|
3351
3006
|
}
|
|
3352
3007
|
function projectDocumentsDir(apmRoot, projectId) {
|
|
3353
3008
|
const id = normalizeProjectIdForPath(projectId);
|
|
3354
|
-
return
|
|
3009
|
+
return join6(apmRoot ?? workspaceApmDir(), "project", id);
|
|
3355
3010
|
}
|
|
3356
3011
|
function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
|
|
3357
3012
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
3358
|
-
return
|
|
3013
|
+
return join6(
|
|
3359
3014
|
projectDocumentsDir(apmRoot, projectId),
|
|
3360
3015
|
...normalized.split("/")
|
|
3361
3016
|
);
|
|
@@ -3375,16 +3030,16 @@ function hashLocalFileContent(content) {
|
|
|
3375
3030
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
3376
3031
|
}
|
|
3377
3032
|
function readLocalManifest(apmRoot, projectId) {
|
|
3378
|
-
const manifestPath3 =
|
|
3033
|
+
const manifestPath3 = join6(
|
|
3379
3034
|
projectDocumentsDir(apmRoot, projectId),
|
|
3380
3035
|
MANIFEST_FILE2
|
|
3381
3036
|
);
|
|
3382
|
-
if (!
|
|
3037
|
+
if (!existsSync6(manifestPath3)) {
|
|
3383
3038
|
return null;
|
|
3384
3039
|
}
|
|
3385
3040
|
try {
|
|
3386
3041
|
return JSON.parse(
|
|
3387
|
-
|
|
3042
|
+
readFileSync6(manifestPath3, "utf8")
|
|
3388
3043
|
);
|
|
3389
3044
|
} catch {
|
|
3390
3045
|
return null;
|
|
@@ -3392,13 +3047,13 @@ function readLocalManifest(apmRoot, projectId) {
|
|
|
3392
3047
|
}
|
|
3393
3048
|
function listLocalDocumentPaths(apmRoot, projectId) {
|
|
3394
3049
|
const root = projectDocumentsDir(apmRoot, projectId);
|
|
3395
|
-
if (!
|
|
3050
|
+
if (!existsSync6(root)) {
|
|
3396
3051
|
return [];
|
|
3397
3052
|
}
|
|
3398
3053
|
const paths = [];
|
|
3399
3054
|
const walk = (dir) => {
|
|
3400
3055
|
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
3401
|
-
const abs =
|
|
3056
|
+
const abs = join6(dir, entry.name);
|
|
3402
3057
|
if (entry.isDirectory()) {
|
|
3403
3058
|
walk(abs);
|
|
3404
3059
|
continue;
|
|
@@ -3516,8 +3171,8 @@ ${diagnostic ?? ""}`);
|
|
|
3516
3171
|
const absPath = toFsPath(
|
|
3517
3172
|
projectDocumentLocalPath(targetApmDir, projectId, doc.path)
|
|
3518
3173
|
);
|
|
3519
|
-
await ensureDirExists(
|
|
3520
|
-
|
|
3174
|
+
await ensureDirExists(dirname5(absPath));
|
|
3175
|
+
writeFileSync5(absPath, doc.content, "utf8");
|
|
3521
3176
|
downloaded += 1;
|
|
3522
3177
|
}
|
|
3523
3178
|
}
|
|
@@ -3526,13 +3181,13 @@ ${diagnostic ?? ""}`);
|
|
|
3526
3181
|
const absPath = toFsPath(
|
|
3527
3182
|
projectDocumentLocalPath(targetApmDir, projectId, path)
|
|
3528
3183
|
);
|
|
3529
|
-
if (
|
|
3184
|
+
if (existsSync6(absPath)) {
|
|
3530
3185
|
rmSync2(absPath, { force: true });
|
|
3531
3186
|
deleted += 1;
|
|
3532
3187
|
}
|
|
3533
3188
|
}
|
|
3534
|
-
|
|
3535
|
-
toFsPath(
|
|
3189
|
+
writeFileSync5(
|
|
3190
|
+
toFsPath(join6(docsDir, MANIFEST_FILE2)),
|
|
3536
3191
|
`${JSON.stringify(remoteManifest, null, 2)}
|
|
3537
3192
|
`,
|
|
3538
3193
|
"utf8"
|
|
@@ -3575,7 +3230,7 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
3575
3230
|
const absPath = toFsPath(
|
|
3576
3231
|
projectDocumentLocalPath(targetApmDir, projectId, path)
|
|
3577
3232
|
);
|
|
3578
|
-
const content =
|
|
3233
|
+
const content = readFileSync6(absPath, "utf8");
|
|
3579
3234
|
const contentHash = hashLocalFileContent(content);
|
|
3580
3235
|
if (remoteHashByPath.get(path) === contentHash) {
|
|
3581
3236
|
continue;
|
|
@@ -3596,20 +3251,20 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
3596
3251
|
}
|
|
3597
3252
|
|
|
3598
3253
|
// src/commands/connect/cli-version-sync.ts
|
|
3599
|
-
import { existsSync as
|
|
3600
|
-
import { join as
|
|
3254
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
3255
|
+
import { join as join7 } from "path";
|
|
3601
3256
|
var CLI_VERSION_FILE = ".cli-version.json";
|
|
3602
3257
|
function manifestPath2(apmDir) {
|
|
3603
|
-
return
|
|
3258
|
+
return join7(apmDir, CLI_VERSION_FILE);
|
|
3604
3259
|
}
|
|
3605
3260
|
function loadManifest2(apmDir) {
|
|
3606
3261
|
const path = toFsPath(manifestPath2(apmDir));
|
|
3607
|
-
if (!
|
|
3262
|
+
if (!existsSync7(path)) {
|
|
3608
3263
|
return null;
|
|
3609
3264
|
}
|
|
3610
3265
|
try {
|
|
3611
3266
|
const parsed = JSON.parse(
|
|
3612
|
-
|
|
3267
|
+
readFileSync7(path, "utf8")
|
|
3613
3268
|
);
|
|
3614
3269
|
if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
|
|
3615
3270
|
return parsed;
|
|
@@ -3620,7 +3275,7 @@ function loadManifest2(apmDir) {
|
|
|
3620
3275
|
}
|
|
3621
3276
|
function saveManifest2(apmDir, cliVersion) {
|
|
3622
3277
|
const manifest = { version: 1, cliVersion };
|
|
3623
|
-
|
|
3278
|
+
writeFileSync6(
|
|
3624
3279
|
toFsPath(manifestPath2(apmDir)),
|
|
3625
3280
|
`${JSON.stringify(manifest, null, 2)}
|
|
3626
3281
|
`,
|
|
@@ -3680,7 +3335,7 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3680
3335
|
const workdir = requireRemoteWorkdir(msg.workdir);
|
|
3681
3336
|
const messageId = msg.messageId;
|
|
3682
3337
|
const taskId = msg.taskId;
|
|
3683
|
-
const branchCacheKey =
|
|
3338
|
+
const branchCacheKey = taskId;
|
|
3684
3339
|
console.log(
|
|
3685
3340
|
`[apm] webide-message action=${msg.action} taskId=${taskId} messageId=${messageId}`
|
|
3686
3341
|
);
|
|
@@ -3726,9 +3381,7 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3726
3381
|
await runPrepStep(
|
|
3727
3382
|
"\u521D\u59CB\u5316\u5DE5\u4F5C\u533A",
|
|
3728
3383
|
async () => {
|
|
3729
|
-
const { didInit } = await ensureWorkspaceInitialized(workdir
|
|
3730
|
-
webide: true
|
|
3731
|
-
});
|
|
3384
|
+
const { didInit } = await ensureWorkspaceInitialized(workdir);
|
|
3732
3385
|
return didInit;
|
|
3733
3386
|
},
|
|
3734
3387
|
(didInit) => didInit ? "\u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A" : "\u5DE5\u4F5C\u533A\u5DF2\u5C31\u7EEA"
|
|
@@ -3872,7 +3525,6 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3872
3525
|
cfg,
|
|
3873
3526
|
{
|
|
3874
3527
|
messageId,
|
|
3875
|
-
sessionId: `webide:${taskId}`,
|
|
3876
3528
|
prompt: msg.content,
|
|
3877
3529
|
model: msg.model,
|
|
3878
3530
|
apiKey: msg.apiKey,
|
|
@@ -3892,7 +3544,6 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3892
3544
|
}),
|
|
3893
3545
|
enableWebIdePlanTools: true,
|
|
3894
3546
|
enableSandbox: false,
|
|
3895
|
-
skipSessionAgentRegistry: true,
|
|
3896
3547
|
onInvalidatePersistedAgentId: () => clearWebIdeAgentId(workdir, taskId),
|
|
3897
3548
|
taskId,
|
|
3898
3549
|
terminalRpc: options?.terminalRpc,
|
|
@@ -4103,12 +3754,12 @@ function installTerminalRpcListener() {
|
|
|
4103
3754
|
}
|
|
4104
3755
|
function call(op, args) {
|
|
4105
3756
|
const id = nextId++;
|
|
4106
|
-
return new Promise((
|
|
3757
|
+
return new Promise((resolve6, reject) => {
|
|
4107
3758
|
if (!parentPort) {
|
|
4108
3759
|
reject(new Error("parentPort \u4E0D\u53EF\u7528"));
|
|
4109
3760
|
return;
|
|
4110
3761
|
}
|
|
4111
|
-
pending.set(id, { resolve:
|
|
3762
|
+
pending.set(id, { resolve: resolve6, reject });
|
|
4112
3763
|
parentPort.postMessage({
|
|
4113
3764
|
type: "terminal-rpc",
|
|
4114
3765
|
id,
|