ai-project-manage-cli 6.0.31 → 6.0.33

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
@@ -238,6 +238,10 @@ var requestConfig = {
238
238
  method: "PUT",
239
239
  path: "/cli/messages/content"
240
240
  }),
241
+ setMessageError: defineEndpoint({
242
+ method: "PUT",
243
+ path: "/cli/messages/error"
244
+ }),
241
245
  upsertCursorMessageLog: defineEndpoint({
242
246
  method: "PUT",
243
247
  path: "/cli/cursor-message-logs"
@@ -496,11 +500,14 @@ import { join as join5 } from "path";
496
500
  import { stringify as yamlStringify } from "yaml";
497
501
 
498
502
  // src/session-messages-xml.ts
503
+ function asXmlText(value) {
504
+ return value ?? "";
505
+ }
499
506
  function escapeXmlAttr(value) {
500
- return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
507
+ return asXmlText(value).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
501
508
  }
502
509
  function wrapCdata(value) {
503
- return `<![CDATA[${value.replace(/]]>/g, "]]]]><![CDATA[>")}]]>`;
510
+ return `<![CDATA[${asXmlText(value).replace(/]]>/g, "]]]]><![CDATA[>")}]]>`;
504
511
  }
505
512
  function formatSessionMessagesXml(sessionId, messages) {
506
513
  const lines = [
@@ -1496,10 +1503,10 @@ async function updateMessageStatus(cfg, messageId, status) {
1496
1503
  await api.cli.updateMessageStatus({ id: messageId, status });
1497
1504
  console.log(`[apm] \u5DF2\u66F4\u65B0\u6D88\u606F\u72B6\u6001: ${messageId} \u2192 ${status}`);
1498
1505
  }
1499
- async function appendMessageContent(cfg, messageId, content) {
1506
+ async function setMessageError(cfg, messageId, error) {
1500
1507
  const api = createApmApiClient(cfg);
1501
- await api.cli.appendMessageContent({ id: messageId, content });
1502
- console.log(`[apm] \u5DF2\u8FFD\u52A0\u6D88\u606F\u5185\u5BB9: ${messageId}`);
1508
+ await api.cli.setMessageError({ id: messageId, error });
1509
+ console.log(`[apm] \u5DF2\u8BBE\u7F6E\u6D88\u606F\u9519\u8BEF: ${messageId}`);
1503
1510
  }
1504
1511
  var SHUTDOWN_DRAIN_MS = 3e3;
1505
1512
  async function handleInboundMessage(cfg, raw, signal) {
@@ -1522,48 +1529,78 @@ async function handleInboundMessage(cfg, raw, signal) {
1522
1529
  }
1523
1530
  const msg = validated.data;
1524
1531
  const messageId = msg.messageId;
1532
+ const runStep = async (step, fn) => {
1533
+ try {
1534
+ return await fn();
1535
+ } catch (err) {
1536
+ const detail = err instanceof Error ? err.message : String(err);
1537
+ throw new Error(`[${step}] ${detail}`);
1538
+ }
1539
+ };
1525
1540
  try {
1526
1541
  if (signal.aborted) return;
1527
- await runBranch(msg.sessionId, { cwd: msg.workdir });
1542
+ await runStep(
1543
+ "branch",
1544
+ () => runBranch(msg.sessionId, { cwd: msg.workdir })
1545
+ );
1528
1546
  if (signal.aborted) return;
1529
- await runPull(msg.sessionId, workspaceApmDir(msg.workdir));
1547
+ await runStep(
1548
+ "pull",
1549
+ () => runPull(msg.sessionId, workspaceApmDir(msg.workdir))
1550
+ );
1530
1551
  if (signal.aborted) return;
1531
- await commitWorkingTreeIfDirty(msg.workdir, "fix: apm pull");
1552
+ await runStep(
1553
+ "commit-pull",
1554
+ () => commitWorkingTreeIfDirty(msg.workdir, "fix: apm pull")
1555
+ );
1532
1556
  if (signal.aborted) return;
1533
- await updateMessageStatus(cfg, messageId, "TYPING");
1534
- await runCursorAgent(
1535
- cfg,
1536
- {
1537
- messageId: msg.messageId,
1538
- sessionId: msg.sessionId,
1539
- prompt: msg.content,
1540
- model: msg.model,
1541
- apiKey: msg.apiKey,
1542
- workdir: msg.workdir
1543
- },
1544
- { signal }
1557
+ await runStep(
1558
+ "status-typing",
1559
+ () => updateMessageStatus(cfg, messageId, "TYPING")
1560
+ );
1561
+ await runStep(
1562
+ "cursor-agent",
1563
+ () => runCursorAgent(
1564
+ cfg,
1565
+ {
1566
+ messageId: msg.messageId,
1567
+ sessionId: msg.sessionId,
1568
+ prompt: msg.content,
1569
+ model: msg.model,
1570
+ apiKey: msg.apiKey,
1571
+ workdir: msg.workdir
1572
+ },
1573
+ { signal }
1574
+ )
1545
1575
  );
1546
- await syncSessionDocuments(
1547
- cfg,
1548
- msg.sessionId,
1549
- workspaceApmDir(msg.workdir)
1576
+ await runStep(
1577
+ "sync-documents",
1578
+ () => syncSessionDocuments(cfg, msg.sessionId, workspaceApmDir(msg.workdir))
1550
1579
  );
1551
- await commitWorkingTreeIfDirty(
1552
- msg.workdir,
1553
- "chore(apm): sync session documents"
1580
+ await runStep(
1581
+ "commit-documents",
1582
+ () => commitWorkingTreeIfDirty(
1583
+ msg.workdir,
1584
+ "chore(apm): sync session documents"
1585
+ )
1586
+ );
1587
+ await runStep(
1588
+ "status-success",
1589
+ () => updateMessageStatus(cfg, messageId, "SUCCESS")
1554
1590
  );
1555
- await updateMessageStatus(cfg, messageId, "SUCCESS");
1556
1591
  } catch (err) {
1557
1592
  console.error(
1558
1593
  "[apm] \u5904\u7406\u6D88\u606F\u5931\u8D25:",
1559
1594
  err instanceof Error ? err.message : err
1560
1595
  );
1596
+ if (err instanceof Error && err.stack) {
1597
+ console.error(err.stack);
1598
+ }
1561
1599
  try {
1562
- await appendMessageContent(
1600
+ await setMessageError(
1563
1601
  cfg,
1564
1602
  messageId,
1565
- `\u5904\u7406\u6D88\u606F\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}
1566
- `
1603
+ err instanceof Error ? err.message : String(err)
1567
1604
  );
1568
1605
  await updateMessageStatus(cfg, messageId, "FAILED");
1569
1606
  } catch (statusErr) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "6.0.31",
3
+ "version": "6.0.33",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -11,6 +11,8 @@
11
11
  内容要求如下:
12
12
  **不管是第几版需求,都要当成第一版来看,禁止有历史版本或者修订版本或者第几版更新的字样**
13
13
 
14
+ **可读性**:信息完整保留,但避免整段只靠长句堆砌。对流程分支、状态条件、按钮对照、范围边界等多步骤/多条件内容,按模板中的「图示原则」**适当补充 Mermaid 图或简表**(每个需求点 0 ~ 1 张);图示用于快速扫读,**可验收细节仍以 bullet 为准**,不得因配图而删减文字要求。
15
+
14
16
  ### 步骤 3: 同步 PRD 到远程
15
17
 
16
18
  执行命令:`apm sync-document <会话 ID> --file=PRD.md`
@@ -1,17 +1,43 @@
1
-
2
1
  ## 需求模板
2
+
3
+ ### 图示原则
4
+
5
+ 信息量保持完整,**文字与图示互补**:bullet 写清可验收细节,图示帮助读者快速建立整体印象。优先用 **Mermaid**(Markdown 内嵌,无需额外图片文件)。
6
+
7
+ | 场景 | 推荐图示 | 作用 |
8
+ | ------------------------------------------- | -------------------------------- | -------------------------- |
9
+ | 多步骤操作流程(审批、暂存/提交、办理路径) | `flowchart` | 一眼看清先后与分支 |
10
+ | 字段展示/必填随状态变化 | `flowchart` 或 `stateDiagram-v2` | 替代「当 A 且 B 时…」长句 |
11
+ | 弹窗/页面内区块与按钮布局 | `block-beta` 或 ASCII 框图 | 标出按钮位置与对照关系 |
12
+ | 多需求点关系、范围边界 | `mindmap` 或简表 | 开篇总览,再展开 bullet |
13
+ | 角色与系统交互时序 | `sequenceDiagram` | 仅步骤多、文字难扫读时使用 |
14
+
15
+ **图示写法**:
16
+
17
+ - 每个需求点 **0 ~ 1 张** 图即可;一张图只表达一个核心概念,节点用业务语言(如「一级审批」「暂存」)。
18
+ - 图 **不替代** bullet:图后仍保留 2 ~ 5 条可验收 bullet,图中未写清的细节(文案、边界、校验时机)必须在文字中写明。
19
+ - 图为辅助:若单条 bullet 已足够清楚,**不必强行配图**。
20
+
3
21
  ### 正文骨架
22
+
4
23
  ```markdown
5
24
  ## 背景
25
+
6
26
  (1 ~ 3 句:业务背景、要解决的问题、预期效果,如果没有可空着,不要强行编)
7
27
 
8
28
  ## 范围
29
+
9
30
  - **包含**:…
10
31
  - **不包含**:…
11
32
 
33
+ (可选:范围较大时,用 mindmap 或简表做一页总览)
34
+
12
35
  ## 需求说明
13
36
 
14
37
  ### 需求点 1:[简短名称]
38
+
39
+ (可选:流程/状态/布局类需求,在此放一张 Mermaid 图)
40
+
15
41
  - …
16
42
  - …
17
43
 
@@ -42,14 +68,67 @@
42
68
 
43
69
  ### 需求点 3:「科室医德考评小组人员名单」字段
44
70
 
71
+ (本需求点适合在 bullet 前加「字段展示与校验」流程图,见下方「图示示例」)
72
+
45
73
  - 原字段展示名 **「科室医德考评人员名单」** 统一改为 **「科室医德考评小组人员名单」**;凡界面、提示、校验文案等涉及该名称处**一并修改**。
46
74
  - 当流程处于 **一级审批** 且该字段**展示**时,须校验为**必填**(在展示场景下触发,而非所有保存入口一律校验)。
47
75
  ```
48
76
 
77
+ ### 图示示例(按需选用)
78
+
79
+ **字段展示与校验**(对应上文需求点 3):
80
+
81
+ ```mermaid
82
+ flowchart LR
83
+ A[进入表单] --> B{流程处于一级审批?}
84
+ B -->|是| C[展示该字段]
85
+ B -->|否| D[按原规则展示/隐藏]
86
+ C --> E{用户操作}
87
+ E -->|暂存或提交| F[校验必填]
88
+ E -->|仅浏览未保存| G[不触发必填校验]
89
+ ```
90
+
91
+ **流程分支**(暂存 vs 提交、审批节点):
92
+
93
+ ```mermaid
94
+ flowchart TD
95
+ A[用户打开新增/编辑弹窗] --> B[填写表单]
96
+ B --> C{点击底部按钮}
97
+ C -->|暂存| D[沿用原「确定」逻辑:校验 + 保存,不推进流程]
98
+ C -->|提交| E[沿用原「办理」逻辑:校验 + 保存并推进流程]
99
+ ```
100
+
101
+ **弹窗底部按钮布局**(对照既有按钮):
102
+
103
+ ```text
104
+ ┌─────────────────────────────────────┐
105
+ │ 新增 / 编辑弹窗 │
106
+ │ …表单字段… │
107
+ ├─────────────────────────────────────┤
108
+ │ [ 取消 ] [ 暂存 ] │ ← 暂存:原「确定」逻辑,仅改文案
109
+ └─────────────────────────────────────┘
110
+ ```
111
+
112
+ **范围总览**(需求点较多时,放在「范围」之后):
113
+
114
+ ```mermaid
115
+ mindmap
116
+ root((本需求))
117
+ 包含
118
+ 弹窗底部操作
119
+ 字段更名与校验
120
+ 不包含
121
+ 历史数据迁移
122
+ 导出能力
123
+ ```
124
+
49
125
  ### 自检列表
126
+
50
127
  - [ ] 含 **背景与目标、范围、需求说明** 三章,叙述完整
51
128
  - [ ] 2 分钟内可通读;每个需求点 2 ~ 5 条 bullet,一层列表
129
+ - [ ] 流程/状态/多分支类需求点有 **图示或简表** 辅助,且 bullet 仍覆盖图中未写清的细节
130
+ - [ ] 图示节点使用业务语言,与正文术语一致;无仅看图无法验收的遗漏
52
131
  - [ ] 场景、按钮行为、校验时机表述清楚,前后一致
53
132
  - [ ] 「范围」与需求点中的 **「不考虑」** 口径一致
54
133
  - [ ] 全文使用业务语言,术语统一
55
- - [ ] 仅材料明确涉及时才有「非功能」「待确认」
134
+ - [ ] 仅材料明确涉及时才有「非功能」「待确认」