ai-project-manage-cli 7.1.18 → 7.1.20
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 +296 -208
- package/dist/webide-message-worker.js +65 -24
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1099,8 +1099,8 @@ import { Command } from "commander";
|
|
|
1099
1099
|
init_config();
|
|
1100
1100
|
|
|
1101
1101
|
// src/commands/init.ts
|
|
1102
|
-
import { join as
|
|
1103
|
-
import { readFileSync as
|
|
1102
|
+
import { join as join6 } from "path";
|
|
1103
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
1104
1104
|
|
|
1105
1105
|
// src/command-utils.ts
|
|
1106
1106
|
init_config();
|
|
@@ -1388,8 +1388,8 @@ async function copyTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
|
|
|
1388
1388
|
|
|
1389
1389
|
// src/deployment-config-sync.ts
|
|
1390
1390
|
init_client();
|
|
1391
|
-
import { join as
|
|
1392
|
-
import { writeFileSync as
|
|
1391
|
+
import { join as join4 } from "path";
|
|
1392
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
1393
1393
|
|
|
1394
1394
|
// src/git-remote.ts
|
|
1395
1395
|
import { execFile } from "child_process";
|
|
@@ -1649,6 +1649,162 @@ async function resolveBranchBaseline(api, sessionId, workdirPath) {
|
|
|
1649
1649
|
|
|
1650
1650
|
// src/deployment-config-sync.ts
|
|
1651
1651
|
init_config();
|
|
1652
|
+
|
|
1653
|
+
// src/workspace-repos.ts
|
|
1654
|
+
import {
|
|
1655
|
+
existsSync as existsSync2,
|
|
1656
|
+
mkdirSync as mkdirSync3,
|
|
1657
|
+
readFileSync as readFileSync3,
|
|
1658
|
+
readdirSync as readdirSync2,
|
|
1659
|
+
statSync as statSync2,
|
|
1660
|
+
writeFileSync as writeFileSync3
|
|
1661
|
+
} from "fs";
|
|
1662
|
+
import { basename as basename2, dirname as dirname2, join as join3, relative, resolve as resolve3 } from "path";
|
|
1663
|
+
var WORKSPACE_REPOS_MANIFEST = "workspace-repos.json";
|
|
1664
|
+
var WORKSPACE_REPOS_VERSION = 1;
|
|
1665
|
+
function manifestPath(workdir) {
|
|
1666
|
+
return join3(workspaceApmDir(workdir), WORKSPACE_REPOS_MANIFEST);
|
|
1667
|
+
}
|
|
1668
|
+
function absoluteRepoPath(workdir, entry) {
|
|
1669
|
+
if (entry.path === "." || entry.path === "") {
|
|
1670
|
+
return workdir;
|
|
1671
|
+
}
|
|
1672
|
+
return resolve3(workdir, entry.path);
|
|
1673
|
+
}
|
|
1674
|
+
function normalizeRepoEntry(raw) {
|
|
1675
|
+
if (!raw || typeof raw !== "object") return null;
|
|
1676
|
+
const o = raw;
|
|
1677
|
+
if (typeof o.path !== "string" || !o.path.trim()) return null;
|
|
1678
|
+
const entry = {
|
|
1679
|
+
path: o.path.trim().replace(/\\/g, "/")
|
|
1680
|
+
};
|
|
1681
|
+
if (typeof o.remoteUrl === "string" && o.remoteUrl.trim()) {
|
|
1682
|
+
entry.remoteUrl = o.remoteUrl.trim();
|
|
1683
|
+
} else if (o.remoteUrl === null) {
|
|
1684
|
+
entry.remoteUrl = null;
|
|
1685
|
+
}
|
|
1686
|
+
return entry;
|
|
1687
|
+
}
|
|
1688
|
+
function readManifest(workdir) {
|
|
1689
|
+
const path19 = toFsPath(manifestPath(workdir));
|
|
1690
|
+
if (!existsSync2(path19)) {
|
|
1691
|
+
return null;
|
|
1692
|
+
}
|
|
1693
|
+
try {
|
|
1694
|
+
const raw = JSON.parse(
|
|
1695
|
+
readFileSync3(path19, "utf8")
|
|
1696
|
+
);
|
|
1697
|
+
if (raw?.version !== WORKSPACE_REPOS_VERSION) {
|
|
1698
|
+
return null;
|
|
1699
|
+
}
|
|
1700
|
+
if (raw.kind !== "single" && raw.kind !== "multi") {
|
|
1701
|
+
return null;
|
|
1702
|
+
}
|
|
1703
|
+
if (!Array.isArray(raw.repos) || raw.repos.length === 0) {
|
|
1704
|
+
return null;
|
|
1705
|
+
}
|
|
1706
|
+
if (typeof raw.workdir !== "string" || !raw.workdir.trim()) {
|
|
1707
|
+
return null;
|
|
1708
|
+
}
|
|
1709
|
+
const repos = raw.repos.map((item) => normalizeRepoEntry(item)).filter((item) => item != null);
|
|
1710
|
+
if (repos.length === 0) {
|
|
1711
|
+
return null;
|
|
1712
|
+
}
|
|
1713
|
+
return {
|
|
1714
|
+
version: WORKSPACE_REPOS_VERSION,
|
|
1715
|
+
kind: raw.kind,
|
|
1716
|
+
workdir: raw.workdir,
|
|
1717
|
+
repos,
|
|
1718
|
+
scannedAt: typeof raw.scannedAt === "string" && raw.scannedAt.trim() ? raw.scannedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
1719
|
+
};
|
|
1720
|
+
} catch {
|
|
1721
|
+
return null;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
function writeManifest(workdir, manifest) {
|
|
1725
|
+
const apmDir = toFsPath(workspaceApmDir(workdir));
|
|
1726
|
+
mkdirSync3(apmDir, { recursive: true });
|
|
1727
|
+
const path19 = toFsPath(manifestPath(workdir));
|
|
1728
|
+
writeFileSync3(path19, `${JSON.stringify(manifest, null, 2)}
|
|
1729
|
+
`, "utf8");
|
|
1730
|
+
}
|
|
1731
|
+
function isPathInsideOrEqual(parentAbs, childAbs) {
|
|
1732
|
+
const parent = normalizeWorkdirPath(parentAbs);
|
|
1733
|
+
const child = normalizeWorkdirPath(childAbs);
|
|
1734
|
+
if (child === parent) return true;
|
|
1735
|
+
const prefix = parent.endsWith("/") ? parent : `${parent}/`;
|
|
1736
|
+
return child.startsWith(prefix);
|
|
1737
|
+
}
|
|
1738
|
+
function findWorkspaceReposManifestNearPath(startDirInput) {
|
|
1739
|
+
let current = resolve3(startDirInput);
|
|
1740
|
+
for (; ; ) {
|
|
1741
|
+
const candidates = /* @__PURE__ */ new Set([normalizeWorkdirPath(current)]);
|
|
1742
|
+
try {
|
|
1743
|
+
if (existsSync2(toFsPath(current))) {
|
|
1744
|
+
candidates.add(resolveWorkdirPath(current));
|
|
1745
|
+
}
|
|
1746
|
+
} catch {
|
|
1747
|
+
}
|
|
1748
|
+
for (const candidate of candidates) {
|
|
1749
|
+
const cached = readManifest(candidate);
|
|
1750
|
+
if (!cached) continue;
|
|
1751
|
+
const cachedWorkdir = resolveWorkdirPath(cached.workdir);
|
|
1752
|
+
const candidateNorm = resolveWorkdirPath(candidate);
|
|
1753
|
+
if (cachedWorkdir === candidateNorm) {
|
|
1754
|
+
return { ...cached, workdir: cachedWorkdir };
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
const parent = dirname2(current);
|
|
1758
|
+
if (parent === current) {
|
|
1759
|
+
return null;
|
|
1760
|
+
}
|
|
1761
|
+
current = parent;
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
function matchWorkspaceRepoEntryForPath(manifest, pathInput) {
|
|
1765
|
+
const target = resolveWorkdirPath(pathInput);
|
|
1766
|
+
const workdir = resolveWorkdirPath(manifest.workdir);
|
|
1767
|
+
let best = null;
|
|
1768
|
+
let bestLen = -1;
|
|
1769
|
+
for (const entry of manifest.repos) {
|
|
1770
|
+
const abs = resolveWorkdirPath(absoluteRepoPath(workdir, entry));
|
|
1771
|
+
if (!isPathInsideOrEqual(abs, target)) {
|
|
1772
|
+
continue;
|
|
1773
|
+
}
|
|
1774
|
+
if (abs.length > bestLen) {
|
|
1775
|
+
best = entry;
|
|
1776
|
+
bestLen = abs.length;
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
return best;
|
|
1780
|
+
}
|
|
1781
|
+
async function enrichWorkspaceReposRemoteUrls(manifest) {
|
|
1782
|
+
let changed = false;
|
|
1783
|
+
const repos = [];
|
|
1784
|
+
for (const entry of manifest.repos) {
|
|
1785
|
+
const abs = absoluteRepoPath(manifest.workdir, entry);
|
|
1786
|
+
const remoteUrl = await tryReadHttpsGitOriginUrl(abs);
|
|
1787
|
+
const next = {
|
|
1788
|
+
path: entry.path,
|
|
1789
|
+
remoteUrl: remoteUrl || null
|
|
1790
|
+
};
|
|
1791
|
+
if ((entry.remoteUrl ?? null) !== next.remoteUrl) {
|
|
1792
|
+
changed = true;
|
|
1793
|
+
}
|
|
1794
|
+
repos.push(next);
|
|
1795
|
+
}
|
|
1796
|
+
const nextManifest = {
|
|
1797
|
+
...manifest,
|
|
1798
|
+
repos,
|
|
1799
|
+
scannedAt: changed ? (/* @__PURE__ */ new Date()).toISOString() : manifest.scannedAt
|
|
1800
|
+
};
|
|
1801
|
+
if (changed) {
|
|
1802
|
+
writeManifest(manifest.workdir, nextManifest);
|
|
1803
|
+
}
|
|
1804
|
+
return nextManifest;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
// src/deployment-config-sync.ts
|
|
1652
1808
|
var TEMPLATE_HINT = "\u4FDD\u7559\u6A21\u677F .apm/apm.config.json";
|
|
1653
1809
|
var SYNC_HINT = "\u767B\u8BB0\u5DE5\u4F5C\u7A7A\u95F4\u8DEF\u5F84\u3001\u7ED1\u5B9A\u4ED3\u5E93\u540E\uFF0C\u53EF\u6267\u884C: apm sync-deploy-config";
|
|
1654
1810
|
async function resolveRepositoryIdForSync(api, workdirPath) {
|
|
@@ -1663,7 +1819,73 @@ async function resolveRepositoryIdForSync(api, workdirPath) {
|
|
|
1663
1819
|
};
|
|
1664
1820
|
}
|
|
1665
1821
|
}
|
|
1666
|
-
async function
|
|
1822
|
+
async function resolveDeployCwdForRepository(workspaceRoot, repositoryId, api) {
|
|
1823
|
+
const start = resolveWorkdirPath(workspaceRoot);
|
|
1824
|
+
let manifest = findWorkspaceReposManifestNearPath(start);
|
|
1825
|
+
if (!manifest) {
|
|
1826
|
+
return null;
|
|
1827
|
+
}
|
|
1828
|
+
try {
|
|
1829
|
+
manifest = await enrichWorkspaceReposRemoteUrls(manifest);
|
|
1830
|
+
} catch {
|
|
1831
|
+
return null;
|
|
1832
|
+
}
|
|
1833
|
+
let client = api;
|
|
1834
|
+
if (!client) {
|
|
1835
|
+
const cfg = await tryReadApmConfig();
|
|
1836
|
+
if (!cfg || !resolveApiKey(cfg)) {
|
|
1837
|
+
return null;
|
|
1838
|
+
}
|
|
1839
|
+
client = createApmApiClient(cfg);
|
|
1840
|
+
}
|
|
1841
|
+
for (const entry of manifest.repos) {
|
|
1842
|
+
const abs = absoluteRepoPath(manifest.workdir, entry);
|
|
1843
|
+
const remoteUrl = toHttpsGitRemoteUrl(entry.remoteUrl ?? "");
|
|
1844
|
+
if (!remoteUrl) {
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1847
|
+
let baseBranch = "";
|
|
1848
|
+
try {
|
|
1849
|
+
const gitRoot = await resolveGitRepoRoot(abs);
|
|
1850
|
+
baseBranch = (await resolveDefaultRemoteBranch(gitRoot)).trim();
|
|
1851
|
+
} catch {
|
|
1852
|
+
continue;
|
|
1853
|
+
}
|
|
1854
|
+
if (!baseBranch) {
|
|
1855
|
+
continue;
|
|
1856
|
+
}
|
|
1857
|
+
try {
|
|
1858
|
+
const matched = await client.cli.matchRepository({
|
|
1859
|
+
url: remoteUrl,
|
|
1860
|
+
baseBranch
|
|
1861
|
+
});
|
|
1862
|
+
if (matched.repositoryId?.trim() === repositoryId) {
|
|
1863
|
+
return abs;
|
|
1864
|
+
}
|
|
1865
|
+
} catch {
|
|
1866
|
+
continue;
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
return null;
|
|
1870
|
+
}
|
|
1871
|
+
async function writeDeploymentConfigContent(apmDir, content, configName) {
|
|
1872
|
+
let parsed;
|
|
1873
|
+
try {
|
|
1874
|
+
parsed = JSON.parse(content);
|
|
1875
|
+
} catch {
|
|
1876
|
+
console.warn(
|
|
1877
|
+
`[apm] \u8FDC\u7A0B\u90E8\u7F72\u914D\u7F6E\u300C${configName}\u300DJSON \u65E0\u6548\uFF08${TEMPLATE_HINT}\uFF09`
|
|
1878
|
+
);
|
|
1879
|
+
return false;
|
|
1880
|
+
}
|
|
1881
|
+
const apmConfigPath = toFsPath(join4(apmDir, "apm.config.json"));
|
|
1882
|
+
writeFileSync4(apmConfigPath, `${JSON.stringify(parsed, null, 2)}
|
|
1883
|
+
`, "utf8");
|
|
1884
|
+
console.log(`[apm] \u5DF2\u540C\u6B65\u5E73\u53F0\u90E8\u7F72\u914D\u7F6E: ${configName}`);
|
|
1885
|
+
console.log("[apm] \u5DF2\u5199\u5165 .apm/apm.config.json");
|
|
1886
|
+
return true;
|
|
1887
|
+
}
|
|
1888
|
+
async function syncRemoteDeploymentConfig(workdirPath, apmDir, options) {
|
|
1667
1889
|
const cfg = await tryReadApmConfig();
|
|
1668
1890
|
if (!cfg || !resolveApiKey(cfg)) {
|
|
1669
1891
|
console.log(
|
|
@@ -1673,10 +1895,14 @@ async function syncRemoteDeploymentConfig(workdirPath, apmDir) {
|
|
|
1673
1895
|
return { synced: false, repositoryId: null };
|
|
1674
1896
|
}
|
|
1675
1897
|
const api = createApmApiClient(cfg);
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
)
|
|
1898
|
+
const preferredId = options?.repositoryId?.trim() || "";
|
|
1899
|
+
let repositoryId = preferredId || null;
|
|
1900
|
+
let diagnostic = null;
|
|
1901
|
+
if (!repositoryId) {
|
|
1902
|
+
const resolved = await resolveRepositoryIdForSync(api, workdirPath);
|
|
1903
|
+
repositoryId = resolved.repositoryId;
|
|
1904
|
+
diagnostic = resolved.diagnostic;
|
|
1905
|
+
}
|
|
1680
1906
|
if (!repositoryId) {
|
|
1681
1907
|
console.log(
|
|
1682
1908
|
`[apm] \u672A\u80FD\u540C\u6B65\u5E73\u53F0\u90E8\u7F72\u914D\u7F6E\uFF08${TEMPLATE_HINT}\uFF09\u3002
|
|
@@ -1693,21 +1919,15 @@ ${diagnostic ?? ""}
|
|
|
1693
1919
|
);
|
|
1694
1920
|
return { synced: false, repositoryId };
|
|
1695
1921
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1922
|
+
const targetApmDir = apmDir ?? workspaceApmDir(workdirPath);
|
|
1923
|
+
const wrote = await writeDeploymentConfigContent(
|
|
1924
|
+
targetApmDir,
|
|
1925
|
+
config.content,
|
|
1926
|
+
config.name
|
|
1927
|
+
);
|
|
1928
|
+
if (!wrote) {
|
|
1703
1929
|
return { synced: false, repositoryId };
|
|
1704
1930
|
}
|
|
1705
|
-
const targetApmDir = apmDir ?? workspaceApmDir(workdirPath);
|
|
1706
|
-
const apmConfigPath = toFsPath(join3(targetApmDir, "apm.config.json"));
|
|
1707
|
-
writeFileSync3(apmConfigPath, `${JSON.stringify(parsed, null, 2)}
|
|
1708
|
-
`, "utf8");
|
|
1709
|
-
console.log(`[apm] \u5DF2\u540C\u6B65\u5E73\u53F0\u90E8\u7F72\u914D\u7F6E: ${config.name}`);
|
|
1710
|
-
console.log("[apm] \u5DF2\u5199\u5165 .apm/apm.config.json");
|
|
1711
1931
|
return { synced: true, repositoryId, configName: config.name };
|
|
1712
1932
|
}
|
|
1713
1933
|
|
|
@@ -1715,14 +1935,14 @@ ${diagnostic ?? ""}
|
|
|
1715
1935
|
init_client();
|
|
1716
1936
|
init_config();
|
|
1717
1937
|
import {
|
|
1718
|
-
existsSync as
|
|
1719
|
-
readdirSync as
|
|
1720
|
-
readFileSync as
|
|
1938
|
+
existsSync as existsSync3,
|
|
1939
|
+
readdirSync as readdirSync3,
|
|
1940
|
+
readFileSync as readFileSync4,
|
|
1721
1941
|
rmSync,
|
|
1722
|
-
writeFileSync as
|
|
1942
|
+
writeFileSync as writeFileSync5
|
|
1723
1943
|
} from "fs";
|
|
1724
1944
|
import { createHash } from "crypto";
|
|
1725
|
-
import { dirname as
|
|
1945
|
+
import { dirname as dirname3, join as join5, relative as relative2, sep } from "path";
|
|
1726
1946
|
var MANIFEST_FILE = "manifest.json";
|
|
1727
1947
|
function normalizeProjectIdForPath(projectId) {
|
|
1728
1948
|
const id = projectId.trim();
|
|
@@ -1736,11 +1956,11 @@ function normalizeProjectIdForPath(projectId) {
|
|
|
1736
1956
|
}
|
|
1737
1957
|
function projectDocumentsDir(apmRoot, projectId) {
|
|
1738
1958
|
const id = normalizeProjectIdForPath(projectId);
|
|
1739
|
-
return
|
|
1959
|
+
return join5(apmRoot ?? workspaceApmDir(), "project", id);
|
|
1740
1960
|
}
|
|
1741
1961
|
function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
|
|
1742
1962
|
const normalized = normalizeLocalDocumentPath(documentPath);
|
|
1743
|
-
return
|
|
1963
|
+
return join5(
|
|
1744
1964
|
projectDocumentsDir(apmRoot, projectId),
|
|
1745
1965
|
...normalized.split("/")
|
|
1746
1966
|
);
|
|
@@ -1760,16 +1980,16 @@ function hashLocalFileContent(content) {
|
|
|
1760
1980
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
1761
1981
|
}
|
|
1762
1982
|
function readLocalManifest(apmRoot, projectId) {
|
|
1763
|
-
const manifestPath3 =
|
|
1983
|
+
const manifestPath3 = join5(
|
|
1764
1984
|
projectDocumentsDir(apmRoot, projectId),
|
|
1765
1985
|
MANIFEST_FILE
|
|
1766
1986
|
);
|
|
1767
|
-
if (!
|
|
1987
|
+
if (!existsSync3(manifestPath3)) {
|
|
1768
1988
|
return null;
|
|
1769
1989
|
}
|
|
1770
1990
|
try {
|
|
1771
1991
|
return JSON.parse(
|
|
1772
|
-
|
|
1992
|
+
readFileSync4(manifestPath3, "utf8")
|
|
1773
1993
|
);
|
|
1774
1994
|
} catch {
|
|
1775
1995
|
return null;
|
|
@@ -1777,13 +1997,13 @@ function readLocalManifest(apmRoot, projectId) {
|
|
|
1777
1997
|
}
|
|
1778
1998
|
function listLocalDocumentPaths(apmRoot, projectId) {
|
|
1779
1999
|
const root = projectDocumentsDir(apmRoot, projectId);
|
|
1780
|
-
if (!
|
|
2000
|
+
if (!existsSync3(root)) {
|
|
1781
2001
|
return [];
|
|
1782
2002
|
}
|
|
1783
2003
|
const paths = [];
|
|
1784
2004
|
const walk = (dir) => {
|
|
1785
|
-
for (const entry of
|
|
1786
|
-
const abs =
|
|
2005
|
+
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
2006
|
+
const abs = join5(dir, entry.name);
|
|
1787
2007
|
if (entry.isDirectory()) {
|
|
1788
2008
|
walk(abs);
|
|
1789
2009
|
continue;
|
|
@@ -1791,7 +2011,7 @@ function listLocalDocumentPaths(apmRoot, projectId) {
|
|
|
1791
2011
|
if (entry.isFile() && entry.name === MANIFEST_FILE) {
|
|
1792
2012
|
continue;
|
|
1793
2013
|
}
|
|
1794
|
-
const rel =
|
|
2014
|
+
const rel = relative2(root, abs).split(sep).join("/");
|
|
1795
2015
|
paths.push(rel);
|
|
1796
2016
|
}
|
|
1797
2017
|
};
|
|
@@ -1901,8 +2121,8 @@ ${diagnostic ?? ""}`);
|
|
|
1901
2121
|
const absPath = toFsPath(
|
|
1902
2122
|
projectDocumentLocalPath(targetApmDir, projectId, doc.path)
|
|
1903
2123
|
);
|
|
1904
|
-
await ensureDirExists(
|
|
1905
|
-
|
|
2124
|
+
await ensureDirExists(dirname3(absPath));
|
|
2125
|
+
writeFileSync5(absPath, doc.content, "utf8");
|
|
1906
2126
|
downloaded += 1;
|
|
1907
2127
|
}
|
|
1908
2128
|
}
|
|
@@ -1911,13 +2131,13 @@ ${diagnostic ?? ""}`);
|
|
|
1911
2131
|
const absPath = toFsPath(
|
|
1912
2132
|
projectDocumentLocalPath(targetApmDir, projectId, path19)
|
|
1913
2133
|
);
|
|
1914
|
-
if (
|
|
2134
|
+
if (existsSync3(absPath)) {
|
|
1915
2135
|
rmSync(absPath, { force: true });
|
|
1916
2136
|
deleted += 1;
|
|
1917
2137
|
}
|
|
1918
2138
|
}
|
|
1919
|
-
|
|
1920
|
-
toFsPath(
|
|
2139
|
+
writeFileSync5(
|
|
2140
|
+
toFsPath(join5(docsDir, MANIFEST_FILE)),
|
|
1921
2141
|
`${JSON.stringify(remoteManifest, null, 2)}
|
|
1922
2142
|
`,
|
|
1923
2143
|
"utf8"
|
|
@@ -1960,7 +2180,7 @@ async function syncProjectDocumentsPush(cfg, workdirPath, apmRoot, options) {
|
|
|
1960
2180
|
const absPath = toFsPath(
|
|
1961
2181
|
projectDocumentLocalPath(targetApmDir, projectId, path19)
|
|
1962
2182
|
);
|
|
1963
|
-
const content =
|
|
2183
|
+
const content = readFileSync4(absPath, "utf8");
|
|
1964
2184
|
const contentHash = hashLocalFileContent(content);
|
|
1965
2185
|
if (remoteHashByPath.get(path19) === contentHash) {
|
|
1966
2186
|
continue;
|
|
@@ -1999,11 +2219,11 @@ async function ensureWorkspaceInitialized(workdir, options) {
|
|
|
1999
2219
|
await syncProjectDocumentsPull(workdir, apmDir);
|
|
2000
2220
|
const trimmedName = options?.name?.trim();
|
|
2001
2221
|
if (trimmedName) {
|
|
2002
|
-
const apmConfigPath = toFsPath(
|
|
2003
|
-
const config =
|
|
2222
|
+
const apmConfigPath = toFsPath(join6(apmDir, "apm.config.json"));
|
|
2223
|
+
const config = readFileSync5(apmConfigPath, "utf8");
|
|
2004
2224
|
const configJson = JSON.parse(config);
|
|
2005
2225
|
configJson.name = trimmedName;
|
|
2006
|
-
|
|
2226
|
+
writeFileSync6(
|
|
2007
2227
|
apmConfigPath,
|
|
2008
2228
|
`${JSON.stringify(configJson, null, 2)}
|
|
2009
2229
|
`,
|
|
@@ -2036,7 +2256,7 @@ async function runInit(name) {
|
|
|
2036
2256
|
// src/commands/login.ts
|
|
2037
2257
|
init_config();
|
|
2038
2258
|
init_client();
|
|
2039
|
-
import { existsSync as
|
|
2259
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2040
2260
|
import { ApiError } from "listpage-http";
|
|
2041
2261
|
async function runLogin(opts) {
|
|
2042
2262
|
const baseUrl = (opts.server?.trim() || process.env.AI_PM_SERVER?.trim() || DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
@@ -2091,169 +2311,13 @@ async function runLogin(opts) {
|
|
|
2091
2311
|
);
|
|
2092
2312
|
const workdir = resolveWorkdirPath();
|
|
2093
2313
|
const apmDir = workspaceApmDir(workdir);
|
|
2094
|
-
if (
|
|
2314
|
+
if (existsSync4(apmDir)) {
|
|
2095
2315
|
await syncRemoteDeploymentConfig(workdir, apmDir);
|
|
2096
2316
|
}
|
|
2097
2317
|
}
|
|
2098
2318
|
|
|
2099
2319
|
// src/commands/branch.ts
|
|
2100
2320
|
init_client();
|
|
2101
|
-
|
|
2102
|
-
// src/workspace-repos.ts
|
|
2103
|
-
import {
|
|
2104
|
-
existsSync as existsSync4,
|
|
2105
|
-
mkdirSync as mkdirSync3,
|
|
2106
|
-
readFileSync as readFileSync5,
|
|
2107
|
-
readdirSync as readdirSync3,
|
|
2108
|
-
statSync as statSync2,
|
|
2109
|
-
writeFileSync as writeFileSync6
|
|
2110
|
-
} from "fs";
|
|
2111
|
-
import { basename as basename2, dirname as dirname3, join as join6, relative as relative2, resolve as resolve3 } from "path";
|
|
2112
|
-
var WORKSPACE_REPOS_MANIFEST = "workspace-repos.json";
|
|
2113
|
-
var WORKSPACE_REPOS_VERSION = 1;
|
|
2114
|
-
function manifestPath(workdir) {
|
|
2115
|
-
return join6(workspaceApmDir(workdir), WORKSPACE_REPOS_MANIFEST);
|
|
2116
|
-
}
|
|
2117
|
-
function absoluteRepoPath(workdir, entry) {
|
|
2118
|
-
if (entry.path === "." || entry.path === "") {
|
|
2119
|
-
return workdir;
|
|
2120
|
-
}
|
|
2121
|
-
return resolve3(workdir, entry.path);
|
|
2122
|
-
}
|
|
2123
|
-
function normalizeRepoEntry(raw) {
|
|
2124
|
-
if (!raw || typeof raw !== "object") return null;
|
|
2125
|
-
const o = raw;
|
|
2126
|
-
if (typeof o.path !== "string" || !o.path.trim()) return null;
|
|
2127
|
-
const entry = {
|
|
2128
|
-
path: o.path.trim().replace(/\\/g, "/")
|
|
2129
|
-
};
|
|
2130
|
-
if (typeof o.remoteUrl === "string" && o.remoteUrl.trim()) {
|
|
2131
|
-
entry.remoteUrl = o.remoteUrl.trim();
|
|
2132
|
-
} else if (o.remoteUrl === null) {
|
|
2133
|
-
entry.remoteUrl = null;
|
|
2134
|
-
}
|
|
2135
|
-
return entry;
|
|
2136
|
-
}
|
|
2137
|
-
function readManifest(workdir) {
|
|
2138
|
-
const path19 = toFsPath(manifestPath(workdir));
|
|
2139
|
-
if (!existsSync4(path19)) {
|
|
2140
|
-
return null;
|
|
2141
|
-
}
|
|
2142
|
-
try {
|
|
2143
|
-
const raw = JSON.parse(
|
|
2144
|
-
readFileSync5(path19, "utf8")
|
|
2145
|
-
);
|
|
2146
|
-
if (raw?.version !== WORKSPACE_REPOS_VERSION) {
|
|
2147
|
-
return null;
|
|
2148
|
-
}
|
|
2149
|
-
if (raw.kind !== "single" && raw.kind !== "multi") {
|
|
2150
|
-
return null;
|
|
2151
|
-
}
|
|
2152
|
-
if (!Array.isArray(raw.repos) || raw.repos.length === 0) {
|
|
2153
|
-
return null;
|
|
2154
|
-
}
|
|
2155
|
-
if (typeof raw.workdir !== "string" || !raw.workdir.trim()) {
|
|
2156
|
-
return null;
|
|
2157
|
-
}
|
|
2158
|
-
const repos = raw.repos.map((item) => normalizeRepoEntry(item)).filter((item) => item != null);
|
|
2159
|
-
if (repos.length === 0) {
|
|
2160
|
-
return null;
|
|
2161
|
-
}
|
|
2162
|
-
return {
|
|
2163
|
-
version: WORKSPACE_REPOS_VERSION,
|
|
2164
|
-
kind: raw.kind,
|
|
2165
|
-
workdir: raw.workdir,
|
|
2166
|
-
repos,
|
|
2167
|
-
scannedAt: typeof raw.scannedAt === "string" && raw.scannedAt.trim() ? raw.scannedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
2168
|
-
};
|
|
2169
|
-
} catch {
|
|
2170
|
-
return null;
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
function writeManifest(workdir, manifest) {
|
|
2174
|
-
const apmDir = toFsPath(workspaceApmDir(workdir));
|
|
2175
|
-
mkdirSync3(apmDir, { recursive: true });
|
|
2176
|
-
const path19 = toFsPath(manifestPath(workdir));
|
|
2177
|
-
writeFileSync6(path19, `${JSON.stringify(manifest, null, 2)}
|
|
2178
|
-
`, "utf8");
|
|
2179
|
-
}
|
|
2180
|
-
function isPathInsideOrEqual(parentAbs, childAbs) {
|
|
2181
|
-
const parent = normalizeWorkdirPath(parentAbs);
|
|
2182
|
-
const child = normalizeWorkdirPath(childAbs);
|
|
2183
|
-
if (child === parent) return true;
|
|
2184
|
-
const prefix = parent.endsWith("/") ? parent : `${parent}/`;
|
|
2185
|
-
return child.startsWith(prefix);
|
|
2186
|
-
}
|
|
2187
|
-
function findWorkspaceReposManifestNearPath(startDirInput) {
|
|
2188
|
-
let current = resolve3(startDirInput);
|
|
2189
|
-
for (; ; ) {
|
|
2190
|
-
const candidates = /* @__PURE__ */ new Set([normalizeWorkdirPath(current)]);
|
|
2191
|
-
try {
|
|
2192
|
-
if (existsSync4(toFsPath(current))) {
|
|
2193
|
-
candidates.add(resolveWorkdirPath(current));
|
|
2194
|
-
}
|
|
2195
|
-
} catch {
|
|
2196
|
-
}
|
|
2197
|
-
for (const candidate of candidates) {
|
|
2198
|
-
const cached = readManifest(candidate);
|
|
2199
|
-
if (!cached) continue;
|
|
2200
|
-
const cachedWorkdir = resolveWorkdirPath(cached.workdir);
|
|
2201
|
-
const candidateNorm = resolveWorkdirPath(candidate);
|
|
2202
|
-
if (cachedWorkdir === candidateNorm) {
|
|
2203
|
-
return { ...cached, workdir: cachedWorkdir };
|
|
2204
|
-
}
|
|
2205
|
-
}
|
|
2206
|
-
const parent = dirname3(current);
|
|
2207
|
-
if (parent === current) {
|
|
2208
|
-
return null;
|
|
2209
|
-
}
|
|
2210
|
-
current = parent;
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
function matchWorkspaceRepoEntryForPath(manifest, pathInput) {
|
|
2214
|
-
const target = resolveWorkdirPath(pathInput);
|
|
2215
|
-
const workdir = resolveWorkdirPath(manifest.workdir);
|
|
2216
|
-
let best = null;
|
|
2217
|
-
let bestLen = -1;
|
|
2218
|
-
for (const entry of manifest.repos) {
|
|
2219
|
-
const abs = resolveWorkdirPath(absoluteRepoPath(workdir, entry));
|
|
2220
|
-
if (!isPathInsideOrEqual(abs, target)) {
|
|
2221
|
-
continue;
|
|
2222
|
-
}
|
|
2223
|
-
if (abs.length > bestLen) {
|
|
2224
|
-
best = entry;
|
|
2225
|
-
bestLen = abs.length;
|
|
2226
|
-
}
|
|
2227
|
-
}
|
|
2228
|
-
return best;
|
|
2229
|
-
}
|
|
2230
|
-
async function enrichWorkspaceReposRemoteUrls(manifest) {
|
|
2231
|
-
let changed = false;
|
|
2232
|
-
const repos = [];
|
|
2233
|
-
for (const entry of manifest.repos) {
|
|
2234
|
-
const abs = absoluteRepoPath(manifest.workdir, entry);
|
|
2235
|
-
const remoteUrl = await tryReadHttpsGitOriginUrl(abs);
|
|
2236
|
-
const next = {
|
|
2237
|
-
path: entry.path,
|
|
2238
|
-
remoteUrl: remoteUrl || null
|
|
2239
|
-
};
|
|
2240
|
-
if ((entry.remoteUrl ?? null) !== next.remoteUrl) {
|
|
2241
|
-
changed = true;
|
|
2242
|
-
}
|
|
2243
|
-
repos.push(next);
|
|
2244
|
-
}
|
|
2245
|
-
const nextManifest = {
|
|
2246
|
-
...manifest,
|
|
2247
|
-
repos,
|
|
2248
|
-
scannedAt: changed ? (/* @__PURE__ */ new Date()).toISOString() : manifest.scannedAt
|
|
2249
|
-
};
|
|
2250
|
-
if (changed) {
|
|
2251
|
-
writeManifest(manifest.workdir, nextManifest);
|
|
2252
|
-
}
|
|
2253
|
-
return nextManifest;
|
|
2254
|
-
}
|
|
2255
|
-
|
|
2256
|
-
// src/commands/branch.ts
|
|
2257
2321
|
var SESSION_BRANCH_PREFIX = "feat/session-";
|
|
2258
2322
|
function branchNameForSession(sessionId) {
|
|
2259
2323
|
const id = sessionId.trim();
|
|
@@ -3861,6 +3925,7 @@ function validateDeployPush(o) {
|
|
|
3861
3925
|
deploymentRunId: o.deploymentRunId.trim(),
|
|
3862
3926
|
workdir: o.workdir.trim(),
|
|
3863
3927
|
environment,
|
|
3928
|
+
...typeof o.repositoryId === "string" && o.repositoryId.trim() ? { repositoryId: o.repositoryId.trim() } : {},
|
|
3864
3929
|
...o.packOnly === true ? { packOnly: true } : {}
|
|
3865
3930
|
}
|
|
3866
3931
|
};
|
|
@@ -6774,7 +6839,8 @@ async function executeDeploy(options) {
|
|
|
6774
6839
|
try {
|
|
6775
6840
|
const configSyncResult = await syncRemoteDeploymentConfig(
|
|
6776
6841
|
cwd,
|
|
6777
|
-
workspaceApmDir(cwd)
|
|
6842
|
+
workspaceApmDir(cwd),
|
|
6843
|
+
options.repositoryId ? { repositoryId: options.repositoryId } : void 0
|
|
6778
6844
|
);
|
|
6779
6845
|
if (configSyncResult.synced && configSyncResult.configName) {
|
|
6780
6846
|
outputParts.push(
|
|
@@ -7049,6 +7115,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
7049
7115
|
if (signal.aborted) return;
|
|
7050
7116
|
const api = createApmApiClient(cfg);
|
|
7051
7117
|
const deploymentRunId = msg.deploymentRunId;
|
|
7118
|
+
const repositoryId = msg.repositoryId?.trim() || "";
|
|
7052
7119
|
await api.cli.updateTaskDeploymentStatus({
|
|
7053
7120
|
id: deploymentRunId,
|
|
7054
7121
|
status: "DEPLOYING"
|
|
@@ -7057,13 +7124,33 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
7057
7124
|
api,
|
|
7058
7125
|
deploymentRunId,
|
|
7059
7126
|
run: async (appendLog) => {
|
|
7060
|
-
const
|
|
7127
|
+
const workspaceRoot = requireRemoteWorkdir(msg.workdir);
|
|
7128
|
+
let cwd = workspaceRoot;
|
|
7129
|
+
if (repositoryId) {
|
|
7130
|
+
const resolved = await resolveDeployCwdForRepository(
|
|
7131
|
+
workspaceRoot,
|
|
7132
|
+
repositoryId,
|
|
7133
|
+
api
|
|
7134
|
+
);
|
|
7135
|
+
if (resolved) {
|
|
7136
|
+
cwd = resolved;
|
|
7137
|
+
appendLog(
|
|
7138
|
+
`[apm] \u591A\u4ED3\u90E8\u7F72\uFF1A\u6309 repositoryId=${repositoryId} \u89E3\u6790 cwd=${cwd}
|
|
7139
|
+
`
|
|
7140
|
+
);
|
|
7141
|
+
} else {
|
|
7142
|
+
appendLog(
|
|
7143
|
+
`[apm] \u672A\u5728 workspace-repos \u547D\u4E2D repositoryId=${repositoryId}\uFF0C\u4F7F\u7528\u5DE5\u4F5C\u7A7A\u95F4\u76EE\u5F55 cwd=${cwd}
|
|
7144
|
+
`
|
|
7145
|
+
);
|
|
7146
|
+
}
|
|
7147
|
+
}
|
|
7061
7148
|
const displayCommand = resolveDeployCommand(
|
|
7062
7149
|
msg.environment,
|
|
7063
7150
|
msg.packOnly
|
|
7064
7151
|
);
|
|
7065
7152
|
console.log(
|
|
7066
|
-
`[apm] deploy start id=${deploymentRunId} env=${msg.environment} cwd=${
|
|
7153
|
+
`[apm] deploy start id=${deploymentRunId} env=${msg.environment} cwd=${cwd}` + (repositoryId ? ` repositoryId=${repositoryId}` : "")
|
|
7067
7154
|
);
|
|
7068
7155
|
console.log(`[apm] deploy command: ${displayCommand}`);
|
|
7069
7156
|
if (signal.aborted) {
|
|
@@ -7071,11 +7158,12 @@ async function handleInboundDeploy(cfg, msg, signal) {
|
|
|
7071
7158
|
}
|
|
7072
7159
|
const deployOptions = {
|
|
7073
7160
|
env: msg.environment,
|
|
7074
|
-
cwd
|
|
7161
|
+
cwd,
|
|
7075
7162
|
packOnly: msg.packOnly,
|
|
7076
7163
|
captureOutput: true,
|
|
7077
7164
|
archiveDeployArtifact: true,
|
|
7078
|
-
deployTrigger: "connect"
|
|
7165
|
+
deployTrigger: "connect",
|
|
7166
|
+
...repositoryId ? { repositoryId } : {}
|
|
7079
7167
|
};
|
|
7080
7168
|
const output = await executeDeploy(deployOptions);
|
|
7081
7169
|
if (output.trim()) {
|
|
@@ -2718,7 +2718,24 @@ async function resolveRepositoryIdForSync(api, workdirPath) {
|
|
|
2718
2718
|
};
|
|
2719
2719
|
}
|
|
2720
2720
|
}
|
|
2721
|
-
async function
|
|
2721
|
+
async function writeDeploymentConfigContent(apmDir, content, configName) {
|
|
2722
|
+
let parsed;
|
|
2723
|
+
try {
|
|
2724
|
+
parsed = JSON.parse(content);
|
|
2725
|
+
} catch {
|
|
2726
|
+
console.warn(
|
|
2727
|
+
`[apm] \u8FDC\u7A0B\u90E8\u7F72\u914D\u7F6E\u300C${configName}\u300DJSON \u65E0\u6548\uFF08${TEMPLATE_HINT}\uFF09`
|
|
2728
|
+
);
|
|
2729
|
+
return false;
|
|
2730
|
+
}
|
|
2731
|
+
const apmConfigPath = toFsPath(join5(apmDir, "apm.config.json"));
|
|
2732
|
+
writeFileSync6(apmConfigPath, `${JSON.stringify(parsed, null, 2)}
|
|
2733
|
+
`, "utf8");
|
|
2734
|
+
console.log(`[apm] \u5DF2\u540C\u6B65\u5E73\u53F0\u90E8\u7F72\u914D\u7F6E: ${configName}`);
|
|
2735
|
+
console.log("[apm] \u5DF2\u5199\u5165 .apm/apm.config.json");
|
|
2736
|
+
return true;
|
|
2737
|
+
}
|
|
2738
|
+
async function syncRemoteDeploymentConfig(workdirPath, apmDir, options) {
|
|
2722
2739
|
const cfg = await tryReadApmConfig();
|
|
2723
2740
|
if (!cfg || !resolveApiKey(cfg)) {
|
|
2724
2741
|
console.log(
|
|
@@ -2728,10 +2745,14 @@ async function syncRemoteDeploymentConfig(workdirPath, apmDir) {
|
|
|
2728
2745
|
return { synced: false, repositoryId: null };
|
|
2729
2746
|
}
|
|
2730
2747
|
const api = createApmApiClient(cfg);
|
|
2731
|
-
const
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
)
|
|
2748
|
+
const preferredId = options?.repositoryId?.trim() || "";
|
|
2749
|
+
let repositoryId = preferredId || null;
|
|
2750
|
+
let diagnostic = null;
|
|
2751
|
+
if (!repositoryId) {
|
|
2752
|
+
const resolved = await resolveRepositoryIdForSync(api, workdirPath);
|
|
2753
|
+
repositoryId = resolved.repositoryId;
|
|
2754
|
+
diagnostic = resolved.diagnostic;
|
|
2755
|
+
}
|
|
2735
2756
|
if (!repositoryId) {
|
|
2736
2757
|
console.log(
|
|
2737
2758
|
`[apm] \u672A\u80FD\u540C\u6B65\u5E73\u53F0\u90E8\u7F72\u914D\u7F6E\uFF08${TEMPLATE_HINT}\uFF09\u3002
|
|
@@ -2748,21 +2769,15 @@ ${diagnostic ?? ""}
|
|
|
2748
2769
|
);
|
|
2749
2770
|
return { synced: false, repositoryId };
|
|
2750
2771
|
}
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2772
|
+
const targetApmDir = apmDir ?? workspaceApmDir(workdirPath);
|
|
2773
|
+
const wrote = await writeDeploymentConfigContent(
|
|
2774
|
+
targetApmDir,
|
|
2775
|
+
config.content,
|
|
2776
|
+
config.name
|
|
2777
|
+
);
|
|
2778
|
+
if (!wrote) {
|
|
2758
2779
|
return { synced: false, repositoryId };
|
|
2759
2780
|
}
|
|
2760
|
-
const targetApmDir = apmDir ?? workspaceApmDir(workdirPath);
|
|
2761
|
-
const apmConfigPath = toFsPath(join5(targetApmDir, "apm.config.json"));
|
|
2762
|
-
writeFileSync6(apmConfigPath, `${JSON.stringify(parsed, null, 2)}
|
|
2763
|
-
`, "utf8");
|
|
2764
|
-
console.log(`[apm] \u5DF2\u540C\u6B65\u5E73\u53F0\u90E8\u7F72\u914D\u7F6E: ${config.name}`);
|
|
2765
|
-
console.log("[apm] \u5DF2\u5199\u5165 .apm/apm.config.json");
|
|
2766
2781
|
return { synced: true, repositoryId, configName: config.name };
|
|
2767
2782
|
}
|
|
2768
2783
|
|
|
@@ -3080,15 +3095,18 @@ function markBranchDone(sessionId, workdir) {
|
|
|
3080
3095
|
}
|
|
3081
3096
|
|
|
3082
3097
|
// src/commands/connect/webide-pull-requests.ts
|
|
3083
|
-
var
|
|
3098
|
+
var PRE_AGENT_PR_ACTIONS = /* @__PURE__ */ new Set([
|
|
3084
3099
|
"generate-cases",
|
|
3085
3100
|
"run-auto-test",
|
|
3086
|
-
//
|
|
3087
|
-
"deploy",
|
|
3101
|
+
// 验收合并前兜底确保 PR 存在
|
|
3088
3102
|
"accept"
|
|
3089
3103
|
]);
|
|
3104
|
+
var POST_AGENT_PR_ACTIONS = /* @__PURE__ */ new Set(["create-pr", "finish-manual-test"]);
|
|
3090
3105
|
function shouldEnsureWebIdePullRequests(action) {
|
|
3091
|
-
return
|
|
3106
|
+
return PRE_AGENT_PR_ACTIONS.has(action);
|
|
3107
|
+
}
|
|
3108
|
+
function shouldEnsureWebIdePullRequestsAfterAgent(action) {
|
|
3109
|
+
return POST_AGENT_PR_ACTIONS.has(action);
|
|
3092
3110
|
}
|
|
3093
3111
|
async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
3094
3112
|
const api = createApmApiClient(cfg);
|
|
@@ -3101,17 +3119,21 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3101
3119
|
"[apm] WebIDE PR\uFF1A\u8BFB\u53D6\u4ED3\u5E93\u6E05\u5355\u5931\u8D25:",
|
|
3102
3120
|
err instanceof Error ? err.message : err
|
|
3103
3121
|
);
|
|
3104
|
-
return;
|
|
3122
|
+
return { ensured: 0, skipped: 0, failed: 1 };
|
|
3105
3123
|
}
|
|
3106
3124
|
console.log(
|
|
3107
3125
|
`[apm] WebIDE PR\uFF1A\u51C6\u5907\u4E3A ${repoRoots.length} \u4E2A\u4ED3\u5E93\u521B\u5EFA feat/task-${taskId}`
|
|
3108
3126
|
);
|
|
3127
|
+
let ensured = 0;
|
|
3128
|
+
let skipped = 0;
|
|
3129
|
+
let failed = 0;
|
|
3109
3130
|
for (const gitRoot of repoRoots) {
|
|
3110
3131
|
const label = formatRepoLabel(workdir, gitRoot);
|
|
3111
3132
|
try {
|
|
3112
3133
|
const originUrl = await tryReadGitOriginUrl(gitRoot);
|
|
3113
3134
|
if (!originUrl) {
|
|
3114
3135
|
console.warn(`[apm] WebIDE PR\uFF1A\u8DF3\u8FC7 ${label}\uFF08\u65E0 remote.origin.url\uFF09`);
|
|
3136
|
+
skipped += 1;
|
|
3115
3137
|
continue;
|
|
3116
3138
|
}
|
|
3117
3139
|
const matched = await api.cli.matchRepository({ url: originUrl });
|
|
@@ -3120,22 +3142,26 @@ async function ensureWebIdePullRequests(cfg, taskId, workdir) {
|
|
|
3120
3142
|
console.warn(
|
|
3121
3143
|
`[apm] WebIDE PR\uFF1A\u8DF3\u8FC7 ${label}\uFF08\u5E73\u53F0\u672A\u767B\u8BB0\u4ED3\u5E93 ${originUrl}\uFF09`
|
|
3122
3144
|
);
|
|
3145
|
+
skipped += 1;
|
|
3123
3146
|
continue;
|
|
3124
3147
|
}
|
|
3125
3148
|
const pr = await api.cli.createWebIdeDraftPullRequest({
|
|
3126
3149
|
taskId,
|
|
3127
3150
|
repositoryId
|
|
3128
3151
|
});
|
|
3152
|
+
ensured += 1;
|
|
3129
3153
|
console.log(
|
|
3130
3154
|
`[apm] WebIDE PR\uFF1A${label} \u2192 #${pr.number} ${pr.state} ${pr.url || ""}`
|
|
3131
3155
|
);
|
|
3132
3156
|
} catch (err) {
|
|
3157
|
+
failed += 1;
|
|
3133
3158
|
console.warn(
|
|
3134
3159
|
`[apm] WebIDE PR\uFF1A${label} \u5931\u8D25:`,
|
|
3135
3160
|
err instanceof Error ? err.message : err
|
|
3136
3161
|
);
|
|
3137
3162
|
}
|
|
3138
3163
|
}
|
|
3164
|
+
return { ensured, skipped, failed };
|
|
3139
3165
|
}
|
|
3140
3166
|
|
|
3141
3167
|
// src/version.ts
|
|
@@ -3437,7 +3463,8 @@ var WEBIDE_CODE_CHANGE_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
3437
3463
|
"start-develop",
|
|
3438
3464
|
"fix-and-retest",
|
|
3439
3465
|
"report-defect",
|
|
3440
|
-
"
|
|
3466
|
+
"create-pr",
|
|
3467
|
+
"finish-manual-test"
|
|
3441
3468
|
]);
|
|
3442
3469
|
function shouldCommitAfterWebIdeMessage(action) {
|
|
3443
3470
|
return WEBIDE_CODE_CHANGE_ACTIONS.has(action);
|
|
@@ -3651,6 +3678,20 @@ async function handleWebIdeInboundMessage(cfg, msg, signal, options) {
|
|
|
3651
3678
|
`[apm] webide \u81EA\u52A8 push action=${msg.action} repos=${pushed}`
|
|
3652
3679
|
);
|
|
3653
3680
|
}
|
|
3681
|
+
if (shouldEnsureWebIdePullRequestsAfterAgent(msg.action)) {
|
|
3682
|
+
if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
|
|
3683
|
+
if (!shouldCommitAfterWebIdeMessage(msg.action)) {
|
|
3684
|
+
const pushed = await pushWorkspaceRepos(workdir);
|
|
3685
|
+
console.log(
|
|
3686
|
+
`[apm] webide create-pr \u524D push action=${msg.action} repos=${pushed}`
|
|
3687
|
+
);
|
|
3688
|
+
}
|
|
3689
|
+
const prResult = await ensureWebIdePullRequests(cfg, taskId, workdir);
|
|
3690
|
+
if (prResult.ensured === 0) {
|
|
3691
|
+
const detail = prResult.failed > 0 ? `\u521B\u5EFA PR \u5931\u8D25\uFF08${prResult.failed} \u4E2A\u4ED3\u5E93\u51FA\u9519\uFF09` : "\u672A\u80FD\u521B\u5EFA PR\uFF1A\u672A\u5339\u914D\u5230\u53EF\u767B\u8BB0\u7684\u4ED3\u5E93\uFF0C\u8BF7\u68C0\u67E5\u5DE5\u4F5C\u533A git remote \u4E0E\u5E73\u53F0\u4ED3\u5E93\u767B\u8BB0";
|
|
3692
|
+
throw new Error(detail);
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3654
3695
|
if (projectId) {
|
|
3655
3696
|
try {
|
|
3656
3697
|
await syncProjectDocumentsPush(cfg, workdir, void 0, { projectId });
|