ai-project-manage-cli 7.1.11 → 7.1.12
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/dist/index.js
CHANGED
|
@@ -505,6 +505,10 @@ var requestConfig = {
|
|
|
505
505
|
method: "POST",
|
|
506
506
|
path: "/cli/webide/draft-pull-requests"
|
|
507
507
|
}),
|
|
508
|
+
webideMergePullRequests: defineEndpoint({
|
|
509
|
+
method: "POST",
|
|
510
|
+
path: "/cli/webide/pull-requests/merge"
|
|
511
|
+
}),
|
|
508
512
|
getRepositoryProjectDocumentManifest: defineEndpoint({
|
|
509
513
|
method: "GET",
|
|
510
514
|
path: "/cli/repository-project-documents/manifest"
|
|
@@ -648,6 +652,22 @@ async function hasUpstream(cwd) {
|
|
|
648
652
|
return false;
|
|
649
653
|
}
|
|
650
654
|
}
|
|
655
|
+
async function pushCurrentBranch(cwd) {
|
|
656
|
+
if (!await isGitRepo(cwd)) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
const originUrl = await tryReadGitOriginUrl(cwd);
|
|
660
|
+
if (!originUrl) {
|
|
661
|
+
console.log("[apm] \u672A\u914D\u7F6E remote.origin\uFF0C\u8DF3\u8FC7 push");
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
if (await hasUpstream(cwd)) {
|
|
665
|
+
await execGit(cwd, ["push"]);
|
|
666
|
+
} else {
|
|
667
|
+
await execGit(cwd, ["push", "-u", "origin", "HEAD"]);
|
|
668
|
+
}
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
651
671
|
var GITIGNORE_COMMIT_MESSAGE = "chore(apm): ignore .apm directory";
|
|
652
672
|
async function commitAndPushGitignore(workdir) {
|
|
653
673
|
if (!await isGitRepo(workdir)) {
|
|
@@ -657,17 +677,12 @@ async function commitAndPushGitignore(workdir) {
|
|
|
657
677
|
await execGit(workdir, ["add", "--", ".gitignore"]);
|
|
658
678
|
await execGit(workdir, ["commit", "-m", GITIGNORE_COMMIT_MESSAGE]);
|
|
659
679
|
console.log(`[apm] \u5DF2\u63D0\u4EA4 .gitignore: ${GITIGNORE_COMMIT_MESSAGE}`);
|
|
660
|
-
const
|
|
661
|
-
if (
|
|
662
|
-
console.log("[apm] \
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
if (await hasUpstream(workdir)) {
|
|
666
|
-
await execGit(workdir, ["push"]);
|
|
680
|
+
const pushed = await pushCurrentBranch(workdir);
|
|
681
|
+
if (pushed) {
|
|
682
|
+
console.log("[apm] \u5DF2\u63A8\u9001 .gitignore");
|
|
667
683
|
} else {
|
|
668
|
-
|
|
684
|
+
console.log("[apm] \u672A\u914D\u7F6E remote.origin\uFF0C\u8BF7\u7A0D\u540E\u624B\u52A8 push .gitignore");
|
|
669
685
|
}
|
|
670
|
-
console.log("[apm] \u5DF2\u63A8\u9001 .gitignore");
|
|
671
686
|
}
|
|
672
687
|
|
|
673
688
|
// src/baseline-resolve.ts
|
|
@@ -6790,6 +6805,35 @@ ${payload}`;
|
|
|
6790
6805
|
};
|
|
6791
6806
|
}
|
|
6792
6807
|
|
|
6808
|
+
// src/commands/connect/webide-merge-tools.ts
|
|
6809
|
+
function createMergeWebIdePullRequestsTool(options) {
|
|
6810
|
+
const { cfg, taskId } = options;
|
|
6811
|
+
return {
|
|
6812
|
+
description: "Merge all open pull requests for this WebIDE task after conflicts are resolved locally and pushed. Call once with no arguments. Do NOT call if conflicts contradict the task requirements \u2014 report the conflict and fail instead.",
|
|
6813
|
+
inputSchema: {
|
|
6814
|
+
type: "object",
|
|
6815
|
+
properties: {
|
|
6816
|
+
confirmedConflictFree: {
|
|
6817
|
+
type: "boolean",
|
|
6818
|
+
description: "Must be true: you have checked each repo, resolved mergeable conflicts consistently with requirements, and pushed. If conflicts contradict requirements, do not call this tool."
|
|
6819
|
+
}
|
|
6820
|
+
},
|
|
6821
|
+
required: ["confirmedConflictFree"]
|
|
6822
|
+
},
|
|
6823
|
+
execute: async (args) => {
|
|
6824
|
+
if (args.confirmedConflictFree !== true) {
|
|
6825
|
+
throw new Error(
|
|
6826
|
+
"MergeWebIdePullRequests \u8981\u6C42 confirmedConflictFree=true\u3002\u82E5\u5B58\u5728\u4E0E\u9700\u6C42\u76F8\u6096\u7684\u51B2\u7A81\uFF0C\u8BF7\u52FF\u8C03\u7528\u672C\u5DE5\u5177\uFF0C\u7528 AppendMessage \u8BF4\u660E\u5E76\u5931\u8D25\u7ED3\u675F\u3002"
|
|
6827
|
+
);
|
|
6828
|
+
}
|
|
6829
|
+
const api = createApmApiClient(cfg);
|
|
6830
|
+
console.log(`[apm] MergeWebIdePullRequests taskId=${taskId}`);
|
|
6831
|
+
const result = await api.cli.webideMergePullRequests({ taskId });
|
|
6832
|
+
return JSON.stringify(result, null, 2);
|
|
6833
|
+
}
|
|
6834
|
+
};
|
|
6835
|
+
}
|
|
6836
|
+
|
|
6793
6837
|
// src/commands/connect/webide-plan-tools.ts
|
|
6794
6838
|
function asString(value) {
|
|
6795
6839
|
return typeof value === "string" ? value.trim() : "";
|
|
@@ -6977,6 +7021,10 @@ function createCursorCustomTools(cfg, messageId, options) {
|
|
|
6977
7021
|
cfg,
|
|
6978
7022
|
taskId: options.taskId
|
|
6979
7023
|
});
|
|
7024
|
+
tools.MergeWebIdePullRequests = createMergeWebIdePullRequestsTool({
|
|
7025
|
+
cfg,
|
|
7026
|
+
taskId: options.taskId
|
|
7027
|
+
});
|
|
6980
7028
|
}
|
|
6981
7029
|
return tools;
|
|
6982
7030
|
}
|
|
@@ -136,6 +136,10 @@ var requestConfig = {
|
|
|
136
136
|
method: "POST",
|
|
137
137
|
path: "/cli/webide/draft-pull-requests"
|
|
138
138
|
}),
|
|
139
|
+
webideMergePullRequests: defineEndpoint({
|
|
140
|
+
method: "POST",
|
|
141
|
+
path: "/cli/webide/pull-requests/merge"
|
|
142
|
+
}),
|
|
139
143
|
getRepositoryProjectDocumentManifest: defineEndpoint({
|
|
140
144
|
method: "GET",
|
|
141
145
|
path: "/cli/repository-project-documents/manifest"
|
|
@@ -381,6 +385,22 @@ async function hasUpstream(cwd) {
|
|
|
381
385
|
return false;
|
|
382
386
|
}
|
|
383
387
|
}
|
|
388
|
+
async function pushCurrentBranch(cwd) {
|
|
389
|
+
if (!await isGitRepo(cwd)) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
const originUrl = await tryReadGitOriginUrl(cwd);
|
|
393
|
+
if (!originUrl) {
|
|
394
|
+
console.log("[apm] \u672A\u914D\u7F6E remote.origin\uFF0C\u8DF3\u8FC7 push");
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
if (await hasUpstream(cwd)) {
|
|
398
|
+
await execGit(cwd, ["push"]);
|
|
399
|
+
} else {
|
|
400
|
+
await execGit(cwd, ["push", "-u", "origin", "HEAD"]);
|
|
401
|
+
}
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
384
404
|
var GITIGNORE_COMMIT_MESSAGE = "chore(apm): ignore .apm directory";
|
|
385
405
|
async function commitAndPushGitignore(workdir) {
|
|
386
406
|
if (!await isGitRepo(workdir)) {
|
|
@@ -390,17 +410,12 @@ async function commitAndPushGitignore(workdir) {
|
|
|
390
410
|
await execGit(workdir, ["add", "--", ".gitignore"]);
|
|
391
411
|
await execGit(workdir, ["commit", "-m", GITIGNORE_COMMIT_MESSAGE]);
|
|
392
412
|
console.log(`[apm] \u5DF2\u63D0\u4EA4 .gitignore: ${GITIGNORE_COMMIT_MESSAGE}`);
|
|
393
|
-
const
|
|
394
|
-
if (
|
|
395
|
-
console.log("[apm] \
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
if (await hasUpstream(workdir)) {
|
|
399
|
-
await execGit(workdir, ["push"]);
|
|
413
|
+
const pushed = await pushCurrentBranch(workdir);
|
|
414
|
+
if (pushed) {
|
|
415
|
+
console.log("[apm] \u5DF2\u63A8\u9001 .gitignore");
|
|
400
416
|
} else {
|
|
401
|
-
|
|
417
|
+
console.log("[apm] \u672A\u914D\u7F6E remote.origin\uFF0C\u8BF7\u7A0D\u540E\u624B\u52A8 push .gitignore");
|
|
402
418
|
}
|
|
403
|
-
console.log("[apm] \u5DF2\u63A8\u9001 .gitignore");
|
|
404
419
|
}
|
|
405
420
|
|
|
406
421
|
// src/baseline-resolve.ts
|
|
@@ -854,6 +869,21 @@ async function commitWorkspaceReposIfDirty(workdir, message) {
|
|
|
854
869
|
}
|
|
855
870
|
return committed;
|
|
856
871
|
}
|
|
872
|
+
async function pushWorkspaceRepos(workdir) {
|
|
873
|
+
const workdirPath = resolveWorkdirPath(workdir);
|
|
874
|
+
const manifest = loadWorkspaceReposCache(workdirPath);
|
|
875
|
+
const repoRoots = resolveWorkspaceRepoAbsolutePaths(manifest);
|
|
876
|
+
let pushed = 0;
|
|
877
|
+
for (const gitRoot of repoRoots) {
|
|
878
|
+
const label = formatRepoLabel(workdirPath, gitRoot);
|
|
879
|
+
const did = await pushCurrentBranch(gitRoot);
|
|
880
|
+
if (did) {
|
|
881
|
+
pushed += 1;
|
|
882
|
+
console.log(`[apm] WebIDE \u5DF2 push @ ${label}`);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return pushed;
|
|
886
|
+
}
|
|
857
887
|
function branchNameForTask(taskId) {
|
|
858
888
|
const id = taskId.trim();
|
|
859
889
|
if (!id) {
|
|
@@ -1525,6 +1555,35 @@ ${payload}`;
|
|
|
1525
1555
|
};
|
|
1526
1556
|
}
|
|
1527
1557
|
|
|
1558
|
+
// src/commands/connect/webide-merge-tools.ts
|
|
1559
|
+
function createMergeWebIdePullRequestsTool(options) {
|
|
1560
|
+
const { cfg, taskId } = options;
|
|
1561
|
+
return {
|
|
1562
|
+
description: "Merge all open pull requests for this WebIDE task after conflicts are resolved locally and pushed. Call once with no arguments. Do NOT call if conflicts contradict the task requirements \u2014 report the conflict and fail instead.",
|
|
1563
|
+
inputSchema: {
|
|
1564
|
+
type: "object",
|
|
1565
|
+
properties: {
|
|
1566
|
+
confirmedConflictFree: {
|
|
1567
|
+
type: "boolean",
|
|
1568
|
+
description: "Must be true: you have checked each repo, resolved mergeable conflicts consistently with requirements, and pushed. If conflicts contradict requirements, do not call this tool."
|
|
1569
|
+
}
|
|
1570
|
+
},
|
|
1571
|
+
required: ["confirmedConflictFree"]
|
|
1572
|
+
},
|
|
1573
|
+
execute: async (args) => {
|
|
1574
|
+
if (args.confirmedConflictFree !== true) {
|
|
1575
|
+
throw new Error(
|
|
1576
|
+
"MergeWebIdePullRequests \u8981\u6C42 confirmedConflictFree=true\u3002\u82E5\u5B58\u5728\u4E0E\u9700\u6C42\u76F8\u6096\u7684\u51B2\u7A81\uFF0C\u8BF7\u52FF\u8C03\u7528\u672C\u5DE5\u5177\uFF0C\u7528 AppendMessage \u8BF4\u660E\u5E76\u5931\u8D25\u7ED3\u675F\u3002"
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
const api = createApmApiClient(cfg);
|
|
1580
|
+
console.log(`[apm] MergeWebIdePullRequests taskId=${taskId}`);
|
|
1581
|
+
const result = await api.cli.webideMergePullRequests({ taskId });
|
|
1582
|
+
return JSON.stringify(result, null, 2);
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1528
1587
|
// src/commands/connect/webide-plan-tools.ts
|
|
1529
1588
|
function asString(value) {
|
|
1530
1589
|
return typeof value === "string" ? value.trim() : "";
|
|
@@ -1712,6 +1771,10 @@ function createCursorCustomTools(cfg, messageId, options) {
|
|
|
1712
1771
|
cfg,
|
|
1713
1772
|
taskId: options.taskId
|
|
1714
1773
|
});
|
|
1774
|
+
tools.MergeWebIdePullRequests = createMergeWebIdePullRequestsTool({
|
|
1775
|
+
cfg,
|
|
1776
|
+
taskId: options.taskId
|
|
1777
|
+
});
|
|
1715
1778
|
}
|
|
1716
1779
|
return tools;
|
|
1717
1780
|
}
|
|
@@ -2559,12 +2622,17 @@ function markBranchDone(sessionId, workdir) {
|
|
|
2559
2622
|
lastBranchKey = sessionWorkdirKey(sessionId, workdir);
|
|
2560
2623
|
}
|
|
2561
2624
|
|
|
2562
|
-
// src/commands/connect/webide-
|
|
2563
|
-
var
|
|
2564
|
-
|
|
2565
|
-
|
|
2625
|
+
// src/commands/connect/webide-pull-requests.ts
|
|
2626
|
+
var TEST_START_ACTIONS = /* @__PURE__ */ new Set([
|
|
2627
|
+
"generate-cases",
|
|
2628
|
+
"run-auto-test",
|
|
2629
|
+
"skip-test",
|
|
2630
|
+
"enter-manual-test"
|
|
2631
|
+
]);
|
|
2632
|
+
function shouldEnsureWebIdePullRequests(action) {
|
|
2633
|
+
return TEST_START_ACTIONS.has(action);
|
|
2566
2634
|
}
|
|
2567
|
-
async function
|
|
2635
|
+
async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
2568
2636
|
const api = createApmApiClient(cfg);
|
|
2569
2637
|
let repoRoots;
|
|
2570
2638
|
try {
|
|
@@ -2572,29 +2640,27 @@ async function ensureWebIdeDraftPullRequests(cfg, taskId, workdir) {
|
|
|
2572
2640
|
repoRoots = resolveWorkspaceRepoAbsolutePaths(manifest);
|
|
2573
2641
|
} catch (err) {
|
|
2574
2642
|
console.warn(
|
|
2575
|
-
"[apm] WebIDE
|
|
2643
|
+
"[apm] WebIDE PR\uFF1A\u8BFB\u53D6\u4ED3\u5E93\u6E05\u5355\u5931\u8D25:",
|
|
2576
2644
|
err instanceof Error ? err.message : err
|
|
2577
2645
|
);
|
|
2578
2646
|
return;
|
|
2579
2647
|
}
|
|
2580
2648
|
console.log(
|
|
2581
|
-
`[apm] WebIDE
|
|
2649
|
+
`[apm] WebIDE PR\uFF1A\u51C6\u5907\u4E3A ${repoRoots.length} \u4E2A\u4ED3\u5E93\u521B\u5EFA feat/task-${taskId}`
|
|
2582
2650
|
);
|
|
2583
2651
|
for (const gitRoot of repoRoots) {
|
|
2584
2652
|
const label = formatRepoLabel(workdir, gitRoot);
|
|
2585
2653
|
try {
|
|
2586
2654
|
const originUrl = await tryReadGitOriginUrl(gitRoot);
|
|
2587
2655
|
if (!originUrl) {
|
|
2588
|
-
console.warn(
|
|
2589
|
-
`[apm] WebIDE \u8349\u7A3F PR\uFF1A\u8DF3\u8FC7 ${label}\uFF08\u65E0 remote.origin.url\uFF09`
|
|
2590
|
-
);
|
|
2656
|
+
console.warn(`[apm] WebIDE PR\uFF1A\u8DF3\u8FC7 ${label}\uFF08\u65E0 remote.origin.url\uFF09`);
|
|
2591
2657
|
continue;
|
|
2592
2658
|
}
|
|
2593
2659
|
const matched = await api.cli.matchRepository({ url: originUrl });
|
|
2594
2660
|
const repositoryId = matched.repositoryId?.trim();
|
|
2595
2661
|
if (!repositoryId) {
|
|
2596
2662
|
console.warn(
|
|
2597
|
-
`[apm] WebIDE
|
|
2663
|
+
`[apm] WebIDE PR\uFF1A\u8DF3\u8FC7 ${label}\uFF08\u5E73\u53F0\u672A\u767B\u8BB0\u4ED3\u5E93 ${originUrl}\uFF09`
|
|
2598
2664
|
);
|
|
2599
2665
|
continue;
|
|
2600
2666
|
}
|
|
@@ -2603,17 +2669,81 @@ async function ensureWebIdeDraftPullRequests(cfg, taskId, workdir) {
|
|
|
2603
2669
|
repositoryId
|
|
2604
2670
|
});
|
|
2605
2671
|
console.log(
|
|
2606
|
-
`[apm] WebIDE
|
|
2672
|
+
`[apm] WebIDE PR\uFF1A${label} \u2192 #${pr.number} ${pr.state} ${pr.url || ""}`
|
|
2607
2673
|
);
|
|
2608
2674
|
} catch (err) {
|
|
2609
2675
|
console.warn(
|
|
2610
|
-
`[apm] WebIDE
|
|
2676
|
+
`[apm] WebIDE PR\uFF1A${label} \u5931\u8D25:`,
|
|
2611
2677
|
err instanceof Error ? err.message : err
|
|
2612
2678
|
);
|
|
2613
2679
|
}
|
|
2614
2680
|
}
|
|
2615
2681
|
}
|
|
2616
2682
|
|
|
2683
|
+
// src/commands/connect/webide-baseline-sync.ts
|
|
2684
|
+
async function abortMergeOrRebase(cwd) {
|
|
2685
|
+
try {
|
|
2686
|
+
await execGit(cwd, ["merge", "--abort"], true);
|
|
2687
|
+
} catch {
|
|
2688
|
+
}
|
|
2689
|
+
try {
|
|
2690
|
+
await execGit(cwd, ["rebase", "--abort"], true);
|
|
2691
|
+
} catch {
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
async function syncWebIdeBaselineOrFail(workdir) {
|
|
2695
|
+
let repoRoots;
|
|
2696
|
+
try {
|
|
2697
|
+
const manifest = loadWorkspaceReposCache(workdir);
|
|
2698
|
+
repoRoots = resolveWorkspaceRepoAbsolutePaths(manifest);
|
|
2699
|
+
} catch (err) {
|
|
2700
|
+
return {
|
|
2701
|
+
ok: false,
|
|
2702
|
+
error: `\u8BFB\u53D6\u5DE5\u4F5C\u533A\u4ED3\u5E93\u6E05\u5355\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`
|
|
2703
|
+
};
|
|
2704
|
+
}
|
|
2705
|
+
const failures = [];
|
|
2706
|
+
for (const repoRoot of repoRoots) {
|
|
2707
|
+
const label = formatRepoLabel(workdir, repoRoot);
|
|
2708
|
+
try {
|
|
2709
|
+
const gitRoot = await resolveGitRepoRoot(repoRoot);
|
|
2710
|
+
const baselineBranch = await resolveDefaultRemoteBranch(gitRoot);
|
|
2711
|
+
await ensureRemoteBaselineBranch(gitRoot, baselineBranch);
|
|
2712
|
+
const currentBranch = await getCurrentBranch(gitRoot);
|
|
2713
|
+
console.log(
|
|
2714
|
+
`[apm] webide accept sync ${label}: ${currentBranch} \u2190 origin/${baselineBranch}`
|
|
2715
|
+
);
|
|
2716
|
+
try {
|
|
2717
|
+
await execGit(
|
|
2718
|
+
gitRoot,
|
|
2719
|
+
["merge", `origin/${baselineBranch}`, "--no-edit"],
|
|
2720
|
+
true
|
|
2721
|
+
);
|
|
2722
|
+
} catch (mergeErr) {
|
|
2723
|
+
await abortMergeOrRebase(gitRoot);
|
|
2724
|
+
const detail = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
|
|
2725
|
+
failures.push(
|
|
2726
|
+
`${label}\uFF1A\u5408\u5E76 origin/${baselineBranch} \u51B2\u7A81\uFF0C\u5DF2\u6267\u884C merge --abort \u64A4\u56DE\u672C\u6B21\u540C\u6B65\u3002${detail}`
|
|
2727
|
+
);
|
|
2728
|
+
}
|
|
2729
|
+
} catch (err) {
|
|
2730
|
+
failures.push(
|
|
2731
|
+
`${label}\uFF1A${err instanceof Error ? err.message : String(err)}`
|
|
2732
|
+
);
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
if (failures.length > 0) {
|
|
2736
|
+
return {
|
|
2737
|
+
ok: false,
|
|
2738
|
+
error: [
|
|
2739
|
+
"\u62C9\u53D6\u6700\u65B0\u57FA\u7EBF\u5931\u8D25\uFF0C\u5DF2\u64A4\u56DE\u672C\u6B21\u540C\u6B65\u64CD\u4F5C\uFF0C\u8BF7\u4EBA\u5DE5\u5904\u7406\u51B2\u7A81\u540E\u91CD\u8BD5\u9A8C\u6536\u5408\u5E76\u3002",
|
|
2740
|
+
...failures.map((f) => `- ${f}`)
|
|
2741
|
+
].join("\n")
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2744
|
+
return { ok: true };
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2617
2747
|
// src/version.ts
|
|
2618
2748
|
import { readFileSync as readFileSync8 } from "fs";
|
|
2619
2749
|
import { dirname as dirname5, join as join8 } from "path";
|
|
@@ -2824,7 +2954,8 @@ function markSkillsSyncedForCliVersion(workdir, cliVersion) {
|
|
|
2824
2954
|
var WEBIDE_CODE_CHANGE_ACTIONS = /* @__PURE__ */ new Set([
|
|
2825
2955
|
"skip-plan",
|
|
2826
2956
|
"start-develop",
|
|
2827
|
-
"fix-and-retest"
|
|
2957
|
+
"fix-and-retest",
|
|
2958
|
+
"report-defect"
|
|
2828
2959
|
]);
|
|
2829
2960
|
function shouldCommitAfterWebIdeMessage(action) {
|
|
2830
2961
|
return WEBIDE_CODE_CHANGE_ACTIONS.has(action);
|
|
@@ -2878,9 +3009,30 @@ async function handleWebIdeInboundMessage(cfg, msg, signal) {
|
|
|
2878
3009
|
`[apm] step=branch skipped taskId=${taskId} workdir=${workdir}`
|
|
2879
3010
|
);
|
|
2880
3011
|
}
|
|
2881
|
-
if (
|
|
3012
|
+
if (shouldEnsureWebIdePullRequests(msg.action)) {
|
|
3013
|
+
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
3014
|
+
const pushed = await pushWorkspaceRepos(workdir);
|
|
3015
|
+
console.log(
|
|
3016
|
+
`[apm] webide \u6D4B\u8BD5\u524D push action=${msg.action} repos=${pushed}`
|
|
3017
|
+
);
|
|
2882
3018
|
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
2883
|
-
await
|
|
3019
|
+
await ensureWebIdePullRequests(cfg, taskId, workdir);
|
|
3020
|
+
}
|
|
3021
|
+
if (msg.action === "accept") {
|
|
3022
|
+
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
3023
|
+
const sync = await syncWebIdeBaselineOrFail(workdir);
|
|
3024
|
+
if (!sync.ok) {
|
|
3025
|
+
await setError(cfg, messageId, sync.error);
|
|
3026
|
+
return;
|
|
3027
|
+
}
|
|
3028
|
+
try {
|
|
3029
|
+
await pushWorkspaceRepos(workdir);
|
|
3030
|
+
} catch (err) {
|
|
3031
|
+
console.warn(
|
|
3032
|
+
"[apm] webide accept \u540C\u6B65\u540E push \u5931\u8D25:",
|
|
3033
|
+
err instanceof Error ? err.message : err
|
|
3034
|
+
);
|
|
3035
|
+
}
|
|
2884
3036
|
}
|
|
2885
3037
|
const savedAgentId = loadWebIdeAgentId(workdir, taskId);
|
|
2886
3038
|
const logSyncRef = { current: null };
|
|
@@ -2974,6 +3126,11 @@ async function handleWebIdeInboundMessage(cfg, msg, signal) {
|
|
|
2974
3126
|
console.log(
|
|
2975
3127
|
`[apm] webide \u515C\u5E95 commit action=${msg.action} repos=${committed}`
|
|
2976
3128
|
);
|
|
3129
|
+
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
3130
|
+
const pushed = await pushWorkspaceRepos(workdir);
|
|
3131
|
+
console.log(
|
|
3132
|
+
`[apm] webide \u81EA\u52A8 push action=${msg.action} repos=${pushed}`
|
|
3133
|
+
);
|
|
2977
3134
|
}
|
|
2978
3135
|
await logSyncRef.current?.markRun(outcome.runId, "finished");
|
|
2979
3136
|
await updateStatus(cfg, messageId, "SUCCESS");
|
package/package.json
CHANGED
package/template/AGENTS.md
CHANGED
|
@@ -29,8 +29,9 @@
|
|
|
29
29
|
- 规则: `.apm/rules/*`
|
|
30
30
|
- reply.md:当需要回复消息时需要读取这个文档,记住回复规则
|
|
31
31
|
- write_doc.md:当需要写文档时需要读取这个文档,记住写文档的规则
|
|
32
|
-
- webide_git_commit.md:WebIDE 开发/修码时读取,按规范分轮 commit
|
|
32
|
+
- webide_git_commit.md:WebIDE 开发/修码时读取,按规范分轮 commit,结束前 push
|
|
33
33
|
- webide_testcase.md:WebIDE 生成测试用例时读取,按规范编写并提交用例
|
|
34
|
+
- webide_merge.md:WebIDE 验收合并时读取;先解冲突再调 MergeWebIdePullRequests,需求相悖则拒绝合并
|
|
34
35
|
|
|
35
36
|
- 仓库项目上下文(`.apm/project/`):
|
|
36
37
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
## WebIDE 合并规范
|
|
2
|
+
|
|
3
|
+
适用场景:WebIDE 验收通过(`accept`)后:同步最新基线 → 对照原始任务审核 → 合并本任务 PR。
|
|
4
|
+
|
|
5
|
+
### 目标
|
|
6
|
+
|
|
7
|
+
将本任务各仓库 `feat/task-<taskId>` 分支上的变更安全合并进基线分支(通常为 `main`)。
|
|
8
|
+
|
|
9
|
+
### 步骤
|
|
10
|
+
|
|
11
|
+
1. **先拉取最新基线并处理冲突,再审核,最后调用合并工具**
|
|
12
|
+
|
|
13
|
+
- 在各相关仓库拉取最新基线(`git fetch`),将基线 merge/rebase 进特性分支。
|
|
14
|
+
- 有冲突时:在本地解冲突后 commit 并 `git push`(必要时 `--force-with-lease` 仅用于已 rebase 的特性分支)。
|
|
15
|
+
- 解冲突原则:保留本任务需求与已确认计划所要求的行为;吸收基线中合理且不冲突的改动。
|
|
16
|
+
- **解冲突失败或无法安全取舍**:立即 `git merge --abort` / `git rebase --abort` 撤回本次同步,保持特性分支为同步前状态;**禁止**调用合并工具。
|
|
17
|
+
|
|
18
|
+
2. **不可调和冲突 / 同步失败 → 拒绝合并**
|
|
19
|
+
|
|
20
|
+
- 若冲突双方改动在需求/业务逻辑上相悖,或本地同步已 abort:
|
|
21
|
+
- **禁止**调用 `MergeWebIdePullRequests`
|
|
22
|
+
- 用 `AppendMessage` 说明冲突文件、矛盾点、为何无法自动取舍,以及已执行的回退
|
|
23
|
+
- 以错误结束本轮(抛错或明确失败),等待人工介入(前端将展示失败信息)
|
|
24
|
+
|
|
25
|
+
3. **对照原始任务审核代码**
|
|
26
|
+
|
|
27
|
+
- 在合并前快速核对:改动是否覆盖任务需求与已确认计划;是否引入明显与需求相悖的行为。
|
|
28
|
+
- 若审核不通过:同样禁止合并,AppendMessage 说明问题并以错误结束。
|
|
29
|
+
|
|
30
|
+
4. **确认可安全合并后**
|
|
31
|
+
- 调用一次 `MergeWebIdePullRequests`(无参数),由平台合并本任务全部 OPEN PR
|
|
32
|
+
- 再用 `AppendMessage` 汇总合并结果(PR 编号、仓库)
|
|
33
|
+
|
|
34
|
+
### 禁止
|
|
35
|
+
|
|
36
|
+
- 未拉取最新基线 / 未检查冲突就直接调合并工具
|
|
37
|
+
- 同步冲突未 abort 就继续合并
|
|
38
|
+
- 为强行合并而删改与需求相悖的关键逻辑却不说明
|
|
39
|
+
- 在仍有草稿 PR / 明显冲突未解决时假装成功
|