ai-project-manage-cli 6.0.91 → 6.0.92

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
@@ -2,6 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
+ import { AssumptionPlanSource } from "@opc/shared";
5
6
 
6
7
  // src/config.ts
7
8
  import { mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -244,9 +245,6 @@ function sessionYamlPath(sessionId, apmRoot) {
244
245
  function sessionMessagesXmlPath(sessionId, apmRoot) {
245
246
  return join2(sessionDir(sessionId, apmRoot), "messages.xml");
246
247
  }
247
- function sessionAssumptionsJsonPath(sessionId, apmRoot) {
248
- return join2(sessionDir(sessionId, apmRoot), "assumptions.json");
249
- }
250
248
  function documentLocalFileName(platformName) {
251
249
  const trimmed = platformName.trim();
252
250
  if (!trimmed) return "document.md";
@@ -402,13 +400,9 @@ var requestConfig = {
402
400
  method: "GET",
403
401
  path: "/cli/documents"
404
402
  }),
405
- listAssumptions: defineEndpoint({
403
+ getDevGate: defineEndpoint({
406
404
  method: "GET",
407
- path: "/cli/assumptions"
408
- }),
409
- markAssumptionsBackfilled: defineEndpoint({
410
- method: "POST",
411
- path: "/cli/assumptions/mark-backfilled"
405
+ path: "/cli/dev-gate"
412
406
  }),
413
407
  listAttachments: defineEndpoint(
414
408
  {
@@ -1715,13 +1709,12 @@ async function runPull(sessionId, remoteWorkdir) {
1715
1709
  const api = createApmApiClient(cfg);
1716
1710
  const workdir = remoteWorkdir === void 0 ? resolveWorkdirPath() : requireRemoteWorkdir(remoteWorkdir);
1717
1711
  const apmRoot = workspaceApmDir(workdir);
1718
- const [detail, members, documents, attachments, messages, assumptions] = await Promise.all([
1712
+ const [detail, members, documents, attachments, messages] = await Promise.all([
1719
1713
  api.cli.sessionDetail({ sessionId: trimmedId }),
1720
1714
  api.cli.sessionMembers({ sessionId: trimmedId }),
1721
1715
  api.cli.listDocuments({ sessionId: trimmedId }),
1722
1716
  api.cli.listAttachments({ sessionId: trimmedId }),
1723
- api.cli.listSessionMessages({ sessionId: trimmedId }),
1724
- api.cli.listAssumptions({ sessionId: trimmedId }).catch(() => null)
1717
+ api.cli.listSessionMessages({ sessionId: trimmedId })
1725
1718
  ]);
1726
1719
  const dir = sessionDir(trimmedId, apmRoot);
1727
1720
  const docsDir = sessionDocsDir(trimmedId, apmRoot);
@@ -1767,20 +1760,6 @@ async function runPull(sessionId, remoteWorkdir) {
1767
1760
  formatSessionMessagesXml(trimmedId, messages),
1768
1761
  "utf8"
1769
1762
  );
1770
- writeFileSync9(
1771
- sessionAssumptionsJsonPath(trimmedId, apmRoot),
1772
- JSON.stringify(
1773
- assumptions ?? {
1774
- sessionId: trimmedId,
1775
- clearedAt: null,
1776
- backfilledAt: null,
1777
- assumptions: []
1778
- },
1779
- null,
1780
- 2
1781
- ),
1782
- "utf8"
1783
- );
1784
1763
  await syncSessionAttachments(cfg, trimmedId, attachments, apmRoot);
1785
1764
  await syncPlatformRules(cfg, trimmedId, workdir, apmRoot);
1786
1765
  await syncRemoteDeploymentConfig(workdir, apmRoot);
@@ -2148,10 +2127,21 @@ async function runSyncDocument(sessionId, options) {
2148
2127
  basename3(absPath)
2149
2128
  );
2150
2129
  console.log(`[apm] \u5DF2\u540C\u6B65\u6587\u6863: ${doc.name} (id=${doc.id})`);
2130
+ const assumptionSync = doc.assumptionSync;
2131
+ if (assumptionSync?.warnings?.length) {
2132
+ for (const warning of assumptionSync.warnings) {
2133
+ console.warn(`[apm] \u5047\u8BBE\u540C\u6B65\u544A\u8B66: ${warning}`);
2134
+ }
2135
+ }
2136
+ if (assumptionSync?.applicable) {
2137
+ console.log(
2138
+ `[apm] \u5047\u8BBE\u89E3\u6790: \u6807\u8BB0 ${assumptionSync.markerCount} \u6761\uFF0C\u5165\u5E93 ${assumptionSync.parsedCount} \u6761\uFF08PM \u53EF\u786E\u8BA4 ${assumptionSync.okCount} \u6761\uFF09`
2139
+ );
2140
+ }
2151
2141
  }
2152
2142
 
2153
- // src/commands/assumptions.ts
2154
- async function runAssumptionsList(sessionId) {
2143
+ // src/commands/dev-gate.ts
2144
+ async function runDevGate(sessionId, source) {
2155
2145
  const trimmedId = sessionId.trim();
2156
2146
  if (!trimmedId) {
2157
2147
  console.error("[apm] sessionId \u4E0D\u80FD\u4E3A\u7A7A");
@@ -2159,19 +2149,14 @@ async function runAssumptionsList(sessionId) {
2159
2149
  }
2160
2150
  const cfg = await ensureLoggedConfig();
2161
2151
  const api = createApmApiClient(cfg);
2162
- const data = await api.cli.listAssumptions({ sessionId: trimmedId });
2163
- console.log(JSON.stringify(data, null, 2));
2164
- }
2165
- async function runAssumptionsMarkBackfilled(sessionId) {
2166
- const trimmedId = sessionId.trim();
2167
- if (!trimmedId) {
2168
- console.error("[apm] sessionId \u4E0D\u80FD\u4E3A\u7A7A");
2152
+ const status = await api.cli.getDevGate({
2153
+ sessionId: trimmedId,
2154
+ source
2155
+ });
2156
+ console.log(JSON.stringify(status, null, 2));
2157
+ if (!status.readyForDev) {
2169
2158
  process.exit(1);
2170
2159
  }
2171
- const cfg = await ensureLoggedConfig();
2172
- const api = createApmApiClient(cfg);
2173
- await api.cli.markAssumptionsBackfilled({ sessionId: trimmedId });
2174
- console.log(`[apm] \u5DF2\u6807\u8BB0\u5047\u8BBE\u56DE\u586B\u5B8C\u6210: sessionId=${trimmedId}`);
2175
2160
  }
2176
2161
 
2177
2162
  // src/commands/append-message.ts
@@ -7021,12 +7006,16 @@ function buildProgram() {
7021
7006
  ).argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").action(async (sessionId) => {
7022
7007
  await runPull(sessionId);
7023
7008
  });
7024
- program.command("assumptions").description("\u5047\u8BBE\u786E\u8BA4\uFF1A\u5217\u51FA\u6216\u6807\u8BB0\u56DE\u586B\u5B8C\u6210").argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").option("--mark-backfilled", "\u6807\u8BB0\u5047\u8BBE\u5DF2\u5199\u56DE\u8BA1\u5212").action(async (sessionId, opts) => {
7025
- if (opts.markBackfilled) {
7026
- await runAssumptionsMarkBackfilled(sessionId);
7027
- return;
7028
- }
7029
- await runAssumptionsList(sessionId);
7009
+ program.command("dev-gate").description("\u67E5\u8BE2\u672C\u7AEF\u5F00\u53D1\u95E8\u7981\u72B6\u6001\uFF08\u5047\u8BBE\u786E\u8BA4 + \u9700\u6C42\u7406\u89E3\u786E\u8BA4\uFF09").argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").requiredOption(
7010
+ "--source <source>",
7011
+ "FRONTEND_PLAN \u6216 BACKEND_PLAN"
7012
+ ).action(async (sessionId, opts) => {
7013
+ const source = opts.source === "BACKEND_PLAN" ? AssumptionPlanSource.BACKEND_PLAN : AssumptionPlanSource.FRONTEND_PLAN;
7014
+ await runDevGate(sessionId, source);
7015
+ });
7016
+ program.command("assumptions").description("\uFF08\u5DF2\u5E9F\u5F03\uFF09\u8BF7\u4F7F\u7528 dev-gate").argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").action(async () => {
7017
+ console.error("[apm] assumptions \u547D\u4EE4\u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528: apm dev-gate <sessionId> --source FRONTEND_PLAN|BACKEND_PLAN");
7018
+ process.exit(1);
7030
7019
  });
7031
7020
  program.command("sync-document").description("\u5C06\u672C\u5730 Markdown \u8986\u76D6\u5F0F upsert \u5230\u5E73\u53F0\u4EFB\u52A1\u6587\u6863").argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").requiredOption(
7032
7021
  "--file <name>",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "6.0.91",
3
+ "version": "6.0.92",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -1,23 +1,27 @@
1
1
  ### 阶段 1:实现计划(前后端可同轮并行)
2
2
 
3
- 前端、后端工程师各自按技能 `apm-write-plan` 执行:先判断本需求是否涉及本端,不涉及则回复「与本端无关」并说明理由;涉及则直接基于需求原文编写实现计划(后端 `BACKEND-PLAN.md` 含「API 契约」,前端 `FRONTEND-PLAN.md`),计划必须包含「依据与假设」与「改动文件白名单」。**禁止改代码。**
4
- 计划存在「假设」时 @ 项目经理逐条确认,然后进入阶段 1.5;计划无假设时直接进入阶段 2。
3
+ 前端、后端工程师各自按技能 `apm-write-plan` 执行:先判断本需求是否涉及本端;涉及则编写 `*-PLAN.md` + `*-ASSUMPTIONS.md`(计划不含假设章节)。**禁止改代码。**
4
+ 有假设时 @ 项目经理在 Web「待您确认」点选;无假设时直接发送「本端需求理解」@ 项目经理。
5
5
 
6
- ### 阶段 2:假设回填(项目经理回复假设后,单人或多人按需)
6
+ ### 阶段 1.5:假设确认后更新计划(有假设时)
7
7
 
8
- 项目经理回复假设确认后,必须安排对应工程师按技能 `apm-write-plan` 步骤 5 执行假设回填:阅读聊天记录中项目经理的回复,把确认的假设移入计划「依据」、被否定的按新口径修订实现步骤与白名单,重新同步计划并逐条回复处理结果。回填完成(假设清零)后才进入阶段 2;**禁止跳过本阶段直接安排开发**。计划无假设时跳过本阶段。
8
+ PM 在 Web 确认假设后,相关工程师按 `apm-update-plan`:`apm pull` ASSUMPTIONS → 更新 PLAN → 发送需求理解 @ 项目经理。
9
+
10
+ ### 阶段 2:需求理解确认
11
+
12
+ 项目经理在聊天回复固定话术:**「理解正确,可进入开发」**(可指定「前端」「后端」)。确认后各端 `apm dev-gate` 应为 `readyForDev: true`。
9
13
 
10
14
  ### 阶段 3:需求开发(前后端可同轮并行)
11
15
 
12
- 前后端工程师按技能 `apm-dev` 各自开发:只允许改动本端计划「改动文件白名单」内的文件;前端接口对接以后端计划的「API 契约」为准。完成标准 = 构建通过 + 回复中逐文件对账白名单。**禁止自行部署。** **不安排联调。**完成后进入阶段 4。
16
+ 前后端工程师按技能 `apm-dev` 各自开发:只允许改动本端计划「改动文件白名单」内的文件。完成标准 = 构建通过 + 回复中逐文件对账白名单。**禁止自行部署。**完成后进入阶段 4。
13
17
 
14
18
  ### 阶段 4:diff 评审(单人)
15
19
 
16
- 评审工程师按技能 `apm-diff-review` 执行:检查 git 改动是否越出白名单、是否夹带与需求无关的修改、计划关键点是否落实。不通过:列出问题清单 @ 对应工程师,回到阶段 3 修复,同一任务最多打回 3 次,超过则 @ 项目经理决策;通过:@ 项目经理交人验收(部署与回归验收由人工或平台完成)。
20
+ 评审工程师按技能 `apm-diff-review` 执行:检查 git 改动是否越出白名单、是否夹带与需求无关的修改、计划关键点是否落实。不通过:列出问题清单 @ 对应工程师,回到阶段 3 修复;通过:@ 项目经理交人验收。
17
21
 
18
22
  ### 阶段 5:需求验收
19
23
 
20
- 项目经理验证并给出结论。全部通过则任务完成;某条不通过时回复「第 N 条不通过,实际现象:xxx」,由对应工程师回到阶段 3 修复该条,修复后重新走阶段 4 评审再重验。
24
+ 项目经理验证并给出结论。全部通过则任务完成;某条不通过时回复「第 N 条不通过,实际现象:xxx」,由对应工程师回到阶段 3 修复。
21
25
 
22
26
  ### BUG 修复流程
23
27
 
@@ -1,21 +1,3 @@
1
- # apm-confirm-assumptions:按 PM 确认结果回填计划
1
+ # apm-confirm-assumptions(已废弃)
2
2
 
3
- ## 何时使用
4
-
5
- 收到项目经理会话消息「已回复所有假设,可以继续后面的流程」后;或 `assumptions.json` 中 `clearedAt` 有值且 `backfilledAt` 为空。
6
-
7
- ## 工作流程
8
-
9
- 1. **Read** `.apm/sessions/<会话ID>/assumptions.json`;不存在或 `backfilledAt` 已有 → 退出。
10
- 2. **Read** 本 Skill;过滤 **本端** 条目(后端只看 `BACKEND_PLAN`,前端只看 `FRONTEND_PLAN`)。
11
- 3. **Read** 本端计划:`docs/BACKEND-PLAN.md` 或 `docs/FRONTEND-PLAN.md`。
12
- 4. 逐条按 `resolution` 更新计划:
13
- - 移入「依据」表,来源写「项目经理确认」;
14
- - 从「假设」章节删除该题;
15
- - `customAnswer` 或影响实现范围时 → 修订「实现步骤 / 改动文件白名单」;后端涉及接口则同步 `docs/API.md`。
16
- 5. **`apm sync-document`** 同步计划(及 API 文档)。
17
- 6. **Read/Update** `TODO.md`:勾选「等待项目经理确认假设」等相关项。
18
- 7. **`append_message`**:摘要回填结果;声明「假设已清零,可进入测试要点编写」。
19
- 8. 执行 **`apm assumptions <会话ID> --mark-backfilled`**。
20
-
21
- **禁止**从 `messages.xml` 解析 PM 对假设的回复——只认 `assumptions.json`。
3
+ 本技能已更名为 **`apm-update-plan`**。请 **Read** `.apm/skills/apm-update-plan/SKILL.md`。
@@ -6,11 +6,12 @@
6
6
 
7
7
  1. 用 **Read** 工具阅读本端计划:前端读 `.apm/sessions/<会话ID>/docs/FRONTEND-PLAN.md`,后端读 `docs/BACKEND-PLAN.md`;计划不存在则退出流程并回复说明(兼容旧流程:若存在 `PRD.md` + `FRONTEND.md` / `BACKEND.md` + `API.md`,按旧文档执行)。
8
8
  2. 前端涉及接口对接时,以 `docs/API.md` 为唯一契约来源,**不等后端部署完成**;`API.md` 不存在或字段没写清时 `@后端` 补充,禁止自行猜测或在计划中重复编写接口定义。
9
- 3. **假设门禁(开发前必须检查)**:
10
- - **Read** `.apm/sessions/<会话ID>/assumptions.json`;
11
- - `PENDING` `quality=OK` → `@项目经理` 请其在 Web「待您确认」Panel 提交,**停止开发**;
12
- - `clearedAt` 有值但 `backfilledAt` 为空 执行 **`apm-confirm-assumptions`**(或 `@` 本端自行回填),**停止开发**;
13
- - 计划「假设」章节仍有未清空项同上,停止开发。
9
+ 3. **开发门禁(开发前必须检查)**:
10
+ - 执行 **`apm dev-gate <会话ID> --source FRONTEND_PLAN`**(后端用 `BACKEND_PLAN`);
11
+ - `pendingAssumptions > 0` → `@项目经理` 请其在 Web「待您确认」Panel 提交,**停止开发**;
12
+ - `!assumptionsCleared` 且有假设**停止开发**;
13
+ - `!understandingConfirmed``@项目经理` 请其在聊天回复「理解正确,可进入开发」,**停止开发**;
14
+ - `readyForDev === true` → 可继续。
14
15
  **禁止**从 `messages.xml` 解析 PM 假设回复。
15
16
 
16
17
  ### 步骤 2: 明确开发模式
@@ -57,24 +58,6 @@
57
58
  - 执行环境说明(测试/生产是否一致、是否需人工执行)
58
59
  - 回滚方案(如适用;回滚 SQL 同样用 ` ```sql ` 代码块,须完整可执行,禁止省略)
59
60
 
60
- 示例:
61
-
62
- ````markdown
63
- ## 目标数据库
64
-
65
- `oxc_platform`(MySQL 8.x)
66
-
67
- ## 变更摘要
68
-
69
- 为 inspection_class 表新增 is_project_add 字段。
70
-
71
- ## 执行 SQL
72
-
73
- ```sql
74
- ALTER TABLE inspection_class ADD COLUMN is_project_add VARCHAR(1) DEFAULT '0';
75
- ```
76
- ````
77
-
78
61
  `BACKEND-PLAN.md` 中不写大段 SQL,只可在实现步骤中注明「须产出 SQL.md」。若会话 `docs/` 下已有 `SQL.md`,在其上追加本次变更,勿另建其他 SQL 文档。
79
62
 
80
63
  ### 步骤 5: 提交并 push 代码,保证工作区干净
@@ -2,11 +2,11 @@
2
2
 
3
3
  ## 何时使用
4
4
 
5
- `apm sync-document` 后平台标记假设 `quality=NEEDS_REWRITE`,或计划被退回需重写「问 / 场景 / 选项」。
5
+ `apm sync-document` 同步 ASSUMPTIONS 失败(问法校验不通过),或计划被退回需重写「问 / 场景 / 选项」。
6
6
 
7
7
  ## 工作流程
8
8
 
9
- 1. **Read** 本端计划文档的「假设」章节与 `qualityIssues`(若有 assumptions.json 中的 technicalNote)。
9
+ 1. **Read** 本端 `docs/FRONTEND-ASSUMPTIONS.md` 或 `docs/BACKEND-ASSUMPTIONS.md`(及 sync 报错中的 qualityIssues)。
10
10
  2. 将研发术语移入 **研发备注**;**问** 改为 PM 可理解的业务句子;补全 **场景** 与 **≥2 个选项**(含 id + label)。
11
11
  3. **禁止多选**;复合口径说明写在 Other 指引中。
12
- 4. 重新 **`apm sync-document`** 同步计划。
12
+ 4. 重新 **`apm sync-document --file *-ASSUMPTIONS.md`** 同步。
@@ -0,0 +1,26 @@
1
+ # apm-update-plan:按 PM 确认结果更新计划
2
+
3
+ ## 何时使用
4
+
5
+ 收到沟通群消息「假设已全部确认。请相关工程师:」后。
6
+
7
+ ## 工作流程
8
+
9
+ 1. **`apm pull`** 拉取最新文档(含 ASSUMPTIONS 确认结果)。
10
+ 2. **Read** 本端 `docs/FRONTEND-ASSUMPTIONS.md` 或 `docs/BACKEND-ASSUMPTIONS.md`(**禁止**读 assumptions.json)。
11
+ 3. **Read** 本端 PLAN:`docs/FRONTEND-PLAN.md` 或 `docs/BACKEND-PLAN.md`。
12
+ 4. 逐条按 ASSUMPTIONS 中「确认结果」更新 PLAN:
13
+ - 移入「依据」表,来源写「项目经理确认」;
14
+ - 影响实现范围时 → 修订「实现步骤 / 改动文件白名单」;后端涉及接口则同步 `docs/API.md`。
15
+ 5. 重写 PLAN §1「需求理解」(融合 PM 确认口径)。
16
+ 6. **`apm sync-document`** 同步 PLAN(及 API 文档)。
17
+ 7. **`append_message`**:本端需求理解摘要 + @项目经理,请其回复「理解正确,可进入开发」。
18
+ 8. **Read/Update** `TODO.md`:勾选相关待办。
19
+
20
+ **禁止** `apm assumptions --mark-backfilled`(已废弃)。
21
+
22
+ **禁止**从 `messages.xml` 解析 PM 对假设的回复——只认 ASSUMPTIONS 文档中的确认结果。
23
+
24
+ ## 何时使用
25
+
26
+ 协作流程阶段 1.5(假设确认后更新计划)。
@@ -20,7 +20,7 @@
20
20
  逐条对照需求原文与计划:
21
21
 
22
22
  - **计划与需求矛盾、或需求关键点在计划中没有覆盖**:不要写清单,先用 `append_message` 指出问题并 `@` 对应工程师打回,等计划修订后再写。
23
- - **计划中的「假设」尚未确认或尚未回填计划**(查 `assumptions.json`:`PENDING` `clearedAt && !backfilledAt`):**不要写清单**,先提醒 PM / 执行 `apm-confirm-assumptions`。
23
+ - **开发门禁未通过**(`apm dev-gate` 返回 `readyForDev: false`):**不要写清单**,先提醒 PM / 执行 `apm-update-plan`。
24
24
  - 计划覆盖完整:进入步骤 3。
25
25
 
26
26
  ### 步骤 3:按模板写清单
@@ -7,7 +7,8 @@
7
7
  | 角色 | 产出文档 | 路径 |
8
8
  | ---- | -------- | ---- |
9
9
  | 后端 | `BACKEND-PLAN.md` + `API.md` | `docs/BACKEND-PLAN.md`、`docs/API.md` |
10
- | 前端 | `FRONTEND-PLAN.md` | `docs/FRONTEND-PLAN.md` |
10
+ | 前端 | `FRONTEND-PLAN.md` + `FRONTEND-ASSUMPTIONS.md` | `docs/FRONTEND-PLAN.md`、`docs/FRONTEND-ASSUMPTIONS.md` |
11
+ | 后端 | 同上 | `docs/BACKEND-ASSUMPTIONS.md` |
11
12
 
12
13
  ---
13
14
 
@@ -24,11 +25,13 @@
24
25
 
25
26
  1. 优先读 `docs/` 现成结论。
26
27
  2. 代码调研预算:**最多 15 个文件**。
27
- 3. 口径不清 → 记入「假设」章节,禁止编造。
28
+ 3. 口径不清 → 记入 **ASSUMPTIONS 文件**,禁止编造。
28
29
 
29
- ### 步骤 3:按模板写计划
30
+ ### 步骤 3:按模板写计划与假设
30
31
 
31
- **Read** `.apm/skills/apm-write-plan/plan-template.md`,**Write** 计划文档。
32
+ 1. **Read** `.apm/skills/apm-write-plan/plan-template.md`,**Write** 本端 `*-PLAN.md`(**不含**假设章节)。
33
+ 2. **Read** `.apm/skills/apm-write-plan/assumptions-template.md`,**Write** 本端 `*-ASSUMPTIONS.md`。
34
+ 3. 无假设时在 ASSUMPTIONS 中写「无,口径均有依据」。
32
35
 
33
36
  ### 步骤 3.5:假设 PM 友好自检(sync 前必做)
34
37
 
@@ -36,18 +39,19 @@
36
39
 
37
40
  - **问** 禁止:`status=`、字段名、表名、类路径、SQL。
38
41
  - **禁止多选**;复合口径由 PM 在 Web「其他」中填写。
39
- - 能自己查清的代码含义 → 移入「依据」,删除假设。
42
+ - 能自己查清的代码含义 → 移入 PLAN「依据」,删除假设。
40
43
  - 技术发现 → 写进 **研发备注**,问句用业务语言。
41
44
 
42
45
  ### 步骤 4:同步与回复
43
46
 
44
- 1. `apm sync-document` 同步计划(及 API 文档)。
45
- 2. **有假设**:`@项目经理` 请其在 Web **「待您确认」** Panel 点选;说明「以上假设确认前不开始开发」。**禁止**在聊天里粘贴研发术语。
46
- 3. **无假设**:回复计划已就绪,可进入测试要点编写。
47
+ 1. `apm sync-document --file FRONTEND-ASSUMPTIONS.md`(或 BACKEND)**先于** PLAN。
48
+ 2. `apm sync-document --file FRONTEND-PLAN.md`(或 BACKEND)。
49
+ 3. **有假设**:@项目经理 请其在 Web **「待您确认」** Panel 点选;说明「以上假设确认前不开始开发」。
50
+ 4. **无假设**:`append_message` 发送「本端需求理解」摘要并 @项目经理 请确认。
47
51
 
48
- ### 假设回填
52
+ ### 假设确认后更新计划
49
53
 
50
- 项目经理确认后由 **`apm-confirm-assumptions`** 技能执行(读 `assumptions.json`,**禁止**读 messages.xml 猜 PM 回复)。
54
+ 项目经理在 Web 确认假设后,执行 **`apm-update-plan`** 技能(读 ASSUMPTIONS.md,**禁止**读 assumptions.json)。
51
55
 
52
56
  ---
53
57
 
@@ -0,0 +1,16 @@
1
+ # 前端待确认口径
2
+
3
+ > 本文件由 apm sync-document 写入;PM 确认后服务端回写「状态/确认结果」。
4
+ > **禁止**手动编辑;已确认条目 AI 禁止修改。
5
+
6
+ #### A1
7
+ - **问**:(业务语言问句,禁止字段名/文件路径)
8
+ - **场景**:(需求未说明的背景)
9
+ - **选项**:
10
+ - opt_a:(选项说明)
11
+ - opt_b:(选项说明)
12
+ - **研发备注**:(仅研发可见的技术说明,可选)
13
+ - **状态**:待确认
14
+ - **确认结果**:
15
+
16
+ > 无假设时正文仅一行:无,口径均有依据。
@@ -1,7 +1,8 @@
1
1
  # 计划文档模板
2
2
 
3
3
  > 后端写 `docs/BACKEND-PLAN.md` + `docs/API.md`(两份文档禁止合并)。
4
- > 前端写 `docs/FRONTEND-PLAN.md`;接口细节只读 `docs/API.md`,禁止在计划中重复抄写。
4
+ > 前端写 `docs/FRONTEND-PLAN.md` + `docs/FRONTEND-ASSUMPTIONS.md`。
5
+ > 假设写在独立的 `*-ASSUMPTIONS.md`,计划内仅保留摘要与链接。
5
6
 
6
7
  ## 后端计划(BACKEND-PLAN.md)
7
8
 
@@ -12,94 +13,60 @@
12
13
 
13
14
  用 3 ~ 5 行复述本端要做什么(产品语言),不复制需求原文。
14
15
 
15
- ## 2. 依据与假设
16
+ ## 2. 依据与待确认口径
16
17
 
17
18
  ### 依据(口径 + 来源)
18
19
 
19
20
  | # | 口径 | 来源 |
20
21
  | --- | ------------------------------ | ----------------------------- |
21
22
  | 1 | 「是否加分」与「是否扣分」互斥 | 需求原文第 1 条 |
22
- | 2 | 加分项不汇总进分类分值 | 需求原文第 2 条 |
23
- | 3 | 分值字段现状为 varchar | 代码现状:inspection_class 表 |
24
23
 
25
- ### 假设(待项目经理确认,确认前不开发)
24
+ ### 待确认口径
26
25
 
27
- #### A1
28
- - **问**(prompt):审批被驳回后,申请人能否修改并重新提交?
29
- - **场景**:需求写了审批流程,未说明驳回后的操作
30
- - **选项**:
31
- - opt_resubmit:允许修改后重新提交
32
- - opt_new:不允许,需新建申请
33
- - **研发备注**:代码 `inspection_flow.status=5` 表示 REJECTED(仅研发可见)
26
+ 本端有 **N** 项待项目经理确认,详见 [BACKEND-ASSUMPTIONS.md](./BACKEND-ASSUMPTIONS.md)。确认前不开始开发。
34
27
 
35
- > PM 若需表达复合口径,在 Web Panel **「其他」** 并文字说明。
28
+ > N 与链接由 sync ASSUMPTIONS 时服务端自动更新,AI 不写具体数字。
36
29
 
37
30
  ## 3. 实现步骤
38
31
 
39
32
  1. 第一步做什么(对应哪条口径)
40
- 2. 第二步做什么
41
- 3. ...(通常 3 ~ 6 步,不写代码细节)
42
-
43
- > 若涉及表结构或数据变更,在步骤中注明「开发须产出 `docs/SQL.md`」,SQL 语句不写在本计划内。
44
- > 若涉及接口变更,在步骤中注明「须同步产出 `docs/API.md`」,接口参数表不写在本计划内。
33
+ 2. ...
45
34
 
46
35
  ## 4. 改动文件白名单
47
36
 
48
- > 开发只允许改这些文件;diff 评审会逐一对账,越界会被打回。
49
- > 开发中确需新增,先更新本清单并在群里说明原因。
50
-
51
- - `src/.../InspectionProjectController.java` — 新增保存入参校验
52
- - `src/.../InspectionProjectService.java` — 互斥逻辑
53
- - ...
37
+ - `src/.../Foo.java` — 说明
54
38
  ```
55
39
 
56
40
  ## 前端计划(FRONTEND-PLAN.md)
57
41
 
58
- > 写计划前必须先 **Read** `docs/API.md`;不存在则退出并 `@后端`,禁止自行编造接口或写「期望接口」。
59
-
60
42
  ```markdown
61
43
  # <需求名> · 前端实现计划
62
44
 
63
45
  ## 1. 需求理解
64
46
 
65
- 用 3 ~ 5 行复述本端要做什么(产品语言),不复制需求原文。
47
+ 用 3 ~ 5 行复述本端要做什么(产品语言)。
66
48
 
67
- ## 2. 依据与假设
49
+ ## 2. 依据与待确认口径
68
50
 
69
51
  ### 依据(口径 + 来源)
70
52
 
71
- | # | 口径 | 来源 |
72
- | --- | ------------------------------ | --------------- |
73
- | 1 | 「是否加分」与「是否扣分」互斥 | 需求原文第 1 条 |
74
- | 2 | 加分项不汇总进分类分值 | 需求原文第 2 条 |
53
+ | # | 口径 | 来源 |
54
+ | --- | ---- | ---- |
55
+ | 1 | | |
75
56
 
76
- ### 假设(待项目经理确认,确认前不开发)
57
+ ### 待确认口径
77
58
 
78
- #### A1
79
- - **问**(prompt):…
80
- - **场景**:…
81
- - **选项**:
82
- - opt_a:…
83
- - opt_b:…
84
-
85
- > 无假设时写「无,口径均有依据」。
59
+ 本端有 **N** 项待项目经理确认,详见 [FRONTEND-ASSUMPTIONS.md](./FRONTEND-ASSUMPTIONS.md)。确认前不开始开发。
86
60
 
87
61
  ## 3. 实现步骤
88
62
 
89
- 1. 第一步做什么(对应哪条口径)
90
- 2. 第二步做什么
91
- 3. 对接 `API.md` 中的某某接口(只写调用时机,不复制参数表)
92
- 4. ...
63
+ 1. ...
93
64
 
94
65
  ## 4. 改动文件白名单
95
66
 
96
- - `src/views/inspection/InspectionProjectForm.vue` — 新增「是否加分」单选与互斥逻辑
97
- - `src/api/inspection.ts` — 新增字段透传
98
- - ...
67
+ - `src/.../Foo.vue` — 说明
99
68
 
100
69
  ## 5. 接口对接要点(引用 API.md,禁止复制)
101
70
 
102
- - 列表:<何时请求、首屏传什么>(见 `API.md` § xxx)
103
- - 详情:<选中后怎么走>(见 `API.md` § xxx)
104
- - 注意:<禁止用列表数据代替详情等>
71
+ - ...
105
72
  ```