ai-project-manage-cli 7.1.39 → 8.0.2
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 +3454 -7707
- package/dist/webide-message-worker.js +320 -796
- 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,16 @@ 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
|
-
matchRepository: defineEndpoint({
|
|
146
|
-
method: "GET",
|
|
147
|
-
path: "/cli/repositories/match"
|
|
148
|
-
}),
|
|
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
87
|
createWebIdeDraftPullRequest: defineEndpoint({
|
|
162
88
|
method: "POST",
|
|
163
89
|
path: "/cli/webide/draft-pull-requests"
|
|
@@ -182,22 +108,6 @@ var requestConfig = {
|
|
|
182
108
|
method: "DELETE",
|
|
183
109
|
path: "/cli/project-documents"
|
|
184
110
|
}),
|
|
185
|
-
createTaskDeployment: defineEndpoint({
|
|
186
|
-
method: "POST",
|
|
187
|
-
path: "/cli/task-deployments"
|
|
188
|
-
}),
|
|
189
|
-
updateTaskDeploymentStatus: defineEndpoint({
|
|
190
|
-
method: "PUT",
|
|
191
|
-
path: "/cli/task-deployments/status"
|
|
192
|
-
}),
|
|
193
|
-
syncTaskDeploymentLog: defineEndpoint({
|
|
194
|
-
method: "PUT",
|
|
195
|
-
path: "/cli/task-deployments/log"
|
|
196
|
-
}),
|
|
197
|
-
completeTaskDeployment: defineEndpoint({
|
|
198
|
-
method: "PUT",
|
|
199
|
-
path: "/cli/task-deployments/complete"
|
|
200
|
-
}),
|
|
201
111
|
getDeployArtifactStorage: defineEndpoint(
|
|
202
112
|
{
|
|
203
113
|
method: "GET",
|
|
@@ -207,10 +117,6 @@ var requestConfig = {
|
|
|
207
117
|
getApmLogStorage: defineEndpoint({
|
|
208
118
|
method: "GET",
|
|
209
119
|
path: "/cli/apm-log-storage"
|
|
210
|
-
}),
|
|
211
|
-
attachTaskDeploymentArtifact: defineEndpoint({
|
|
212
|
-
method: "PUT",
|
|
213
|
-
path: "/cli/task-deployments/artifact"
|
|
214
120
|
})
|
|
215
121
|
}
|
|
216
122
|
};
|
|
@@ -338,6 +244,147 @@ function requireRemoteWorkdir(workdir) {
|
|
|
338
244
|
return resolveWorkdirPath(trimmed);
|
|
339
245
|
}
|
|
340
246
|
|
|
247
|
+
// src/command-utils.ts
|
|
248
|
+
import { copyFileSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
|
|
249
|
+
import { dirname, join as join2, resolve as resolve2 } from "path";
|
|
250
|
+
import { fileURLToPath } from "url";
|
|
251
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
252
|
+
var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
|
|
253
|
+
function workspaceApmDir(cwd = resolveWorkdirPath()) {
|
|
254
|
+
return resolve2(resolve2(cwd), ".apm");
|
|
255
|
+
}
|
|
256
|
+
function isWorkspaceApmInitialized(workdir) {
|
|
257
|
+
const apmDir = workspaceApmDir(workdir);
|
|
258
|
+
const fsApmDir = toFsPath(apmDir);
|
|
259
|
+
if (!existsSync(fsApmDir)) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
const st = statSync(fsApmDir);
|
|
263
|
+
if (!st.isDirectory()) {
|
|
264
|
+
throw new Error(
|
|
265
|
+
`\u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u4E0B\u7684 .apm \u4E0D\u662F\u76EE\u5F55\uFF0C\u8BF7\u68C0\u67E5\u672C\u5730\u63A5\u5165\u72B6\u6001\u3002`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
return readdirSync(fsApmDir).length > 0;
|
|
269
|
+
}
|
|
270
|
+
var WEBIDE_SUBDIR = "webide";
|
|
271
|
+
var WEBIDE_ATTACHMENTS_SUBDIR = "attachments";
|
|
272
|
+
function webideTaskDir(taskId, workdir) {
|
|
273
|
+
return join2(workdir, ".apm", WEBIDE_SUBDIR, taskId);
|
|
274
|
+
}
|
|
275
|
+
function webideAttachmentsDir(taskId, workdir) {
|
|
276
|
+
return join2(webideTaskDir(taskId, workdir), WEBIDE_ATTACHMENTS_SUBDIR);
|
|
277
|
+
}
|
|
278
|
+
async function ensureLoggedConfig() {
|
|
279
|
+
const cfg = await ensureApmConfig();
|
|
280
|
+
if (!resolveApiKey(cfg)) {
|
|
281
|
+
console.error(
|
|
282
|
+
"[apm] \u672A\u68C0\u6D4B\u5230 API Key\uFF0C\u8BF7\u5148\u6267\u884C: apm login --api-key cm_xxx"
|
|
283
|
+
);
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
return cfg;
|
|
287
|
+
}
|
|
288
|
+
async function ensureDirExists(dir) {
|
|
289
|
+
mkdirSync2(dir, { recursive: true });
|
|
290
|
+
}
|
|
291
|
+
async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
|
|
292
|
+
const dir = workspaceApmDir(cwd);
|
|
293
|
+
const fsDir = toFsPath(dir);
|
|
294
|
+
if (existsSync(fsDir) && !statSync(fsDir).isDirectory()) {
|
|
295
|
+
throw new Error(`[apm] \u8DEF\u5F84\u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u76EE\u5F55: ${dir}`);
|
|
296
|
+
}
|
|
297
|
+
mkdirSync2(fsDir, { recursive: true });
|
|
298
|
+
}
|
|
299
|
+
var WEBIDE_AGENTS_TEMPLATE_NAME = "AGENTS.webide.md";
|
|
300
|
+
function shouldSkipTemplateEntry(name) {
|
|
301
|
+
return name === ".DS_Store" || name === "Thumbs.db";
|
|
302
|
+
}
|
|
303
|
+
function isWebIdeRuleFileName(name) {
|
|
304
|
+
return name.startsWith("webide");
|
|
305
|
+
}
|
|
306
|
+
function copyTemplateEntry(src, dest) {
|
|
307
|
+
const fsSrc = toFsPath(src);
|
|
308
|
+
const fsDest = toFsPath(dest);
|
|
309
|
+
const st = statSync(fsSrc);
|
|
310
|
+
if (st.isDirectory()) {
|
|
311
|
+
mkdirSync2(fsDest, { recursive: true });
|
|
312
|
+
for (const name of readdirSync(fsSrc)) {
|
|
313
|
+
if (shouldSkipTemplateEntry(name)) continue;
|
|
314
|
+
copyTemplateEntry(join2(src, name), join2(dest, name));
|
|
315
|
+
}
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (!st.isFile()) return;
|
|
319
|
+
mkdirSync2(toFsPath(dirname(dest)), { recursive: true });
|
|
320
|
+
copyFileSync(fsSrc, fsDest);
|
|
321
|
+
}
|
|
322
|
+
function listWebIdeRuleFileNames(rulesDir) {
|
|
323
|
+
const fsRulesDir = toFsPath(rulesDir);
|
|
324
|
+
if (!existsSync(fsRulesDir) || !statSync(fsRulesDir).isDirectory()) {
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
327
|
+
return readdirSync(fsRulesDir).filter((name) => {
|
|
328
|
+
if (shouldSkipTemplateEntry(name) || !isWebIdeRuleFileName(name)) {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
return statSync(toFsPath(join2(rulesDir, name))).isFile();
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
|
|
335
|
+
const required = ["AGENTS.md", "rules"];
|
|
336
|
+
for (const item of required) {
|
|
337
|
+
const path = join2(apmDir, item);
|
|
338
|
+
if (!existsSync(toFsPath(path))) {
|
|
339
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const rulesDir = join2(apmDir, "rules");
|
|
343
|
+
const ruleNames = listWebIdeRuleFileNames(rulesDir);
|
|
344
|
+
if (ruleNames.length === 0) {
|
|
345
|
+
throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 webide \u89C4\u5219: ${rulesDir}`);
|
|
346
|
+
}
|
|
347
|
+
const leakedRules = join2(workdir, "rules");
|
|
348
|
+
const apmRules = join2(apmDir, "rules");
|
|
349
|
+
if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "webide_reply.md")))) {
|
|
350
|
+
throw new Error(
|
|
351
|
+
`[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
356
|
+
const resolvedTarget = resolve2(targetDir);
|
|
357
|
+
const templateDir = resolve2(CLI_TEMPLATE_DIR);
|
|
358
|
+
const fsTemplateDir = toFsPath(templateDir);
|
|
359
|
+
if (!existsSync(fsTemplateDir) || !statSync(fsTemplateDir).isDirectory()) {
|
|
360
|
+
throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
|
|
361
|
+
}
|
|
362
|
+
const agentsSrc = join2(templateDir, WEBIDE_AGENTS_TEMPLATE_NAME);
|
|
363
|
+
if (!existsSync(toFsPath(agentsSrc))) {
|
|
364
|
+
throw new Error(`[apm] \u672A\u627E\u5230 WebIDE \u6307\u5357: ${agentsSrc}`);
|
|
365
|
+
}
|
|
366
|
+
const rulesSrc = join2(templateDir, "rules");
|
|
367
|
+
const ruleNames = listWebIdeRuleFileNames(rulesSrc);
|
|
368
|
+
if (ruleNames.length === 0) {
|
|
369
|
+
throw new Error(`[apm] CLI \u6A21\u677F\u4E2D\u6CA1\u6709 webide \u89C4\u5219: ${rulesSrc}`);
|
|
370
|
+
}
|
|
371
|
+
mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
|
|
372
|
+
copyFileSync(
|
|
373
|
+
toFsPath(agentsSrc),
|
|
374
|
+
toFsPath(join2(resolvedTarget, "AGENTS.md"))
|
|
375
|
+
);
|
|
376
|
+
const rulesDest = join2(resolvedTarget, "rules");
|
|
377
|
+
mkdirSync2(toFsPath(rulesDest), { recursive: true });
|
|
378
|
+
for (const name of ruleNames) {
|
|
379
|
+
copyTemplateEntry(join2(rulesSrc, name), join2(rulesDest, name));
|
|
380
|
+
}
|
|
381
|
+
assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/git-utils.ts
|
|
385
|
+
import { execFile as execFile2 } from "child_process";
|
|
386
|
+
import { promisify as promisify2 } from "util";
|
|
387
|
+
|
|
341
388
|
// src/git-remote.ts
|
|
342
389
|
import { execFile } from "child_process";
|
|
343
390
|
import { promisify } from "util";
|
|
@@ -392,8 +439,6 @@ async function tryReadHttpsGitOriginUrl(cwd) {
|
|
|
392
439
|
}
|
|
393
440
|
|
|
394
441
|
// src/git-utils.ts
|
|
395
|
-
import { execFile as execFile2 } from "child_process";
|
|
396
|
-
import { promisify as promisify2 } from "util";
|
|
397
442
|
var execFileAsync2 = promisify2(execFile2);
|
|
398
443
|
function gitExecEnv() {
|
|
399
444
|
const existing = process.env.GIT_SSH_COMMAND?.trim();
|
|
@@ -474,323 +519,50 @@ async function branchHasChangesAgainstBase(cwd, baseBranch, headBranch) {
|
|
|
474
519
|
let headRef = head;
|
|
475
520
|
try {
|
|
476
521
|
await execGit(cwd, ["fetch", "origin", head], true);
|
|
477
|
-
await execGit(cwd, ["rev-parse", "--verify", `origin/${head}`], true);
|
|
478
|
-
headRef = `origin/${head}`;
|
|
479
|
-
} catch {
|
|
480
|
-
await execGit(cwd, ["rev-parse", "--verify", head], true);
|
|
481
|
-
}
|
|
482
|
-
const baseRef = `origin/${base}`;
|
|
483
|
-
const ahead = (await execGit(cwd, ["rev-list", "--count", `${baseRef}..${headRef}`], true)).trim();
|
|
484
|
-
if ((Number.parseInt(ahead, 10) || 0) <= 0) {
|
|
485
|
-
return false;
|
|
486
|
-
}
|
|
487
|
-
try {
|
|
488
|
-
await execGit(cwd, ["diff", "--quiet", `${baseRef}...${headRef}`], true);
|
|
489
|
-
return false;
|
|
490
|
-
} catch {
|
|
491
|
-
return true;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
var FEATURE_BRANCH_RE = /^feat\/(task|session)-.+/;
|
|
495
|
-
function isFeatureBranchName(branch) {
|
|
496
|
-
return FEATURE_BRANCH_RE.test(branch.trim().replace(/^origin\//, ""));
|
|
497
|
-
}
|
|
498
|
-
async function resolveFeatureBranchBaseFromGit(cwd, headBranch) {
|
|
499
|
-
const head = headBranch.trim().replace(/^origin\//, "");
|
|
500
|
-
if (!head) {
|
|
501
|
-
throw new Error("[apm] head \u5206\u652F\u540D\u4E3A\u7A7A\uFF0C\u65E0\u6CD5\u63A8\u65AD\u57FA\u7EBF");
|
|
502
|
-
}
|
|
503
|
-
try {
|
|
504
|
-
const reflog = await execGit(
|
|
505
|
-
cwd,
|
|
506
|
-
["reflog", "show", "--date=iso", head],
|
|
507
|
-
true
|
|
508
|
-
);
|
|
509
|
-
for (const line of reflog.split("\n")) {
|
|
510
|
-
const created = line.match(
|
|
511
|
-
/Created from (?:refs\/remotes\/origin\/|origin\/)?(\S+)/i
|
|
512
|
-
);
|
|
513
|
-
if (created?.[1]) {
|
|
514
|
-
const name = created[1].replace(/^origin\//, "");
|
|
515
|
-
if (name && name !== head && !isFeatureBranchName(name)) {
|
|
516
|
-
return name;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
const moving = line.match(
|
|
520
|
-
/checkout: moving from (\S+) to (?:origin\/)?\S+/i
|
|
521
|
-
);
|
|
522
|
-
if (moving?.[1]) {
|
|
523
|
-
const from = moving[1].replace(/^origin\//, "");
|
|
524
|
-
if (from && from !== head && !isFeatureBranchName(from)) {
|
|
525
|
-
return from;
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
} catch {
|
|
530
|
-
}
|
|
531
|
-
await execGit(cwd, ["fetch", "origin", "--prune"], true);
|
|
532
|
-
let headRef = head;
|
|
533
|
-
try {
|
|
534
|
-
await execGit(cwd, ["rev-parse", "--verify", `origin/${head}`], true);
|
|
535
|
-
headRef = `origin/${head}`;
|
|
536
|
-
} catch {
|
|
537
|
-
await execGit(cwd, ["rev-parse", "--verify", head], true);
|
|
538
|
-
}
|
|
539
|
-
const refsOut = await execGit(
|
|
540
|
-
cwd,
|
|
541
|
-
["for-each-ref", "--format=%(refname:short)", "refs/remotes/origin/"],
|
|
542
|
-
true
|
|
543
|
-
);
|
|
544
|
-
let best = null;
|
|
545
|
-
for (const ref of refsOut.split("\n").map((s) => s.trim()).filter(Boolean)) {
|
|
546
|
-
const name = ref.replace(/^origin\//, "");
|
|
547
|
-
if (!name || name === "HEAD" || name === head || isFeatureBranchName(name)) {
|
|
548
|
-
continue;
|
|
549
|
-
}
|
|
550
|
-
try {
|
|
551
|
-
await execGit(
|
|
552
|
-
cwd,
|
|
553
|
-
["merge-base", "--is-ancestor", `origin/${name}`, headRef],
|
|
554
|
-
true
|
|
555
|
-
);
|
|
556
|
-
const ahead = Number.parseInt(
|
|
557
|
-
(await execGit(
|
|
558
|
-
cwd,
|
|
559
|
-
["rev-list", "--count", `origin/${name}..${headRef}`],
|
|
560
|
-
true
|
|
561
|
-
)).trim(),
|
|
562
|
-
10
|
|
563
|
-
);
|
|
564
|
-
if (!Number.isFinite(ahead) || ahead < 0) continue;
|
|
565
|
-
if (!best || ahead < best.ahead) {
|
|
566
|
-
best = { name, ahead };
|
|
567
|
-
}
|
|
568
|
-
} catch {
|
|
569
|
-
continue;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
if (best) {
|
|
573
|
-
return best.name;
|
|
574
|
-
}
|
|
575
|
-
throw new Error(
|
|
576
|
-
`[apm] \u65E0\u6CD5\u63A8\u65AD ${head} \u57FA\u4E8E\u54EA\u6761\u5206\u652F\u521B\u5EFA\uFF0C\u8BF7\u786E\u8BA4\u672C\u5730 reflog \u6216 origin \u8FDC\u7A0B\u5206\u652F`
|
|
577
|
-
);
|
|
578
|
-
}
|
|
579
|
-
async function hasUpstream(cwd) {
|
|
580
|
-
try {
|
|
581
|
-
await execGit(cwd, ["rev-parse", "--abbrev-ref", "@{upstream}"], true);
|
|
582
|
-
return true;
|
|
583
|
-
} catch {
|
|
584
|
-
return false;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
async function pushCurrentBranch(cwd) {
|
|
588
|
-
if (!await isGitRepo(cwd)) {
|
|
589
|
-
return false;
|
|
590
|
-
}
|
|
591
|
-
const originUrl = await tryReadGitOriginUrl(cwd);
|
|
592
|
-
if (!originUrl) {
|
|
593
|
-
console.log("[apm] \u672A\u914D\u7F6E remote.origin\uFF0C\u8DF3\u8FC7 push");
|
|
594
|
-
return false;
|
|
595
|
-
}
|
|
596
|
-
if (await hasUpstream(cwd)) {
|
|
597
|
-
await execGit(cwd, ["push"]);
|
|
598
|
-
} else {
|
|
599
|
-
await execGit(cwd, ["push", "-u", "origin", "HEAD"]);
|
|
600
|
-
}
|
|
601
|
-
return true;
|
|
602
|
-
}
|
|
603
|
-
|
|
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}`);
|
|
522
|
+
await execGit(cwd, ["rev-parse", "--verify", `origin/${head}`], true);
|
|
523
|
+
headRef = `origin/${head}`;
|
|
524
|
+
} catch {
|
|
525
|
+
await execGit(cwd, ["rev-parse", "--verify", head], true);
|
|
723
526
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
527
|
+
const baseRef = `origin/${base}`;
|
|
528
|
+
const ahead = (await execGit(cwd, ["rev-list", "--count", `${baseRef}..${headRef}`], true)).trim();
|
|
529
|
+
if ((Number.parseInt(ahead, 10) || 0) <= 0) {
|
|
530
|
+
return false;
|
|
727
531
|
}
|
|
728
|
-
|
|
729
|
-
|
|
532
|
+
try {
|
|
533
|
+
await execGit(cwd, ["diff", "--quiet", `${baseRef}...${headRef}`], true);
|
|
534
|
+
return false;
|
|
535
|
+
} catch {
|
|
536
|
+
return true;
|
|
730
537
|
}
|
|
731
|
-
assertTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
|
|
732
538
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
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
|
-
});
|
|
539
|
+
var FEATURE_BRANCH_RE = /^feat\/task-.+/;
|
|
540
|
+
function isFeatureBranchName(branch) {
|
|
541
|
+
return FEATURE_BRANCH_RE.test(branch.trim().replace(/^origin\//, ""));
|
|
744
542
|
}
|
|
745
|
-
function
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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
|
-
);
|
|
543
|
+
async function hasUpstream(cwd) {
|
|
544
|
+
try {
|
|
545
|
+
await execGit(cwd, ["rev-parse", "--abbrev-ref", "@{upstream}"], true);
|
|
546
|
+
return true;
|
|
547
|
+
} catch {
|
|
548
|
+
return false;
|
|
764
549
|
}
|
|
765
550
|
}
|
|
766
|
-
async function
|
|
767
|
-
|
|
768
|
-
|
|
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}`);
|
|
551
|
+
async function pushCurrentBranch(cwd) {
|
|
552
|
+
if (!await isGitRepo(cwd)) {
|
|
553
|
+
return false;
|
|
776
554
|
}
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
555
|
+
const originUrl = await tryReadGitOriginUrl(cwd);
|
|
556
|
+
if (!originUrl) {
|
|
557
|
+
console.log("[apm] \u672A\u914D\u7F6E remote.origin\uFF0C\u8DF3\u8FC7 push");
|
|
558
|
+
return false;
|
|
781
559
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
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));
|
|
560
|
+
if (await hasUpstream(cwd)) {
|
|
561
|
+
await execGit(cwd, ["push"]);
|
|
562
|
+
} else {
|
|
563
|
+
await execGit(cwd, ["push", "-u", "origin", "HEAD"]);
|
|
792
564
|
}
|
|
793
|
-
|
|
565
|
+
return true;
|
|
794
566
|
}
|
|
795
567
|
|
|
796
568
|
// src/workspace-repos.ts
|
|
@@ -802,7 +574,7 @@ import {
|
|
|
802
574
|
statSync as statSync2,
|
|
803
575
|
writeFileSync as writeFileSync2
|
|
804
576
|
} from "fs";
|
|
805
|
-
import { basename
|
|
577
|
+
import { basename, dirname as dirname2, join as join3, relative, resolve as resolve3 } from "path";
|
|
806
578
|
var WORKSPACE_REPOS_MANIFEST = "workspace-repos.json";
|
|
807
579
|
var WORKSPACE_REPOS_VERSION = 1;
|
|
808
580
|
var SKIP_DIR_NAMES = /* @__PURE__ */ new Set([".apm", "node_modules"]);
|
|
@@ -1026,7 +798,7 @@ function resolveWorkspaceRepoAbsolutePaths(manifest) {
|
|
|
1026
798
|
}
|
|
1027
799
|
function formatRepoLabel(workdir, repoAbs) {
|
|
1028
800
|
const rel = toRelativeRepoPath(resolveWorkdirPath(workdir), repoAbs);
|
|
1029
|
-
return rel === "." ?
|
|
801
|
+
return rel === "." ? basename(repoAbs) || repoAbs : rel;
|
|
1030
802
|
}
|
|
1031
803
|
|
|
1032
804
|
// src/commands/branch.ts
|
|
@@ -1099,57 +871,47 @@ function branchNameForTask(taskId) {
|
|
|
1099
871
|
async function ensureFeatureBranch(branch, baselineBranch, options) {
|
|
1100
872
|
const cwd = options.cwd ?? process.cwd();
|
|
1101
873
|
const gitRoot = await resolveGitRepoRoot(cwd);
|
|
1102
|
-
const commitMessage = options.message?.trim() || `chore(apm): \u540C\u6B65\u5DE5\u4F5C\u533A (${branch})`;
|
|
1103
874
|
await ensureGitRepo(gitRoot);
|
|
1104
|
-
await ensureRemoteBaselineBranch(gitRoot, baselineBranch);
|
|
1105
875
|
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
|
-
}
|
|
876
|
+
if (current === branch) {
|
|
877
|
+
console.log(`[apm] \u5DF2\u5728\u5206\u652F ${branch}\uFF0C\u8DF3\u8FC7`);
|
|
878
|
+
return branch;
|
|
1119
879
|
}
|
|
1120
|
-
|
|
1121
|
-
if (
|
|
1122
|
-
await execGit(gitRoot, [
|
|
1123
|
-
|
|
880
|
+
await ensureRemoteBaselineBranch(gitRoot, baselineBranch);
|
|
881
|
+
if (await isWorkingTreeDirty(gitRoot)) {
|
|
882
|
+
await execGit(gitRoot, [
|
|
883
|
+
"stash",
|
|
884
|
+
"push",
|
|
885
|
+
"-u",
|
|
886
|
+
"-m",
|
|
887
|
+
`apm: switch to ${branch}`
|
|
888
|
+
]);
|
|
889
|
+
}
|
|
890
|
+
const remoteExists = await remoteBranchExists(gitRoot, branch);
|
|
891
|
+
if (remoteExists) {
|
|
892
|
+
await execGit(gitRoot, ["fetch", "origin", branch]);
|
|
893
|
+
await execGit(gitRoot, ["checkout", "-B", branch, `origin/${branch}`]);
|
|
894
|
+
} else if (await localBranchExists(gitRoot, branch)) {
|
|
895
|
+
await execGit(gitRoot, ["checkout", branch]);
|
|
896
|
+
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
1124
897
|
} 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;
|
|
898
|
+
await execGit(gitRoot, ["fetch", "origin", baselineBranch]);
|
|
899
|
+
try {
|
|
900
|
+
await execGit(gitRoot, [
|
|
901
|
+
"checkout",
|
|
902
|
+
"-b",
|
|
903
|
+
branch,
|
|
904
|
+
`origin/${baselineBranch}`
|
|
905
|
+
]);
|
|
906
|
+
await execGit(gitRoot, ["push", "-u", "origin", branch]);
|
|
907
|
+
} catch (err) {
|
|
908
|
+
if (await localBranchExists(gitRoot, branch)) {
|
|
909
|
+
if (await getCurrentBranch(gitRoot) !== branch) {
|
|
910
|
+
await execGit(gitRoot, ["checkout", branch]);
|
|
1152
911
|
}
|
|
912
|
+
console.log(`[apm] \u5206\u652F ${branch} \u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
|
|
913
|
+
} else {
|
|
914
|
+
throw err;
|
|
1153
915
|
}
|
|
1154
916
|
}
|
|
1155
917
|
}
|
|
@@ -1168,9 +930,7 @@ async function runTaskBranch(taskId, options = {}) {
|
|
|
1168
930
|
});
|
|
1169
931
|
const baselineBranch = projectBaseline.baseBranch?.trim() ?? "";
|
|
1170
932
|
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
|
-
);
|
|
933
|
+
throw new Error("[apm] \u9879\u76EE\u672A\u914D\u7F6E\u57FA\u7840\u5206\u652F\uFF0C\u65E0\u6CD5\u521B\u5EFA WebIDE \u7279\u6027\u5206\u652F");
|
|
1174
934
|
}
|
|
1175
935
|
const cwd = options.cwd ?? process.cwd();
|
|
1176
936
|
const workdirPath = resolveWorkdirPath(cwd);
|
|
@@ -1500,132 +1260,6 @@ ${JSON.stringify(event, null, 2)}
|
|
|
1500
1260
|
\`\`\``;
|
|
1501
1261
|
}
|
|
1502
1262
|
|
|
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
1263
|
// src/commands/connect/abort-signal-debug.ts
|
|
1630
1264
|
import {
|
|
1631
1265
|
getEventListeners,
|
|
@@ -1689,25 +1323,11 @@ ${stack}`
|
|
|
1689
1323
|
);
|
|
1690
1324
|
}
|
|
1691
1325
|
|
|
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
1326
|
// src/commands/connect/append-message-tool.ts
|
|
1706
|
-
function createAppendMessageCustomTools(
|
|
1707
|
-
const doAppend = appendContent2 ?? ((content) => appendMessageContent(cfg, messageId, content));
|
|
1327
|
+
function createAppendMessageCustomTools(messageId, appendContent2) {
|
|
1708
1328
|
return {
|
|
1709
1329
|
AppendMessage: {
|
|
1710
|
-
description: "\u5411\u5F53\u524D
|
|
1330
|
+
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
1331
|
inputSchema: {
|
|
1712
1332
|
type: "object",
|
|
1713
1333
|
properties: {
|
|
@@ -1727,7 +1347,7 @@ function createAppendMessageCustomTools(cfg, messageId, appendContent2) {
|
|
|
1727
1347
|
};
|
|
1728
1348
|
}
|
|
1729
1349
|
try {
|
|
1730
|
-
await
|
|
1350
|
+
await appendContent2(content);
|
|
1731
1351
|
console.log(`[apm] AppendMessage \u5DF2\u8FFD\u52A0: messageId=${messageId}`);
|
|
1732
1352
|
return "\u5DF2\u8FFD\u52A0\u6D88\u606F\u5185\u5BB9";
|
|
1733
1353
|
} catch (err) {
|
|
@@ -2147,11 +1767,7 @@ var WORKSPACE_BOUNDARY_HINT = `[\u5DE5\u4F5C\u533A\u8FB9\u754C]
|
|
|
2147
1767
|
\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
1768
|
function createCursorCustomTools(cfg, messageId, options) {
|
|
2149
1769
|
const tools = {
|
|
2150
|
-
...createAppendMessageCustomTools(
|
|
2151
|
-
cfg,
|
|
2152
|
-
messageId,
|
|
2153
|
-
options?.appendMessageContent
|
|
2154
|
-
),
|
|
1770
|
+
...createAppendMessageCustomTools(messageId, options.appendMessageContent),
|
|
2155
1771
|
AskQuestion: createAskQuestionTool({
|
|
2156
1772
|
onInvoke: options?.onAskQuestion,
|
|
2157
1773
|
execute: options?.askQuestionExecute
|
|
@@ -2211,11 +1827,6 @@ var noopRemoteLogSync = {
|
|
|
2211
1827
|
async flush(_session) {
|
|
2212
1828
|
}
|
|
2213
1829
|
};
|
|
2214
|
-
var logCtx = (ctx, agentId) => ({
|
|
2215
|
-
sessionId: ctx.sessionId,
|
|
2216
|
-
messageId: ctx.messageId,
|
|
2217
|
-
agentId
|
|
2218
|
-
});
|
|
2219
1830
|
function formatCursorRunFailure(runId, options) {
|
|
2220
1831
|
const details = [
|
|
2221
1832
|
options?.statusError?.trim(),
|
|
@@ -2229,19 +1840,6 @@ function formatCursorRunFailure(runId, options) {
|
|
|
2229
1840
|
}
|
|
2230
1841
|
return `Cursor run \u5931\u8D25: ${runId} \u2014 ${details.join("\uFF1B")}`;
|
|
2231
1842
|
}
|
|
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
1843
|
async function obtainAgent(ctx) {
|
|
2246
1844
|
const agentOptions = {
|
|
2247
1845
|
apiKey: ctx.apiKey,
|
|
@@ -2258,29 +1856,22 @@ async function obtainAgent(ctx) {
|
|
|
2258
1856
|
...ctx.mode ? { mode: ctx.mode } : {},
|
|
2259
1857
|
...ctx.mcpServers ? { mcpServers: ctx.mcpServers } : {}
|
|
2260
1858
|
};
|
|
2261
|
-
const
|
|
2262
|
-
const savedAgentId = explicitAgentId || (!ctx.skipSessionAgentRegistry && ctx.user ? loadSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user) : void 0);
|
|
1859
|
+
const savedAgentId = ctx.resumeAgentId?.trim();
|
|
2263
1860
|
if (savedAgentId) {
|
|
2264
1861
|
try {
|
|
2265
1862
|
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);
|
|
1863
|
+
console.log(`[apm] \u590D\u7528 Agent user=${ctx.user} agentId=${savedAgentId}`);
|
|
2270
1864
|
return { agent, resumed: true };
|
|
2271
1865
|
} catch (err) {
|
|
2272
1866
|
console.warn(
|
|
2273
1867
|
`[apm] \u590D\u7528 Agent \u5931\u8D25\uFF08agentId=${savedAgentId}\uFF09\uFF0C\u56DE\u9000\u4E3A\u65B0\u5EFA:`,
|
|
2274
1868
|
err instanceof Error ? err.message : err
|
|
2275
1869
|
);
|
|
2276
|
-
|
|
2277
|
-
invalidatePersistedAgentId(ctx);
|
|
2278
|
-
}
|
|
1870
|
+
ctx.onInvalidatePersistedAgentId?.();
|
|
2279
1871
|
}
|
|
2280
1872
|
}
|
|
2281
1873
|
try {
|
|
2282
1874
|
const agent = await Agent.create(agentOptions);
|
|
2283
|
-
persistSessionAgentId(ctx, agent.agentId);
|
|
2284
1875
|
return { agent, resumed: false };
|
|
2285
1876
|
} catch (err) {
|
|
2286
1877
|
if (ctx.enableSandbox && err instanceof Error && /sandbox/i.test(err.message)) {
|
|
@@ -2291,7 +1882,7 @@ async function obtainAgent(ctx) {
|
|
|
2291
1882
|
}
|
|
2292
1883
|
}
|
|
2293
1884
|
async function runCursorAgent(cfg, ctx, options) {
|
|
2294
|
-
const signal = options
|
|
1885
|
+
const signal = options.signal;
|
|
2295
1886
|
logAbortSignalStats(signal, "runCursorAgent:start");
|
|
2296
1887
|
if (signal?.aborted) {
|
|
2297
1888
|
throw new Error("\u8FDE\u63A5\u5DF2\u5173\u95ED\uFF0C\u4EFB\u52A1\u4E2D\u65AD");
|
|
@@ -2302,54 +1893,36 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2302
1893
|
}
|
|
2303
1894
|
const workdir = resolveWorkdirPath(ctx.workdir);
|
|
2304
1895
|
const customTools = createCursorCustomTools(cfg, ctx.messageId, {
|
|
2305
|
-
onAskQuestion: options
|
|
2306
|
-
appendMessageContent: options
|
|
2307
|
-
askQuestionExecute: options
|
|
2308
|
-
enableWebIdePlanTools: options
|
|
2309
|
-
taskId: options
|
|
1896
|
+
onAskQuestion: options.onAskQuestion,
|
|
1897
|
+
appendMessageContent: options.appendMessageContent,
|
|
1898
|
+
askQuestionExecute: options.askQuestionExecute,
|
|
1899
|
+
enableWebIdePlanTools: options.enableWebIdePlanTools,
|
|
1900
|
+
taskId: options.taskId,
|
|
2310
1901
|
workdir,
|
|
2311
|
-
terminalRpc: options
|
|
1902
|
+
terminalRpc: options.terminalRpc
|
|
2312
1903
|
});
|
|
2313
|
-
const enableSandbox = Boolean(options
|
|
1904
|
+
const enableSandbox = Boolean(options.enableSandbox);
|
|
2314
1905
|
let prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
|
|
2315
1906
|
prompt = withWorkspaceBoundaryHint(prompt);
|
|
2316
1907
|
console.log(
|
|
2317
|
-
`[apm] Cursor Agent \u5F00\u59CB messageId=${ctx.messageId}
|
|
1908
|
+
`[apm] Cursor Agent \u5F00\u59CB messageId=${ctx.messageId} cwd=${workdir} sandbox=${enableSandbox}`
|
|
2318
1909
|
);
|
|
2319
1910
|
const { agent, resumed } = await obtainAgent({
|
|
2320
1911
|
apiKey,
|
|
2321
1912
|
model: ctx.model,
|
|
2322
1913
|
cwd: workdir,
|
|
2323
|
-
workdir,
|
|
2324
|
-
sessionId: ctx.sessionId,
|
|
2325
1914
|
user: ctx.user,
|
|
2326
1915
|
mode: ctx.mode,
|
|
2327
1916
|
resumeAgentId: ctx.resumeAgentId,
|
|
2328
1917
|
customTools,
|
|
2329
1918
|
enableSandbox,
|
|
2330
|
-
|
|
2331
|
-
onInvalidatePersistedAgentId: options?.onInvalidatePersistedAgentId
|
|
1919
|
+
onInvalidatePersistedAgentId: options.onInvalidatePersistedAgentId
|
|
2332
1920
|
});
|
|
2333
1921
|
const invalidateAgentMapping = () => {
|
|
2334
|
-
|
|
2335
|
-
workdir,
|
|
2336
|
-
sessionId: ctx.sessionId,
|
|
2337
|
-
user: ctx.user,
|
|
2338
|
-
skipSessionAgentRegistry: options?.skipSessionAgentRegistry,
|
|
2339
|
-
onInvalidatePersistedAgentId: options?.onInvalidatePersistedAgentId
|
|
2340
|
-
});
|
|
1922
|
+
options.onInvalidatePersistedAgentId?.();
|
|
2341
1923
|
};
|
|
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
|
-
);
|
|
1924
|
+
const eventSession = options.eventSession ?? new EventSession(prompt);
|
|
1925
|
+
const syncRemoteLog = options.createRemoteLogSync ? options.createRemoteLogSync(agent.agentId) : noopRemoteLogSync;
|
|
2353
1926
|
let activeRun;
|
|
2354
1927
|
const abortRun = () => {
|
|
2355
1928
|
if (!activeRun?.supports("cancel")) return;
|
|
@@ -2361,14 +1934,14 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2361
1934
|
const run = await agent.send(prompt, {
|
|
2362
1935
|
...ctx.mode ? { mode: ctx.mode } : {},
|
|
2363
1936
|
local: {
|
|
2364
|
-
...options
|
|
1937
|
+
...options.forceSend ? { force: true } : {},
|
|
2365
1938
|
customTools
|
|
2366
1939
|
}
|
|
2367
1940
|
});
|
|
2368
1941
|
activeRun = run;
|
|
2369
1942
|
logAbortSignalStats(signal, "runCursorAgent:after-send");
|
|
2370
1943
|
console.log(`[apm] Cursor run id=${run.id} agentId=${agent.agentId}`);
|
|
2371
|
-
await options
|
|
1944
|
+
await options.onRunStarted?.({ agentId: agent.agentId, runId: run.id });
|
|
2372
1945
|
let lastRunErrorStatus;
|
|
2373
1946
|
for await (const event of run.stream()) {
|
|
2374
1947
|
if (signal?.aborted) {
|
|
@@ -2384,7 +1957,7 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2384
1957
|
);
|
|
2385
1958
|
}
|
|
2386
1959
|
}
|
|
2387
|
-
options
|
|
1960
|
+
options.onStreamEvent?.(event);
|
|
2388
1961
|
eventSession.addEvent(event);
|
|
2389
1962
|
syncRemoteLog.schedule(eventSession);
|
|
2390
1963
|
}
|
|
@@ -2461,17 +2034,17 @@ async function runCursorAgent(cfg, ctx, options) {
|
|
|
2461
2034
|
}
|
|
2462
2035
|
|
|
2463
2036
|
// src/commands/connect/webide-agent-registry.ts
|
|
2464
|
-
import { existsSync as
|
|
2465
|
-
import { dirname as
|
|
2466
|
-
function
|
|
2467
|
-
return
|
|
2037
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2038
|
+
import { dirname as dirname3, resolve as resolve4 } from "node:path";
|
|
2039
|
+
function registryPath(workdir, taskId) {
|
|
2040
|
+
return resolve4(workdir, ".apm", "webide", taskId, "cursor-agent.json");
|
|
2468
2041
|
}
|
|
2469
|
-
function
|
|
2470
|
-
if (!
|
|
2042
|
+
function readRegistry(path) {
|
|
2043
|
+
if (!existsSync3(path)) {
|
|
2471
2044
|
return {};
|
|
2472
2045
|
}
|
|
2473
2046
|
try {
|
|
2474
|
-
const parsed = JSON.parse(
|
|
2047
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
2475
2048
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2476
2049
|
const raw = parsed;
|
|
2477
2050
|
const state = {};
|
|
@@ -2499,16 +2072,16 @@ function readRegistry2(path) {
|
|
|
2499
2072
|
}
|
|
2500
2073
|
return {};
|
|
2501
2074
|
}
|
|
2502
|
-
function
|
|
2503
|
-
|
|
2504
|
-
|
|
2075
|
+
function writeRegistry(path, registry) {
|
|
2076
|
+
mkdirSync4(dirname3(path), { recursive: true });
|
|
2077
|
+
writeFileSync3(path, `${JSON.stringify(registry, null, 2)}
|
|
2505
2078
|
`, "utf8");
|
|
2506
2079
|
}
|
|
2507
2080
|
function syncWebIdeTaskState(workdir, taskId, patch) {
|
|
2508
2081
|
const trimmedTaskId = taskId.trim();
|
|
2509
2082
|
if (!trimmedTaskId) return;
|
|
2510
|
-
const path =
|
|
2511
|
-
const current =
|
|
2083
|
+
const path = registryPath(workdir, trimmedTaskId);
|
|
2084
|
+
const current = readRegistry(path);
|
|
2512
2085
|
const next = {
|
|
2513
2086
|
...current,
|
|
2514
2087
|
taskId: trimmedTaskId,
|
|
@@ -2532,30 +2105,30 @@ function syncWebIdeTaskState(workdir, taskId, patch) {
|
|
|
2532
2105
|
if (patch.status !== void 0) {
|
|
2533
2106
|
next.status = patch.status;
|
|
2534
2107
|
}
|
|
2535
|
-
|
|
2108
|
+
writeRegistry(path, next);
|
|
2536
2109
|
}
|
|
2537
2110
|
function loadWebIdeAgentId(workdir, taskId) {
|
|
2538
|
-
return
|
|
2111
|
+
return readRegistry(registryPath(workdir, taskId)).agentId;
|
|
2539
2112
|
}
|
|
2540
2113
|
function saveWebIdeAgentId(workdir, taskId, agentId) {
|
|
2541
2114
|
syncWebIdeTaskState(workdir, taskId, { agentId });
|
|
2542
2115
|
}
|
|
2543
2116
|
function clearWebIdeAgentId(workdir, taskId) {
|
|
2544
|
-
const path =
|
|
2545
|
-
if (!
|
|
2117
|
+
const path = registryPath(workdir, taskId);
|
|
2118
|
+
if (!existsSync3(path)) return;
|
|
2546
2119
|
syncWebIdeTaskState(workdir, taskId, { agentId: "" });
|
|
2547
2120
|
}
|
|
2548
2121
|
|
|
2549
2122
|
// src/commands/clean-webide-cache.ts
|
|
2550
|
-
import { existsSync as
|
|
2551
|
-
import { resolve as
|
|
2123
|
+
import { existsSync as existsSync4, rmSync } from "node:fs";
|
|
2124
|
+
import { resolve as resolve5 } from "node:path";
|
|
2552
2125
|
import { getDefaultSdkStateRoot } from "@cursor/sdk";
|
|
2553
2126
|
async function purgeCursorAgentStoreForAgent(workdir, agentId) {
|
|
2554
2127
|
const trimmedAgentId = agentId.trim();
|
|
2555
2128
|
const trimmedWorkdir = workdir.trim();
|
|
2556
2129
|
if (!trimmedAgentId || !trimmedWorkdir) return false;
|
|
2557
2130
|
const stateRoot = getDefaultSdkStateRoot(trimmedWorkdir);
|
|
2558
|
-
if (!
|
|
2131
|
+
if (!existsSync4(stateRoot)) return false;
|
|
2559
2132
|
const { SqliteLocalAgentStore } = await import(
|
|
2560
2133
|
/* @vite-ignore */
|
|
2561
2134
|
"@cursor/sdk/sqlite"
|
|
@@ -2619,8 +2192,8 @@ async function cleanWebIdeWorkspaceCache(taskId, workdir) {
|
|
|
2619
2192
|
`[apm] \u65E0 WebIDE agentId\uFF0C\u8DF3\u8FC7 agent store \u6E05\u7406 taskId=${trimmedTaskId}`
|
|
2620
2193
|
);
|
|
2621
2194
|
}
|
|
2622
|
-
const dir =
|
|
2623
|
-
if (
|
|
2195
|
+
const dir = resolve5(trimmedWorkdir, ".apm", "webide", trimmedTaskId);
|
|
2196
|
+
if (existsSync4(dir)) {
|
|
2624
2197
|
rmSync(dir, { recursive: true, force: true });
|
|
2625
2198
|
console.log(`[apm] \u5DF2\u6E05\u7406 WebIDE \u7F13\u5B58 ${dir}`);
|
|
2626
2199
|
} else {
|
|
@@ -2742,14 +2315,14 @@ var MinioClient = class {
|
|
|
2742
2315
|
async deleteObjectsByPrefix(bucket, prefix) {
|
|
2743
2316
|
const objectsStream = this.inner.listObjectsV2(bucket, prefix, true);
|
|
2744
2317
|
const keys = [];
|
|
2745
|
-
await new Promise((
|
|
2318
|
+
await new Promise((resolve6, reject) => {
|
|
2746
2319
|
objectsStream.on("data", (obj) => {
|
|
2747
2320
|
if (obj.name) {
|
|
2748
2321
|
keys.push(obj.name);
|
|
2749
2322
|
}
|
|
2750
2323
|
});
|
|
2751
2324
|
objectsStream.on("error", reject);
|
|
2752
|
-
objectsStream.on("end",
|
|
2325
|
+
objectsStream.on("end", resolve6);
|
|
2753
2326
|
});
|
|
2754
2327
|
const chunkSize = 500;
|
|
2755
2328
|
for (let i = 0; i < keys.length; i += chunkSize) {
|
|
@@ -2938,56 +2511,33 @@ function resolveMessageReplyFallback(fallback) {
|
|
|
2938
2511
|
}
|
|
2939
2512
|
|
|
2940
2513
|
// 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) {
|
|
2514
|
+
async function initializeWorkspace(workdir) {
|
|
2958
2515
|
await ensureWorkspaceApmDirForInit(workdir);
|
|
2959
2516
|
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
|
-
);
|
|
2517
|
+
await copyWebIdeTemplateFiles(apmDir, workdir);
|
|
2518
|
+
console.log(`[apm] \u5DF2\u6309 WebIDE \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
|
|
2969
2519
|
return { didInit: true };
|
|
2970
2520
|
}
|
|
2971
|
-
async function ensureWorkspaceInitialized(workdir
|
|
2521
|
+
async function ensureWorkspaceInitialized(workdir) {
|
|
2972
2522
|
if (isWorkspaceApmInitialized(workdir)) {
|
|
2973
2523
|
return { didInit: false };
|
|
2974
2524
|
}
|
|
2975
2525
|
console.log(
|
|
2976
|
-
|
|
2526
|
+
`[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
2527
|
);
|
|
2978
|
-
return initializeWorkspace(workdir
|
|
2528
|
+
return initializeWorkspace(workdir);
|
|
2979
2529
|
}
|
|
2980
2530
|
|
|
2981
2531
|
// src/commands/connect/pre-step-cache.ts
|
|
2982
|
-
function
|
|
2983
|
-
return `${
|
|
2532
|
+
function taskWorkdirKey(taskId, workdir) {
|
|
2533
|
+
return `${taskId}\0${workdir}`;
|
|
2984
2534
|
}
|
|
2985
2535
|
var lastBranchKey = null;
|
|
2986
|
-
function shouldRunBranch(
|
|
2987
|
-
return lastBranchKey !==
|
|
2536
|
+
function shouldRunBranch(taskId, workdir) {
|
|
2537
|
+
return lastBranchKey !== taskWorkdirKey(taskId, workdir);
|
|
2988
2538
|
}
|
|
2989
|
-
function markBranchDone(
|
|
2990
|
-
lastBranchKey =
|
|
2539
|
+
function markBranchDone(taskId, workdir) {
|
|
2540
|
+
lastBranchKey = taskWorkdirKey(taskId, workdir);
|
|
2991
2541
|
}
|
|
2992
2542
|
|
|
2993
2543
|
// src/commands/connect/webide-pull-requests.ts
|
|
@@ -3085,7 +2635,7 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3085
2635
|
};
|
|
3086
2636
|
}
|
|
3087
2637
|
if (!projectBaseBranch) {
|
|
3088
|
-
const tip = "\u9879\u76EE\u672A\u914D\u7F6E\u57FA\u7840\u5206\u652F\uFF0C\u65E0\u6CD5\
|
|
2638
|
+
const tip = "\u9879\u76EE\u672A\u914D\u7F6E\u57FA\u7840\u5206\u652F\uFF0C\u65E0\u6CD5\u521B\u5EFA PR";
|
|
3089
2639
|
console.warn(`[apm] WebIDE PR\uFF1A${tip}`);
|
|
3090
2640
|
return {
|
|
3091
2641
|
...empty(),
|
|
@@ -3109,7 +2659,7 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3109
2659
|
try {
|
|
3110
2660
|
const current = await getCurrentBranch(gitRoot);
|
|
3111
2661
|
if (!isFeatureBranchName(current)) {
|
|
3112
|
-
const tip = `${label}\uFF1A\u5F53\u524D\u5206\u652F ${current} \u4E0D\u662F feat/task
|
|
2662
|
+
const tip = `${label}\uFF1A\u5F53\u524D\u5206\u652F ${current} \u4E0D\u662F feat/task-*\uFF0C\u4E0D\u7B26\u5408\u521B\u5EFA PR \u6761\u4EF6`;
|
|
3113
2663
|
console.warn(`[apm] WebIDE PR\uFF1A${tip}`);
|
|
3114
2664
|
tips.push(tip);
|
|
3115
2665
|
skipped += 1;
|
|
@@ -3135,7 +2685,7 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3135
2685
|
continue;
|
|
3136
2686
|
}
|
|
3137
2687
|
const headBranch = current;
|
|
3138
|
-
const originUrl = await tryReadGitOriginUrl(gitRoot);
|
|
2688
|
+
const originUrl = await tryReadHttpsGitOriginUrl(gitRoot) ?? await tryReadGitOriginUrl(gitRoot);
|
|
3139
2689
|
if (!originUrl) {
|
|
3140
2690
|
const tip = `${label}\uFF1A\u65E0 remote.origin.url`;
|
|
3141
2691
|
console.warn(`[apm] WebIDE PR\uFF1A\u8DF3\u8FC7 ${tip}`);
|
|
@@ -3149,29 +2699,7 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3149
2699
|
});
|
|
3150
2700
|
continue;
|
|
3151
2701
|
}
|
|
3152
|
-
const
|
|
3153
|
-
url: originUrl,
|
|
3154
|
-
baseBranch: projectBaseBranch
|
|
3155
|
-
});
|
|
3156
|
-
const repositoryId = matched.repositoryId?.trim();
|
|
3157
|
-
if (!repositoryId) {
|
|
3158
|
-
const tip = `${label}\uFF1A\u5E73\u53F0\u672A\u627E\u5230\u4ED3\u5E93\uFF08remote=${originUrl}\uFF0C\u57FA\u7EBF=${projectBaseBranch}\uFF09`;
|
|
3159
|
-
console.warn(`[apm] WebIDE PR\uFF1A\u8DF3\u8FC7 ${tip}`);
|
|
3160
|
-
tips.push(tip);
|
|
3161
|
-
skipped += 1;
|
|
3162
|
-
items.push({
|
|
3163
|
-
label,
|
|
3164
|
-
outcome: "skipped",
|
|
3165
|
-
headBranch,
|
|
3166
|
-
baseBranch: projectBaseBranch,
|
|
3167
|
-
detail: tip
|
|
3168
|
-
});
|
|
3169
|
-
continue;
|
|
3170
|
-
}
|
|
3171
|
-
const baseBranch = await resolveFeatureBranchBaseFromGit(
|
|
3172
|
-
gitRoot,
|
|
3173
|
-
headBranch
|
|
3174
|
-
);
|
|
2702
|
+
const baseBranch = projectBaseBranch;
|
|
3175
2703
|
const hasChanges = await branchHasChangesAgainstBase(
|
|
3176
2704
|
gitRoot,
|
|
3177
2705
|
baseBranch,
|
|
@@ -3193,7 +2721,7 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3193
2721
|
}
|
|
3194
2722
|
const pr = await api.cli.createWebIdeDraftPullRequest({
|
|
3195
2723
|
taskId,
|
|
3196
|
-
|
|
2724
|
+
originUrl,
|
|
3197
2725
|
headBranch,
|
|
3198
2726
|
baseBranch
|
|
3199
2727
|
});
|
|
@@ -3227,23 +2755,23 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3227
2755
|
}
|
|
3228
2756
|
|
|
3229
2757
|
// src/version.ts
|
|
3230
|
-
import { readFileSync as
|
|
3231
|
-
import { dirname as
|
|
2758
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
2759
|
+
import { dirname as dirname4, join as join4 } from "path";
|
|
3232
2760
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3233
2761
|
function readCliVersion() {
|
|
3234
2762
|
try {
|
|
3235
|
-
const dir =
|
|
3236
|
-
const pkgPath =
|
|
3237
|
-
const pkg = JSON.parse(
|
|
2763
|
+
const dir = dirname4(fileURLToPath2(import.meta.url));
|
|
2764
|
+
const pkgPath = join4(dir, "..", "package.json");
|
|
2765
|
+
const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
|
|
3238
2766
|
return pkg.version ?? "0.0.0";
|
|
3239
2767
|
} catch {
|
|
3240
2768
|
return "0.0.0";
|
|
3241
2769
|
}
|
|
3242
2770
|
}
|
|
3243
2771
|
|
|
3244
|
-
// src/commands/sync-
|
|
3245
|
-
import { existsSync as
|
|
3246
|
-
import { join as
|
|
2772
|
+
// src/commands/sync-webide-attachments.ts
|
|
2773
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
2774
|
+
import { join as join5 } from "path";
|
|
3247
2775
|
var MANIFEST_FILE = ".sync-manifest.json";
|
|
3248
2776
|
async function downloadAttachment(cfg, attachmentId) {
|
|
3249
2777
|
const base = cfg.baseUrl.trim().replace(/\/+$/, "");
|
|
@@ -3259,13 +2787,13 @@ async function downloadAttachment(cfg, attachmentId) {
|
|
|
3259
2787
|
return Buffer.from(await res.arrayBuffer());
|
|
3260
2788
|
}
|
|
3261
2789
|
function loadManifest(dir) {
|
|
3262
|
-
const path =
|
|
3263
|
-
if (!
|
|
2790
|
+
const path = join5(dir, MANIFEST_FILE);
|
|
2791
|
+
if (!existsSync5(path)) {
|
|
3264
2792
|
return { version: 1, attachments: {} };
|
|
3265
2793
|
}
|
|
3266
2794
|
try {
|
|
3267
2795
|
const parsed = JSON.parse(
|
|
3268
|
-
|
|
2796
|
+
readFileSync5(path, "utf8")
|
|
3269
2797
|
);
|
|
3270
2798
|
if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
|
|
3271
2799
|
return parsed;
|
|
@@ -3275,15 +2803,15 @@ function loadManifest(dir) {
|
|
|
3275
2803
|
return { version: 1, attachments: {} };
|
|
3276
2804
|
}
|
|
3277
2805
|
function saveManifest(dir, manifest) {
|
|
3278
|
-
|
|
3279
|
-
|
|
2806
|
+
writeFileSync4(
|
|
2807
|
+
join5(dir, MANIFEST_FILE),
|
|
3280
2808
|
`${JSON.stringify(manifest, null, 2)}
|
|
3281
2809
|
`,
|
|
3282
2810
|
"utf8"
|
|
3283
2811
|
);
|
|
3284
2812
|
}
|
|
3285
2813
|
function isAttachmentUpToDate(entry, item, dest) {
|
|
3286
|
-
if (!entry || !
|
|
2814
|
+
if (!entry || !existsSync5(dest)) return false;
|
|
3287
2815
|
if (entry.name !== item.name) return false;
|
|
3288
2816
|
const createdAt = item.createdAt ?? "";
|
|
3289
2817
|
return entry.createdAt === createdAt;
|
|
@@ -3298,7 +2826,7 @@ async function syncAttachmentsToDirectory(cfg, attachments, dir, logLabel) {
|
|
|
3298
2826
|
const nextManifest = { version: 1, attachments: {} };
|
|
3299
2827
|
const names = [];
|
|
3300
2828
|
for (const item of attachments) {
|
|
3301
|
-
const dest =
|
|
2829
|
+
const dest = join5(dir, item.name);
|
|
3302
2830
|
const entry = manifest.attachments[item.id];
|
|
3303
2831
|
const createdAt = item.createdAt ?? "";
|
|
3304
2832
|
names.push(item.name);
|
|
@@ -3308,7 +2836,7 @@ async function syncAttachmentsToDirectory(cfg, attachments, dir, logLabel) {
|
|
|
3308
2836
|
continue;
|
|
3309
2837
|
}
|
|
3310
2838
|
const buffer = await downloadAttachment(cfg, item.id);
|
|
3311
|
-
|
|
2839
|
+
writeFileSync4(dest, buffer);
|
|
3312
2840
|
nextManifest.attachments[item.id] = {
|
|
3313
2841
|
name: item.name,
|
|
3314
2842
|
createdAt
|
|
@@ -3330,14 +2858,14 @@ async function syncWebIdeAttachments(cfg, taskId, workdir, attachments) {
|
|
|
3330
2858
|
|
|
3331
2859
|
// src/project-documents-sync.ts
|
|
3332
2860
|
import {
|
|
3333
|
-
existsSync as
|
|
2861
|
+
existsSync as existsSync6,
|
|
3334
2862
|
readdirSync as readdirSync3,
|
|
3335
|
-
readFileSync as
|
|
2863
|
+
readFileSync as readFileSync6,
|
|
3336
2864
|
rmSync as rmSync2,
|
|
3337
|
-
writeFileSync as
|
|
2865
|
+
writeFileSync as writeFileSync5
|
|
3338
2866
|
} from "fs";
|
|
3339
2867
|
import { createHash } from "crypto";
|
|
3340
|
-
import { dirname as
|
|
2868
|
+
import { dirname as dirname5, join as join6, relative as relative2, sep } from "path";
|
|
3341
2869
|
var MANIFEST_FILE2 = "manifest.json";
|
|
3342
2870
|
function normalizeProjectIdForPath(projectId) {
|
|
3343
2871
|
const id = projectId.trim();
|
|
@@ -3351,11 +2879,11 @@ function normalizeProjectIdForPath(projectId) {
|
|
|
3351
2879
|
}
|
|
3352
2880
|
function projectDocumentsDir(apmRoot, projectId) {
|
|
3353
2881
|
const id = normalizeProjectIdForPath(projectId);
|
|
3354
|
-
return
|
|
2882
|
+
return join6(apmRoot ?? workspaceApmDir(), "project", id);
|
|
3355
2883
|
}
|
|
3356
2884
|
function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
|
|
3357
2885
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
3358
|
-
return
|
|
2886
|
+
return join6(
|
|
3359
2887
|
projectDocumentsDir(apmRoot, projectId),
|
|
3360
2888
|
...normalized.split("/")
|
|
3361
2889
|
);
|
|
@@ -3375,16 +2903,16 @@ function hashLocalFileContent(content) {
|
|
|
3375
2903
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
3376
2904
|
}
|
|
3377
2905
|
function readLocalManifest(apmRoot, projectId) {
|
|
3378
|
-
const manifestPath3 =
|
|
2906
|
+
const manifestPath3 = join6(
|
|
3379
2907
|
projectDocumentsDir(apmRoot, projectId),
|
|
3380
2908
|
MANIFEST_FILE2
|
|
3381
2909
|
);
|
|
3382
|
-
if (!
|
|
2910
|
+
if (!existsSync6(manifestPath3)) {
|
|
3383
2911
|
return null;
|
|
3384
2912
|
}
|
|
3385
2913
|
try {
|
|
3386
2914
|
return JSON.parse(
|
|
3387
|
-
|
|
2915
|
+
readFileSync6(manifestPath3, "utf8")
|
|
3388
2916
|
);
|
|
3389
2917
|
} catch {
|
|
3390
2918
|
return null;
|
|
@@ -3392,13 +2920,13 @@ function readLocalManifest(apmRoot, projectId) {
|
|
|
3392
2920
|
}
|
|
3393
2921
|
function listLocalDocumentPaths(apmRoot, projectId) {
|
|
3394
2922
|
const root = projectDocumentsDir(apmRoot, projectId);
|
|
3395
|
-
if (!
|
|
2923
|
+
if (!existsSync6(root)) {
|
|
3396
2924
|
return [];
|
|
3397
2925
|
}
|
|
3398
2926
|
const paths = [];
|
|
3399
2927
|
const walk = (dir) => {
|
|
3400
2928
|
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
3401
|
-
const abs =
|
|
2929
|
+
const abs = join6(dir, entry.name);
|
|
3402
2930
|
if (entry.isDirectory()) {
|
|
3403
2931
|
walk(abs);
|
|
3404
2932
|
continue;
|
|
@@ -3516,8 +3044,8 @@ ${diagnostic ?? ""}`);
|
|
|
3516
3044
|
const absPath = toFsPath(
|
|
3517
3045
|
projectDocumentLocalPath(targetApmDir, projectId, doc.path)
|
|
3518
3046
|
);
|
|
3519
|
-
await ensureDirExists(
|
|
3520
|
-
|
|
3047
|
+
await ensureDirExists(dirname5(absPath));
|
|
3048
|
+
writeFileSync5(absPath, doc.content, "utf8");
|
|
3521
3049
|
downloaded += 1;
|
|
3522
3050
|
}
|
|
3523
3051
|
}
|
|
@@ -3526,13 +3054,13 @@ ${diagnostic ?? ""}`);
|
|
|
3526
3054
|
const absPath = toFsPath(
|
|
3527
3055
|
projectDocumentLocalPath(targetApmDir, projectId, path)
|
|
3528
3056
|
);
|
|
3529
|
-
if (
|
|
3057
|
+
if (existsSync6(absPath)) {
|
|
3530
3058
|
rmSync2(absPath, { force: true });
|
|
3531
3059
|
deleted += 1;
|
|
3532
3060
|
}
|
|
3533
3061
|
}
|
|
3534
|
-
|
|
3535
|
-
toFsPath(
|
|
3062
|
+
writeFileSync5(
|
|
3063
|
+
toFsPath(join6(docsDir, MANIFEST_FILE2)),
|
|
3536
3064
|
`${JSON.stringify(remoteManifest, null, 2)}
|
|
3537
3065
|
`,
|
|
3538
3066
|
"utf8"
|
|
@@ -3575,7 +3103,7 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
3575
3103
|
const absPath = toFsPath(
|
|
3576
3104
|
projectDocumentLocalPath(targetApmDir, projectId, path)
|
|
3577
3105
|
);
|
|
3578
|
-
const content =
|
|
3106
|
+
const content = readFileSync6(absPath, "utf8");
|
|
3579
3107
|
const contentHash = hashLocalFileContent(content);
|
|
3580
3108
|
if (remoteHashByPath.get(path) === contentHash) {
|
|
3581
3109
|
continue;
|
|
@@ -3596,20 +3124,20 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
3596
3124
|
}
|
|
3597
3125
|
|
|
3598
3126
|
// src/commands/connect/cli-version-sync.ts
|
|
3599
|
-
import { existsSync as
|
|
3600
|
-
import { join as
|
|
3127
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
3128
|
+
import { join as join7 } from "path";
|
|
3601
3129
|
var CLI_VERSION_FILE = ".cli-version.json";
|
|
3602
3130
|
function manifestPath2(apmDir) {
|
|
3603
|
-
return
|
|
3131
|
+
return join7(apmDir, CLI_VERSION_FILE);
|
|
3604
3132
|
}
|
|
3605
3133
|
function loadManifest2(apmDir) {
|
|
3606
3134
|
const path = toFsPath(manifestPath2(apmDir));
|
|
3607
|
-
if (!
|
|
3135
|
+
if (!existsSync7(path)) {
|
|
3608
3136
|
return null;
|
|
3609
3137
|
}
|
|
3610
3138
|
try {
|
|
3611
3139
|
const parsed = JSON.parse(
|
|
3612
|
-
|
|
3140
|
+
readFileSync7(path, "utf8")
|
|
3613
3141
|
);
|
|
3614
3142
|
if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
|
|
3615
3143
|
return parsed;
|
|
@@ -3620,7 +3148,7 @@ function loadManifest2(apmDir) {
|
|
|
3620
3148
|
}
|
|
3621
3149
|
function saveManifest2(apmDir, cliVersion) {
|
|
3622
3150
|
const manifest = { version: 1, cliVersion };
|
|
3623
|
-
|
|
3151
|
+
writeFileSync6(
|
|
3624
3152
|
toFsPath(manifestPath2(apmDir)),
|
|
3625
3153
|
`${JSON.stringify(manifest, null, 2)}
|
|
3626
3154
|
`,
|
|
@@ -3680,7 +3208,7 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3680
3208
|
const workdir = requireRemoteWorkdir(msg.workdir);
|
|
3681
3209
|
const messageId = msg.messageId;
|
|
3682
3210
|
const taskId = msg.taskId;
|
|
3683
|
-
const branchCacheKey =
|
|
3211
|
+
const branchCacheKey = taskId;
|
|
3684
3212
|
console.log(
|
|
3685
3213
|
`[apm] webide-message action=${msg.action} taskId=${taskId} messageId=${messageId}`
|
|
3686
3214
|
);
|
|
@@ -3726,9 +3254,7 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3726
3254
|
await runPrepStep(
|
|
3727
3255
|
"\u521D\u59CB\u5316\u5DE5\u4F5C\u533A",
|
|
3728
3256
|
async () => {
|
|
3729
|
-
const { didInit } = await ensureWorkspaceInitialized(workdir
|
|
3730
|
-
webide: true
|
|
3731
|
-
});
|
|
3257
|
+
const { didInit } = await ensureWorkspaceInitialized(workdir);
|
|
3732
3258
|
return didInit;
|
|
3733
3259
|
},
|
|
3734
3260
|
(didInit) => didInit ? "\u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A" : "\u5DE5\u4F5C\u533A\u5DF2\u5C31\u7EEA"
|
|
@@ -3872,7 +3398,6 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3872
3398
|
cfg,
|
|
3873
3399
|
{
|
|
3874
3400
|
messageId,
|
|
3875
|
-
sessionId: `webide:${taskId}`,
|
|
3876
3401
|
prompt: msg.content,
|
|
3877
3402
|
model: msg.model,
|
|
3878
3403
|
apiKey: msg.apiKey,
|
|
@@ -3892,7 +3417,6 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3892
3417
|
}),
|
|
3893
3418
|
enableWebIdePlanTools: true,
|
|
3894
3419
|
enableSandbox: false,
|
|
3895
|
-
skipSessionAgentRegistry: true,
|
|
3896
3420
|
onInvalidatePersistedAgentId: () => clearWebIdeAgentId(workdir, taskId),
|
|
3897
3421
|
taskId,
|
|
3898
3422
|
terminalRpc: options?.terminalRpc,
|
|
@@ -4103,12 +3627,12 @@ function installTerminalRpcListener() {
|
|
|
4103
3627
|
}
|
|
4104
3628
|
function call(op, args) {
|
|
4105
3629
|
const id = nextId++;
|
|
4106
|
-
return new Promise((
|
|
3630
|
+
return new Promise((resolve6, reject) => {
|
|
4107
3631
|
if (!parentPort) {
|
|
4108
3632
|
reject(new Error("parentPort \u4E0D\u53EF\u7528"));
|
|
4109
3633
|
return;
|
|
4110
3634
|
}
|
|
4111
|
-
pending.set(id, { resolve:
|
|
3635
|
+
pending.set(id, { resolve: resolve6, reject });
|
|
4112
3636
|
parentPort.postMessage({
|
|
4113
3637
|
type: "terminal-rpc",
|
|
4114
3638
|
id,
|