ai-project-manage-cli 8.1.23 → 8.1.24

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
@@ -1430,9 +1430,77 @@ async function runConnect(options) {
1430
1430
  }
1431
1431
  }
1432
1432
 
1433
+ // src/utils/home-repository.ts
1434
+ import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1435
+ import { join as join8, resolve as resolve3 } from "path";
1436
+ var DEFAULT_REPOS_MANIFEST = "/home/repository.json";
1437
+ function isSimpleChildDirName(name) {
1438
+ if (!name || name === "." || name === "..") return false;
1439
+ if (name.includes("/") || name.includes("\\")) return false;
1440
+ return true;
1441
+ }
1442
+ function resolveReposManifestPath(explicit) {
1443
+ const fromOpt = explicit?.trim() || "";
1444
+ if (fromOpt) return fromOpt;
1445
+ const fromEnv = process.env.APM_REPOS_MANIFEST?.trim() || "";
1446
+ if (fromEnv) return fromEnv;
1447
+ return null;
1448
+ }
1449
+ function resolveCliReposManifestPath(explicit) {
1450
+ return resolveReposManifestPath(explicit) ?? DEFAULT_REPOS_MANIFEST;
1451
+ }
1452
+ function loadHomeRepositoryEntries(manifestPath2) {
1453
+ const label = manifestPath2.trim();
1454
+ if (!label) {
1455
+ throw new Error("[apm] \u591A\u4ED3\u6E05\u5355\u8DEF\u5F84\u4E3A\u7A7A");
1456
+ }
1457
+ const path = toFsPath(label);
1458
+ if (!existsSync6(path)) {
1459
+ throw new Error(`[apm] \u672A\u627E\u5230\u591A\u4ED3\u6E05\u5355 ${label}`);
1460
+ }
1461
+ let parsed;
1462
+ try {
1463
+ parsed = JSON.parse(readFileSync5(path, "utf8"));
1464
+ } catch (err) {
1465
+ const detail = err instanceof Error ? err.message : String(err);
1466
+ throw new Error(`[apm] \u89E3\u6790 ${label} \u5931\u8D25: ${detail}`);
1467
+ }
1468
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1469
+ throw new Error(
1470
+ `[apm] ${label} \u987B\u4E3A\u5BF9\u8C61\uFF1Akey=\u4E0B\u7EA7\u76EE\u5F55\uFF0Cvalue=git \u5730\u5740`
1471
+ );
1472
+ }
1473
+ const entries = [];
1474
+ for (const [rawKey, rawVal] of Object.entries(
1475
+ parsed
1476
+ )) {
1477
+ const pathKey = rawKey.trim();
1478
+ if (!isSimpleChildDirName(pathKey)) {
1479
+ throw new Error(
1480
+ `[apm] ${label} \u975E\u6CD5\u76EE\u5F55 key: ${JSON.stringify(rawKey)}\uFF08\u987B\u4E3A\u5F53\u524D\u4E0B\u7EA7\u76EE\u5F55\u540D\uFF09`
1481
+ );
1482
+ }
1483
+ if (typeof rawVal !== "string" || !rawVal.trim()) {
1484
+ throw new Error(
1485
+ `[apm] ${label}[${pathKey}] \u987B\u4E3A\u975E\u7A7A git \u5730\u5740\u5B57\u7B26\u4E32`
1486
+ );
1487
+ }
1488
+ entries.push({ path: pathKey, remoteUrl: rawVal.trim() });
1489
+ }
1490
+ entries.sort((a, b) => a.path.localeCompare(b.path));
1491
+ if (entries.length === 0) {
1492
+ throw new Error(`[apm] ${label} \u4E3A\u7A7A\uFF0C\u65E0\u4ED3\u5E93\u53EF\u786E\u8BA4`);
1493
+ }
1494
+ return entries;
1495
+ }
1496
+ function resolveHomeRepositoryAbsolutePaths(workdirInput, entries) {
1497
+ const workdir = resolveWorkdirPath(workdirInput);
1498
+ return entries.map((entry) => resolve3(join8(workdir, entry.path)));
1499
+ }
1500
+
1433
1501
  // src/utils/git.ts
1434
1502
  import { execFile } from "child_process";
1435
- import { dirname as dirname3, join as join8 } from "path";
1503
+ import { dirname as dirname3, join as join9 } from "path";
1436
1504
  import { fileURLToPath as fileURLToPath3 } from "url";
1437
1505
  import { promisify } from "util";
1438
1506
  var execFileAsync = promisify(execFile);
@@ -1516,7 +1584,7 @@ async function resolveGitRepoRoot(cwd) {
1516
1584
  return (await execGit(cwd, ["rev-parse", "--show-toplevel"], true)).trim();
1517
1585
  }
1518
1586
  function resolveGitScript(name) {
1519
- return join8(dirname3(fileURLToPath3(import.meta.url)), "scripts", name);
1587
+ return join9(dirname3(fileURLToPath3(import.meta.url)), "scripts", name);
1520
1588
  }
1521
1589
  async function runGitScript(name, options) {
1522
1590
  const skipCode = options.skipCode ?? 2;
@@ -1573,69 +1641,15 @@ async function pushCurrentBranch(cwd) {
1573
1641
  });
1574
1642
  }
1575
1643
 
1576
- // src/utils/home-repository.ts
1577
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
1578
- import { join as join9, resolve as resolve3 } from "path";
1579
- var DEFAULT_REPOS_MANIFEST = "/home/repository.json";
1580
- function isSimpleChildDirName(name) {
1581
- if (!name || name === "." || name === "..") return false;
1582
- if (name.includes("/") || name.includes("\\")) return false;
1583
- return true;
1584
- }
1585
- function resolveReposManifestPath(explicit) {
1586
- const fromOpt = explicit?.trim() || "";
1587
- if (fromOpt) return fromOpt;
1588
- const fromEnv = process.env.APM_REPOS_MANIFEST?.trim() || "";
1589
- if (fromEnv) return fromEnv;
1590
- return DEFAULT_REPOS_MANIFEST;
1591
- }
1592
- function loadHomeRepositoryEntries(manifestPath) {
1593
- const label = manifestPath.trim() || DEFAULT_REPOS_MANIFEST;
1594
- const path = toFsPath(label);
1595
- if (!existsSync6(path)) {
1596
- throw new Error(`[apm] \u672A\u627E\u5230\u591A\u4ED3\u6E05\u5355 ${label}`);
1597
- }
1598
- let parsed;
1599
- try {
1600
- parsed = JSON.parse(readFileSync5(path, "utf8"));
1601
- } catch (err) {
1602
- const detail = err instanceof Error ? err.message : String(err);
1603
- throw new Error(`[apm] \u89E3\u6790 ${label} \u5931\u8D25: ${detail}`);
1604
- }
1605
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1606
- throw new Error(
1607
- `[apm] ${label} \u987B\u4E3A\u5BF9\u8C61\uFF1Akey=\u4E0B\u7EA7\u76EE\u5F55\uFF0Cvalue=git \u5730\u5740`
1608
- );
1609
- }
1610
- const entries = [];
1611
- for (const [rawKey, rawVal] of Object.entries(
1612
- parsed
1613
- )) {
1614
- const pathKey = rawKey.trim();
1615
- if (!isSimpleChildDirName(pathKey)) {
1616
- throw new Error(
1617
- `[apm] ${label} \u975E\u6CD5\u76EE\u5F55 key: ${JSON.stringify(rawKey)}\uFF08\u987B\u4E3A\u5F53\u524D\u4E0B\u7EA7\u76EE\u5F55\u540D\uFF09`
1618
- );
1619
- }
1620
- if (typeof rawVal !== "string" || !rawVal.trim()) {
1621
- throw new Error(
1622
- `[apm] ${label}[${pathKey}] \u987B\u4E3A\u975E\u7A7A git \u5730\u5740\u5B57\u7B26\u4E32`
1623
- );
1624
- }
1625
- entries.push({ path: pathKey, remoteUrl: rawVal.trim() });
1626
- }
1627
- entries.sort((a, b) => a.path.localeCompare(b.path));
1628
- if (entries.length === 0) {
1629
- throw new Error(`[apm] ${label} \u4E3A\u7A7A\uFF0C\u65E0\u4ED3\u5E93\u53EF\u786E\u8BA4`);
1630
- }
1631
- return entries;
1632
- }
1633
- function resolveHomeRepositoryAbsolutePaths(workdirInput, entries) {
1634
- const workdir = resolveWorkdirPath(workdirInput);
1635
- return entries.map((entry) => resolve3(join9(workdir, entry.path)));
1636
- }
1637
-
1638
1644
  // src/utils/workspace-repos.ts
1645
+ import {
1646
+ existsSync as existsSync7,
1647
+ mkdirSync as mkdirSync5,
1648
+ readFileSync as readFileSync6,
1649
+ readdirSync as readdirSync3,
1650
+ statSync as statSync3,
1651
+ writeFileSync as writeFileSync4
1652
+ } from "fs";
1639
1653
  import { basename, dirname as dirname4, join as join10, relative, resolve as resolve4 } from "path";
1640
1654
 
1641
1655
  // src/utils/git-remote.ts
@@ -1644,9 +1658,96 @@ import { promisify as promisify2 } from "util";
1644
1658
  var execFileAsync2 = promisify2(execFile2);
1645
1659
 
1646
1660
  // src/utils/workspace-repos.ts
1661
+ var WORKSPACE_REPOS_MANIFEST = "workspace-repos.json";
1662
+ var WORKSPACE_REPOS_VERSION = 1;
1663
+ function manifestPath(workdir) {
1664
+ return join10(workspaceApmDir(workdir), WORKSPACE_REPOS_MANIFEST);
1665
+ }
1666
+ function absoluteRepoPath(workdir, entry) {
1667
+ return resolve4(workdir, entry.path);
1668
+ }
1647
1669
  function toRelativeRepoPath(workdir, repoAbs) {
1648
1670
  return relative(workdir, repoAbs).replace(/\\/g, "/");
1649
1671
  }
1672
+ function normalizeRepoEntry(raw) {
1673
+ if (!raw || typeof raw !== "object") return null;
1674
+ const o = raw;
1675
+ if (typeof o.path !== "string" || !o.path.trim()) return null;
1676
+ const path = o.path.trim().replace(/\\/g, "/");
1677
+ if (path === "." || path.includes("/")) return null;
1678
+ const entry = { path };
1679
+ if (typeof o.remoteUrl === "string" && o.remoteUrl.trim()) {
1680
+ entry.remoteUrl = o.remoteUrl.trim();
1681
+ } else if (o.remoteUrl === null) {
1682
+ entry.remoteUrl = null;
1683
+ }
1684
+ return entry;
1685
+ }
1686
+ function readManifest(workdir) {
1687
+ const path = toFsPath(manifestPath(workdir));
1688
+ if (!existsSync7(path)) {
1689
+ return null;
1690
+ }
1691
+ try {
1692
+ const raw = JSON.parse(
1693
+ readFileSync6(path, "utf8")
1694
+ );
1695
+ if (raw?.version !== WORKSPACE_REPOS_VERSION) {
1696
+ return null;
1697
+ }
1698
+ if (raw.kind !== "multi") {
1699
+ return null;
1700
+ }
1701
+ if (!Array.isArray(raw.repos) || raw.repos.length === 0) {
1702
+ return null;
1703
+ }
1704
+ if (typeof raw.workdir !== "string" || !raw.workdir.trim()) {
1705
+ return null;
1706
+ }
1707
+ const repos = raw.repos.map((item) => normalizeRepoEntry(item)).filter((item) => item != null);
1708
+ if (repos.length === 0) {
1709
+ return null;
1710
+ }
1711
+ return {
1712
+ version: WORKSPACE_REPOS_VERSION,
1713
+ kind: "multi",
1714
+ workdir: raw.workdir,
1715
+ repos,
1716
+ scannedAt: typeof raw.scannedAt === "string" && raw.scannedAt.trim() ? raw.scannedAt : (/* @__PURE__ */ new Date()).toISOString()
1717
+ };
1718
+ } catch {
1719
+ return null;
1720
+ }
1721
+ }
1722
+ function loadWorkspaceReposCache(workdirInput) {
1723
+ const workdir = resolveWorkdirPath(workdirInput);
1724
+ const cached = readManifest(workdir);
1725
+ if (!cached) {
1726
+ throw new Error(
1727
+ `[apm] \u672A\u627E\u5230\u5DE5\u4F5C\u533A\u4ED3\u5E93\u7F13\u5B58 .apm/${WORKSPACE_REPOS_MANIFEST}\uFF0C\u8BF7\u5148\u6267\u884C\u4ED3\u5E93\u68C0\u6D4B`
1728
+ );
1729
+ }
1730
+ if (normalizeWorkdirPath(cached.workdir) !== normalizeWorkdirPath(workdir)) {
1731
+ throw new Error(
1732
+ `[apm] \u5DE5\u4F5C\u533A\u4ED3\u5E93\u7F13\u5B58 workdir \u4E0D\u5339\u914D\uFF1A\u7F13\u5B58=${cached.workdir} \u5F53\u524D=${workdir}\uFF0C\u8BF7\u5F3A\u5236\u91CD\u65B0\u626B\u63CF`
1733
+ );
1734
+ }
1735
+ if (!Array.isArray(cached.repos) || cached.repos.length === 0) {
1736
+ throw new Error(`[apm] \u5DE5\u4F5C\u533A\u4ED3\u5E93\u7F13\u5B58\u65E0\u6548\uFF08repos \u4E3A\u7A7A\uFF09\uFF0C\u8BF7\u5F3A\u5236\u91CD\u65B0\u626B\u63CF`);
1737
+ }
1738
+ console.log(
1739
+ `[apm] \u8BFB\u53D6\u5DE5\u4F5C\u533A\u4ED3\u5E93\u7F13\u5B58 repos=${cached.repos.map((r) => r.path).join(", ")}`
1740
+ );
1741
+ return {
1742
+ ...cached,
1743
+ workdir
1744
+ };
1745
+ }
1746
+ function resolveWorkspaceRepoAbsolutePaths(manifest) {
1747
+ return manifest.repos.map(
1748
+ (entry) => absoluteRepoPath(manifest.workdir, entry)
1749
+ );
1750
+ }
1650
1751
  function formatRepoLabel(workdir, repoAbs) {
1651
1752
  const rel = toRelativeRepoPath(resolveWorkdirPath(workdir), repoAbs);
1652
1753
  return rel || basename(repoAbs) || repoAbs;
@@ -1725,11 +1826,21 @@ async function ensureTaskFeatureBranch(branch, projectId, options) {
1725
1826
  return branch;
1726
1827
  }
1727
1828
  function resolveTaskBranchRepoRoots(workdirPath, reposManifest) {
1728
- const manifestPath = resolveReposManifestPath(reposManifest);
1729
- const entries = loadHomeRepositoryEntries(manifestPath);
1730
- const roots = resolveHomeRepositoryAbsolutePaths(workdirPath, entries);
1829
+ const manifestPath2 = resolveReposManifestPath(reposManifest);
1830
+ if (manifestPath2) {
1831
+ const entries = loadHomeRepositoryEntries(manifestPath2);
1832
+ const roots2 = resolveHomeRepositoryAbsolutePaths(workdirPath, entries);
1833
+ console.log(
1834
+ `[apm] \u8BFB\u53D6\u5916\u90E8\u591A\u4ED3\u6E05\u5355 ${manifestPath2} repos=${entries.map((e) => `${e.path}\u2192${e.remoteUrl}`).join(", ")}`
1835
+ );
1836
+ return roots2;
1837
+ }
1838
+ const workspace = loadWorkspaceReposCache(workdirPath);
1839
+ const roots = resolveWorkspaceRepoAbsolutePaths(workspace);
1731
1840
  console.log(
1732
- `[apm] \u8BFB\u53D6 ${manifestPath} repos=${entries.map((e) => `${e.path}\u2192${e.remoteUrl}`).join(", ")}`
1841
+ `[apm] \u8BFB\u53D6\u5DE5\u4F5C\u533A\u4ED3\u5E93\u6E05\u5355 repos=${workspace.repos.map(
1842
+ (r) => r.remoteUrl ? `${r.path}\u2192${r.remoteUrl}` : r.path
1843
+ ).join(", ")}`
1733
1844
  );
1734
1845
  return roots;
1735
1846
  }
@@ -1799,7 +1910,7 @@ async function runEnsureTaskBranchCli(options = {}) {
1799
1910
  }
1800
1911
  const result = await runTaskBranch(taskId, projectId, {
1801
1912
  cwd: workdir,
1802
- reposManifest: options.reposManifest
1913
+ reposManifest: resolveCliReposManifestPath(options.reposManifest)
1803
1914
  });
1804
1915
  console.log(
1805
1916
  `[apm] \u7279\u6027\u5206\u652F\u5DF2\u5C31\u7EEA\uFF08\u5168\u90E8 ${result.repos.length} \u4E2A\u4ED3\uFF09 branch=${result.branch} projectId=${result.projectId}`
@@ -1808,7 +1919,7 @@ async function runEnsureTaskBranchCli(options = {}) {
1808
1919
 
1809
1920
  // src/utils/user-prompt-cache.ts
1810
1921
  import { createHash } from "crypto";
1811
- import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
1922
+ import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
1812
1923
  import { join as join11 } from "path";
1813
1924
  import { tmpdir } from "os";
1814
1925
  var CACHE_ROOT = join11(tmpdir(), "apm-hooks");
@@ -1830,9 +1941,9 @@ function formatUserPromptAsCommitMessage(prompt) {
1830
1941
  }
1831
1942
  function loadUserPromptCommitMessage(workdirInput) {
1832
1943
  const path = toFsPath(userPromptCachePath(workdirInput));
1833
- if (!existsSync7(path)) return null;
1944
+ if (!existsSync8(path)) return null;
1834
1945
  try {
1835
- const raw = readFileSync6(path, "utf8");
1946
+ const raw = readFileSync7(path, "utf8");
1836
1947
  const msg = formatUserPromptAsCommitMessage(raw);
1837
1948
  return msg || null;
1838
1949
  } catch {
@@ -1873,7 +1984,7 @@ async function runCommitTaskReposCli(options = {}) {
1873
1984
  }
1874
1985
  const result = await syncTaskRepos(workdir, {
1875
1986
  message,
1876
- reposManifest: options.reposManifest
1987
+ reposManifest: resolveCliReposManifestPath(options.reposManifest)
1877
1988
  });
1878
1989
  console.log(
1879
1990
  `[apm] \u591A\u4ED3\u6536\u5C3E\u5B8C\u6210 committed=${result.committed} commitSkipped=${result.commitSkipped} pushed=${result.pushed} pushSkipped=${result.pushSkipped} failed=${result.failed.length} repos=${result.repos.length}`
@@ -518,7 +518,6 @@ async function pushCurrentBranch(cwd) {
518
518
  // src/utils/home-repository.ts
519
519
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
520
520
  import { join as join4, resolve as resolve3 } from "path";
521
- var DEFAULT_REPOS_MANIFEST = "/home/repository.json";
522
521
  function isSimpleChildDirName(name) {
523
522
  if (!name || name === "." || name === "..") return false;
524
523
  if (name.includes("/") || name.includes("\\")) return false;
@@ -529,10 +528,13 @@ function resolveReposManifestPath(explicit) {
529
528
  if (fromOpt) return fromOpt;
530
529
  const fromEnv = process.env.APM_REPOS_MANIFEST?.trim() || "";
531
530
  if (fromEnv) return fromEnv;
532
- return DEFAULT_REPOS_MANIFEST;
531
+ return null;
533
532
  }
534
533
  function loadHomeRepositoryEntries(manifestPath2) {
535
- const label = manifestPath2.trim() || DEFAULT_REPOS_MANIFEST;
534
+ const label = manifestPath2.trim();
535
+ if (!label) {
536
+ throw new Error("[apm] \u591A\u4ED3\u6E05\u5355\u8DEF\u5F84\u4E3A\u7A7A");
537
+ }
536
538
  const path = toFsPath(label);
537
539
  if (!existsSync2(path)) {
538
540
  throw new Error(`[apm] \u672A\u627E\u5230\u591A\u4ED3\u6E05\u5355 ${label}`);
@@ -970,10 +972,20 @@ async function resolveProjectIdForTask(taskId) {
970
972
  }
971
973
  function resolveTaskBranchRepoRoots(workdirPath, reposManifest) {
972
974
  const manifestPath2 = resolveReposManifestPath(reposManifest);
973
- const entries = loadHomeRepositoryEntries(manifestPath2);
974
- const roots = resolveHomeRepositoryAbsolutePaths(workdirPath, entries);
975
+ if (manifestPath2) {
976
+ const entries = loadHomeRepositoryEntries(manifestPath2);
977
+ const roots2 = resolveHomeRepositoryAbsolutePaths(workdirPath, entries);
978
+ console.log(
979
+ `[apm] \u8BFB\u53D6\u5916\u90E8\u591A\u4ED3\u6E05\u5355 ${manifestPath2} repos=${entries.map((e) => `${e.path}\u2192${e.remoteUrl}`).join(", ")}`
980
+ );
981
+ return roots2;
982
+ }
983
+ const workspace = loadWorkspaceReposCache(workdirPath);
984
+ const roots = resolveWorkspaceRepoAbsolutePaths(workspace);
975
985
  console.log(
976
- `[apm] \u8BFB\u53D6 ${manifestPath2} repos=${entries.map((e) => `${e.path}\u2192${e.remoteUrl}`).join(", ")}`
986
+ `[apm] \u8BFB\u53D6\u5DE5\u4F5C\u533A\u4ED3\u5E93\u6E05\u5355 repos=${workspace.repos.map(
987
+ (r) => r.remoteUrl ? `${r.path}\u2192${r.remoteUrl}` : r.path
988
+ ).join(", ")}`
977
989
  );
978
990
  return roots;
979
991
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "8.1.23",
3
+ "version": "8.1.24",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,