ai-project-manage-cli 5.0.12 → 5.0.13

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.
Files changed (2) hide show
  1. package/dist/index.js +77 -27
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -499,8 +499,9 @@ function formatSessionMessagesXml(sessionId, messages) {
499
499
  }
500
500
 
501
501
  // src/commands/sync-session-attachments.ts
502
- import { writeFileSync as writeFileSync3 } from "fs";
502
+ import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
503
503
  import { join as join4 } from "path";
504
+ var MANIFEST_FILE = ".sync-manifest.json";
504
505
  async function downloadAttachment(cfg, sessionId, attachmentId) {
505
506
  const base = cfg.baseUrl.trim().replace(/\/+$/, "");
506
507
  const q = new URLSearchParams({ sessionId, attachmentId });
@@ -515,16 +516,65 @@ async function downloadAttachment(cfg, sessionId, attachmentId) {
515
516
  }
516
517
  return Buffer.from(await res.arrayBuffer());
517
518
  }
519
+ function loadManifest(dir) {
520
+ const path8 = join4(dir, MANIFEST_FILE);
521
+ if (!existsSync2(path8)) {
522
+ return { version: 1, attachments: {} };
523
+ }
524
+ try {
525
+ const parsed = JSON.parse(
526
+ readFileSync3(path8, "utf8")
527
+ );
528
+ if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
529
+ return parsed;
530
+ }
531
+ } catch {
532
+ }
533
+ return { version: 1, attachments: {} };
534
+ }
535
+ function saveManifest(dir, manifest) {
536
+ writeFileSync3(
537
+ join4(dir, MANIFEST_FILE),
538
+ `${JSON.stringify(manifest, null, 2)}
539
+ `,
540
+ "utf8"
541
+ );
542
+ }
543
+ function isAttachmentUpToDate(entry, item, dest) {
544
+ if (!entry || !existsSync2(dest)) return false;
545
+ if (entry.name !== item.name) return false;
546
+ const createdAt = item.createdAt ?? "";
547
+ return entry.createdAt === createdAt;
548
+ }
518
549
  async function syncSessionAttachments(cfg, sessionId, attachments, apmRoot) {
519
- if (attachments.length === 0) return;
520
550
  const dir = join4(sessionDir(sessionId, apmRoot), SESSION_ATTACHMENTS_SUBDIR);
521
551
  await ensureDirExists(dir);
552
+ if (attachments.length === 0) {
553
+ saveManifest(dir, { version: 1, attachments: {} });
554
+ return;
555
+ }
556
+ const manifest = loadManifest(dir);
557
+ const nextManifest = { version: 1, attachments: {} };
522
558
  for (const item of attachments) {
523
559
  const dest = join4(dir, item.name);
560
+ const entry = manifest.attachments[item.id];
561
+ const createdAt = item.createdAt ?? "";
562
+ if (isAttachmentUpToDate(entry, item, dest)) {
563
+ nextManifest.attachments[item.id] = entry;
564
+ console.log(
565
+ `[apm] \u9644\u4EF6\u65E0\u53D8\u5316\uFF0C\u5DF2\u8DF3\u8FC7: ${SESSION_ATTACHMENTS_SUBDIR}/${item.name}`
566
+ );
567
+ continue;
568
+ }
524
569
  const buffer = await downloadAttachment(cfg, sessionId, item.id);
525
570
  writeFileSync3(dest, buffer);
571
+ nextManifest.attachments[item.id] = {
572
+ name: item.name,
573
+ createdAt
574
+ };
526
575
  console.log(`[apm] \u5DF2\u4E0B\u8F7D\u9644\u4EF6: ${SESSION_ATTACHMENTS_SUBDIR}/${item.name}`);
527
576
  }
577
+ saveManifest(dir, nextManifest);
528
578
  }
529
579
 
530
580
  // src/commands/pull.ts
@@ -592,7 +642,7 @@ async function runPull(sessionId, apmRoot) {
592
642
  import { spawnSync } from "child_process";
593
643
 
594
644
  // src/version.ts
595
- import { readFileSync as readFileSync3 } from "fs";
645
+ import { readFileSync as readFileSync4 } from "fs";
596
646
  import { dirname as dirname2, join as join6 } from "path";
597
647
  import { fileURLToPath as fileURLToPath2 } from "url";
598
648
  var CLI_PACKAGE_NAME = "ai-project-manage-cli";
@@ -600,7 +650,7 @@ function readCliVersion() {
600
650
  try {
601
651
  const dir = dirname2(fileURLToPath2(import.meta.url));
602
652
  const pkgPath = join6(dir, "..", "package.json");
603
- const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
653
+ const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
604
654
  return pkg.version ?? "0.0.0";
605
655
  } catch {
606
656
  return "0.0.0";
@@ -667,14 +717,14 @@ async function runUpdate() {
667
717
  }
668
718
 
669
719
  // src/commands/update-skills.ts
670
- import { existsSync as existsSync3, mkdirSync as mkdirSync4, statSync as statSync3 } from "fs";
720
+ import { existsSync as existsSync4, mkdirSync as mkdirSync4, statSync as statSync3 } from "fs";
671
721
  import { join as join8 } from "path";
672
722
 
673
723
  // src/skills-sync.ts
674
724
  import {
675
725
  copyFileSync,
676
726
  cpSync as cpSync2,
677
- existsSync as existsSync2,
727
+ existsSync as existsSync3,
678
728
  mkdirSync as mkdirSync3,
679
729
  readdirSync as readdirSync2,
680
730
  rmSync,
@@ -690,14 +740,14 @@ function sanitizeSkillDirName(name) {
690
740
  return trimmed.replace(/[/\\:*?"<>|]/g, "_");
691
741
  }
692
742
  function listBaseSkillDirNames() {
693
- if (!existsSync2(BASE_SKILLS_TEMPLATE_DIR)) return [];
743
+ if (!existsSync3(BASE_SKILLS_TEMPLATE_DIR)) return [];
694
744
  return readdirSync2(BASE_SKILLS_TEMPLATE_DIR).filter((name) => {
695
745
  const path8 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
696
746
  return statSync2(path8).isDirectory();
697
747
  });
698
748
  }
699
749
  function syncAgentsGuide(apmDir) {
700
- if (!existsSync2(AGENTS_TEMPLATE_PATH)) return false;
750
+ if (!existsSync3(AGENTS_TEMPLATE_PATH)) return false;
701
751
  mkdirSync3(apmDir, { recursive: true });
702
752
  copyFileSync(AGENTS_TEMPLATE_PATH, join7(apmDir, "AGENTS.md"));
703
753
  return true;
@@ -730,7 +780,7 @@ function syncSupplementarySkills(skillsDir, list) {
730
780
  written.push(dirName);
731
781
  }
732
782
  const removed = [];
733
- if (!existsSync2(skillsDir)) return { written, skipped, removed };
783
+ if (!existsSync3(skillsDir)) return { written, skipped, removed };
734
784
  for (const entry of readdirSync2(skillsDir)) {
735
785
  const full = join7(skillsDir, entry);
736
786
  if (!statSync2(full).isDirectory()) continue;
@@ -745,7 +795,7 @@ function syncSupplementarySkills(skillsDir, list) {
745
795
  // src/commands/update-skills.ts
746
796
  async function runUpdateSkills() {
747
797
  const apmDir = workspaceApmDir();
748
- if (!existsSync3(apmDir)) {
798
+ if (!existsSync4(apmDir)) {
749
799
  console.error("[apm] \u672A\u627E\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5148\u6267\u884C apm init");
750
800
  process.exit(1);
751
801
  }
@@ -786,7 +836,7 @@ async function runUpdateSkills() {
786
836
  }
787
837
 
788
838
  // src/commands/sync-document.ts
789
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
839
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
790
840
  async function runSyncDocument(sessionId, options) {
791
841
  const trimmedSessionId = sessionId.trim();
792
842
  if (!trimmedSessionId) {
@@ -799,7 +849,7 @@ async function runSyncDocument(sessionId, options) {
799
849
  process.exit(1);
800
850
  }
801
851
  const absPath = resolveSessionDocumentPath(trimmedSessionId, fileArg);
802
- if (!existsSync4(absPath)) {
852
+ if (!existsSync5(absPath)) {
803
853
  const docsDir = sessionDocsDir(trimmedSessionId);
804
854
  console.error(
805
855
  `[apm] \u6587\u6863\u4E0D\u5B58\u5728: ${absPath}
@@ -807,7 +857,7 @@ async function runSyncDocument(sessionId, options) {
807
857
  );
808
858
  process.exit(1);
809
859
  }
810
- const content = readFileSync4(absPath, "utf8");
860
+ const content = readFileSync5(absPath, "utf8");
811
861
  const name = documentPlatformName(absPath);
812
862
  const cfg = await ensureLoggedConfig();
813
863
  const api = createApmApiClient(cfg);
@@ -1156,19 +1206,19 @@ async function runConnect(options) {
1156
1206
  import path5 from "node:path";
1157
1207
 
1158
1208
  // src/commands/deploy/internal/apm-config.ts
1159
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
1209
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
1160
1210
  import { resolve as resolve4 } from "node:path";
1161
1211
  function loadApmConfig(options) {
1162
1212
  const p = resolve4(
1163
1213
  process.cwd(),
1164
1214
  options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
1165
1215
  );
1166
- if (!existsSync5(p)) {
1216
+ if (!existsSync6(p)) {
1167
1217
  console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
1168
1218
  process.exit(1);
1169
1219
  }
1170
1220
  try {
1171
- const raw = readFileSync5(p, "utf8");
1221
+ const raw = readFileSync6(p, "utf8");
1172
1222
  return JSON.parse(raw);
1173
1223
  } catch (e) {
1174
1224
  console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
@@ -1265,7 +1315,7 @@ import path4 from "node:path";
1265
1315
  import Docker from "dockerode";
1266
1316
 
1267
1317
  // src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
1268
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
1318
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
1269
1319
  import path from "node:path";
1270
1320
  function asOptionalTlsBuffer(value) {
1271
1321
  if (typeof value !== "string") {
@@ -1277,8 +1327,8 @@ function asOptionalTlsBuffer(value) {
1277
1327
  if (normalized === "") {
1278
1328
  return void 0;
1279
1329
  }
1280
- if (existsSync6(normalized)) {
1281
- return readFileSync6(normalized);
1330
+ if (existsSync7(normalized)) {
1331
+ return readFileSync7(normalized);
1282
1332
  }
1283
1333
  const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
1284
1334
  if (looksLikePath) {
@@ -1488,7 +1538,7 @@ var DockerodeClient = class {
1488
1538
  var createDockerodeClient = (config) => new DockerodeClient(config);
1489
1539
 
1490
1540
  // src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
1491
- import { existsSync as existsSync7, readFileSync as readFileSync7, statSync as statSync4 } from "node:fs";
1541
+ import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync4 } from "node:fs";
1492
1542
  import path2 from "node:path";
1493
1543
  function stripSurroundingQuotes(value) {
1494
1544
  const t = value.trim();
@@ -1505,10 +1555,10 @@ function loadEnvFromFile(envFilePath) {
1505
1555
  return {};
1506
1556
  }
1507
1557
  const targetPath = path2.resolve(envFilePath);
1508
- if (!existsSync7(targetPath) || !statSync4(targetPath).isFile()) {
1558
+ if (!existsSync8(targetPath) || !statSync4(targetPath).isFile()) {
1509
1559
  return {};
1510
1560
  }
1511
- const raw = readFileSync7(targetPath, "utf-8");
1561
+ const raw = readFileSync8(targetPath, "utf-8");
1512
1562
  const result = {};
1513
1563
  for (const line of raw.split(/\r?\n/)) {
1514
1564
  const normalized = line.trim();
@@ -1679,12 +1729,12 @@ function dockerPushImage(params, cwd) {
1679
1729
  }
1680
1730
 
1681
1731
  // src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
1682
- import { existsSync as existsSync8 } from "node:fs";
1732
+ import { existsSync as existsSync9 } from "node:fs";
1683
1733
  import path3 from "node:path";
1684
1734
  function resolveDockerBuildPaths(cwd) {
1685
1735
  const dockerfilePath = path3.join(cwd, "Dockerfile");
1686
1736
  Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
1687
- if (!existsSync8(dockerfilePath)) {
1737
+ if (!existsSync9(dockerfilePath)) {
1688
1738
  throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
1689
1739
  }
1690
1740
  Logger.info("\u2713 Dockerfile \u5B58\u5728");
@@ -1813,16 +1863,16 @@ import { copyFile, readdir as readdir2, stat } from "node:fs/promises";
1813
1863
  import path7 from "node:path";
1814
1864
 
1815
1865
  // src/commands/deploy/internal/load-apm-dotenv.ts
1816
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
1866
+ import { existsSync as existsSync10, readFileSync as readFileSync9 } from "node:fs";
1817
1867
  import { join as join9 } from "node:path";
1818
1868
  function loadApmDotEnvIfPresent() {
1819
1869
  const p = join9(workspaceApmDir(), ".env");
1820
- if (!existsSync9(p)) {
1870
+ if (!existsSync10(p)) {
1821
1871
  return;
1822
1872
  }
1823
1873
  let text;
1824
1874
  try {
1825
- text = readFileSync8(p, "utf8");
1875
+ text = readFileSync9(p, "utf8");
1826
1876
  } catch {
1827
1877
  return;
1828
1878
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "5.0.12",
3
+ "version": "5.0.13",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,