ai-project-manage-cli 6.0.26 → 6.0.28

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
@@ -525,13 +525,10 @@ function formatSessionMessagesXml(sessionId, messages) {
525
525
  import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
526
526
  import { join as join4 } from "path";
527
527
  var MANIFEST_FILE = ".sync-manifest.json";
528
- async function downloadAttachment(cfg, sessionId, attachmentId) {
528
+ async function downloadAttachment(cfg, attachmentId) {
529
529
  const base = cfg.baseUrl.trim().replace(/\/+$/, "");
530
- const q = new URLSearchParams({ sessionId, attachmentId });
531
- const url = `${base}/api/v1/cli/attachments/file?${q.toString()}`;
532
- const res = await fetch(url, {
533
- headers: { Authorization: `Bearer ${cfg.token}` }
534
- });
530
+ const url = `${base}/api/v1/tasks/attachments/file?${new URLSearchParams({ attachmentId })}`;
531
+ const res = await fetch(url);
535
532
  if (!res.ok) {
536
533
  throw new Error(
537
534
  `[apm] \u4E0B\u8F7D\u9644\u4EF6\u5931\u8D25 (${res.status}): attachmentId=${attachmentId}`
@@ -589,7 +586,7 @@ async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
589
586
  );
590
587
  continue;
591
588
  }
592
- const buffer = await downloadAttachment(cfg, sessionId, item.id);
589
+ const buffer = await downloadAttachment(cfg, item.id);
593
590
  writeFileSync3(dest, buffer);
594
591
  nextManifest.attachments[item.id] = {
595
592
  name: item.name,
@@ -888,7 +885,73 @@ async function runUpdateSkills() {
888
885
  }
889
886
 
890
887
  // src/commands/sync-document.ts
891
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
888
+ import { existsSync as existsSync6 } from "fs";
889
+ import { basename as basename2 } from "path";
890
+
891
+ // src/commands/sync-session-documents.ts
892
+ import { existsSync as existsSync5, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "fs";
893
+ import { join as join9 } from "path";
894
+ function listLocalMarkdownFiles(docsDir) {
895
+ if (!existsSync5(docsDir)) {
896
+ return [];
897
+ }
898
+ return readdirSync3(docsDir).filter(
899
+ (name) => name.toLowerCase().endsWith(".md")
900
+ );
901
+ }
902
+ function remoteDocumentByLocalName(remoteDocuments, localFileName) {
903
+ const platformName = documentPlatformName(localFileName);
904
+ return remoteDocuments.find((doc) => {
905
+ const remoteLocalName = documentLocalFileName(doc.name);
906
+ return remoteLocalName === localFileName || documentPlatformName(doc.name) === platformName;
907
+ });
908
+ }
909
+ async function upsertLocalDocumentFile(api, sessionId, docsDir, fileName) {
910
+ const absPath = join9(docsDir, fileName);
911
+ const content = readFileSync5(absPath, "utf8");
912
+ const name = documentPlatformName(absPath);
913
+ return api.cli.upsertDocument({
914
+ sessionId,
915
+ name,
916
+ content
917
+ });
918
+ }
919
+ async function syncSessionDocuments(cfg, sessionId, apmRoot, options) {
920
+ const trimmedSessionId = sessionId.trim();
921
+ if (!trimmedSessionId) {
922
+ return 0;
923
+ }
924
+ const docsDir = sessionDocsDir(trimmedSessionId, apmRoot);
925
+ const localFiles = listLocalMarkdownFiles(docsDir);
926
+ if (localFiles.length === 0) {
927
+ return 0;
928
+ }
929
+ const api = options?.api ?? createApmApiClient(cfg);
930
+ const remoteDocuments = options?.remoteDocuments ?? await api.cli.listDocuments({ sessionId: trimmedSessionId });
931
+ let synced = 0;
932
+ for (const fileName of localFiles) {
933
+ const absPath = join9(docsDir, fileName);
934
+ const content = readFileSync5(absPath, "utf8");
935
+ const remote = remoteDocumentByLocalName(remoteDocuments, fileName);
936
+ if (remote && remote.content === content) {
937
+ continue;
938
+ }
939
+ const doc = await upsertLocalDocumentFile(
940
+ api,
941
+ trimmedSessionId,
942
+ docsDir,
943
+ fileName
944
+ );
945
+ synced += 1;
946
+ console.log(`[apm] \u5DF2\u540C\u6B65\u6587\u6863: ${doc.name} (id=${doc.id})`);
947
+ }
948
+ if (synced === 0) {
949
+ console.log("[apm] \u4F1A\u8BDD\u6587\u6863\u65E0\u53D8\u5316\uFF0C\u8DF3\u8FC7\u63A8\u9001");
950
+ }
951
+ return synced;
952
+ }
953
+
954
+ // src/commands/sync-document.ts
892
955
  async function runSyncDocument(sessionId, options) {
893
956
  const trimmedSessionId = sessionId.trim();
894
957
  if (!trimmedSessionId) {
@@ -901,24 +964,24 @@ async function runSyncDocument(sessionId, options) {
901
964
  process.exit(1);
902
965
  }
903
966
  const absPath = resolveSessionDocumentPath(trimmedSessionId, fileArg);
904
- if (!existsSync5(absPath)) {
905
- const docsDir = sessionDocsDir(trimmedSessionId);
967
+ if (!existsSync6(absPath)) {
968
+ const docsDir2 = sessionDocsDir(trimmedSessionId);
906
969
  console.error(
907
970
  `[apm] \u6587\u6863\u4E0D\u5B58\u5728: ${absPath}
908
- [apm] \u8BF7\u786E\u8BA4\u5DF2 pull\uFF0C\u4E14 ${docsDir} \u4E0B\u5B58\u5728\u5BF9\u5E94\u6587\u4EF6`
971
+ [apm] \u8BF7\u786E\u8BA4\u5DF2 pull\uFF0C\u4E14 ${docsDir2} \u4E0B\u5B58\u5728\u5BF9\u5E94\u6587\u4EF6`
909
972
  );
910
973
  process.exit(1);
911
974
  }
912
- const content = readFileSync5(absPath, "utf8");
913
- const name = documentPlatformName(absPath);
914
975
  const cfg = await ensureLoggedConfig();
915
976
  const api = createApmApiClient(cfg);
916
- const doc = await api.cli.upsertDocument({
917
- sessionId: trimmedSessionId,
918
- name,
919
- content
920
- });
921
- console.log(`[apm] \u5DF2\u540C\u6B65\u6587\u6863: ${name} (id=${doc.id})`);
977
+ const docsDir = sessionDocsDir(trimmedSessionId);
978
+ const doc = await upsertLocalDocumentFile(
979
+ api,
980
+ trimmedSessionId,
981
+ docsDir,
982
+ basename2(absPath)
983
+ );
984
+ console.log(`[apm] \u5DF2\u540C\u6B65\u6587\u6863: ${doc.name} (id=${doc.id})`);
922
985
  }
923
986
 
924
987
  // src/commands/append-message.ts
@@ -1041,6 +1104,7 @@ function validateAgentWsMessage(value, kind) {
1041
1104
 
1042
1105
  // src/commands/connect/cursor-agent.ts
1043
1106
  import { Agent, CursorAgentError } from "@cursor/sdk";
1107
+ import { setMaxListeners } from "node:events";
1044
1108
  import { resolve as resolve3 } from "path";
1045
1109
 
1046
1110
  // src/session-utils.ts
@@ -1288,6 +1352,7 @@ async function syncCursorMessageLog(cfg, ctx, events) {
1288
1352
  }
1289
1353
 
1290
1354
  // src/commands/connect/cursor-agent.ts
1355
+ setMaxListeners(50);
1291
1356
  var logCtx = (ctx, agentId) => ({
1292
1357
  sessionId: ctx.sessionId,
1293
1358
  messageId: ctx.messageId,
@@ -1396,6 +1461,15 @@ async function handleInboundMessage(cfg, raw) {
1396
1461
  apiKey: msg.apiKey,
1397
1462
  workdir: msg.workdir
1398
1463
  });
1464
+ await syncSessionDocuments(
1465
+ cfg,
1466
+ msg.sessionId,
1467
+ workspaceApmDir(msg.workdir)
1468
+ );
1469
+ await commitWorkingTreeIfDirty(
1470
+ msg.workdir,
1471
+ "chore(apm): sync session documents"
1472
+ );
1399
1473
  await updateMessageStatus(cfg, messageId, "SUCCESS");
1400
1474
  } catch (err) {
1401
1475
  console.error(
@@ -1492,14 +1566,14 @@ async function runConnect(options) {
1492
1566
  import path5 from "node:path";
1493
1567
 
1494
1568
  // src/commands/deploy/internal/apm-config.ts
1495
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
1569
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
1496
1570
  import { resolve as resolve4 } from "node:path";
1497
1571
  function loadApmConfig(options) {
1498
1572
  const p = resolve4(
1499
1573
  process.cwd(),
1500
1574
  options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
1501
1575
  );
1502
- if (!existsSync6(p)) {
1576
+ if (!existsSync7(p)) {
1503
1577
  console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
1504
1578
  process.exit(1);
1505
1579
  }
@@ -1626,7 +1700,7 @@ import path4 from "node:path";
1626
1700
  import Docker from "dockerode";
1627
1701
 
1628
1702
  // src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
1629
- import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
1703
+ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "node:fs";
1630
1704
  import path from "node:path";
1631
1705
  function asOptionalTlsBuffer(value) {
1632
1706
  if (typeof value !== "string") {
@@ -1638,7 +1712,7 @@ function asOptionalTlsBuffer(value) {
1638
1712
  if (normalized === "") {
1639
1713
  return void 0;
1640
1714
  }
1641
- if (existsSync7(normalized)) {
1715
+ if (existsSync8(normalized)) {
1642
1716
  return readFileSync7(normalized);
1643
1717
  }
1644
1718
  const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
@@ -1849,7 +1923,7 @@ var DockerodeClient = class {
1849
1923
  var createDockerodeClient = (config) => new DockerodeClient(config);
1850
1924
 
1851
1925
  // src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
1852
- import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync4 } from "node:fs";
1926
+ import { existsSync as existsSync9, readFileSync as readFileSync8, statSync as statSync4 } from "node:fs";
1853
1927
  import path2 from "node:path";
1854
1928
  function stripSurroundingQuotes(value) {
1855
1929
  const t = value.trim();
@@ -1866,7 +1940,7 @@ function loadEnvFromFile(envFilePath) {
1866
1940
  return {};
1867
1941
  }
1868
1942
  const targetPath = path2.resolve(envFilePath);
1869
- if (!existsSync8(targetPath) || !statSync4(targetPath).isFile()) {
1943
+ if (!existsSync9(targetPath) || !statSync4(targetPath).isFile()) {
1870
1944
  return {};
1871
1945
  }
1872
1946
  const raw = readFileSync8(targetPath, "utf-8");
@@ -2040,12 +2114,12 @@ function dockerPushImage(params, cwd) {
2040
2114
  }
2041
2115
 
2042
2116
  // src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
2043
- import { existsSync as existsSync9 } from "node:fs";
2117
+ import { existsSync as existsSync10 } from "node:fs";
2044
2118
  import path3 from "node:path";
2045
2119
  function resolveDockerBuildPaths(cwd) {
2046
2120
  const dockerfilePath = path3.join(cwd, "Dockerfile");
2047
2121
  Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
2048
- if (!existsSync9(dockerfilePath)) {
2122
+ if (!existsSync10(dockerfilePath)) {
2049
2123
  throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
2050
2124
  }
2051
2125
  Logger.info("\u2713 Dockerfile \u5B58\u5728");
@@ -2646,7 +2720,7 @@ function registerDeployCommands(program) {
2646
2720
  function buildProgram() {
2647
2721
  const program = new Command();
2648
2722
  program.name("apm").description(
2649
- `OPC \u5E73\u53F0\u547D\u4EE4\u884C\uFF08\u4F1A\u8BDD\u5DE5\u4F5C\u533A\u4E0E\u7814\u53D1\u81EA\u52A8\u5316\uFF09\u3002
2723
+ `\u6BD4\u90BB\u661F\u56FE\u547D\u4EE4\u884C\uFF08\u4F1A\u8BDD\u5DE5\u4F5C\u533A\u4E0E\u7814\u53D1\u81EA\u52A8\u5316\uFF09\u3002
2650
2724
  \u672A\u4F20 --server \u65F6\u4F18\u5148\u4F7F\u7528\u73AF\u5883\u53D8\u91CF AI_PM_SERVER\uFF0C\u5426\u5219\u9ED8\u8BA4 ${DEFAULT_BASE_URL}\u3002`
2651
2725
  ).version(readCliVersion(), "-V, --version", "\u663E\u793A\u7248\u672C\u53F7").helpOption("-h, --help", "\u663E\u793A\u5E2E\u52A9").showHelpAfterError(true);
2652
2726
  program.command("login").description(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "6.0.26",
3
+ "version": "6.0.28",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -18,9 +18,11 @@
18
18
 
19
19
  ## 在保存完成之后需要同步到远程
20
20
 
21
- 同步命令: `apm sync-document <会话 ID> --file=<文档名称>
21
+ 通过 `apm connect` 连接平台时,每轮 Agent 结束后会自动推送 `docs/` 下变更的 Markdown,一般无需手动同步。
22
22
 
23
- 示例: `apm sync-document <会话ID> --file=张三.md`
23
+ 手动同步命令: `apm sync-document <会话 ID> --file=<文档名称>`
24
+
25
+ 示例: `apm sync-document <会话ID> --file=张三-工作日志.md`
24
26
 
25
27
  ## 注意事项
26
28