ai-project-manage-cli 5.0.5 → 5.0.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
@@ -26,7 +26,7 @@ apm init [--name=我的项目]
26
26
 
27
27
  ```bash
28
28
  apm pull <sessionId>
29
- apm sync-document <sessionId> --file docs/PRD.md
29
+ apm sync-document <sessionId> --file PRD
30
30
  apm update-skills
31
31
  apm branch <sessionId>
32
32
  ```
package/dist/index.js CHANGED
@@ -88,6 +88,9 @@ function sessionRulePath(sessionId, apmRoot) {
88
88
  function sessionYamlPath(sessionId, apmRoot) {
89
89
  return join2(sessionDir(sessionId, apmRoot), "session.yaml");
90
90
  }
91
+ function sessionMessagesXmlPath(sessionId, apmRoot) {
92
+ return join2(sessionDir(sessionId, apmRoot), "messages.xml");
93
+ }
91
94
  function documentLocalFileName(platformName) {
92
95
  const trimmed = platformName.trim();
93
96
  if (!trimmed) return "document.md";
@@ -101,6 +104,11 @@ function documentPlatformName(filePath) {
101
104
  }
102
105
  return base;
103
106
  }
107
+ function resolveSessionDocumentPath(sessionId, documentName, apmRoot) {
108
+ const base = basename(documentName.trim().replace(/\\/g, "/"));
109
+ const fileName = documentLocalFileName(base);
110
+ return join2(sessionDocsDir(sessionId, apmRoot), fileName);
111
+ }
104
112
  async function ensureLoggedConfig() {
105
113
  const cfg = await ensureApmConfig();
106
114
  if (!cfg.token) {
@@ -146,9 +154,6 @@ async function copyTemplateFiles(targetDir) {
146
154
  })
147
155
  );
148
156
  }
149
- function resolveCwdPath(file) {
150
- return resolve(process.cwd(), file);
151
- }
152
157
 
153
158
  // src/commands/init.ts
154
159
  async function runInit(name) {
@@ -189,6 +194,10 @@ var requestConfig = {
189
194
  method: "GET",
190
195
  path: "/cli/sessions/members"
191
196
  }),
197
+ listSessionMessages: defineEndpoint({
198
+ method: "GET",
199
+ path: "/cli/messages"
200
+ }),
192
201
  listDocuments: defineEndpoint({
193
202
  method: "GET",
194
203
  path: "/cli/documents"
@@ -440,6 +449,48 @@ import { writeFileSync as writeFileSync4 } from "fs";
440
449
  import { join as join5 } from "path";
441
450
  import { stringify as yamlStringify } from "yaml";
442
451
 
452
+ // src/session-messages-xml.ts
453
+ function escapeXmlAttr(value) {
454
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
455
+ }
456
+ function wrapCdata(value) {
457
+ return `<![CDATA[${value.replace(/]]>/g, "]]]]><![CDATA[>")}]]>`;
458
+ }
459
+ function optionalAttr(name, value) {
460
+ if (value == null || value === "") {
461
+ return "";
462
+ }
463
+ return ` ${name}="${escapeXmlAttr(value)}"`;
464
+ }
465
+ function formatSessionMessagesXml(sessionId, messages) {
466
+ const lines = [
467
+ '<?xml version="1.0" encoding="UTF-8"?>',
468
+ `<messages sessionId="${escapeXmlAttr(sessionId)}">`
469
+ ];
470
+ for (const message of messages) {
471
+ const attrs = [
472
+ `id="${escapeXmlAttr(message.id)}"`,
473
+ `senderId="${escapeXmlAttr(message.senderId)}"`,
474
+ message.sender ? `senderName="${escapeXmlAttr(message.sender.displayName)}"` : "",
475
+ message.sender ? `senderPosition="${escapeXmlAttr(message.sender.position)}"` : "",
476
+ message.sender ? `proxyMode="${escapeXmlAttr(message.sender.proxyMode)}"` : "",
477
+ `status="${escapeXmlAttr(message.status)}"`,
478
+ `createdAt="${escapeXmlAttr(message.createdAt)}"`,
479
+ `contentUpdatedAt="${escapeXmlAttr(message.contentUpdatedAt)}"`
480
+ ].filter(Boolean).join(" ");
481
+ lines.push(
482
+ ` <message ${attrs}${optionalAttr(
483
+ "roundId",
484
+ message.roundId
485
+ )}${optionalAttr("sentAt", message.sentAt)}>`,
486
+ ` <content>${wrapCdata(message.content)}</content>`,
487
+ " </message>"
488
+ );
489
+ }
490
+ lines.push("</messages>", "");
491
+ return lines.join("\n");
492
+ }
493
+
443
494
  // src/commands/sync-session-attachments.ts
444
495
  import { writeFileSync as writeFileSync3 } from "fs";
445
496
  import { join as join4 } from "path";
@@ -480,12 +531,15 @@ async function runPull(sessionId, apmRoot) {
480
531
  }
481
532
  const cfg = await ensureLoggedConfig();
482
533
  const api = createApmApiClient(cfg);
483
- const [detail, members, documents, attachments] = await Promise.all([
484
- api.cli.sessionDetail({ sessionId: trimmedId }),
485
- api.cli.sessionMembers({ sessionId: trimmedId }),
486
- api.cli.listDocuments({ sessionId: trimmedId }),
487
- api.cli.listAttachments({ sessionId: trimmedId })
488
- ]);
534
+ const [detail, members, documents, attachments, messages] = await Promise.all(
535
+ [
536
+ api.cli.sessionDetail({ sessionId: trimmedId }),
537
+ api.cli.sessionMembers({ sessionId: trimmedId }),
538
+ api.cli.listDocuments({ sessionId: trimmedId }),
539
+ api.cli.listAttachments({ sessionId: trimmedId }),
540
+ api.cli.listSessionMessages({ sessionId: trimmedId })
541
+ ]
542
+ );
489
543
  const dir = sessionDir(trimmedId, apmRoot);
490
544
  const docsDir = sessionDocsDir(trimmedId, apmRoot);
491
545
  await ensureDirExists(docsDir);
@@ -519,6 +573,11 @@ async function runPull(sessionId, apmRoot) {
519
573
  `,
520
574
  "utf8"
521
575
  );
576
+ writeFileSync4(
577
+ sessionMessagesXmlPath(trimmedId, apmRoot),
578
+ formatSessionMessagesXml(trimmedId, messages),
579
+ "utf8"
580
+ );
522
581
  await syncSessionAttachments(cfg, trimmedId, attachments, apmRoot);
523
582
  console.log(`[apm] \u5DF2\u540C\u6B65\u4F1A\u8BDD\u5DE5\u4F5C\u533A: ${dir}`);
524
583
  return dir;
@@ -648,12 +707,16 @@ async function runSyncDocument(sessionId, options) {
648
707
  }
649
708
  const fileArg = options.file?.trim();
650
709
  if (!fileArg) {
651
- console.error("[apm] \u8BF7\u6307\u5B9A --file <\u672C\u5730\u8DEF\u5F84>");
710
+ console.error("[apm] \u8BF7\u6307\u5B9A --file <\u6587\u6863\u540D\u79F0>");
652
711
  process.exit(1);
653
712
  }
654
- const absPath = resolveCwdPath(fileArg);
713
+ const absPath = resolveSessionDocumentPath(trimmedSessionId, fileArg);
655
714
  if (!existsSync3(absPath)) {
656
- console.error(`[apm] \u6587\u6863\u4E0D\u5B58\u5728: ${absPath}`);
715
+ const docsDir = sessionDocsDir(trimmedSessionId);
716
+ console.error(
717
+ `[apm] \u6587\u6863\u4E0D\u5B58\u5728: ${absPath}
718
+ [apm] \u8BF7\u786E\u8BA4\u5DF2 pull\uFF0C\u4E14 ${docsDir} \u4E0B\u5B58\u5728\u5BF9\u5E94\u6587\u4EF6`
719
+ );
657
720
  process.exit(1);
658
721
  }
659
722
  const content = readFileSync4(absPath, "utf8");
@@ -1766,7 +1829,10 @@ function buildProgram() {
1766
1829
  ).argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").action(async (sessionId) => {
1767
1830
  await runPull(sessionId);
1768
1831
  });
1769
- program.command("sync-document").description("\u5C06\u672C\u5730 Markdown \u8986\u76D6\u5F0F upsert \u5230\u5E73\u53F0\u9700\u6C42\u6587\u6863").argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").requiredOption("--file <path>", "\u672C\u5730\u6587\u4EF6\u8DEF\u5F84").action(async (sessionId, opts) => {
1832
+ program.command("sync-document").description("\u5C06\u672C\u5730 Markdown \u8986\u76D6\u5F0F upsert \u5230\u5E73\u53F0\u9700\u6C42\u6587\u6863").argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").requiredOption(
1833
+ "--file <name>",
1834
+ "\u6587\u6863\u540D\u79F0\uFF08\u5982 PRD \u6216 PRD.md\uFF09\uFF0C\u8BFB\u53D6 .apm/sessions/<sessionId>/docs/ \u4E0B\u5BF9\u5E94\u6587\u4EF6"
1835
+ ).action(async (sessionId, opts) => {
1770
1836
  await runSyncDocument(sessionId, { file: opts.file });
1771
1837
  });
1772
1838
  program.command("append-message").description("\u5411\u5E73\u53F0\u4F1A\u8BDD\u6D88\u606F\u8FFD\u52A0\u5185\u5BB9\uFF08PUT /api/cli/messages/content\uFF09").requiredOption("--id <messageId>", "\u6D88\u606F ID").requiredOption("--content <content>", "\u8981\u8FFD\u52A0\u7684\u6D88\u606F\u5185\u5BB9").action(async (opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "5.0.5",
3
+ "version": "5.0.7",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -0,0 +1,22 @@
1
+ ## APM 指南
2
+
3
+ ### 回复消息命令
4
+
5
+ - 命令: `apm append-message --id=<消息ID> --content=<消息内容>`
6
+ - 注意事项:如果消息内容中包含文档地址,不要把前缀也写出来,直接用文档名称即可,并且文档名称要用倒引号包裹
7
+
8
+ ### 创建/更新群文档命令
9
+
10
+ - 命令: `apm sync-document <会话ID> --file <文档名称>`
11
+ - 注意事项:文档名称是指`.apm/sessions/<会话ID>/` 这个目录下的某个文档,参数直接文档名称,比如 PRD.md。
12
+
13
+ ## 工作流程
14
+
15
+ - 读取 `.apm/sessions/<会话ID>/session.yaml`,必要时读取`messages.xml` 了解当前会话状态与历史消息
16
+ - 根据用户提示找到你对应的人设(system_persona)
17
+ - 根据人设完成用户指定的任务
18
+
19
+ ## 目录声明
20
+
21
+ - 技能目录: ./skills
22
+ - 群文档目录: ./sessions/<会话 ID>/docs