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 +1 -1
- package/dist/index.js +79 -13
- package/package.json +1 -1
- package/template/AGENTS.md +22 -0
package/README.md
CHANGED
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, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
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
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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 <\
|
|
710
|
+
console.error("[apm] \u8BF7\u6307\u5B9A --file <\u6587\u6863\u540D\u79F0>");
|
|
652
711
|
process.exit(1);
|
|
653
712
|
}
|
|
654
|
-
const absPath =
|
|
713
|
+
const absPath = resolveSessionDocumentPath(trimmedSessionId, fileArg);
|
|
655
714
|
if (!existsSync3(absPath)) {
|
|
656
|
-
|
|
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(
|
|
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
|
@@ -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
|