ai-project-manage-cli 8.1.6 → 8.1.7

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 CHANGED
@@ -39,6 +39,8 @@ apm connect
39
39
  apm connect --server https://your-server.com
40
40
  ```
41
41
 
42
+ 启动前会检测 npm registry 上当前大版本的最新包;若落后则先 `npm install -g` 更新,再以新版本重新连接。跨大版本请手动执行 `apm update --major`。
43
+
42
44
  同一时刻仅允许一个 connect。
43
45
 
44
46
  `apm connect` 处理完 WebIDE 消息后,会将 `.apm/project/<项目ID>/` 下的项目文档变更推回平台。
package/dist/index.js CHANGED
@@ -324,6 +324,14 @@ var requestConfig = {
324
324
  method: "PUT",
325
325
  path: "/cli/webide/plan"
326
326
  }),
327
+ webideUpsertChecklist: defineEndpoint({
328
+ method: "PUT",
329
+ path: "/cli/webide/checklist"
330
+ }),
331
+ webideGetChecklist: defineEndpoint({
332
+ method: "GET",
333
+ path: "/cli/webide/checklist"
334
+ }),
327
335
  webideReplaceTestCases: defineEndpoint({
328
336
  method: "PUT",
329
337
  path: "/cli/webide/test-cases"
@@ -512,6 +520,8 @@ async function runLogin(opts) {
512
520
 
513
521
  // src/commands/update.ts
514
522
  import { spawnSync } from "child_process";
523
+ import { existsSync as existsSync2 } from "fs";
524
+ import { join as join4 } from "path";
515
525
 
516
526
  // src/version.ts
517
527
  import { readFileSync as readFileSync2 } from "fs";
@@ -530,6 +540,7 @@ function readCliVersion() {
530
540
  }
531
541
 
532
542
  // src/commands/update.ts
543
+ var APM_SKIP_SELF_UPDATE_ENV = "APM_SKIP_SELF_UPDATE";
533
544
  var useNpmShell = process.platform === "win32";
534
545
  function runNpm(args, options = {}) {
535
546
  return spawnSync(useNpmShell ? "npm.cmd" : "npm", args, {
@@ -622,10 +633,17 @@ function npmAvailable() {
622
633
  return !r.error && r.status === 0;
623
634
  }
624
635
  async function runUpdate(options = {}) {
636
+ if (process.env[APM_SKIP_SELF_UPDATE_ENV] === "1") {
637
+ return { didUpdate: false };
638
+ }
625
639
  const current = readCliVersion();
626
640
  const currentMajor = parseMajorVersion(current);
627
641
  const globalLatest = await fetchLatestPublishedVersion();
628
642
  const latestInMajor = options.allowMajorUpgrade ? null : await fetchLatestPublishedVersionInMajor(currentMajor);
643
+ if (options.quietIfCurrent && !options.allowMajorUpgrade && !latestInMajor && !globalLatest) {
644
+ console.warn(`[apm] \u65E0\u6CD5\u68C0\u6D4B\u6700\u65B0\u7248\u672C\uFF0C\u7EE7\u7EED\u4F7F\u7528\u5F53\u524D ${current}`);
645
+ return { didUpdate: false };
646
+ }
629
647
  const resolved = resolveUpdateTarget({
630
648
  current,
631
649
  allowMajorUpgrade: options.allowMajorUpgrade,
@@ -633,8 +651,10 @@ async function runUpdate(options = {}) {
633
651
  globalLatest
634
652
  });
635
653
  if (resolved.action === "skip") {
636
- console.log(`[apm] \u5DF2\u662F\u6700\u65B0\u7248\u672C ${current}`);
637
- return;
654
+ if (!options.quietIfCurrent) {
655
+ console.log(`[apm] \u5DF2\u662F\u6700\u65B0\u7248\u672C ${current}`);
656
+ }
657
+ return { didUpdate: false };
638
658
  }
639
659
  if (resolved.majorUpgradeAvailable) {
640
660
  console.log(
@@ -671,14 +691,57 @@ async function runUpdate(options = {}) {
671
691
  } else {
672
692
  console.log(`[apm] \u5DF2\u662F\u6700\u65B0\u7248\u672C ${current}`);
673
693
  }
694
+ return { didUpdate: expectedBump };
695
+ }
696
+ function resolveApmEntryPath(entryArg = process.argv[1]) {
697
+ const npmResult = runNpm(["root", "-g"], {
698
+ encoding: "utf8",
699
+ stdio: ["ignore", "pipe", "pipe"]
700
+ });
701
+ if (npmResult.status === 0) {
702
+ const globalRoot = npmResult.stdout?.toString().trim();
703
+ if (globalRoot) {
704
+ const candidate = join4(globalRoot, CLI_PACKAGE_NAME, "dist", "index.js");
705
+ if (existsSync2(candidate)) {
706
+ return candidate;
707
+ }
708
+ }
709
+ }
710
+ const fromArgv = entryArg?.trim();
711
+ if (fromArgv && existsSync2(fromArgv)) {
712
+ return fromArgv;
713
+ }
714
+ if (fromArgv) {
715
+ return fromArgv;
716
+ }
717
+ console.error("[apm] \u65E0\u6CD5\u89E3\u6790 apm \u5165\u53E3\u8DEF\u5F84");
718
+ process.exit(1);
719
+ }
720
+ function reexecConnectAfterUpdate(options) {
721
+ console.log("[apm] \u66F4\u65B0\u5B8C\u6210\uFF0C\u6B63\u5728\u4EE5\u65B0\u7248\u672C\u91CD\u65B0\u8FDE\u63A5\u2026");
722
+ const apmScript = resolveApmEntryPath();
723
+ const args = [apmScript, "connect"];
724
+ const server = options.server?.trim();
725
+ if (server) {
726
+ args.push("--server", server);
727
+ }
728
+ const result = spawnSync(process.execPath, args, {
729
+ stdio: "inherit",
730
+ env: { ...process.env, [APM_SKIP_SELF_UPDATE_ENV]: "1" }
731
+ });
732
+ if (result.error) {
733
+ console.error("[apm] \u91CD\u542F connect \u5931\u8D25:", result.error.message);
734
+ process.exit(1);
735
+ }
736
+ process.exit(result.status ?? 0);
674
737
  }
675
738
 
676
739
  // src/commands/update-skills.ts
677
- import { existsSync as existsSync2, statSync as statSync2 } from "fs";
740
+ import { existsSync as existsSync3, statSync as statSync2 } from "fs";
678
741
  async function syncWorkspaceSkills(workdir) {
679
742
  const apmDir = workspaceApmDir(workdir);
680
743
  const fsApmDir = toFsPath(apmDir);
681
- if (!existsSync2(fsApmDir)) {
744
+ if (!existsSync3(fsApmDir)) {
682
745
  throw new Error("[apm] \u672A\u627E\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5148\u6267\u884C apm init");
683
746
  }
684
747
  const apmStat = statSync2(fsApmDir);
@@ -690,7 +753,7 @@ async function syncWorkspaceSkills(workdir) {
690
753
  }
691
754
  async function runUpdateSkills() {
692
755
  const apmDir = workspaceApmDir();
693
- if (!existsSync2(apmDir)) {
756
+ if (!existsSync3(apmDir)) {
694
757
  console.error("[apm] \u672A\u627E\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5148\u6267\u884C apm init");
695
758
  process.exit(1);
696
759
  }
@@ -703,14 +766,14 @@ async function runUpdateSkills() {
703
766
 
704
767
  // src/utils/project-documents.ts
705
768
  import {
706
- existsSync as existsSync3,
769
+ existsSync as existsSync4,
707
770
  readdirSync as readdirSync2,
708
771
  readFileSync as readFileSync3,
709
772
  rmSync,
710
773
  writeFileSync as writeFileSync2
711
774
  } from "fs";
712
775
  import { createHash } from "crypto";
713
- import { dirname as dirname3, join as join4, relative, sep } from "path";
776
+ import { dirname as dirname3, join as join5, relative, sep } from "path";
714
777
 
715
778
  // src/utils/git.ts
716
779
  import { execFile as execFile2 } from "child_process";
@@ -784,11 +847,11 @@ function normalizeProjectIdForPath(projectId) {
784
847
  }
785
848
  function projectDocumentsDir(apmRoot, projectId) {
786
849
  const id = normalizeProjectIdForPath(projectId);
787
- return join4(apmRoot ?? workspaceApmDir(), "project", id);
850
+ return join5(apmRoot ?? workspaceApmDir(), "project", id);
788
851
  }
789
852
  function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
790
853
  const normalized = normalizeLocalDocumentPath(documentPath);
791
- return join4(
854
+ return join5(
792
855
  projectDocumentsDir(apmRoot, projectId),
793
856
  ...normalized.split("/")
794
857
  );
@@ -808,11 +871,11 @@ function hashLocalFileContent(content) {
808
871
  return createHash("sha256").update(content, "utf8").digest("hex");
809
872
  }
810
873
  function readLocalManifest(apmRoot, projectId) {
811
- const manifestPath = join4(
874
+ const manifestPath = join5(
812
875
  projectDocumentsDir(apmRoot, projectId),
813
876
  MANIFEST_FILE
814
877
  );
815
- if (!existsSync3(manifestPath)) {
878
+ if (!existsSync4(manifestPath)) {
816
879
  return null;
817
880
  }
818
881
  try {
@@ -825,13 +888,13 @@ function readLocalManifest(apmRoot, projectId) {
825
888
  }
826
889
  function listLocalDocumentPaths(apmRoot, projectId) {
827
890
  const root = projectDocumentsDir(apmRoot, projectId);
828
- if (!existsSync3(root)) {
891
+ if (!existsSync4(root)) {
829
892
  return [];
830
893
  }
831
894
  const paths = [];
832
895
  const walk = (dir) => {
833
896
  for (const entry of readdirSync2(dir, { withFileTypes: true })) {
834
- const abs = join4(dir, entry.name);
897
+ const abs = join5(dir, entry.name);
835
898
  if (entry.isDirectory()) {
836
899
  walk(abs);
837
900
  continue;
@@ -960,13 +1023,13 @@ ${diagnostic ?? ""}`);
960
1023
  const absPath = toFsPath(
961
1024
  projectDocumentLocalPath(targetApmDir, projectId, path)
962
1025
  );
963
- if (existsSync3(absPath)) {
1026
+ if (existsSync4(absPath)) {
964
1027
  rmSync(absPath, { force: true });
965
1028
  deleted += 1;
966
1029
  }
967
1030
  }
968
1031
  writeFileSync2(
969
- toFsPath(join4(docsDir, MANIFEST_FILE)),
1032
+ toFsPath(join5(docsDir, MANIFEST_FILE)),
970
1033
  `${JSON.stringify(remoteManifest, null, 2)}
971
1034
  `,
972
1035
  "utf8"
@@ -1284,7 +1347,7 @@ function handleCancelAction(payload, ctx) {
1284
1347
  }
1285
1348
 
1286
1349
  // src/commands/connect/core/worker/worker.ts
1287
- import { dirname as dirname4, join as join5 } from "path";
1350
+ import { dirname as dirname4, join as join6 } from "path";
1288
1351
  import { fileURLToPath as fileURLToPath3 } from "url";
1289
1352
  import { Worker } from "node:worker_threads";
1290
1353
 
@@ -1310,7 +1373,7 @@ function resolveWebIdeWorkerHeapMb(env = process.env, totalMemoryBytes = totalme
1310
1373
  }
1311
1374
 
1312
1375
  // src/commands/connect/core/worker/worker.ts
1313
- var workerFile = join5(
1376
+ var workerFile = join6(
1314
1377
  dirname4(fileURLToPath3(import.meta.url)),
1315
1378
  "worker-script.js"
1316
1379
  );
@@ -1663,14 +1726,14 @@ function dispatchConnectAction(payload, ctx) {
1663
1726
 
1664
1727
  // src/commands/connect-lock.ts
1665
1728
  import {
1666
- existsSync as existsSync4,
1729
+ existsSync as existsSync5,
1667
1730
  mkdirSync as mkdirSync3,
1668
1731
  readFileSync as readFileSync4,
1669
1732
  unlinkSync,
1670
1733
  writeFileSync as writeFileSync3
1671
1734
  } from "fs";
1672
- import { join as join6 } from "path";
1673
- var CONNECT_LOCK_PATH = join6(APM_CONFIG_DIR, "connect.lock");
1735
+ import { join as join7 } from "path";
1736
+ var CONNECT_LOCK_PATH = join7(APM_CONFIG_DIR, "connect.lock");
1674
1737
  function isProcessAlive(pid) {
1675
1738
  if (!Number.isInteger(pid) || pid <= 0) return false;
1676
1739
  try {
@@ -1681,7 +1744,7 @@ function isProcessAlive(pid) {
1681
1744
  }
1682
1745
  }
1683
1746
  function readConnectLock() {
1684
- if (!existsSync4(CONNECT_LOCK_PATH)) return null;
1747
+ if (!existsSync5(CONNECT_LOCK_PATH)) return null;
1685
1748
  try {
1686
1749
  const raw = readFileSync4(CONNECT_LOCK_PATH, "utf8");
1687
1750
  const parsed = JSON.parse(raw);
@@ -1847,6 +1910,10 @@ function resolveConnectServerOption(options) {
1847
1910
  return void 0;
1848
1911
  }
1849
1912
  async function runConnect(options) {
1913
+ const { didUpdate } = await runUpdate({ quietIfCurrent: true });
1914
+ if (didUpdate) {
1915
+ reexecConnectAfterUpdate(options);
1916
+ }
1850
1917
  const cfg = await ensureLoggedConfig();
1851
1918
  const serverOverride = resolveConnectServerOption(options);
1852
1919
  if (serverOverride) {
@@ -1973,7 +2040,7 @@ function buildProgram() {
1973
2040
  await runSyncProjectDocuments(opts);
1974
2041
  });
1975
2042
  program.command("connect").description(
1976
- "\u8FDE\u63A5\u5E73\u53F0 WebSocket\uFF08/ws/agent\uFF09\uFF0C\u7EF4\u6301\u5FC3\u8DF3\u5E76\u5904\u7406\u4E0B\u884C webide-message"
2043
+ "\u8FDE\u63A5\u524D\u68C0\u6D4B\u5E76\u66F4\u65B0\u5230\u5F53\u524D\u5927\u7248\u672C\u6700\u65B0 CLI\uFF0C\u518D\u8FDE\u63A5\u5E73\u53F0 WebSocket\uFF08/ws/agent\uFF09"
1977
2044
  ).option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u8986\u76D6 config \u4E2D\u7684 baseUrl").action(async (opts) => {
1978
2045
  await runConnect({ server: opts.server });
1979
2046
  });
@@ -72,6 +72,14 @@ var requestConfig = {
72
72
  method: "PUT",
73
73
  path: "/cli/webide/plan"
74
74
  }),
75
+ webideUpsertChecklist: defineEndpoint({
76
+ method: "PUT",
77
+ path: "/cli/webide/checklist"
78
+ }),
79
+ webideGetChecklist: defineEndpoint({
80
+ method: "GET",
81
+ path: "/cli/webide/checklist"
82
+ }),
75
83
  webideReplaceTestCases: defineEndpoint({
76
84
  method: "PUT",
77
85
  path: "/cli/webide/test-cases"
@@ -1499,7 +1507,7 @@ function createMergeWebIdePullRequestsTool(options) {
1499
1507
  const { webideMergePullRequests } = options;
1500
1508
  return {
1501
1509
  MergeWebIdePullRequests: {
1502
- description: "Merge all open pull requests for this WebIDE task. Call once with confirmedConflictFree=true. No baseline sync or review is required before calling.",
1510
+ description: "Merge all open pull requests for this WebIDE task. During accept, call UpsertWebIdeChecklist first with the full acceptance checklist, then call this once with confirmedConflictFree=true. No baseline sync is required before merging.",
1503
1511
  inputSchema: {
1504
1512
  type: "object",
1505
1513
  properties: {
@@ -1586,6 +1594,63 @@ function createUpsertWebIdePlanTool(options) {
1586
1594
  }
1587
1595
  };
1588
1596
  }
1597
+ function createUpsertWebIdeChecklistTool(options) {
1598
+ const { webideUpsertChecklist } = options;
1599
+ return {
1600
+ UpsertWebIdeChecklist: {
1601
+ description: "Persist or replace the acceptance checklist markdown for this WebIDE task. Call with the full checklist (what changed, which repos/files, how to verify) before merging PRs. Use during accept so humans can review later.",
1602
+ inputSchema: {
1603
+ type: "object",
1604
+ properties: {
1605
+ content: {
1606
+ type: "string",
1607
+ description: "Full acceptance checklist in Markdown (Chinese): summary of code changes, scope by repo, key files, verification notes"
1608
+ }
1609
+ },
1610
+ required: ["content"]
1611
+ },
1612
+ execute: async (args) => {
1613
+ const content = asString(args.content);
1614
+ if (!content) {
1615
+ throw new Error("UpsertWebIdeChecklist \u7F3A\u5C11 content");
1616
+ }
1617
+ await webideUpsertChecklist({ content });
1618
+ return JSON.stringify({ ok: true, chars: content.length }, null, 2);
1619
+ }
1620
+ }
1621
+ };
1622
+ }
1623
+ function createGetWebIdeChecklistTool(options) {
1624
+ const { boundTaskId, webideGetChecklist } = options;
1625
+ return {
1626
+ GetWebIdeChecklist: {
1627
+ description: "Fetch the acceptance checklist markdown for a WebIDE task by taskId. Returns content=null if none has been written yet. Use when you need to read or revise an existing checklist.",
1628
+ inputSchema: {
1629
+ type: "object",
1630
+ properties: {
1631
+ taskId: {
1632
+ type: "string",
1633
+ description: "WebIDE task id whose checklist to load"
1634
+ }
1635
+ },
1636
+ required: ["taskId"]
1637
+ },
1638
+ execute: async (args) => {
1639
+ const taskId = asString(args.taskId);
1640
+ if (!taskId) {
1641
+ throw new Error("GetWebIdeChecklist \u7F3A\u5C11 taskId");
1642
+ }
1643
+ if (taskId !== boundTaskId) {
1644
+ throw new Error(
1645
+ `GetWebIdeChecklist \u7684 taskId \u987B\u4E3A\u5F53\u524D\u4EFB\u52A1 ${boundTaskId}`
1646
+ );
1647
+ }
1648
+ const result = await webideGetChecklist({ taskId });
1649
+ return JSON.stringify(result, null, 2);
1650
+ }
1651
+ }
1652
+ };
1653
+ }
1589
1654
 
1590
1655
  // src/commands/connect/tools/webide-test-case-tools.ts
1591
1656
  function asString2(value) {
@@ -1618,7 +1683,7 @@ function createUpsertWebIdeTestCasesTool(options) {
1618
1683
  const { webideReplaceTestCases } = options;
1619
1684
  return {
1620
1685
  UpsertWebIdeTestCases: {
1621
- description: "Persist generated automated test cases for this WebIDE task (full replace) and mark the workflow TEST_READY. Call once with the complete case list after reviewing the task and code changes.",
1686
+ description: "Persist generated automated test cases for this WebIDE task (full replace). Call once with the complete case list after reviewing the task and code changes. Does not change workflow phase.",
1622
1687
  inputSchema: {
1623
1688
  type: "object",
1624
1689
  properties: {
@@ -2364,6 +2429,23 @@ function createCursorCustomTools(cfg2, options) {
2364
2429
  })
2365
2430
  );
2366
2431
  }
2432
+ if (wantsTool("UpsertWebIdeChecklist", options, enablePlan)) {
2433
+ Object.assign(
2434
+ tools,
2435
+ createUpsertWebIdeChecklistTool({
2436
+ webideUpsertChecklist: (args) => cli.webideUpsertChecklist({ taskId, ...args })
2437
+ })
2438
+ );
2439
+ }
2440
+ if (wantsTool("GetWebIdeChecklist", options, enablePlan)) {
2441
+ Object.assign(
2442
+ tools,
2443
+ createGetWebIdeChecklistTool({
2444
+ boundTaskId: taskId,
2445
+ webideGetChecklist: (args) => cli.webideGetChecklist(args)
2446
+ })
2447
+ );
2448
+ }
2367
2449
  if (wantsTool("UpsertWebIdeTestCases", options, enablePlan)) {
2368
2450
  Object.assign(
2369
2451
  tools,
@@ -4145,100 +4227,6 @@ async function cleanWebIdeWorkspaceCache(taskId, workdir, cfg2) {
4145
4227
  }
4146
4228
  }
4147
4229
 
4148
- // src/commands/connect/webide-run-action.ts
4149
- function startActionForInbound(action) {
4150
- switch (action) {
4151
- case "request-assessment":
4152
- return "start-assessment";
4153
- case "request-design":
4154
- case "request-revise-design":
4155
- return "start-design";
4156
- case "request-write-plan":
4157
- case "request-revise-plan":
4158
- return "start-write-plan";
4159
- case "request-develop":
4160
- case "skip-plan":
4161
- return "start-develop";
4162
- case "request-start-project":
4163
- return "start-project";
4164
- case "request-execute-sql":
4165
- return "start-execute-sql";
4166
- case "request-bugfix":
4167
- return "start-bugfix";
4168
- case "request-organize-code":
4169
- case "request-patch":
4170
- return "start-organize-code";
4171
- case "request-accept":
4172
- return "start-accept";
4173
- default:
4174
- return null;
4175
- }
4176
- }
4177
- function completeActionForInbound(action) {
4178
- switch (action) {
4179
- case "request-assessment":
4180
- case "confirm-assumptions":
4181
- return "complete-assessment";
4182
- case "request-design":
4183
- case "request-revise-design":
4184
- return "complete-design";
4185
- case "request-write-plan":
4186
- case "request-revise-plan":
4187
- return "complete-write-plan";
4188
- case "request-develop":
4189
- case "skip-plan":
4190
- return "complete-develop";
4191
- case "request-start-project":
4192
- return "complete-project";
4193
- case "request-execute-sql":
4194
- return "complete-execute-sql";
4195
- case "request-bugfix":
4196
- return "complete-bugfix";
4197
- case "request-organize-code":
4198
- case "request-patch":
4199
- return "complete-organize-code";
4200
- case "request-accept":
4201
- return "complete-accept";
4202
- default:
4203
- return null;
4204
- }
4205
- }
4206
- async function webIdeRunAction(cfg2, taskId, action, params) {
4207
- const api = createApmApiClient(cfg2);
4208
- await api.cli.webideRunAction({ taskId, action, params });
4209
- console.log(`[apm] webide runAction ok action=${action} taskId=${taskId}`);
4210
- }
4211
- async function webIdeSyncTransitionPrepEvents(cfg2, taskId, startAction, prepEvents) {
4212
- try {
4213
- const api = createApmApiClient(cfg2);
4214
- await api.cli.webideUpdateTransitionPrepEvents({
4215
- taskId,
4216
- startAction,
4217
- prepEvents
4218
- });
4219
- } catch (err) {
4220
- console.warn(
4221
- `[apm] sync transition prepEvents failed taskId=${taskId}:`,
4222
- err instanceof Error ? err.message : err
4223
- );
4224
- }
4225
- }
4226
- async function webIdeDiscardTransitionPrepDraft(cfg2, taskId, startAction) {
4227
- try {
4228
- const api = createApmApiClient(cfg2);
4229
- await api.cli.webideUpdateTransitionPrepEvents({
4230
- taskId,
4231
- startAction,
4232
- discardDraft: true
4233
- });
4234
- } catch (err) {
4235
- console.warn(
4236
- `[apm] discard transition prep draft failed taskId=${taskId}:`,
4237
- err instanceof Error ? err.message : err
4238
- );
4239
- }
4240
- }
4241
-
4242
4230
  // src/commands/connect/webide-ask-question.ts
4243
4231
  function asString5(value) {
4244
4232
  return typeof value === "string" ? value.trim() : "";
@@ -4298,9 +4286,8 @@ async function fetchAssumptionAnswersAndContinueAssessment(options) {
4298
4286
  resolution: row.resolution
4299
4287
  });
4300
4288
  }
4301
- await webIdeRunAction(cfg2, taskId, "continue-assessment");
4302
4289
  console.log(
4303
- `[apm] \u5047\u8BBE\u7ED3\u679C\u5DF2\u62C9\u53D6\u5E76\u7EE7\u7EED\u8BC4\u4F30 taskId=${taskId} count=${answers.length}`
4290
+ `[apm] \u5047\u8BBE\u7ED3\u679C\u5DF2\u62C9\u53D6 taskId=${taskId} count=${answers.length}`
4304
4291
  );
4305
4292
  return JSON.stringify({ title, answers }, null, 2);
4306
4293
  }
@@ -4790,6 +4777,102 @@ function parseWebIdePromptPayload(content) {
4790
4777
  return null;
4791
4778
  }
4792
4779
 
4780
+ // src/commands/connect/webide-run-action.ts
4781
+ function startActionForInbound(action) {
4782
+ switch (action) {
4783
+ case "request-assessment":
4784
+ return "start-assessment";
4785
+ case "request-design":
4786
+ case "request-revise-design":
4787
+ return "start-design";
4788
+ case "request-write-plan":
4789
+ case "request-revise-plan":
4790
+ return "start-write-plan";
4791
+ case "request-develop":
4792
+ case "skip-plan":
4793
+ return "start-develop";
4794
+ case "request-start-project":
4795
+ return "start-project";
4796
+ case "request-execute-sql":
4797
+ return "start-execute-sql";
4798
+ case "request-bugfix":
4799
+ return "start-bugfix";
4800
+ case "request-organize-code":
4801
+ case "request-patch":
4802
+ return "start-organize-code";
4803
+ case "request-accept":
4804
+ return "start-accept";
4805
+ case "confirm-assumptions":
4806
+ return "continue-assessment";
4807
+ default:
4808
+ return null;
4809
+ }
4810
+ }
4811
+ function completeActionForInbound(action) {
4812
+ switch (action) {
4813
+ case "request-assessment":
4814
+ case "confirm-assumptions":
4815
+ return "complete-assessment";
4816
+ case "request-design":
4817
+ case "request-revise-design":
4818
+ return "complete-design";
4819
+ case "request-write-plan":
4820
+ case "request-revise-plan":
4821
+ return "complete-write-plan";
4822
+ case "request-develop":
4823
+ case "skip-plan":
4824
+ return "complete-develop";
4825
+ case "request-start-project":
4826
+ return "complete-project";
4827
+ case "request-execute-sql":
4828
+ return "complete-execute-sql";
4829
+ case "request-bugfix":
4830
+ return "complete-bugfix";
4831
+ case "request-organize-code":
4832
+ case "request-patch":
4833
+ return "complete-organize-code";
4834
+ case "request-accept":
4835
+ return "complete-accept";
4836
+ default:
4837
+ return null;
4838
+ }
4839
+ }
4840
+ async function webIdeRunAction(cfg2, taskId, action, params) {
4841
+ const api = createApmApiClient(cfg2);
4842
+ await api.cli.webideRunAction({ taskId, action, params });
4843
+ console.log(`[apm] webide runAction ok action=${action} taskId=${taskId}`);
4844
+ }
4845
+ async function webIdeSyncTransitionPrepEvents(cfg2, taskId, startAction, prepEvents) {
4846
+ try {
4847
+ const api = createApmApiClient(cfg2);
4848
+ await api.cli.webideUpdateTransitionPrepEvents({
4849
+ taskId,
4850
+ startAction,
4851
+ prepEvents
4852
+ });
4853
+ } catch (err) {
4854
+ console.warn(
4855
+ `[apm] sync transition prepEvents failed taskId=${taskId}:`,
4856
+ err instanceof Error ? err.message : err
4857
+ );
4858
+ }
4859
+ }
4860
+ async function webIdeDiscardTransitionPrepDraft(cfg2, taskId, startAction) {
4861
+ try {
4862
+ const api = createApmApiClient(cfg2);
4863
+ await api.cli.webideUpdateTransitionPrepEvents({
4864
+ taskId,
4865
+ startAction,
4866
+ discardDraft: true
4867
+ });
4868
+ } catch (err) {
4869
+ console.warn(
4870
+ `[apm] discard transition prep draft failed taskId=${taskId}:`,
4871
+ err instanceof Error ? err.message : err
4872
+ );
4873
+ }
4874
+ }
4875
+
4793
4876
  // src/commands/connect/core/worker/handlers/webide-message.ts
4794
4877
  var WEBIDE_CODE_CHANGE_ACTIONS = /* @__PURE__ */ new Set([
4795
4878
  "skip-plan",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "8.1.6",
3
+ "version": "8.1.7",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -17,7 +17,7 @@
17
17
  - `webide_sql_execute.md`:execute-sql 轮次连库执行 SQL 时 Read
18
18
  - `webide_terminal.md`:长驻进程禁止用 Shell;本地服务由顶栏「启动项目」触发,开发任务不要自行起服务
19
19
  - `webide_testcase.md`:生成测试用例并调用 `UpsertWebIdeTestCases`
20
- - `webide_merge.md`:验收通过后调用 `MergeWebIdePullRequests`
20
+ - `webide_merge.md`:验收通过后先 `UpsertWebIdeChecklist` 写验收清单,再 `MergeWebIdePullRequests`
21
21
 
22
22
  ### 目录
23
23
 
@@ -25,4 +25,4 @@
25
25
  - 任务附件:`.apm/webide/<taskId>/attachments/`(prompt 出现「任务附件」时按路径查看)
26
26
  - 仓库清单:`.apm/workspace-repos.json`(先确认单仓 / 多仓;多仓必须写清改动范围并点名仓库)
27
27
 
28
- 计划、用例、合并 PR 走 WebIDE 专用工具(`AskQuestion`、`RecommendPlan`、`UpsertWebIdePlan`、`UpsertWebIdeTestCases`、`MergeWebIdePullRequests` 等)。本地服务由用户在顶栏「启动项目」启动,开发任务不要自行起长驻进程。
28
+ 计划、用例、验收清单、合并 PR 走 WebIDE 专用工具(`AskQuestion`、`RecommendPlan`、`UpsertWebIdePlan`、`UpsertWebIdeChecklist`、`GetWebIdeChecklist`、`UpsertWebIdeTestCases`、`MergeWebIdePullRequests` 等)。本地服务由用户在顶栏「启动项目」启动,开发任务不要自行起长驻进程。
@@ -1,16 +1,24 @@
1
1
  ## WebIDE 合并规范
2
2
 
3
- 适用场景:WebIDE 验收通过(`accept`)后合并本任务 PR。
3
+ 适用场景:WebIDE 验收通过(`accept` / `request-accept`)后,先落库验收清单,再合并本任务 PR。
4
4
 
5
5
  ### 目标
6
6
 
7
- 将本任务各仓库特性分支上的变更合并进基线分支(通常为 `main`)。
7
+ 1. 留下一份可事后查阅的「验收清单」(描述本任务实际改了什么)。
8
+ 2. 将各仓库特性分支上的变更合并进基线分支(通常为 `main`)。
8
9
 
9
10
  ### 步骤
10
11
 
11
- 1. 调用一次 `MergeWebIdePullRequests`(`confirmedConflictFree=true`),由平台合并本任务全部 OPEN PR。
12
- 2. 用 `AppendMessage` 汇总合并结果(PR 编号、仓库)。
12
+ 1. **先写验收清单**:调用一次 `UpsertWebIdeChecklist`,提交完整 Markdown 全文(不要只提交 diff)。若需对照已有清单,可先 `GetWebIdeChecklist`(传当前 `taskId`)。建议结构:
13
+ - 改动摘要
14
+ - 按仓库的改动范围
15
+ - 关键改动点(模块 / 文件 / 接口 / 页面)
16
+ - 如何验收 / 回归点
17
+ - 备注(已知限制、未做事项、SQL/配置;无则写「无」)
18
+ 2. 调用一次 `MergeWebIdePullRequests`(`confirmedConflictFree=true`),由平台合并本任务全部 OPEN PR。
19
+ 3. 用 `AppendMessage` 汇总:清单已落库 + 合并结果(PR 编号、仓库)。
13
20
 
14
21
  ### 禁止
15
22
 
23
+ - **禁止**跳过 `UpsertWebIdeChecklist` 直接合并
16
24
  - 在合并之外自行执行同步基线、代码审核、部署等额外流程