ai-project-manage-cli 5.0.14 → 5.0.16

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
@@ -10,6 +10,12 @@ import { join } from "path";
10
10
  var APM_CONFIG_DIR = join(homedir(), ".config", "apm");
11
11
  var APM_CONFIG_PATH = join(APM_CONFIG_DIR, "config.json");
12
12
  var DEFAULT_BASE_URL = "http://127.0.0.1:3000";
13
+ function resolveClientMachineId(cfg) {
14
+ return (cfg.clientMachineId ?? cfg.userId ?? "").trim();
15
+ }
16
+ function resolveAccount(cfg) {
17
+ return (cfg.account ?? cfg.email ?? "").trim();
18
+ }
13
19
  async function readApmConfig() {
14
20
  try {
15
21
  const raw = readFileSync(APM_CONFIG_PATH, "utf8");
@@ -18,14 +24,17 @@ async function readApmConfig() {
18
24
  return null;
19
25
  }
20
26
  const rawCfg = v;
21
- if (typeof rawCfg.baseUrl !== "string" || typeof rawCfg.userId !== "string" || typeof rawCfg.token !== "string") {
27
+ if (typeof rawCfg.baseUrl !== "string" || typeof rawCfg.token !== "string") {
22
28
  return null;
23
29
  }
24
30
  const cfg = v;
31
+ const clientMachineId = resolveClientMachineId(cfg);
32
+ const account = resolveAccount(cfg);
25
33
  return {
26
34
  baseUrl: cfg.baseUrl.trim().replace(/\/+$/, ""),
27
- userId: cfg.userId,
28
35
  token: cfg.token,
36
+ ...clientMachineId ? { clientMachineId } : {},
37
+ ...account ? { account } : {},
29
38
  ...typeof cfg.email === "string" ? { email: cfg.email } : {}
30
39
  };
31
40
  } catch {
@@ -35,8 +44,9 @@ async function readApmConfig() {
35
44
  function defaultApmConfig() {
36
45
  return {
37
46
  baseUrl: DEFAULT_BASE_URL,
38
- userId: "",
47
+ clientMachineId: "",
39
48
  token: "",
49
+ account: "",
40
50
  email: ""
41
51
  };
42
52
  }
@@ -54,11 +64,13 @@ async function ensureApmConfig() {
54
64
  return defaults;
55
65
  }
56
66
  async function writeApmConfig(cfg) {
67
+ const clientMachineId = resolveClientMachineId(cfg);
68
+ const account = resolveAccount(cfg);
57
69
  const normalized = {
58
70
  baseUrl: cfg.baseUrl.trim().replace(/\/+$/, ""),
59
- userId: cfg.userId,
60
71
  token: cfg.token,
61
- ...typeof cfg.email === "string" ? { email: cfg.email } : {}
72
+ ...clientMachineId ? { clientMachineId } : {},
73
+ ...account ? { account, email: account } : {}
62
74
  };
63
75
  mkdirSync(APM_CONFIG_DIR, { recursive: true });
64
76
  writeFileSync(APM_CONFIG_PATH, JSON.stringify(normalized, null, 2) + "\n", {
@@ -96,6 +108,12 @@ function sessionDocsDir(sessionId, apmRoot) {
96
108
  function sessionRulePath(sessionId, apmRoot) {
97
109
  return join2(sessionDir(sessionId, apmRoot), "RULE.md");
98
110
  }
111
+ function sessionTaskPath(sessionId, apmRoot) {
112
+ return join2(sessionDir(sessionId, apmRoot), "TASK.md");
113
+ }
114
+ function sessionLogPath(sessionId, apmRoot) {
115
+ return join2(sessionDir(sessionId, apmRoot), "LOG.md");
116
+ }
99
117
  function sessionYamlPath(sessionId, apmRoot) {
100
118
  return join2(sessionDir(sessionId, apmRoot), "session.yaml");
101
119
  }
@@ -231,7 +249,7 @@ var requestConfig = {
231
249
  }),
232
250
  branchBaseline: defineEndpoint({
233
251
  method: "GET",
234
- path: "/cli/requirements/branch-baseline"
252
+ path: "/cli/tasks/branch-baseline"
235
253
  }),
236
254
  listSkills: defineEndpoint({
237
255
  method: "GET",
@@ -256,13 +274,13 @@ async function runLogin(opts) {
256
274
  const baseUrl = (opts.server?.trim() || process.env.AI_PM_SERVER?.trim() || DEFAULT_BASE_URL).replace(/\/+$/, "");
257
275
  const api = createApmApiClient({
258
276
  baseUrl,
259
- userId: "",
277
+ clientMachineId: "",
260
278
  token: ""
261
279
  });
262
280
  let data;
263
281
  try {
264
282
  data = await api.auth.login({
265
- email: opts.email,
283
+ account: opts.email,
266
284
  password: opts.password
267
285
  });
268
286
  } catch (raw) {
@@ -277,24 +295,29 @@ async function runLogin(opts) {
277
295
  console.error("[apm] \u8BF7\u6C42\u5931\u8D25:", raw instanceof Error ? raw.message : raw);
278
296
  process.exit(1);
279
297
  }
280
- const userId = data?.user?.id;
298
+ const clientMachineId = data?.clientMachine?.id;
281
299
  const token = data?.token;
282
- if (!userId || !token) {
300
+ if (!clientMachineId || !token) {
283
301
  console.error(
284
- "[apm] \u54CD\u5E94\u7F3A\u5C11 user.id / token\uFF08\u8BF7\u786E\u8BA4\u670D\u52A1\u7AEF\u4E3A /api/v1/auth/login\uFF09"
302
+ "[apm] \u54CD\u5E94\u7F3A\u5C11 clientMachine.id / token\uFF08\u8BF7\u786E\u8BA4\u670D\u52A1\u7AEF\u4E3A /api/v1/auth/login\uFF09"
285
303
  );
286
304
  process.exit(1);
287
305
  }
288
306
  const cfg = {
289
307
  baseUrl,
290
- userId,
308
+ clientMachineId,
291
309
  token,
310
+ account: opts.email,
292
311
  email: opts.email
293
312
  };
294
313
  await writeApmConfig(cfg);
295
314
  console.error(`[apm] \u5DF2\u4FDD\u5B58\u767B\u5F55\u4FE1\u606F: ${APM_CONFIG_PATH}`);
296
315
  console.log(
297
- JSON.stringify({ userId: cfg.userId, baseUrl: cfg.baseUrl }, null, 2)
316
+ JSON.stringify(
317
+ { clientMachineId: cfg.clientMachineId, baseUrl: cfg.baseUrl },
318
+ null,
319
+ 2
320
+ )
298
321
  );
299
322
  }
300
323
 
@@ -489,7 +512,7 @@ function formatSessionMessagesXml(sessionId, messages) {
489
512
  lines.push(
490
513
  ` <message id="${escapeXmlAttr(message.id)}" name="${escapeXmlAttr(
491
514
  message.name
492
- )}" position="${escapeXmlAttr(message.position)}"${roundAttr}>`,
515
+ )}" expert="${escapeXmlAttr(message.expert)}"${roundAttr}>`,
493
516
  ` <content>${wrapCdata(message.content)}</content>`,
494
517
  " </message>"
495
518
  );
@@ -603,6 +626,12 @@ async function runPull(sessionId, apmRoot) {
603
626
  detail.description ?? "",
604
627
  "utf8"
605
628
  );
629
+ writeFileSync4(
630
+ sessionTaskPath(trimmedId, apmRoot),
631
+ detail.task.description ?? "",
632
+ "utf8"
633
+ );
634
+ writeFileSync4(sessionLogPath(trimmedId, apmRoot), detail.log ?? "", "utf8");
606
635
  for (const doc of documents) {
607
636
  const fileName = documentLocalFileName(doc.name);
608
637
  writeFileSync4(join5(docsDir, fileName), doc.content ?? "", "utf8");
@@ -613,7 +642,7 @@ async function runPull(sessionId, apmRoot) {
613
642
  description: "./RULE.md",
614
643
  members: members.map((m) => ({
615
644
  name: m.displayName,
616
- position: m.position,
645
+ expert: m.expert,
617
646
  system_persona: m.systemPersona,
618
647
  skills: []
619
648
  })),
@@ -734,6 +763,7 @@ import {
734
763
  import { join as join7 } from "path";
735
764
  var AGENTS_TEMPLATE_PATH = join7(CLI_TEMPLATE_DIR, "AGENTS.md");
736
765
  var BASE_SKILLS_TEMPLATE_DIR = join7(CLI_TEMPLATE_DIR, "skills");
766
+ var BASE_RULES_TEMPLATE_DIR = join7(CLI_TEMPLATE_DIR, "rules");
737
767
  function sanitizeSkillDirName(name) {
738
768
  const trimmed = name.trim();
739
769
  if (!trimmed) return "skill";
@@ -752,6 +782,23 @@ function syncAgentsGuide(apmDir) {
752
782
  copyFileSync(AGENTS_TEMPLATE_PATH, join7(apmDir, "AGENTS.md"));
753
783
  return true;
754
784
  }
785
+ function listBaseRuleFileNames() {
786
+ if (!existsSync3(BASE_RULES_TEMPLATE_DIR)) return [];
787
+ return readdirSync2(BASE_RULES_TEMPLATE_DIR).filter((name) => {
788
+ const path8 = join7(BASE_RULES_TEMPLATE_DIR, name);
789
+ return statSync2(path8).isFile();
790
+ });
791
+ }
792
+ function syncBaseRules(rulesDir) {
793
+ mkdirSync3(rulesDir, { recursive: true });
794
+ const names = listBaseRuleFileNames();
795
+ for (const name of names) {
796
+ const src = join7(BASE_RULES_TEMPLATE_DIR, name);
797
+ const dest = join7(rulesDir, name);
798
+ copyFileSync(src, dest);
799
+ }
800
+ return names;
801
+ }
755
802
  function syncBaseSkills(skillsDir) {
756
803
  mkdirSync3(skillsDir, { recursive: true });
757
804
  const names = listBaseSkillDirNames();
@@ -809,6 +856,11 @@ async function runUpdateSkills() {
809
856
  if (syncAgentsGuide(apmDir)) {
810
857
  console.log("[apm] \u5DF2\u540C\u6B65 APM \u6307\u5357: .apm/AGENTS.md");
811
858
  }
859
+ const rulesDir = join8(apmDir, "rules");
860
+ const ruleNames = syncBaseRules(rulesDir);
861
+ for (const name of ruleNames) {
862
+ console.log(`[apm] \u5DF2\u540C\u6B65\u57FA\u7840\u89C4\u5219: rules/${name}`);
863
+ }
812
864
  const skillsDir = join8(apmDir, "skills");
813
865
  mkdirSync4(skillsDir, { recursive: true });
814
866
  const baseNames = syncBaseSkills(skillsDir);
@@ -831,7 +883,7 @@ async function runUpdateSkills() {
831
883
  console.log(`[apm] \u5DF2\u79FB\u9664\u5DF2\u4E0B\u7EBF\u7684\u8865\u5145\u6280\u80FD: skills/${name}/`);
832
884
  }
833
885
  console.log(
834
- `[apm] \u6280\u80FD\u540C\u6B65\u5B8C\u6210\uFF1A${baseNames.length} \u4E2A\u57FA\u7840\u6280\u80FD\uFF0C${written.length} \u4E2A\u8865\u5145\u6280\u80FD`
886
+ `[apm] \u540C\u6B65\u5B8C\u6210\uFF1A${ruleNames.length} \u4E2A\u57FA\u7840\u89C4\u5219\uFF0C${baseNames.length} \u4E2A\u57FA\u7840\u6280\u80FD\uFF0C${written.length} \u4E2A\u8865\u5145\u6280\u80FD`
835
887
  );
836
888
  }
837
889
 
@@ -1102,6 +1154,7 @@ async function handleInboundMessage(cfg, raw) {
1102
1154
  try {
1103
1155
  await runBranch(msg.sessionId, { cwd: msg.workdir });
1104
1156
  await runPull(msg.sessionId, workspaceApmDir(msg.workdir));
1157
+ await commitWorkingTreeIfDirty(msg.workdir, "fix: apm pull");
1105
1158
  await updateMessageStatus(cfg, messageId, "TYPING");
1106
1159
  await runCursorAgent(cfg, {
1107
1160
  messageId: msg.messageId,
@@ -1134,13 +1187,13 @@ async function handleInboundMessage(cfg, raw) {
1134
1187
  }
1135
1188
  }
1136
1189
  }
1137
- function startHeartbeat(ws, userId) {
1190
+ function startHeartbeat(ws, clientMachineId) {
1138
1191
  const send = () => {
1139
1192
  if (ws.readyState === WebSocket.OPEN) {
1140
1193
  ws.send(
1141
1194
  serializeAgentWsMessage({
1142
1195
  type: "heartbeat",
1143
- userId
1196
+ userId: clientMachineId
1144
1197
  })
1145
1198
  );
1146
1199
  }
@@ -1154,8 +1207,9 @@ async function runConnect(options) {
1154
1207
  if (options.server?.trim()) {
1155
1208
  cfg.baseUrl = options.server.trim().replace(/\/+$/, "");
1156
1209
  }
1157
- if (!cfg.userId?.trim()) {
1158
- console.error("[apm] config \u7F3A\u5C11 userId\uFF0C\u8BF7\u91CD\u65B0 apm login");
1210
+ const clientMachineId = resolveClientMachineId(cfg);
1211
+ if (!clientMachineId) {
1212
+ console.error("[apm] config \u7F3A\u5C11 clientMachineId\uFF0C\u8BF7\u91CD\u65B0 apm login");
1159
1213
  process.exit(1);
1160
1214
  }
1161
1215
  const url = buildAgentWsUrl(cfg.baseUrl, cfg.token);
@@ -1178,7 +1232,7 @@ async function runConnect(options) {
1178
1232
  };
1179
1233
  ws.on("open", () => {
1180
1234
  console.log("[apm] WebSocket \u5DF2\u8FDE\u63A5");
1181
- stopHeartbeat = startHeartbeat(ws, cfg.userId);
1235
+ stopHeartbeat = startHeartbeat(ws, clientMachineId);
1182
1236
  });
1183
1237
  ws.on("message", (data) => {
1184
1238
  const text = Buffer.isBuffer(data) ? data.toString("utf8") : String(data);
@@ -1862,40 +1916,6 @@ function registerDeployBackendCommands(program) {
1862
1916
  import { copyFile, readdir as readdir2, stat } from "node:fs/promises";
1863
1917
  import path7 from "node:path";
1864
1918
 
1865
- // src/commands/deploy/internal/load-apm-dotenv.ts
1866
- import { existsSync as existsSync10, readFileSync as readFileSync9 } from "node:fs";
1867
- import { join as join9 } from "node:path";
1868
- function loadApmDotEnvIfPresent() {
1869
- const p = join9(workspaceApmDir(), ".env");
1870
- if (!existsSync10(p)) {
1871
- return;
1872
- }
1873
- let text;
1874
- try {
1875
- text = readFileSync9(p, "utf8");
1876
- } catch {
1877
- return;
1878
- }
1879
- for (const line of text.split("\n")) {
1880
- const t = line.trim();
1881
- if (!t || t.startsWith("#")) {
1882
- continue;
1883
- }
1884
- const eq = t.indexOf("=");
1885
- if (eq <= 0) {
1886
- continue;
1887
- }
1888
- const key = t.slice(0, eq).trim();
1889
- let val = t.slice(eq + 1).trim();
1890
- if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
1891
- val = val.slice(1, -1);
1892
- }
1893
- if (process.env[key] === void 0) {
1894
- process.env[key] = val;
1895
- }
1896
- }
1897
- }
1898
-
1899
1919
  // src/commands/deploy/internal/minio.ts
1900
1920
  import { statSync as statSync5 } from "node:fs";
1901
1921
  import { readdir, readFile } from "node:fs/promises";
@@ -2059,31 +2079,6 @@ function artifactObjectKey(namePrefix, branchSegment, relativePath) {
2059
2079
  const rel = sanitizeRelativePath(relativePath);
2060
2080
  return `${base}/${branchSegment}/dist/${rel}`;
2061
2081
  }
2062
- function mergeMinioFromEnv(settings) {
2063
- const ep = process.env.MINIO_ENDPOINT?.trim();
2064
- const portRaw = process.env.MINIO_PORT?.trim();
2065
- const sslRaw = process.env.MINIO_USE_SSL?.trim().toLowerCase();
2066
- const ak = process.env.MINIO_ACCESS_KEY?.trim();
2067
- const sk = process.env.MINIO_SECRET_KEY?.trim();
2068
- const bucket = process.env.MINIO_BUCKET?.trim();
2069
- const port = portRaw ? Number.parseInt(portRaw, 10) : void 0;
2070
- let useSsl = settings.useSsl;
2071
- if (sslRaw === "true" || sslRaw === "1") {
2072
- useSsl = true;
2073
- }
2074
- if (sslRaw === "false" || sslRaw === "0") {
2075
- useSsl = false;
2076
- }
2077
- return {
2078
- ...settings,
2079
- endpoint: ep || settings.endpoint,
2080
- port: port !== void 0 && Number.isFinite(port) && port > 0 ? port : settings.port,
2081
- useSsl,
2082
- accessKey: ak || settings.accessKey,
2083
- secretKey: sk || settings.secretKey,
2084
- bucket: bucket || settings.bucket
2085
- };
2086
- }
2087
2082
  async function ensureArtifactRootIndexHtml(root) {
2088
2083
  const indexHtmlPath = path7.join(root, "index.html");
2089
2084
  try {
@@ -2124,7 +2119,7 @@ async function ensureArtifactRootIndexHtml(root) {
2124
2119
  }
2125
2120
  function registerDeployFrontendCommands(program) {
2126
2121
  program.command("deploy-frontend").description(
2127
- "\u9012\u5F52\u4E0A\u4F20\u524D\u7AEF\u4EA7\u7269\u76EE\u5F55\u5230 MinIO\uFF0C\u5E76\u5728\u6210\u529F\u540E\u4E3A\u8BE5\u6876\u8BBE\u7F6E\u533F\u540D\u53EF\u8BFB\u7B56\u7565\uFF08\u53EF\u5148\u914D\u7F6E .apm/.env \u7684 MINIO_*\uFF0C\u5DF2\u6709\u73AF\u5883\u53D8\u91CF\u4F18\u5148\uFF09"
2122
+ "\u9012\u5F52\u4E0A\u4F20\u524D\u7AEF\u4EA7\u7269\u76EE\u5F55\u5230 MinIO\uFF0C\u5E76\u5728\u6210\u529F\u540E\u4E3A\u8BE5\u6876\u8BBE\u7F6E\u533F\u540D\u53EF\u8BFB\u7B56\u7565\uFF08MinIO \u8FDE\u63A5\u4FE1\u606F\u4EC5\u6765\u81EA apm.config.json frontendDeploy\uFF09"
2128
2123
  ).argument("[name]", "\u73AF\u5883\u540D", "online").option(
2129
2124
  "--dir <path>",
2130
2125
  "\u4EA7\u7269\u76EE\u5F55\uFF1B\u5355\u4ED3\u9ED8\u8BA4 apps/web/dist\uFF08\u9700\u5148 rush build / vite build\uFF09",
@@ -2138,12 +2133,9 @@ function registerDeployFrontendCommands(program) {
2138
2133
  (v) => Number.parseInt(String(v), 10)
2139
2134
  ).action(
2140
2135
  async (name, opts) => {
2141
- loadApmDotEnvIfPresent();
2142
2136
  const cfg = loadApmConfig({ configPath: opts.config });
2143
2137
  const namePrefix = resolveArtifactNamePrefix(cfg);
2144
- const settings = mergeMinioFromEnv(
2145
- resolveFrontendDeployFromApmConfig(cfg)
2146
- );
2138
+ const settings = resolveFrontendDeployFromApmConfig(cfg);
2147
2139
  const minio = new MinioClient({
2148
2140
  endPoint: settings.endpoint,
2149
2141
  port: settings.port,
@@ -2249,16 +2241,16 @@ function buildProgram() {
2249
2241
  await runUpdate();
2250
2242
  });
2251
2243
  program.command("update-skills").description(
2252
- "\u540C\u6B65\u6280\u80FD\u5230 .apm/skills/\uFF1A\u57FA\u7840\u6280\u80FD\u6765\u81EA CLI \u6A21\u677F\uFF0C\u8865\u5145\u6280\u80FD\u6765\u81EA\u5E73\u53F0"
2244
+ "\u540C\u6B65 .apm/ \u4E0B\u7684\u89C4\u5219\u4E0E\u6280\u80FD\uFF1A\u57FA\u7840\u5185\u5BB9\u6765\u81EA CLI \u6A21\u677F\uFF0C\u8865\u5145\u6280\u80FD\u6765\u81EA\u5E73\u53F0"
2253
2245
  ).action(async () => {
2254
2246
  await runUpdateSkills();
2255
2247
  });
2256
2248
  program.command("pull").description(
2257
- "\u62C9\u53D6\u6C9F\u901A\u7FA4\u6570\u636E\u5230 .apm/sessions/<sessionId>/\uFF08session.yaml\u3001RULE.md\u3001docs\u3001attachments\uFF09"
2249
+ "\u62C9\u53D6\u6C9F\u901A\u7FA4\u6570\u636E\u5230 .apm/sessions/<sessionId>/\uFF08session.yaml\u3001RULE.md\u3001TASK.md\u3001LOG.md\u3001docs\u3001attachments\uFF09"
2258
2250
  ).argument("<sessionId>", "\u6C9F\u901A\u7FA4 ID").action(async (sessionId) => {
2259
2251
  await runPull(sessionId);
2260
2252
  });
2261
- 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(
2253
+ 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(
2262
2254
  "--file <name>",
2263
2255
  "\u6587\u6863\u540D\u79F0\uFF08\u5982 PRD \u6216 PRD.md\uFF09\uFF0C\u8BFB\u53D6 .apm/sessions/<sessionId>/docs/ \u4E0B\u5BF9\u5E94\u6587\u4EF6"
2264
2256
  ).action(async (sessionId, opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "5.0.14",
3
+ "version": "5.0.16",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -37,4 +37,4 @@
37
37
  "minio": "~8.0.7",
38
38
  "dockerode": "~5.0.0"
39
39
  }
40
- }
40
+ }
@@ -1,12 +1,5 @@
1
1
  ## APM 指南
2
2
 
3
- ### 回复消息命令
4
-
5
- - 命令: `apm append-message --id=<消息ID> --content=<消息内容>`
6
- - 注意事项:
7
- - 如果消息内容中包含文档地址,不要把前缀也写出来,直接用文档名称即可,并且文档名称要用倒引号包裹
8
- - 这个是补充消息内容,只要消息没有结束,都可以用这个命令来继续补充发言。
9
-
10
3
  ### 创建/更新群文档命令
11
4
 
12
5
  - 命令: `apm sync-document <会话ID> --file <文档名称>`
@@ -17,13 +10,19 @@
17
10
  1. 读取 `.apm/sessions/<会话ID>/session.yaml`,必要时读取`messages.xml` 了解当前会话状态与历史消息
18
11
  2. 根据你的名字从 session.yaml 中找到你对应的人设(system_persona)
19
12
  3. 根据人设完成用户指定的任务
20
- 4. 任务有阶段行进展或者任务完成后必须使用 `apm append-message` 回复消息,回复要求简洁不用对本轮工作进行总结
21
- 5. 工作日志放到 `.apm/sessions/<会话ID>/docs/<position>.md` 中,并执行`apm sync-document <会话ID> --file=<position>`同步到远程
13
+ 4. 任务有阶段行进展或者任务完成后必须回复消息(具体见规则 `reply.md`)
14
+ 5. 写工作日志(具体见规则 `write_doc.md`)
22
15
 
23
16
  ## 目录声明
24
-
25
- - APM 指南: `.apm/AGENTS.md`
26
- - 技能: `.apm/skills/<技能名称>/SKILL.md`,当 `system_persona` 依赖相关技能时可以在这里按需查找
27
- - 群文档: `.apm/sessions/<会话 ID>/docs/xxxx.md`,当需要相关上下文可以在这里查找
28
- - 协作规则: `.apm/sessions/<会话 ID>/RULE.md`,在这里可以看到不同成员的协作规则
29
- - 历史消息记录: `.apm/sessions/<会话 ID>/message.xml`,当需要查看历史消息记录时可以阅读这个文档
17
+ **除了技能和规则**,后面的所有文件都在 `.apm/sessions/<会话ID>` 下,
18
+
19
+ + 技能: `.apm/skills/<技能名称>/SKILL.md`,一些常用的工作方法,根据你当前的角色按需阅读
20
+ + 规则: `.apm/rules/*`
21
+ - reply.md:当需要回复消息时需要读取这个文档,记住回复规则
22
+ - write_doc.md:当需要写文档时需要读取这个文档,记住写文档的规则
23
+ + 本轮会话状态: `session.yaml`,从这里可以看到每个成员的信息,找到可以协助你一起解决问题的人,可以结合 `RULE.md`一起看
24
+ + 群文档: `docs/xxxx.md`,当需要相关上下文可以在这里查找,按需阅读
25
+ + 协作规则: `RULE.md`,在这里可以看到不同成员的协作规则,从而找其他成员协助你一起解决问题,按需阅读
26
+ + 团队日志: `LOG.md`,在这里可以看到之前每个成员都做了什么,按需阅读
27
+ + 历史消息记录: `message.xml`,历史消息列表,数据量很大,按需阅读
28
+ + 初始目标: `TASK.md`,最初的目标,不一定具体,团队成员会有人负责让这个任务变得具体,仅供参考。如果你是相关的角色,则你需要先读取这个目标,然后规划接下来的动作。
@@ -0,0 +1,15 @@
1
+ ## 群内回复规则
2
+
3
+ 1. 如果回复的内容包含文档地址,不要把前缀也写出来,直接用文档名称即可。例如: 我已经把待处理的内容更新到了 `PRD.md` 中,请查阅。
4
+ 2. 回复的内容并非对你工作的总结,要尽可能简洁,不要长篇大论,如果同步的内容确实较多,你可以先写文档,然后指引用户去阅读你写的文档。
5
+ 3. 只要你有任何进展都想都可以调用下面的命令进行回复,你可以一直补充内容。
6
+
7
+ ## 执行回复的方法
8
+
9
+ 命令: `apm append-message --id=<消息ID> --content=<你要回复的消息内容>`
10
+
11
+ 示例: apm append-message --id=xxxxx --content="我已经把待处理的内容更新到了 `PRD.md`,请查阅"
12
+
13
+ ## 写文档的方法
14
+
15
+ 如果知道写文档的方法,可以阅读 `./write_doc.md`
@@ -0,0 +1,30 @@
1
+ ## 写工作日志
2
+
3
+ 命名方式: <你的名字>-工作日志.md
4
+ 保存位置: .apm/sessions/<会话 ID>/docs/<文件名>
5
+ 日志格式:见如下 markdown 中间的内容
6
+
7
+ ```markdown
8
+ ## <简要总结本轮干了什么>
9
+
10
+ <内容>
11
+ ```
12
+
13
+ ## 写其他文件
14
+
15
+ 命名方式: <你的名字>-<主题>.md
16
+ 保存位置: .apm/sessions/<会话 ID>/docs/<文件名>
17
+ 文档内容格式: 根据你的主题来,不限制,禁止记流水账。
18
+
19
+ ## 在保存完成之后需要同步到远程
20
+
21
+ 同步命令: `apm sync-document <会话 ID> --file=<文档名称>
22
+
23
+ 示例: `apm sync-document <会话ID> --file=张三.md`
24
+
25
+ ## 注意事项
26
+
27
+ 1. 文档内容可以被其他团队成员看到,要有价值,禁止记流水账
28
+ 2. 你可以根据你的名字查到自己写的文档,并且禁止更改其他人写的文档
29
+ 3. 不要随便创建新文档,可以在已有文档的基础上添加内容
30
+ 4. 文档不可删除,不可更新文档名称,在写入时要谨慎