ai-project-manage-cli 5.0.11 → 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 +83 -35
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -242,7 +242,7 @@ var requestConfig = {
242
242
 
243
243
  // src/api/client.ts
244
244
  function createApmApiClient(cfg) {
245
- const baseURL = `${cfg.baseUrl.trim().replace(/\/+$/, "")}/api`;
245
+ const baseURL = `${cfg.baseUrl.trim().replace(/\/+$/, "")}/api/v1`;
246
246
  return createApiClient(requestConfig, {
247
247
  baseURL,
248
248
  getToken: () => cfg.token || void 0,
@@ -281,7 +281,7 @@ async function runLogin(opts) {
281
281
  const token = data?.token;
282
282
  if (!userId || !token) {
283
283
  console.error(
284
- "[apm] \u54CD\u5E94\u7F3A\u5C11 user.id / token\uFF08\u8BF7\u786E\u8BA4\u670D\u52A1\u7AEF\u4E3A /api/auth/login\uFF09"
284
+ "[apm] \u54CD\u5E94\u7F3A\u5C11 user.id / token\uFF08\u8BF7\u786E\u8BA4\u670D\u52A1\u7AEF\u4E3A /api/v1/auth/login\uFF09"
285
285
  );
286
286
  process.exit(1);
287
287
  }
@@ -499,12 +499,13 @@ 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 });
507
- const url = `${base}/api/cli/attachments/file?${q.toString()}`;
508
+ const url = `${base}/api/v1/cli/attachments/file?${q.toString()}`;
508
509
  const res = await fetch(url, {
509
510
  headers: { Authorization: `Bearer ${cfg.token}` }
510
511
  });
@@ -515,18 +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);
526
- console.log(
527
- `[apm] \u5DF2\u4E0B\u8F7D\u9644\u4EF6: ${SESSION_ATTACHMENTS_SUBDIR}/${item.name}`
528
- );
571
+ nextManifest.attachments[item.id] = {
572
+ name: item.name,
573
+ createdAt
574
+ };
575
+ console.log(`[apm] \u5DF2\u4E0B\u8F7D\u9644\u4EF6: ${SESSION_ATTACHMENTS_SUBDIR}/${item.name}`);
529
576
  }
577
+ saveManifest(dir, nextManifest);
530
578
  }
531
579
 
532
580
  // src/commands/pull.ts
@@ -594,7 +642,7 @@ async function runPull(sessionId, apmRoot) {
594
642
  import { spawnSync } from "child_process";
595
643
 
596
644
  // src/version.ts
597
- import { readFileSync as readFileSync3 } from "fs";
645
+ import { readFileSync as readFileSync4 } from "fs";
598
646
  import { dirname as dirname2, join as join6 } from "path";
599
647
  import { fileURLToPath as fileURLToPath2 } from "url";
600
648
  var CLI_PACKAGE_NAME = "ai-project-manage-cli";
@@ -602,7 +650,7 @@ function readCliVersion() {
602
650
  try {
603
651
  const dir = dirname2(fileURLToPath2(import.meta.url));
604
652
  const pkgPath = join6(dir, "..", "package.json");
605
- const pkg = JSON.parse(readFileSync3(pkgPath, "utf8"));
653
+ const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
606
654
  return pkg.version ?? "0.0.0";
607
655
  } catch {
608
656
  return "0.0.0";
@@ -669,14 +717,14 @@ async function runUpdate() {
669
717
  }
670
718
 
671
719
  // src/commands/update-skills.ts
672
- 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";
673
721
  import { join as join8 } from "path";
674
722
 
675
723
  // src/skills-sync.ts
676
724
  import {
677
725
  copyFileSync,
678
726
  cpSync as cpSync2,
679
- existsSync as existsSync2,
727
+ existsSync as existsSync3,
680
728
  mkdirSync as mkdirSync3,
681
729
  readdirSync as readdirSync2,
682
730
  rmSync,
@@ -692,14 +740,14 @@ function sanitizeSkillDirName(name) {
692
740
  return trimmed.replace(/[/\\:*?"<>|]/g, "_");
693
741
  }
694
742
  function listBaseSkillDirNames() {
695
- if (!existsSync2(BASE_SKILLS_TEMPLATE_DIR)) return [];
743
+ if (!existsSync3(BASE_SKILLS_TEMPLATE_DIR)) return [];
696
744
  return readdirSync2(BASE_SKILLS_TEMPLATE_DIR).filter((name) => {
697
745
  const path8 = join7(BASE_SKILLS_TEMPLATE_DIR, name);
698
746
  return statSync2(path8).isDirectory();
699
747
  });
700
748
  }
701
749
  function syncAgentsGuide(apmDir) {
702
- if (!existsSync2(AGENTS_TEMPLATE_PATH)) return false;
750
+ if (!existsSync3(AGENTS_TEMPLATE_PATH)) return false;
703
751
  mkdirSync3(apmDir, { recursive: true });
704
752
  copyFileSync(AGENTS_TEMPLATE_PATH, join7(apmDir, "AGENTS.md"));
705
753
  return true;
@@ -732,7 +780,7 @@ function syncSupplementarySkills(skillsDir, list) {
732
780
  written.push(dirName);
733
781
  }
734
782
  const removed = [];
735
- if (!existsSync2(skillsDir)) return { written, skipped, removed };
783
+ if (!existsSync3(skillsDir)) return { written, skipped, removed };
736
784
  for (const entry of readdirSync2(skillsDir)) {
737
785
  const full = join7(skillsDir, entry);
738
786
  if (!statSync2(full).isDirectory()) continue;
@@ -747,7 +795,7 @@ function syncSupplementarySkills(skillsDir, list) {
747
795
  // src/commands/update-skills.ts
748
796
  async function runUpdateSkills() {
749
797
  const apmDir = workspaceApmDir();
750
- if (!existsSync3(apmDir)) {
798
+ if (!existsSync4(apmDir)) {
751
799
  console.error("[apm] \u672A\u627E\u5230 .apm \u76EE\u5F55\uFF0C\u8BF7\u5148\u6267\u884C apm init");
752
800
  process.exit(1);
753
801
  }
@@ -788,7 +836,7 @@ async function runUpdateSkills() {
788
836
  }
789
837
 
790
838
  // src/commands/sync-document.ts
791
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
839
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
792
840
  async function runSyncDocument(sessionId, options) {
793
841
  const trimmedSessionId = sessionId.trim();
794
842
  if (!trimmedSessionId) {
@@ -801,7 +849,7 @@ async function runSyncDocument(sessionId, options) {
801
849
  process.exit(1);
802
850
  }
803
851
  const absPath = resolveSessionDocumentPath(trimmedSessionId, fileArg);
804
- if (!existsSync4(absPath)) {
852
+ if (!existsSync5(absPath)) {
805
853
  const docsDir = sessionDocsDir(trimmedSessionId);
806
854
  console.error(
807
855
  `[apm] \u6587\u6863\u4E0D\u5B58\u5728: ${absPath}
@@ -809,7 +857,7 @@ async function runSyncDocument(sessionId, options) {
809
857
  );
810
858
  process.exit(1);
811
859
  }
812
- const content = readFileSync4(absPath, "utf8");
860
+ const content = readFileSync5(absPath, "utf8");
813
861
  const name = documentPlatformName(absPath);
814
862
  const cfg = await ensureLoggedConfig();
815
863
  const api = createApmApiClient(cfg);
@@ -1158,19 +1206,19 @@ async function runConnect(options) {
1158
1206
  import path5 from "node:path";
1159
1207
 
1160
1208
  // src/commands/deploy/internal/apm-config.ts
1161
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
1209
+ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
1162
1210
  import { resolve as resolve4 } from "node:path";
1163
1211
  function loadApmConfig(options) {
1164
1212
  const p = resolve4(
1165
1213
  process.cwd(),
1166
1214
  options?.configPath ?? resolve4(workspaceApmDir(), "apm.config.json")
1167
1215
  );
1168
- if (!existsSync5(p)) {
1216
+ if (!existsSync6(p)) {
1169
1217
  console.error(`\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6\uFF1A${p}`);
1170
1218
  process.exit(1);
1171
1219
  }
1172
1220
  try {
1173
- const raw = readFileSync5(p, "utf8");
1221
+ const raw = readFileSync6(p, "utf8");
1174
1222
  return JSON.parse(raw);
1175
1223
  } catch (e) {
1176
1224
  console.error(`\u65E0\u6CD5\u89E3\u6790 apm.config.json\uFF1A${p}`, e);
@@ -1267,7 +1315,7 @@ import path4 from "node:path";
1267
1315
  import Docker from "dockerode";
1268
1316
 
1269
1317
  // src/commands/deploy/internal/backend-deploy/dockerode-client/connection-options.ts
1270
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
1318
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
1271
1319
  import path from "node:path";
1272
1320
  function asOptionalTlsBuffer(value) {
1273
1321
  if (typeof value !== "string") {
@@ -1279,8 +1327,8 @@ function asOptionalTlsBuffer(value) {
1279
1327
  if (normalized === "") {
1280
1328
  return void 0;
1281
1329
  }
1282
- if (existsSync6(normalized)) {
1283
- return readFileSync6(normalized);
1330
+ if (existsSync7(normalized)) {
1331
+ return readFileSync7(normalized);
1284
1332
  }
1285
1333
  const looksLikePath = /[\\/]/.test(normalized) || normalized.endsWith(".pem");
1286
1334
  if (looksLikePath) {
@@ -1490,7 +1538,7 @@ var DockerodeClient = class {
1490
1538
  var createDockerodeClient = (config) => new DockerodeClient(config);
1491
1539
 
1492
1540
  // src/commands/deploy/internal/backend-deploy/dockerode-client/env.ts
1493
- 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";
1494
1542
  import path2 from "node:path";
1495
1543
  function stripSurroundingQuotes(value) {
1496
1544
  const t = value.trim();
@@ -1507,10 +1555,10 @@ function loadEnvFromFile(envFilePath) {
1507
1555
  return {};
1508
1556
  }
1509
1557
  const targetPath = path2.resolve(envFilePath);
1510
- if (!existsSync7(targetPath) || !statSync4(targetPath).isFile()) {
1558
+ if (!existsSync8(targetPath) || !statSync4(targetPath).isFile()) {
1511
1559
  return {};
1512
1560
  }
1513
- const raw = readFileSync7(targetPath, "utf-8");
1561
+ const raw = readFileSync8(targetPath, "utf-8");
1514
1562
  const result = {};
1515
1563
  for (const line of raw.split(/\r?\n/)) {
1516
1564
  const normalized = line.trim();
@@ -1681,12 +1729,12 @@ function dockerPushImage(params, cwd) {
1681
1729
  }
1682
1730
 
1683
1731
  // src/commands/deploy/internal/backend-deploy/resolve-dockerfile.ts
1684
- import { existsSync as existsSync8 } from "node:fs";
1732
+ import { existsSync as existsSync9 } from "node:fs";
1685
1733
  import path3 from "node:path";
1686
1734
  function resolveDockerBuildPaths(cwd) {
1687
1735
  const dockerfilePath = path3.join(cwd, "Dockerfile");
1688
1736
  Logger.info(`\u67E5\u627EDockerfile\u6587\u4EF6\uFF0C\u8DEF\u5F84: ${dockerfilePath}`);
1689
- if (!existsSync8(dockerfilePath)) {
1737
+ if (!existsSync9(dockerfilePath)) {
1690
1738
  throw new Error(`Dockerfile \u4E0D\u5B58\u5728\uFF1A${dockerfilePath}`);
1691
1739
  }
1692
1740
  Logger.info("\u2713 Dockerfile \u5B58\u5728");
@@ -1815,16 +1863,16 @@ import { copyFile, readdir as readdir2, stat } from "node:fs/promises";
1815
1863
  import path7 from "node:path";
1816
1864
 
1817
1865
  // src/commands/deploy/internal/load-apm-dotenv.ts
1818
- import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
1866
+ import { existsSync as existsSync10, readFileSync as readFileSync9 } from "node:fs";
1819
1867
  import { join as join9 } from "node:path";
1820
1868
  function loadApmDotEnvIfPresent() {
1821
1869
  const p = join9(workspaceApmDir(), ".env");
1822
- if (!existsSync9(p)) {
1870
+ if (!existsSync10(p)) {
1823
1871
  return;
1824
1872
  }
1825
1873
  let text;
1826
1874
  try {
1827
- text = readFileSync8(p, "utf8");
1875
+ text = readFileSync9(p, "utf8");
1828
1876
  } catch {
1829
1877
  return;
1830
1878
  }
@@ -2186,7 +2234,7 @@ function buildProgram() {
2186
2234
  \u672A\u4F20 --server \u65F6\u4F18\u5148\u4F7F\u7528\u73AF\u5883\u53D8\u91CF AI_PM_SERVER\uFF0C\u5426\u5219\u9ED8\u8BA4 ${DEFAULT_BASE_URL}\u3002`
2187
2235
  ).version(readCliVersion(), "-V, --version", "\u663E\u793A\u7248\u672C\u53F7").helpOption("-h, --help", "\u663E\u793A\u5E2E\u52A9").showHelpAfterError(true);
2188
2236
  program.command("login").description(
2189
- "\u8C03\u7528 POST /api/auth/login\uFF0C\u5C06 token \u5199\u5165 ~/.config/apm/config.json"
2237
+ "\u8C03\u7528 POST /api/v1/auth/login\uFF0C\u5C06 token \u5199\u5165 ~/.config/apm/config.json"
2190
2238
  ).requiredOption("--email <\u90AE\u7BB1>", "\u767B\u5F55\u90AE\u7BB1").requiredOption("--password <\u5BC6\u7801>", "\u767B\u5F55\u5BC6\u7801").option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u4F8B\u5982 http://127.0.0.1:3000").action(
2191
2239
  async (opts) => {
2192
2240
  await runLogin(opts);
@@ -2216,7 +2264,7 @@ function buildProgram() {
2216
2264
  ).action(async (sessionId, opts) => {
2217
2265
  await runSyncDocument(sessionId, { file: opts.file });
2218
2266
  });
2219
- 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) => {
2267
+ program.command("append-message").description("\u5411\u5E73\u53F0\u4F1A\u8BDD\u6D88\u606F\u8FFD\u52A0\u5185\u5BB9\uFF08PUT /api/v1/cli/messages/content\uFF09").requiredOption("--id <messageId>", "\u6D88\u606F ID").requiredOption("--content <content>", "\u8981\u8FFD\u52A0\u7684\u6D88\u606F\u5185\u5BB9").action(async (opts) => {
2220
2268
  await runAppendMessage(opts);
2221
2269
  });
2222
2270
  program.command("update-message-status").description("\u66F4\u65B0\u5E73\u53F0\u4F1A\u8BDD\u6D88\u606F\u72B6\u6001").requiredOption("--id <messageId>", "\u6D88\u606F ID").requiredOption("--status <status>", "CREATED | TYPING | SUCCESS | FAILED").action(async (opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "5.0.11",
3
+ "version": "5.0.13",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,