@mp-lb/forum-cli 0.1.5 → 0.1.6
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.d.ts +18 -12
- package/dist/index.js +1321 -867
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1753,15 +1753,362 @@ var require_jsx_runtime = __commonJS({
|
|
|
1753
1753
|
}
|
|
1754
1754
|
});
|
|
1755
1755
|
|
|
1756
|
+
// src/createCheckoutIgnoreMatcher.ts
|
|
1757
|
+
import ignore from "ignore";
|
|
1758
|
+
|
|
1759
|
+
// src/mapSyncRulePath.ts
|
|
1760
|
+
var assertSafeRelativePath = (relativePath) => {
|
|
1761
|
+
const segments2 = relativePath.split("/");
|
|
1762
|
+
if (relativePath.startsWith("/") || segments2.some((segment) => segment === "." || segment === "..")) {
|
|
1763
|
+
throw new Error(`Unsafe checkout path: ${relativePath}`);
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
var toRelativePath = (storePath) => {
|
|
1767
|
+
const relativePath = storePath.replace(/^\/+/, "");
|
|
1768
|
+
assertSafeRelativePath(relativePath);
|
|
1769
|
+
return relativePath;
|
|
1770
|
+
};
|
|
1771
|
+
var joinRelativePath = (...parts) => parts.flatMap((part) => part.split("/")).filter(Boolean).join("/");
|
|
1772
|
+
var addLeadingSlash = (relativePath) => relativePath ? `/${relativePath}` : "/";
|
|
1773
|
+
var stripSyncRuleTarget = (localRelativePath, rule) => {
|
|
1774
|
+
if (!rule.target) {
|
|
1775
|
+
return localRelativePath;
|
|
1776
|
+
}
|
|
1777
|
+
if (localRelativePath === rule.target) {
|
|
1778
|
+
return "";
|
|
1779
|
+
}
|
|
1780
|
+
if (!localRelativePath.startsWith(`${rule.target}/`)) {
|
|
1781
|
+
return null;
|
|
1782
|
+
}
|
|
1783
|
+
return localRelativePath.slice(rule.target.length + 1);
|
|
1784
|
+
};
|
|
1785
|
+
var mapLocalPathToSyncRuleRemotePath = (localStorePath, rule) => {
|
|
1786
|
+
const localRelativePath = toRelativePath(localStorePath);
|
|
1787
|
+
const ruleRelativePath = stripSyncRuleTarget(localRelativePath, rule);
|
|
1788
|
+
if (ruleRelativePath === null) {
|
|
1789
|
+
throw new Error(
|
|
1790
|
+
`Path is outside sync rule target ${rule.target || "."}: ${localRelativePath}`
|
|
1791
|
+
);
|
|
1792
|
+
}
|
|
1793
|
+
return addLeadingSlash(joinRelativePath(rule.path, ruleRelativePath));
|
|
1794
|
+
};
|
|
1795
|
+
var mapRemotePathToSyncRuleLocalPath = (remoteStorePath, rule) => {
|
|
1796
|
+
const remoteRelativePath = toRelativePath(remoteStorePath);
|
|
1797
|
+
if (rule.path && remoteRelativePath !== rule.path && !remoteRelativePath.startsWith(`${rule.path}/`)) {
|
|
1798
|
+
throw new Error(
|
|
1799
|
+
`Remote path is outside sync rule path ${rule.path}: ${remoteRelativePath}`
|
|
1800
|
+
);
|
|
1801
|
+
}
|
|
1802
|
+
const ruleRelativePath = rule.path ? remoteRelativePath === rule.path ? "" : remoteRelativePath.slice(rule.path.length + 1) : remoteRelativePath;
|
|
1803
|
+
return addLeadingSlash(joinRelativePath(rule.target, ruleRelativePath));
|
|
1804
|
+
};
|
|
1805
|
+
|
|
1806
|
+
// src/createCheckoutIgnoreMatcher.ts
|
|
1807
|
+
var createCheckoutIgnoreMatcher = (rule, sharedPatterns, personalPatterns) => {
|
|
1808
|
+
const matcher = ignore().add([...sharedPatterns, ...personalPatterns]);
|
|
1809
|
+
return {
|
|
1810
|
+
ignores: (candidate) => {
|
|
1811
|
+
const local = candidate.replace(/\/$/, "");
|
|
1812
|
+
if (rule.target && local !== rule.target && !local.startsWith(`${rule.target}/`))
|
|
1813
|
+
return false;
|
|
1814
|
+
const remote = mapLocalPathToSyncRuleRemotePath(local, rule).replace(
|
|
1815
|
+
/^\//,
|
|
1816
|
+
""
|
|
1817
|
+
);
|
|
1818
|
+
return remote !== "" && matcher.ignores(candidate.endsWith("/") ? `${remote}/` : remote);
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
// src/checkoutIgnore.ts
|
|
1824
|
+
import path3 from "path";
|
|
1825
|
+
|
|
1826
|
+
// src/sharedIgnoreFile.ts
|
|
1827
|
+
import path2 from "path";
|
|
1828
|
+
import { readFile } from "fs/promises";
|
|
1829
|
+
|
|
1830
|
+
// ../../packages/core/src/storeIgnore.ts
|
|
1831
|
+
var segments = (relativePath) => relativePath.split("/").filter(Boolean);
|
|
1832
|
+
var basename = (relativePath) => {
|
|
1833
|
+
const parts = segments(relativePath);
|
|
1834
|
+
return parts[parts.length - 1] ?? "";
|
|
1835
|
+
};
|
|
1836
|
+
var dirRule = (name) => ({
|
|
1837
|
+
label: name,
|
|
1838
|
+
pattern: `${name}/`,
|
|
1839
|
+
matches: (relativePath) => segments(relativePath).slice(0, -1).includes(name)
|
|
1840
|
+
});
|
|
1841
|
+
var ENV_EXAMPLE_SUFFIXES = [".example", ".sample", ".template", ".dist"];
|
|
1842
|
+
var envRule = {
|
|
1843
|
+
label: ".env",
|
|
1844
|
+
pattern: ".env",
|
|
1845
|
+
matches: (relativePath) => {
|
|
1846
|
+
const name = basename(relativePath);
|
|
1847
|
+
if (name !== ".env" && !name.startsWith(".env.")) {
|
|
1848
|
+
return false;
|
|
1849
|
+
}
|
|
1850
|
+
return !ENV_EXAMPLE_SUFFIXES.some((suffix) => name.endsWith(suffix));
|
|
1851
|
+
}
|
|
1852
|
+
};
|
|
1853
|
+
var logRule = {
|
|
1854
|
+
label: "*.log",
|
|
1855
|
+
pattern: "*.log",
|
|
1856
|
+
matches: (relativePath) => basename(relativePath).endsWith(".log")
|
|
1857
|
+
};
|
|
1858
|
+
var vitepressRule = {
|
|
1859
|
+
label: ".vitepress/cache",
|
|
1860
|
+
pattern: ".vitepress/cache/",
|
|
1861
|
+
matches: (relativePath) => relativePath.includes(".vitepress/cache/") || relativePath.includes(".vitepress/dist/")
|
|
1862
|
+
};
|
|
1863
|
+
var KNOWN_JUNK_RULES = [
|
|
1864
|
+
dirRule("node_modules"),
|
|
1865
|
+
dirRule("dist"),
|
|
1866
|
+
dirRule("build"),
|
|
1867
|
+
dirRule(".next"),
|
|
1868
|
+
dirRule(".nuxt"),
|
|
1869
|
+
dirRule(".svelte-kit"),
|
|
1870
|
+
dirRule(".turbo"),
|
|
1871
|
+
dirRule(".cache"),
|
|
1872
|
+
dirRule("coverage"),
|
|
1873
|
+
dirRule("target"),
|
|
1874
|
+
dirRule("__pycache__"),
|
|
1875
|
+
dirRule(".venv"),
|
|
1876
|
+
vitepressRule,
|
|
1877
|
+
envRule,
|
|
1878
|
+
logRule
|
|
1879
|
+
];
|
|
1880
|
+
var detectJunk = (paths, rules = KNOWN_JUNK_RULES) => {
|
|
1881
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
1882
|
+
for (const path22 of paths) {
|
|
1883
|
+
const rule = rules.find((candidate) => candidate.matches(path22));
|
|
1884
|
+
if (!rule) continue;
|
|
1885
|
+
const existing = grouped.get(rule);
|
|
1886
|
+
if (existing) existing.push(path22);
|
|
1887
|
+
else grouped.set(rule, [path22]);
|
|
1888
|
+
}
|
|
1889
|
+
return rules.filter((rule) => grouped.has(rule)).map((rule) => ({
|
|
1890
|
+
rule,
|
|
1891
|
+
paths: [...grouped.get(rule) ?? []].sort(
|
|
1892
|
+
(left, right) => left < right ? -1 : left > right ? 1 : 0
|
|
1893
|
+
)
|
|
1894
|
+
}));
|
|
1895
|
+
};
|
|
1896
|
+
var IGNORE_PROPOSAL_RULES = [
|
|
1897
|
+
{ marker: "package.json", markerKind: "file", patterns: ["node_modules/"] },
|
|
1898
|
+
{ marker: ".vitepress", markerKind: "dir", patterns: [".vitepress/cache/"] },
|
|
1899
|
+
{ marker: "next.config.js", markerKind: "file", patterns: [".next/"] },
|
|
1900
|
+
{ marker: "next.config.mjs", markerKind: "file", patterns: [".next/"] },
|
|
1901
|
+
{ marker: "Cargo.toml", markerKind: "file", patterns: ["target/"] },
|
|
1902
|
+
{
|
|
1903
|
+
marker: "pyproject.toml",
|
|
1904
|
+
markerKind: "file",
|
|
1905
|
+
patterns: ["__pycache__/", ".venv/"]
|
|
1906
|
+
}
|
|
1907
|
+
];
|
|
1908
|
+
var analyzeIgnoreSignals = ({
|
|
1909
|
+
presentPaths,
|
|
1910
|
+
presentMarkers,
|
|
1911
|
+
gitignorePatterns = [],
|
|
1912
|
+
rules = KNOWN_JUNK_RULES,
|
|
1913
|
+
proposalRules = IGNORE_PROPOSAL_RULES
|
|
1914
|
+
}) => {
|
|
1915
|
+
const findings = [];
|
|
1916
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1917
|
+
const add = (finding) => {
|
|
1918
|
+
if (seen.has(finding.pattern)) return;
|
|
1919
|
+
seen.add(finding.pattern);
|
|
1920
|
+
findings.push(finding);
|
|
1921
|
+
};
|
|
1922
|
+
for (const group of detectJunk(presentPaths, rules)) {
|
|
1923
|
+
add({
|
|
1924
|
+
source: "present",
|
|
1925
|
+
severity: "imminent",
|
|
1926
|
+
label: group.rule.label,
|
|
1927
|
+
pattern: group.rule.pattern,
|
|
1928
|
+
matchedPaths: group.paths
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1931
|
+
for (const rule of proposalRules) {
|
|
1932
|
+
if (!presentMarkers.has(rule.marker)) continue;
|
|
1933
|
+
for (const pattern of rule.patterns) {
|
|
1934
|
+
add({
|
|
1935
|
+
source: "marker",
|
|
1936
|
+
severity: "predicted",
|
|
1937
|
+
label: `${rule.marker} \u2192 ${pattern}`,
|
|
1938
|
+
pattern,
|
|
1939
|
+
matchedPaths: []
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
for (const pattern of gitignorePatterns) {
|
|
1944
|
+
if (!pattern.trim()) continue;
|
|
1945
|
+
findings.push({
|
|
1946
|
+
source: "gitignore",
|
|
1947
|
+
severity: "predicted",
|
|
1948
|
+
label: pattern,
|
|
1949
|
+
pattern,
|
|
1950
|
+
matchedPaths: []
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
const maxSeverity = findings.some(
|
|
1954
|
+
(finding) => finding.severity === "imminent"
|
|
1955
|
+
) ? "imminent" : findings.length > 0 ? "predicted" : null;
|
|
1956
|
+
return {
|
|
1957
|
+
findings,
|
|
1958
|
+
proposedPatterns: findings.map((finding) => finding.pattern),
|
|
1959
|
+
maxSeverity
|
|
1960
|
+
};
|
|
1961
|
+
};
|
|
1962
|
+
var parseLocalIgnoreFile = (text) => text.split(/\r?\n/).filter((line) => line.length > 0);
|
|
1963
|
+
|
|
1964
|
+
// src/atomicWriteTextFile.ts
|
|
1965
|
+
import path from "path";
|
|
1966
|
+
import { chmod, mkdir, rename, rm, writeFile } from "fs/promises";
|
|
1967
|
+
var atomicWriteTextFile = async (filePath, text, isExecutable = false) => {
|
|
1968
|
+
const parentDir = path.dirname(filePath);
|
|
1969
|
+
const tempPath = path.join(
|
|
1970
|
+
parentDir,
|
|
1971
|
+
`.${path.basename(filePath)}.${process.pid}.${Date.now()}.tmp`
|
|
1972
|
+
);
|
|
1973
|
+
await mkdir(parentDir, { recursive: true });
|
|
1974
|
+
try {
|
|
1975
|
+
await writeFile(tempPath, text, "utf8");
|
|
1976
|
+
await chmod(tempPath, isExecutable ? 493 : 420);
|
|
1977
|
+
await rename(tempPath, filePath);
|
|
1978
|
+
} catch (error51) {
|
|
1979
|
+
await rm(tempPath, { force: true }).catch(() => {
|
|
1980
|
+
});
|
|
1981
|
+
throw error51;
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1984
|
+
|
|
1985
|
+
// src/planSharedIgnore.ts
|
|
1986
|
+
var equal = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
1987
|
+
var planSharedIgnore = ({
|
|
1988
|
+
base,
|
|
1989
|
+
local,
|
|
1990
|
+
remote
|
|
1991
|
+
}) => {
|
|
1992
|
+
if (local === null) return { action: "restore", patterns: remote };
|
|
1993
|
+
if (equal(local, remote)) return { action: "unchanged", patterns: local };
|
|
1994
|
+
if (base === null) return { action: "conflict", patterns: local };
|
|
1995
|
+
if (equal(local, base)) return { action: "retrieve", patterns: remote };
|
|
1996
|
+
if (equal(remote, base)) return { action: "publish", patterns: local };
|
|
1997
|
+
return { action: "conflict", patterns: local };
|
|
1998
|
+
};
|
|
1999
|
+
|
|
2000
|
+
// src/sharedIgnoreFile.ts
|
|
2001
|
+
var readSharedIgnoreFile = async (filePath) => {
|
|
2002
|
+
try {
|
|
2003
|
+
return parseLocalIgnoreFile(await readFile(filePath, "utf8"));
|
|
2004
|
+
} catch (error51) {
|
|
2005
|
+
if (error51.code === "ENOENT") return null;
|
|
2006
|
+
throw error51;
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
var writeSharedIgnoreFile = async (filePath, patterns) => {
|
|
2010
|
+
await atomicWriteTextFile(
|
|
2011
|
+
filePath,
|
|
2012
|
+
patterns.length ? `${patterns.join("\n")}
|
|
2013
|
+
` : ""
|
|
2014
|
+
);
|
|
2015
|
+
};
|
|
2016
|
+
var readState = async (statePath) => {
|
|
2017
|
+
try {
|
|
2018
|
+
return JSON.parse(await readFile(statePath, "utf8"));
|
|
2019
|
+
} catch (error51) {
|
|
2020
|
+
if (error51.code === "ENOENT") return {};
|
|
2021
|
+
throw error51;
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
var reconcileSharedIgnoreFile = async ({
|
|
2025
|
+
rootDir,
|
|
2026
|
+
sharedFilePath,
|
|
2027
|
+
store,
|
|
2028
|
+
remote,
|
|
2029
|
+
publish,
|
|
2030
|
+
dryRun = false
|
|
2031
|
+
}) => {
|
|
2032
|
+
const statePath = path2.join(rootDir, ".forum", "ignore-state.json");
|
|
2033
|
+
const state = await readState(statePath);
|
|
2034
|
+
const local = await readSharedIgnoreFile(sharedFilePath);
|
|
2035
|
+
const plan = planSharedIgnore({ base: state[store] ?? null, local, remote });
|
|
2036
|
+
if (dryRun || plan.action === "conflict") return plan;
|
|
2037
|
+
if (plan.action === "publish") await publish(plan.patterns);
|
|
2038
|
+
if (plan.action === "retrieve" || plan.action === "restore") {
|
|
2039
|
+
await writeSharedIgnoreFile(sharedFilePath, plan.patterns);
|
|
2040
|
+
}
|
|
2041
|
+
if (JSON.stringify(state[store]) !== JSON.stringify(plan.patterns)) {
|
|
2042
|
+
state[store] = plan.patterns;
|
|
2043
|
+
await atomicWriteTextFile(statePath, `${JSON.stringify(state, null, 2)}
|
|
2044
|
+
`);
|
|
2045
|
+
}
|
|
2046
|
+
return plan;
|
|
2047
|
+
};
|
|
2048
|
+
|
|
2049
|
+
// src/checkoutIgnore.ts
|
|
2050
|
+
var sharedIgnorePath = (rootDir, store) => path3.join(rootDir, ".forum", "stores", encodeURIComponent(store), "ignore");
|
|
2051
|
+
var prepareCheckoutIgnore = async ({
|
|
2052
|
+
rootDir,
|
|
2053
|
+
syncRules,
|
|
2054
|
+
client,
|
|
2055
|
+
dryRun = false
|
|
2056
|
+
}) => {
|
|
2057
|
+
const personal = await readSharedIgnoreFile(path3.join(rootDir, ".forum/usr_ignore")) ?? [];
|
|
2058
|
+
const patternsByStore = {};
|
|
2059
|
+
const changes = [];
|
|
2060
|
+
for (const rule of syncRules) {
|
|
2061
|
+
if (patternsByStore[rule.store]) continue;
|
|
2062
|
+
const storeRef = {
|
|
2063
|
+
workspaceSlug: rule.storeOwner,
|
|
2064
|
+
storeSlug: rule.storeSlug
|
|
2065
|
+
};
|
|
2066
|
+
const metadata = await client.readStoreByRef(storeRef);
|
|
2067
|
+
if (!metadata) throw new Error(`Store not found: ${rule.store}`);
|
|
2068
|
+
const sharedFilePath = sharedIgnorePath(rootDir, rule.store);
|
|
2069
|
+
const plan = await reconcileSharedIgnoreFile({
|
|
2070
|
+
rootDir,
|
|
2071
|
+
sharedFilePath,
|
|
2072
|
+
store: rule.store,
|
|
2073
|
+
remote: metadata.ignore ?? [],
|
|
2074
|
+
dryRun,
|
|
2075
|
+
publish: async (patterns) => {
|
|
2076
|
+
await client.syncStoreIgnoreByRef({
|
|
2077
|
+
...storeRef,
|
|
2078
|
+
expectedIgnore: metadata.ignore ?? [],
|
|
2079
|
+
ignore: patterns
|
|
2080
|
+
});
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
2083
|
+
patternsByStore[rule.store] = [...plan.patterns, ...personal];
|
|
2084
|
+
if (plan.action !== "unchanged")
|
|
2085
|
+
changes.push({
|
|
2086
|
+
...plan,
|
|
2087
|
+
relativePath: path3.relative(rootDir, sharedFilePath),
|
|
2088
|
+
store: rule.store
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
const matchersByRule = {};
|
|
2092
|
+
for (const rule of syncRules) {
|
|
2093
|
+
const patterns = patternsByStore[rule.store];
|
|
2094
|
+
matchersByRule[rule.id] = createCheckoutIgnoreMatcher(
|
|
2095
|
+
rule,
|
|
2096
|
+
patterns.slice(0, patterns.length - personal.length),
|
|
2097
|
+
personal
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
return { patternsByStore, changes, matchersByRule };
|
|
2101
|
+
};
|
|
2102
|
+
|
|
1756
2103
|
// src/index.ts
|
|
1757
2104
|
import { realpathSync, watch as watch2 } from "fs";
|
|
1758
|
-
import
|
|
2105
|
+
import path21 from "path";
|
|
1759
2106
|
import {
|
|
1760
2107
|
lstat as lstat2,
|
|
1761
|
-
mkdir as
|
|
1762
|
-
readFile as
|
|
2108
|
+
mkdir as mkdir6,
|
|
2109
|
+
readFile as readFile8,
|
|
1763
2110
|
rename as rename4,
|
|
1764
|
-
rm as
|
|
2111
|
+
rm as rm5,
|
|
1765
2112
|
writeFile as writeFile6
|
|
1766
2113
|
} from "fs/promises";
|
|
1767
2114
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
@@ -2534,10 +2881,10 @@ function mergeDefs(...defs) {
|
|
|
2534
2881
|
function cloneDef(schema) {
|
|
2535
2882
|
return mergeDefs(schema._zod.def);
|
|
2536
2883
|
}
|
|
2537
|
-
function getElementAtPath(obj,
|
|
2538
|
-
if (!
|
|
2884
|
+
function getElementAtPath(obj, path22) {
|
|
2885
|
+
if (!path22)
|
|
2539
2886
|
return obj;
|
|
2540
|
-
return
|
|
2887
|
+
return path22.reduce((acc, key) => acc?.[key], obj);
|
|
2541
2888
|
}
|
|
2542
2889
|
function promiseAllObject(promisesObj) {
|
|
2543
2890
|
const keys = Object.keys(promisesObj);
|
|
@@ -2946,11 +3293,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
2946
3293
|
}
|
|
2947
3294
|
return false;
|
|
2948
3295
|
}
|
|
2949
|
-
function prefixIssues(
|
|
3296
|
+
function prefixIssues(path22, issues) {
|
|
2950
3297
|
return issues.map((iss) => {
|
|
2951
3298
|
var _a3;
|
|
2952
3299
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
2953
|
-
iss.path.unshift(
|
|
3300
|
+
iss.path.unshift(path22);
|
|
2954
3301
|
return iss;
|
|
2955
3302
|
});
|
|
2956
3303
|
}
|
|
@@ -3097,16 +3444,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3097
3444
|
}
|
|
3098
3445
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
3099
3446
|
const fieldErrors = { _errors: [] };
|
|
3100
|
-
const processError = (error52,
|
|
3447
|
+
const processError = (error52, path22 = []) => {
|
|
3101
3448
|
for (const issue2 of error52.issues) {
|
|
3102
3449
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3103
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3450
|
+
issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
|
|
3104
3451
|
} else if (issue2.code === "invalid_key") {
|
|
3105
|
-
processError({ issues: issue2.issues }, [...
|
|
3452
|
+
processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
|
|
3106
3453
|
} else if (issue2.code === "invalid_element") {
|
|
3107
|
-
processError({ issues: issue2.issues }, [...
|
|
3454
|
+
processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
|
|
3108
3455
|
} else {
|
|
3109
|
-
const fullpath = [...
|
|
3456
|
+
const fullpath = [...path22, ...issue2.path];
|
|
3110
3457
|
if (fullpath.length === 0) {
|
|
3111
3458
|
fieldErrors._errors.push(mapper(issue2));
|
|
3112
3459
|
} else {
|
|
@@ -3133,17 +3480,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3133
3480
|
}
|
|
3134
3481
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
3135
3482
|
const result = { errors: [] };
|
|
3136
|
-
const processError = (error52,
|
|
3483
|
+
const processError = (error52, path22 = []) => {
|
|
3137
3484
|
var _a3, _b;
|
|
3138
3485
|
for (const issue2 of error52.issues) {
|
|
3139
3486
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3140
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3487
|
+
issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
|
|
3141
3488
|
} else if (issue2.code === "invalid_key") {
|
|
3142
|
-
processError({ issues: issue2.issues }, [...
|
|
3489
|
+
processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
|
|
3143
3490
|
} else if (issue2.code === "invalid_element") {
|
|
3144
|
-
processError({ issues: issue2.issues }, [...
|
|
3491
|
+
processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
|
|
3145
3492
|
} else {
|
|
3146
|
-
const fullpath = [...
|
|
3493
|
+
const fullpath = [...path22, ...issue2.path];
|
|
3147
3494
|
if (fullpath.length === 0) {
|
|
3148
3495
|
result.errors.push(mapper(issue2));
|
|
3149
3496
|
continue;
|
|
@@ -3175,8 +3522,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3175
3522
|
}
|
|
3176
3523
|
function toDotPath(_path) {
|
|
3177
3524
|
const segs = [];
|
|
3178
|
-
const
|
|
3179
|
-
for (const seg of
|
|
3525
|
+
const path22 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
3526
|
+
for (const seg of path22) {
|
|
3180
3527
|
if (typeof seg === "number")
|
|
3181
3528
|
segs.push(`[${seg}]`);
|
|
3182
3529
|
else if (typeof seg === "symbol")
|
|
@@ -15868,13 +16215,13 @@ function resolveRef(ref, ctx) {
|
|
|
15868
16215
|
if (!ref.startsWith("#")) {
|
|
15869
16216
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
15870
16217
|
}
|
|
15871
|
-
const
|
|
15872
|
-
if (
|
|
16218
|
+
const path22 = ref.slice(1).split("/").filter(Boolean);
|
|
16219
|
+
if (path22.length === 0) {
|
|
15873
16220
|
return ctx.rootSchema;
|
|
15874
16221
|
}
|
|
15875
16222
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
15876
|
-
if (
|
|
15877
|
-
const key =
|
|
16223
|
+
if (path22[0] === defsKey) {
|
|
16224
|
+
const key = path22[1];
|
|
15878
16225
|
if (!key || !ctx.defs[key]) {
|
|
15879
16226
|
throw new Error(`Reference not found: ${ref}`);
|
|
15880
16227
|
}
|
|
@@ -17212,8 +17559,8 @@ var normalizeStorePath = (value) => {
|
|
|
17212
17559
|
}
|
|
17213
17560
|
return segments2.length === 0 ? "/" : `/${segments2.join("/")}`;
|
|
17214
17561
|
};
|
|
17215
|
-
var storePathToArray = (
|
|
17216
|
-
const normalizedPath = normalizeStorePath(
|
|
17562
|
+
var storePathToArray = (path22) => {
|
|
17563
|
+
const normalizedPath = normalizeStorePath(path22);
|
|
17217
17564
|
return normalizedPath === "/" ? [] : normalizedPath.split("/").filter(Boolean);
|
|
17218
17565
|
};
|
|
17219
17566
|
var storePathSchema = external_exports.string().trim().min(1).transform((value) => normalizeStorePath(value));
|
|
@@ -18289,7 +18636,7 @@ var storeVisibilityValueSchema = external_exports.union([
|
|
|
18289
18636
|
var storeVisibilitySchema = storeVisibilityValueSchema.default(
|
|
18290
18637
|
WORKSPACE_STORE_VISIBILITY
|
|
18291
18638
|
);
|
|
18292
|
-
var storeIgnorePatternsSchema = external_exports.array(external_exports.string().
|
|
18639
|
+
var storeIgnorePatternsSchema = external_exports.array(external_exports.string().min(1));
|
|
18293
18640
|
var storeSearchSettingsSchema = external_exports.object({
|
|
18294
18641
|
enabled: external_exports.boolean().default(false),
|
|
18295
18642
|
semanticEnabled: external_exports.boolean().default(false),
|
|
@@ -18434,10 +18781,15 @@ var pinnedStoreIdsValueSchema = external_exports.array(storePreferenceIdSchema);
|
|
|
18434
18781
|
var recentStoresValueSchema = external_exports.array(recentStoreVisitSchema);
|
|
18435
18782
|
var pinnedStoreIdsSchema = pinnedStoreIdsValueSchema.default([]);
|
|
18436
18783
|
var recentStoresSchema = recentStoresValueSchema.default([]);
|
|
18784
|
+
var createTypeLastUsedAtSchema = external_exports.record(
|
|
18785
|
+
external_exports.string().min(1).max(100),
|
|
18786
|
+
external_exports.string().datetime()
|
|
18787
|
+
);
|
|
18437
18788
|
var userPreferencesSchema = external_exports.object({
|
|
18438
18789
|
id: storeOwnerIdSchema,
|
|
18439
18790
|
pinnedStoreIds: pinnedStoreIdsSchema,
|
|
18440
18791
|
recentStores: recentStoresSchema,
|
|
18792
|
+
createTypeLastUsedAt: createTypeLastUsedAtSchema.default({}),
|
|
18441
18793
|
recentStoresEnabled: external_exports.boolean().default(true),
|
|
18442
18794
|
showHomeWelcomeBanner: external_exports.boolean().default(true),
|
|
18443
18795
|
showHiddenFiles: external_exports.boolean().default(false),
|
|
@@ -18457,6 +18809,7 @@ var userPreferencesSchema = external_exports.object({
|
|
|
18457
18809
|
var userPreferencesUpdateSchema = external_exports.object({
|
|
18458
18810
|
pinnedStoreIds: pinnedStoreIdsValueSchema,
|
|
18459
18811
|
recentStores: recentStoresValueSchema,
|
|
18812
|
+
createTypeLastUsedAt: createTypeLastUsedAtSchema,
|
|
18460
18813
|
recentStoresEnabled: external_exports.boolean(),
|
|
18461
18814
|
showHomeWelcomeBanner: external_exports.boolean(),
|
|
18462
18815
|
showHiddenFiles: external_exports.boolean(),
|
|
@@ -19189,21 +19542,21 @@ var isKey = (value) => /^\w*$/.test(value);
|
|
|
19189
19542
|
var isUndefined = (val) => val === void 0;
|
|
19190
19543
|
var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
|
|
19191
19544
|
var stringToPath = (input) => compact(input.replace(/["|']|\]/g, "").split(/\.|\[/));
|
|
19192
|
-
var get = (object2,
|
|
19193
|
-
if (!
|
|
19545
|
+
var get = (object2, path22, defaultValue) => {
|
|
19546
|
+
if (!path22 || !isObject2(object2)) {
|
|
19194
19547
|
return defaultValue;
|
|
19195
19548
|
}
|
|
19196
|
-
const paths = isKey(
|
|
19549
|
+
const paths = isKey(path22) ? [path22] : stringToPath(path22);
|
|
19197
19550
|
const result = paths.reduce((result2, key) => {
|
|
19198
19551
|
return isNullOrUndefined(result2) ? void 0 : result2[key];
|
|
19199
19552
|
}, object2);
|
|
19200
|
-
return isUndefined(result) || result === object2 ? isUndefined(object2[
|
|
19553
|
+
return isUndefined(result) || result === object2 ? isUndefined(object2[path22]) ? defaultValue : object2[path22] : result;
|
|
19201
19554
|
};
|
|
19202
19555
|
var isBoolean = (value) => typeof value === "boolean";
|
|
19203
19556
|
var isFunction = (value) => typeof value === "function";
|
|
19204
|
-
var set2 = (object2,
|
|
19557
|
+
var set2 = (object2, path22, value) => {
|
|
19205
19558
|
let index = -1;
|
|
19206
|
-
const tempPath = isKey(
|
|
19559
|
+
const tempPath = isKey(path22) ? [path22] : stringToPath(path22);
|
|
19207
19560
|
const length = tempPath.length;
|
|
19208
19561
|
const lastIndex = length - 1;
|
|
19209
19562
|
while (++index < length) {
|
|
@@ -19401,12 +19754,12 @@ function isEmptyArray(obj) {
|
|
|
19401
19754
|
}
|
|
19402
19755
|
return true;
|
|
19403
19756
|
}
|
|
19404
|
-
function unset(object2,
|
|
19405
|
-
if (isString(
|
|
19406
|
-
delete object2[
|
|
19757
|
+
function unset(object2, path22) {
|
|
19758
|
+
if (isString(path22) && Object.prototype.hasOwnProperty.call(object2, path22)) {
|
|
19759
|
+
delete object2[path22];
|
|
19407
19760
|
return object2;
|
|
19408
19761
|
}
|
|
19409
|
-
const paths = Array.isArray(
|
|
19762
|
+
const paths = Array.isArray(path22) ? path22 : isKey(path22) ? [path22] : stringToPath(path22);
|
|
19410
19763
|
const childObject = paths.length === 1 ? object2 : baseGet(object2, paths);
|
|
19411
19764
|
const index = paths.length - 1;
|
|
19412
19765
|
const key = paths[index];
|
|
@@ -23131,7 +23484,7 @@ var publicActionSubmitResultSchema = external_exports.unknown();
|
|
|
23131
23484
|
|
|
23132
23485
|
// ../../packages/core/src/widgetRuntime.ts
|
|
23133
23486
|
var widgetRuntimeOutputPathSchema = storePathSchema.refine(
|
|
23134
|
-
(
|
|
23487
|
+
(path22) => path22 !== "/",
|
|
23135
23488
|
{
|
|
23136
23489
|
message: "Path must not be the root directory."
|
|
23137
23490
|
}
|
|
@@ -23181,7 +23534,7 @@ var widgetRuntimeCompleteAttachmentUploadInputSchema = storeRefSchema.safeExtend
|
|
|
23181
23534
|
treeVisibility: external_exports.enum(["visible", "hidden"]).optional(),
|
|
23182
23535
|
uploadIntentId: external_exports.string().trim().min(1)
|
|
23183
23536
|
});
|
|
23184
|
-
var widgetRuntimeLinkPathSchema = external_exports.string().trim().min(1).max(2048).refine((
|
|
23537
|
+
var widgetRuntimeLinkPathSchema = external_exports.string().trim().min(1).max(2048).refine((path22) => path22.startsWith("/") && !path22.startsWith("//"), {
|
|
23185
23538
|
message: "Link path must be a relative application path."
|
|
23186
23539
|
});
|
|
23187
23540
|
var widgetRuntimeCreateSigningLinkInputSchema = storeRefSchema.safeExtend({
|
|
@@ -23232,168 +23585,10 @@ var storeMemberSchema = external_exports.object({
|
|
|
23232
23585
|
createdAt: external_exports.string().datetime().default(() => (/* @__PURE__ */ new Date()).toISOString())
|
|
23233
23586
|
});
|
|
23234
23587
|
|
|
23235
|
-
// ../../packages/core/src/storeIgnore.ts
|
|
23236
|
-
var segments = (relativePath) => relativePath.split("/").filter(Boolean);
|
|
23237
|
-
var basename = (relativePath) => {
|
|
23238
|
-
const parts = segments(relativePath);
|
|
23239
|
-
return parts[parts.length - 1] ?? "";
|
|
23240
|
-
};
|
|
23241
|
-
var dirRule = (name) => ({
|
|
23242
|
-
label: name,
|
|
23243
|
-
pattern: `${name}/`,
|
|
23244
|
-
matches: (relativePath) => segments(relativePath).slice(0, -1).includes(name)
|
|
23245
|
-
});
|
|
23246
|
-
var ENV_EXAMPLE_SUFFIXES = [".example", ".sample", ".template", ".dist"];
|
|
23247
|
-
var envRule = {
|
|
23248
|
-
label: ".env",
|
|
23249
|
-
pattern: ".env",
|
|
23250
|
-
matches: (relativePath) => {
|
|
23251
|
-
const name = basename(relativePath);
|
|
23252
|
-
if (name !== ".env" && !name.startsWith(".env.")) {
|
|
23253
|
-
return false;
|
|
23254
|
-
}
|
|
23255
|
-
return !ENV_EXAMPLE_SUFFIXES.some((suffix) => name.endsWith(suffix));
|
|
23256
|
-
}
|
|
23257
|
-
};
|
|
23258
|
-
var logRule = {
|
|
23259
|
-
label: "*.log",
|
|
23260
|
-
pattern: "*.log",
|
|
23261
|
-
matches: (relativePath) => basename(relativePath).endsWith(".log")
|
|
23262
|
-
};
|
|
23263
|
-
var vitepressRule = {
|
|
23264
|
-
label: ".vitepress/cache",
|
|
23265
|
-
pattern: ".vitepress/cache/",
|
|
23266
|
-
matches: (relativePath) => relativePath.includes(".vitepress/cache/") || relativePath.includes(".vitepress/dist/")
|
|
23267
|
-
};
|
|
23268
|
-
var KNOWN_JUNK_RULES = [
|
|
23269
|
-
dirRule("node_modules"),
|
|
23270
|
-
dirRule("dist"),
|
|
23271
|
-
dirRule("build"),
|
|
23272
|
-
dirRule(".next"),
|
|
23273
|
-
dirRule(".nuxt"),
|
|
23274
|
-
dirRule(".svelte-kit"),
|
|
23275
|
-
dirRule(".turbo"),
|
|
23276
|
-
dirRule(".cache"),
|
|
23277
|
-
dirRule("coverage"),
|
|
23278
|
-
dirRule("target"),
|
|
23279
|
-
dirRule("__pycache__"),
|
|
23280
|
-
dirRule(".venv"),
|
|
23281
|
-
vitepressRule,
|
|
23282
|
-
envRule,
|
|
23283
|
-
logRule
|
|
23284
|
-
];
|
|
23285
|
-
var detectJunk = (paths, rules = KNOWN_JUNK_RULES) => {
|
|
23286
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
23287
|
-
for (const path20 of paths) {
|
|
23288
|
-
const rule = rules.find((candidate) => candidate.matches(path20));
|
|
23289
|
-
if (!rule) continue;
|
|
23290
|
-
const existing = grouped.get(rule);
|
|
23291
|
-
if (existing) existing.push(path20);
|
|
23292
|
-
else grouped.set(rule, [path20]);
|
|
23293
|
-
}
|
|
23294
|
-
return rules.filter((rule) => grouped.has(rule)).map((rule) => ({
|
|
23295
|
-
rule,
|
|
23296
|
-
paths: [...grouped.get(rule) ?? []].sort(
|
|
23297
|
-
(left, right) => left < right ? -1 : left > right ? 1 : 0
|
|
23298
|
-
)
|
|
23299
|
-
}));
|
|
23300
|
-
};
|
|
23301
|
-
var IGNORE_PROPOSAL_RULES = [
|
|
23302
|
-
{ marker: "package.json", markerKind: "file", patterns: ["node_modules/"] },
|
|
23303
|
-
{ marker: ".vitepress", markerKind: "dir", patterns: [".vitepress/cache/"] },
|
|
23304
|
-
{ marker: "next.config.js", markerKind: "file", patterns: [".next/"] },
|
|
23305
|
-
{ marker: "next.config.mjs", markerKind: "file", patterns: [".next/"] },
|
|
23306
|
-
{ marker: "Cargo.toml", markerKind: "file", patterns: ["target/"] },
|
|
23307
|
-
{
|
|
23308
|
-
marker: "pyproject.toml",
|
|
23309
|
-
markerKind: "file",
|
|
23310
|
-
patterns: ["__pycache__/", ".venv/"]
|
|
23311
|
-
}
|
|
23312
|
-
];
|
|
23313
|
-
var analyzeIgnoreSignals = ({
|
|
23314
|
-
presentPaths,
|
|
23315
|
-
presentMarkers,
|
|
23316
|
-
gitignorePatterns = [],
|
|
23317
|
-
rules = KNOWN_JUNK_RULES,
|
|
23318
|
-
proposalRules = IGNORE_PROPOSAL_RULES
|
|
23319
|
-
}) => {
|
|
23320
|
-
const findings = [];
|
|
23321
|
-
const seen = /* @__PURE__ */ new Set();
|
|
23322
|
-
const add = (finding) => {
|
|
23323
|
-
if (seen.has(finding.pattern)) return;
|
|
23324
|
-
seen.add(finding.pattern);
|
|
23325
|
-
findings.push(finding);
|
|
23326
|
-
};
|
|
23327
|
-
for (const group of detectJunk(presentPaths, rules)) {
|
|
23328
|
-
add({
|
|
23329
|
-
source: "present",
|
|
23330
|
-
severity: "imminent",
|
|
23331
|
-
label: group.rule.label,
|
|
23332
|
-
pattern: group.rule.pattern,
|
|
23333
|
-
matchedPaths: group.paths
|
|
23334
|
-
});
|
|
23335
|
-
}
|
|
23336
|
-
for (const rule of proposalRules) {
|
|
23337
|
-
if (!presentMarkers.has(rule.marker)) continue;
|
|
23338
|
-
for (const pattern of rule.patterns) {
|
|
23339
|
-
add({
|
|
23340
|
-
source: "marker",
|
|
23341
|
-
severity: "predicted",
|
|
23342
|
-
label: `${rule.marker} \u2192 ${pattern}`,
|
|
23343
|
-
pattern,
|
|
23344
|
-
matchedPaths: []
|
|
23345
|
-
});
|
|
23346
|
-
}
|
|
23347
|
-
}
|
|
23348
|
-
for (const pattern of gitignorePatterns) {
|
|
23349
|
-
const trimmed = pattern.trim();
|
|
23350
|
-
if (!trimmed) continue;
|
|
23351
|
-
add({
|
|
23352
|
-
source: "gitignore",
|
|
23353
|
-
severity: "predicted",
|
|
23354
|
-
label: trimmed,
|
|
23355
|
-
pattern: trimmed,
|
|
23356
|
-
matchedPaths: []
|
|
23357
|
-
});
|
|
23358
|
-
}
|
|
23359
|
-
const maxSeverity = findings.some(
|
|
23360
|
-
(finding) => finding.severity === "imminent"
|
|
23361
|
-
) ? "imminent" : findings.length > 0 ? "predicted" : null;
|
|
23362
|
-
return {
|
|
23363
|
-
findings,
|
|
23364
|
-
proposedPatterns: findings.map((finding) => finding.pattern),
|
|
23365
|
-
maxSeverity
|
|
23366
|
-
};
|
|
23367
|
-
};
|
|
23368
|
-
var resolveIgnorePatterns = ({
|
|
23369
|
-
bakedIn,
|
|
23370
|
-
storeSetting,
|
|
23371
|
-
localOverride
|
|
23372
|
-
}) => {
|
|
23373
|
-
const seen = /* @__PURE__ */ new Set();
|
|
23374
|
-
const resolved = [];
|
|
23375
|
-
for (const pattern of [...bakedIn, ...storeSetting, ...localOverride]) {
|
|
23376
|
-
const trimmed = pattern.trim();
|
|
23377
|
-
if (!trimmed || seen.has(trimmed)) continue;
|
|
23378
|
-
seen.add(trimmed);
|
|
23379
|
-
resolved.push(trimmed);
|
|
23380
|
-
}
|
|
23381
|
-
return resolved;
|
|
23382
|
-
};
|
|
23383
|
-
var parseLocalIgnoreFile = (text) => {
|
|
23384
|
-
const patterns = [];
|
|
23385
|
-
for (const rawLine of text.split(/\r?\n/)) {
|
|
23386
|
-
const line = rawLine.trim();
|
|
23387
|
-
if (!line || line.startsWith("#")) continue;
|
|
23388
|
-
patterns.push(line);
|
|
23389
|
-
}
|
|
23390
|
-
return patterns;
|
|
23391
|
-
};
|
|
23392
|
-
|
|
23393
23588
|
// ../../packages/store-tree/src/patterns.ts
|
|
23394
23589
|
var escapeRegex2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23395
|
-
var basename2 = (
|
|
23396
|
-
const segments2 =
|
|
23590
|
+
var basename2 = (path22) => {
|
|
23591
|
+
const segments2 = path22.split("/").filter(Boolean);
|
|
23397
23592
|
return segments2[segments2.length - 1] ?? "";
|
|
23398
23593
|
};
|
|
23399
23594
|
var normalizeStorePathPattern = (pattern) => pattern.trim();
|
|
@@ -23411,7 +23606,7 @@ var storePathPatternToRegex = (pattern) => {
|
|
|
23411
23606
|
return new RegExp(source, "i");
|
|
23412
23607
|
};
|
|
23413
23608
|
var doesStorePathPatternMatch = ({
|
|
23414
|
-
path:
|
|
23609
|
+
path: path22,
|
|
23415
23610
|
pattern,
|
|
23416
23611
|
mode = "path"
|
|
23417
23612
|
}) => {
|
|
@@ -23419,7 +23614,7 @@ var doesStorePathPatternMatch = ({
|
|
|
23419
23614
|
if (!normalizedPattern) {
|
|
23420
23615
|
return true;
|
|
23421
23616
|
}
|
|
23422
|
-
const normalizedPath = normalizeStorePath(
|
|
23617
|
+
const normalizedPath = normalizeStorePath(path22);
|
|
23423
23618
|
const target = mode === "basename" ? basename2(normalizedPath) : normalizedPath;
|
|
23424
23619
|
if (patternHasWildcard(normalizedPattern)) {
|
|
23425
23620
|
return storePathPatternToRegex(normalizedPattern).test(target);
|
|
@@ -23507,8 +23702,8 @@ var isIssueRecord = (value) => {
|
|
|
23507
23702
|
return isRecord2(value) && typeof value.message === "string";
|
|
23508
23703
|
};
|
|
23509
23704
|
var formatIssue = (issue2) => {
|
|
23510
|
-
const
|
|
23511
|
-
return
|
|
23705
|
+
const path22 = Array.isArray(issue2.path) && issue2.path.length > 0 ? issue2.path.map(String).join(".") : "";
|
|
23706
|
+
return path22 ? `${path22}: ${issue2.message}` : issue2.message;
|
|
23512
23707
|
};
|
|
23513
23708
|
var formatIssueArray = (issues) => {
|
|
23514
23709
|
if (!issues.every(isIssueRecord)) {
|
|
@@ -23981,7 +24176,7 @@ var buildContentChangedConflictExplainer = (issues) => {
|
|
|
23981
24176
|
body: [
|
|
23982
24177
|
pathSubject(
|
|
23983
24178
|
paths,
|
|
23984
|
-
(
|
|
24179
|
+
(path22) => `${path22} changed both locally and remotely.`,
|
|
23985
24180
|
(count) => `${count} files changed both locally and remotely.`
|
|
23986
24181
|
),
|
|
23987
24182
|
"Forum left these files alone because either overwrite direction could lose work."
|
|
@@ -24013,7 +24208,7 @@ var buildLocalDeleteRemoteChangeExplainer = (issues) => {
|
|
|
24013
24208
|
body: [
|
|
24014
24209
|
pathSubject(
|
|
24015
24210
|
paths,
|
|
24016
|
-
(
|
|
24211
|
+
(path22) => `${path22} was deleted locally, but the remote file changed.`,
|
|
24017
24212
|
(count) => `${count} files were deleted locally, but changed remotely.`
|
|
24018
24213
|
),
|
|
24019
24214
|
"Forum did not delete newer remote work automatically."
|
|
@@ -24045,7 +24240,7 @@ var buildMoveDestinationConflictExplainer = (issues) => {
|
|
|
24045
24240
|
body: [
|
|
24046
24241
|
pathSubject(
|
|
24047
24242
|
paths,
|
|
24048
|
-
(
|
|
24243
|
+
(path22) => `${path22} is the destination of a remote move, but already exists locally.`,
|
|
24049
24244
|
(count) => `${count} paths are remote move destinations that already exist locally.`
|
|
24050
24245
|
),
|
|
24051
24246
|
"Forum synced unrelated files but left these paths alone."
|
|
@@ -24080,7 +24275,7 @@ var buildMoveRemoteChangeConflictExplainer = (issues) => {
|
|
|
24080
24275
|
body: [
|
|
24081
24276
|
pathSubject(
|
|
24082
24277
|
paths,
|
|
24083
|
-
(
|
|
24278
|
+
(path22) => `${path22} was involved in a move while the other side changed it.`,
|
|
24084
24279
|
(count) => `${count} files were involved in moves while the other side changed them.`
|
|
24085
24280
|
),
|
|
24086
24281
|
"Forum did not combine the move and content change automatically."
|
|
@@ -24112,7 +24307,7 @@ var buildMoveMoveConflictExplainer = (issues) => {
|
|
|
24112
24307
|
body: [
|
|
24113
24308
|
pathSubject(
|
|
24114
24309
|
paths,
|
|
24115
|
-
(
|
|
24310
|
+
(path22) => `${path22} moved locally and remotely to different paths.`,
|
|
24116
24311
|
(count) => `${count} files moved locally and remotely to different paths.`
|
|
24117
24312
|
),
|
|
24118
24313
|
"Forum left these moves unresolved because choosing a path automatically could hide work."
|
|
@@ -24144,7 +24339,7 @@ var buildDeleteMoveConflictExplainer = (issues) => {
|
|
|
24144
24339
|
body: [
|
|
24145
24340
|
pathSubject(
|
|
24146
24341
|
paths,
|
|
24147
|
-
(
|
|
24342
|
+
(path22) => `${path22} was deleted on one side and moved on the other.`,
|
|
24148
24343
|
(count) => `${count} files were deleted on one side and moved on the other.`
|
|
24149
24344
|
),
|
|
24150
24345
|
"Forum did not choose between delete and move automatically."
|
|
@@ -24176,7 +24371,7 @@ var buildReferenceLocalFileConflictExplainer = (issues) => {
|
|
|
24176
24371
|
body: [
|
|
24177
24372
|
pathSubject(
|
|
24178
24373
|
paths,
|
|
24179
|
-
(
|
|
24374
|
+
(path22) => `${path22} is now a remote reference, but the local file has changes.`,
|
|
24180
24375
|
(count) => `${count} paths are now remote references, but local files have changes.`
|
|
24181
24376
|
),
|
|
24182
24377
|
"Forum left the local files alone because replacing them would discard local work."
|
|
@@ -24208,7 +24403,7 @@ var buildUnsupportedLocalEntryExplainer = (issues) => {
|
|
|
24208
24403
|
body: [
|
|
24209
24404
|
pathSubject(
|
|
24210
24405
|
paths,
|
|
24211
|
-
(
|
|
24406
|
+
(path22) => `${path22} is an unsupported local filesystem entry.`,
|
|
24212
24407
|
(count) => `${count} local filesystem entries are unsupported.`
|
|
24213
24408
|
),
|
|
24214
24409
|
"Forum skipped these paths and continued with unrelated files where it could."
|
|
@@ -24240,7 +24435,7 @@ var buildReadOnlyLocalChangeExplainer = (issues) => {
|
|
|
24240
24435
|
body: [
|
|
24241
24436
|
pathSubject(
|
|
24242
24437
|
paths,
|
|
24243
|
-
(
|
|
24438
|
+
(path22) => `${path22} has local changes, but its sync rule is read-only.`,
|
|
24244
24439
|
(count) => `${count} files have local changes, but their sync rules are read-only.`
|
|
24245
24440
|
),
|
|
24246
24441
|
"Forum left these files alone so remote updates cannot overwrite local work."
|
|
@@ -24337,7 +24532,7 @@ var checkoutConflictIssuesFromResult = (result) => checkoutIssuesFromResult(resu
|
|
|
24337
24532
|
(issue2) => issue2.type === "conflict"
|
|
24338
24533
|
);
|
|
24339
24534
|
var formatCheckoutExplainer = (explainer) => {
|
|
24340
|
-
const pathLines = explainer.paths.length <= 1 ? [] : ["", ...formatPathList(explainer.paths).map((
|
|
24535
|
+
const pathLines = explainer.paths.length <= 1 ? [] : ["", ...formatPathList(explainer.paths).map((path22) => ` ${path22}`)];
|
|
24341
24536
|
const actionLines = explainer.actions.map(
|
|
24342
24537
|
(action) => `${styleText.bold(`${action.label}:`)} ${action.text}`
|
|
24343
24538
|
);
|
|
@@ -24361,7 +24556,7 @@ var formatCheckoutExplainers = (result) => {
|
|
|
24361
24556
|
|
|
24362
24557
|
// src/gitIntegration.ts
|
|
24363
24558
|
import { execFile as execFile2 } from "child_process";
|
|
24364
|
-
import
|
|
24559
|
+
import path4 from "path";
|
|
24365
24560
|
import { promisify as promisify2 } from "util";
|
|
24366
24561
|
var execFileAsync2 = promisify2(execFile2);
|
|
24367
24562
|
var gitErrorMessage = (error51) => {
|
|
@@ -24386,7 +24581,7 @@ var runGit = async (cwd, args) => {
|
|
|
24386
24581
|
};
|
|
24387
24582
|
var resolveGitRoot = async (cwd) => {
|
|
24388
24583
|
const result = await runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
24389
|
-
return
|
|
24584
|
+
return path4.resolve(cwd, result.stdout.trim());
|
|
24390
24585
|
};
|
|
24391
24586
|
var readGitStatusEntries = async (gitRoot) => {
|
|
24392
24587
|
const result = await runGit(gitRoot, [
|
|
@@ -24466,59 +24661,80 @@ var commitGitChanges = async (gitRoot, message) => {
|
|
|
24466
24661
|
};
|
|
24467
24662
|
|
|
24468
24663
|
// src/checkoutNaming.ts
|
|
24469
|
-
|
|
24470
|
-
|
|
24471
|
-
var
|
|
24472
|
-
"forum.yaml",
|
|
24473
|
-
"forum.yml",
|
|
24474
|
-
"doctrine.yaml",
|
|
24475
|
-
"doctrine.yml"
|
|
24476
|
-
];
|
|
24477
|
-
var defaultProjectConfigFilename = "forum.yaml";
|
|
24478
|
-
var checkoutStateDirectoryNames = [".forum", ".doctrine"];
|
|
24664
|
+
var defaultProjectConfigFilename = ".forum/sync.yaml";
|
|
24665
|
+
var projectConfigFilenames = [defaultProjectConfigFilename];
|
|
24666
|
+
var checkoutStateDirectoryNames = [".forum"];
|
|
24479
24667
|
var defaultCheckoutStateDirectoryName = ".forum";
|
|
24480
|
-
var resolveCheckoutStateDirectoryName = (
|
|
24481
|
-
|
|
24482
|
-
|
|
24483
|
-
|
|
24668
|
+
var resolveCheckoutStateDirectoryName = () => defaultCheckoutStateDirectoryName;
|
|
24669
|
+
var isCheckoutStateDirectoryPath = (relativePath) => relativePath.split("/").includes(defaultCheckoutStateDirectoryName);
|
|
24670
|
+
|
|
24671
|
+
// src/resolveAmbiguousSyncMoves.ts
|
|
24672
|
+
import { rm as rm2 } from "fs/promises";
|
|
24673
|
+
import path5 from "path";
|
|
24674
|
+
var resolveAmbiguousSyncMoves = async ({
|
|
24675
|
+
conflictPolicy,
|
|
24676
|
+
dryRun,
|
|
24677
|
+
localPath,
|
|
24678
|
+
manifestFiles,
|
|
24679
|
+
snapshot,
|
|
24680
|
+
structuralPreflight
|
|
24681
|
+
}) => {
|
|
24682
|
+
const blocked = structuralPreflight.blockedDetails;
|
|
24683
|
+
if (!conflictPolicy || !blocked.length || !blocked.every((detail) => detail.conflict?.type === "ambiguous-local-move"))
|
|
24684
|
+
return [];
|
|
24685
|
+
const details = [];
|
|
24686
|
+
if (conflictPolicy === "remote") {
|
|
24687
|
+
for (const { relativePath } of blocked) {
|
|
24688
|
+
if (manifestFiles[relativePath]) {
|
|
24689
|
+
manifestFiles[relativePath] = {
|
|
24690
|
+
...manifestFiles[relativePath],
|
|
24691
|
+
remoteRevisionNumber: null
|
|
24692
|
+
};
|
|
24693
|
+
} else {
|
|
24694
|
+
if (!dryRun)
|
|
24695
|
+
await rm2(path5.join(localPath, relativePath), { force: true });
|
|
24696
|
+
snapshot.localFileByPath.delete(relativePath);
|
|
24697
|
+
snapshot.candidatePaths = snapshot.candidatePaths.filter(
|
|
24698
|
+
(candidate) => candidate !== relativePath
|
|
24699
|
+
);
|
|
24700
|
+
details.push({ relativePath, status: "deleted" });
|
|
24701
|
+
}
|
|
24484
24702
|
}
|
|
24485
24703
|
}
|
|
24486
|
-
|
|
24704
|
+
structuralPreflight.blockedDetails = [];
|
|
24705
|
+
return details;
|
|
24487
24706
|
};
|
|
24488
|
-
var isCheckoutStateDirectoryPath = (relativePath) => checkoutStateDirectoryNames.some(
|
|
24489
|
-
(name) => relativePath === name || relativePath.startsWith(`${name}/`)
|
|
24490
|
-
);
|
|
24491
24707
|
|
|
24492
24708
|
// src/checkout.ts
|
|
24493
24709
|
import { createHash as createHash2 } from "crypto";
|
|
24494
|
-
import
|
|
24710
|
+
import path9 from "path";
|
|
24495
24711
|
import {
|
|
24496
24712
|
lstat,
|
|
24497
|
-
mkdir as
|
|
24713
|
+
mkdir as mkdir4,
|
|
24498
24714
|
readdir as readdir2,
|
|
24499
|
-
readFile as
|
|
24715
|
+
readFile as readFile3,
|
|
24500
24716
|
rename as rename2,
|
|
24501
|
-
rm as
|
|
24717
|
+
rm as rm3,
|
|
24502
24718
|
stat,
|
|
24503
24719
|
writeFile as writeFile3
|
|
24504
24720
|
} from "fs/promises";
|
|
24505
24721
|
import { TextDecoder as TextDecoder2 } from "util";
|
|
24506
|
-
import
|
|
24722
|
+
import ignore2 from "ignore";
|
|
24507
24723
|
|
|
24508
24724
|
// src/buildCheckoutFileManifestEntry.ts
|
|
24509
|
-
var toManifestRemotePath = (
|
|
24725
|
+
var toManifestRemotePath = (path22) => path22.startsWith("/") ? path22 : `/${path22}`;
|
|
24510
24726
|
var buildCheckoutFileManifestEntry = ({
|
|
24511
24727
|
storageClass,
|
|
24512
24728
|
hash: hash2,
|
|
24513
24729
|
manifestEntry,
|
|
24514
|
-
path:
|
|
24730
|
+
path: path22,
|
|
24515
24731
|
remoteFile,
|
|
24516
24732
|
source,
|
|
24517
24733
|
syncedAt
|
|
24518
24734
|
}) => {
|
|
24519
24735
|
const remoteFileId = remoteFile.id ?? remoteFile._id ?? manifestEntry?.remoteFileId;
|
|
24520
24736
|
if (!remoteFileId) {
|
|
24521
|
-
throw new Error(`Remote file ${
|
|
24737
|
+
throw new Error(`Remote file ${path22} did not include a file id`);
|
|
24522
24738
|
}
|
|
24523
24739
|
return {
|
|
24524
24740
|
storageClass,
|
|
@@ -24526,7 +24742,7 @@ var buildCheckoutFileManifestEntry = ({
|
|
|
24526
24742
|
isExecutable: storageClass === "text" ? remoteFile.isExecutable === true || void 0 : void 0,
|
|
24527
24743
|
lastSyncedAt: syncedAt,
|
|
24528
24744
|
remoteFileId,
|
|
24529
|
-
remotePath: remoteFile.path ?? manifestEntry?.remotePath ?? toManifestRemotePath(
|
|
24745
|
+
remotePath: remoteFile.path ?? manifestEntry?.remotePath ?? toManifestRemotePath(path22),
|
|
24530
24746
|
remoteUpdatedAt: remoteFile.updatedAt ?? null,
|
|
24531
24747
|
remoteRevisionNumber: remoteFile.revisionNumber ?? null,
|
|
24532
24748
|
...source ? { source } : {}
|
|
@@ -24628,14 +24844,14 @@ var buildSyncCheckoutSnapshot = ({
|
|
|
24628
24844
|
};
|
|
24629
24845
|
|
|
24630
24846
|
// src/checkoutDirectories.ts
|
|
24631
|
-
import
|
|
24632
|
-
import { mkdir, readdir, rmdir } from "fs/promises";
|
|
24847
|
+
import path6 from "path";
|
|
24848
|
+
import { mkdir as mkdir2, readdir, rmdir } from "fs/promises";
|
|
24633
24849
|
var parentDirectoriesForPath = (relativePath) => {
|
|
24634
24850
|
const directories = [];
|
|
24635
|
-
let directory =
|
|
24851
|
+
let directory = path6.posix.dirname(relativePath);
|
|
24636
24852
|
while (directory && directory !== ".") {
|
|
24637
24853
|
directories.push(directory);
|
|
24638
|
-
directory =
|
|
24854
|
+
directory = path6.posix.dirname(directory);
|
|
24639
24855
|
}
|
|
24640
24856
|
return directories;
|
|
24641
24857
|
};
|
|
@@ -24660,7 +24876,7 @@ var prepareCheckoutDirectories = async ({
|
|
|
24660
24876
|
const directories = checkoutParentDirectories(relativePaths);
|
|
24661
24877
|
await Promise.all(
|
|
24662
24878
|
directories.map(
|
|
24663
|
-
(directory) =>
|
|
24879
|
+
(directory) => mkdir2(path6.join(localPath, directory), { recursive: true })
|
|
24664
24880
|
)
|
|
24665
24881
|
);
|
|
24666
24882
|
return directories;
|
|
@@ -24674,7 +24890,7 @@ var cleanupCheckoutDirectories = async ({
|
|
|
24674
24890
|
if (checkoutStateDirectoryNames.includes(directory)) {
|
|
24675
24891
|
continue;
|
|
24676
24892
|
}
|
|
24677
|
-
const absolutePath =
|
|
24893
|
+
const absolutePath = path6.join(localPath, directory);
|
|
24678
24894
|
try {
|
|
24679
24895
|
const entries = await readdir(absolutePath);
|
|
24680
24896
|
if (entries.length > 0) {
|
|
@@ -24697,13 +24913,13 @@ var cleanupCheckoutDirectories = async ({
|
|
|
24697
24913
|
};
|
|
24698
24914
|
|
|
24699
24915
|
// src/planRemoteDirectoryCleanup.ts
|
|
24700
|
-
import
|
|
24916
|
+
import path7 from "path";
|
|
24701
24917
|
var ancestorDirectories = (relativePath) => {
|
|
24702
24918
|
const directories = [];
|
|
24703
|
-
let directory =
|
|
24919
|
+
let directory = path7.posix.dirname(relativePath);
|
|
24704
24920
|
while (directory && directory !== ".") {
|
|
24705
24921
|
directories.push(directory);
|
|
24706
|
-
directory =
|
|
24922
|
+
directory = path7.posix.dirname(directory);
|
|
24707
24923
|
}
|
|
24708
24924
|
return directories;
|
|
24709
24925
|
};
|
|
@@ -24720,7 +24936,7 @@ var planRemoteDirectoryCleanup = (removedPaths) => {
|
|
|
24720
24936
|
};
|
|
24721
24937
|
|
|
24722
24938
|
// src/cleanupRemoteCheckoutDirectories.ts
|
|
24723
|
-
var
|
|
24939
|
+
var addLeadingSlash2 = (relativePath) => relativePath ? `/${relativePath}` : "/";
|
|
24724
24940
|
var cleanupRemoteCheckoutDirectories = async ({
|
|
24725
24941
|
client,
|
|
24726
24942
|
removedPaths,
|
|
@@ -24728,7 +24944,7 @@ var cleanupRemoteCheckoutDirectories = async ({
|
|
|
24728
24944
|
}) => {
|
|
24729
24945
|
const removed = [];
|
|
24730
24946
|
for (const directory of planRemoteDirectoryCleanup(removedPaths)) {
|
|
24731
|
-
const directoryPath =
|
|
24947
|
+
const directoryPath = addLeadingSlash2(directory);
|
|
24732
24948
|
try {
|
|
24733
24949
|
const listing = await client.listDirectoryByRef({
|
|
24734
24950
|
...storeRef,
|
|
@@ -24751,53 +24967,6 @@ var cleanupRemoteCheckoutDirectories = async ({
|
|
|
24751
24967
|
return removed;
|
|
24752
24968
|
};
|
|
24753
24969
|
|
|
24754
|
-
// src/mapSyncRulePath.ts
|
|
24755
|
-
var assertSafeRelativePath = (relativePath) => {
|
|
24756
|
-
const segments2 = relativePath.split("/");
|
|
24757
|
-
if (relativePath.startsWith("/") || segments2.some((segment) => segment === "." || segment === "..")) {
|
|
24758
|
-
throw new Error(`Unsafe checkout path: ${relativePath}`);
|
|
24759
|
-
}
|
|
24760
|
-
};
|
|
24761
|
-
var toRelativePath = (storePath) => {
|
|
24762
|
-
const relativePath = storePath.replace(/^\/+/, "");
|
|
24763
|
-
assertSafeRelativePath(relativePath);
|
|
24764
|
-
return relativePath;
|
|
24765
|
-
};
|
|
24766
|
-
var joinRelativePath = (...parts) => parts.flatMap((part) => part.split("/")).filter(Boolean).join("/");
|
|
24767
|
-
var addLeadingSlash2 = (relativePath) => relativePath ? `/${relativePath}` : "/";
|
|
24768
|
-
var stripSyncRuleTarget = (localRelativePath, rule) => {
|
|
24769
|
-
if (!rule.target) {
|
|
24770
|
-
return localRelativePath;
|
|
24771
|
-
}
|
|
24772
|
-
if (localRelativePath === rule.target) {
|
|
24773
|
-
return "";
|
|
24774
|
-
}
|
|
24775
|
-
if (!localRelativePath.startsWith(`${rule.target}/`)) {
|
|
24776
|
-
return null;
|
|
24777
|
-
}
|
|
24778
|
-
return localRelativePath.slice(rule.target.length + 1);
|
|
24779
|
-
};
|
|
24780
|
-
var mapLocalPathToSyncRuleRemotePath = (localStorePath, rule) => {
|
|
24781
|
-
const localRelativePath = toRelativePath(localStorePath);
|
|
24782
|
-
const ruleRelativePath = stripSyncRuleTarget(localRelativePath, rule);
|
|
24783
|
-
if (ruleRelativePath === null) {
|
|
24784
|
-
throw new Error(
|
|
24785
|
-
`Path is outside sync rule target ${rule.target || "."}: ${localRelativePath}`
|
|
24786
|
-
);
|
|
24787
|
-
}
|
|
24788
|
-
return addLeadingSlash2(joinRelativePath(rule.path, ruleRelativePath));
|
|
24789
|
-
};
|
|
24790
|
-
var mapRemotePathToSyncRuleLocalPath = (remoteStorePath, rule) => {
|
|
24791
|
-
const remoteRelativePath = toRelativePath(remoteStorePath);
|
|
24792
|
-
if (rule.path && remoteRelativePath !== rule.path && !remoteRelativePath.startsWith(`${rule.path}/`)) {
|
|
24793
|
-
throw new Error(
|
|
24794
|
-
`Remote path is outside sync rule path ${rule.path}: ${remoteRelativePath}`
|
|
24795
|
-
);
|
|
24796
|
-
}
|
|
24797
|
-
const ruleRelativePath = rule.path ? remoteRelativePath === rule.path ? "" : remoteRelativePath.slice(rule.path.length + 1) : remoteRelativePath;
|
|
24798
|
-
return addLeadingSlash2(joinRelativePath(rule.target, ruleRelativePath));
|
|
24799
|
-
};
|
|
24800
|
-
|
|
24801
24970
|
// src/planSyncCheckoutPaths.ts
|
|
24802
24971
|
var detailRelatedPaths = (detail) => [
|
|
24803
24972
|
detail.relativePath,
|
|
@@ -24971,6 +25140,8 @@ var planRemoteRenameBeforePull = ({
|
|
|
24971
25140
|
|
|
24972
25141
|
// src/planSyncCheckoutFile.ts
|
|
24973
25142
|
var planSyncCheckoutFile = ({
|
|
25143
|
+
conflictPolicy,
|
|
25144
|
+
resolvedConflict,
|
|
24974
25145
|
force,
|
|
24975
25146
|
localIsExecutable = false,
|
|
24976
25147
|
localHash,
|
|
@@ -24983,6 +25154,34 @@ var planSyncCheckoutFile = ({
|
|
|
24983
25154
|
}) => {
|
|
24984
25155
|
const hasLocal = localHash !== null;
|
|
24985
25156
|
const hasManifest = manifestHash !== null;
|
|
25157
|
+
const localChanged = localHash !== manifestHash || localIsExecutable !== manifestIsExecutable;
|
|
25158
|
+
if (resolvedConflict && remoteKind === "file") {
|
|
25159
|
+
return {
|
|
25160
|
+
type: resolvedConflict === "remote" ? "pullRemote" : hasLocal ? "pushLocal" : "deleteRemote"
|
|
25161
|
+
};
|
|
25162
|
+
}
|
|
25163
|
+
if (conflictPolicy && remoteKind !== "reference") {
|
|
25164
|
+
if (!hasLocal && hasManifest && remoteKind === "file") {
|
|
25165
|
+
return {
|
|
25166
|
+
type: conflictPolicy === "local" || !remoteVersionChanged ? "deleteRemote" : "pullRemote"
|
|
25167
|
+
};
|
|
25168
|
+
}
|
|
25169
|
+
if (hasLocal && !hasManifest && (remoteKind === "file" || remotePathExists) && remoteHash !== localHash) {
|
|
25170
|
+
return { type: conflictPolicy === "local" ? "pushLocal" : "pullRemote" };
|
|
25171
|
+
}
|
|
25172
|
+
if (hasLocal && hasManifest && localChanged) {
|
|
25173
|
+
if (remoteKind === "missing" && !remotePathExists) {
|
|
25174
|
+
return {
|
|
25175
|
+
type: conflictPolicy === "local" ? "pushLocal" : "deleteLocal"
|
|
25176
|
+
};
|
|
25177
|
+
}
|
|
25178
|
+
if (remoteVersionChanged) {
|
|
25179
|
+
return {
|
|
25180
|
+
type: conflictPolicy === "local" ? "pushLocal" : "pullRemote"
|
|
25181
|
+
};
|
|
25182
|
+
}
|
|
25183
|
+
}
|
|
25184
|
+
}
|
|
24986
25185
|
if (remoteKind === "reference") {
|
|
24987
25186
|
if (!force && (hasManifest || hasLocal)) {
|
|
24988
25187
|
return {
|
|
@@ -25038,7 +25237,6 @@ var planSyncCheckoutFile = ({
|
|
|
25038
25237
|
message: "untracked local file differs from the existing remote file; use fm push --force to keep local (recommended) or fm pull --force to accept remote"
|
|
25039
25238
|
};
|
|
25040
25239
|
}
|
|
25041
|
-
const localChanged = localHash !== manifestHash || localIsExecutable !== manifestIsExecutable;
|
|
25042
25240
|
if (!force && localChanged && remoteVersionChanged) {
|
|
25043
25241
|
return {
|
|
25044
25242
|
type: "conflict",
|
|
@@ -25081,19 +25279,9 @@ var selectCheckoutFilePathsForSyncRule = ({
|
|
|
25081
25279
|
|
|
25082
25280
|
// src/projectConfig.ts
|
|
25083
25281
|
import { createHash } from "crypto";
|
|
25084
|
-
import
|
|
25085
|
-
import { access, readFile, writeFile } from "fs/promises";
|
|
25282
|
+
import path8 from "path";
|
|
25283
|
+
import { access, mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
25086
25284
|
import { parse as parse3, stringify } from "yaml";
|
|
25087
|
-
var warnedLegacyIgnorePaths = /* @__PURE__ */ new Set();
|
|
25088
|
-
var warnLegacyIgnoreField = (filePath) => {
|
|
25089
|
-
if (warnedLegacyIgnorePaths.has(filePath)) {
|
|
25090
|
-
return;
|
|
25091
|
-
}
|
|
25092
|
-
warnedLegacyIgnorePaths.add(filePath);
|
|
25093
|
-
renderWarning(
|
|
25094
|
-
`ignore in ${filePath} is no longer used; move these to the store with \`fm ignore add\`, or to .forum/ignore`
|
|
25095
|
-
);
|
|
25096
|
-
};
|
|
25097
25285
|
var fileExists = async (filePath) => {
|
|
25098
25286
|
try {
|
|
25099
25287
|
await access(filePath);
|
|
@@ -25126,7 +25314,9 @@ var parseProjectConfig = (filePath, source) => {
|
|
|
25126
25314
|
);
|
|
25127
25315
|
}
|
|
25128
25316
|
if (ignore3 !== void 0) {
|
|
25129
|
-
|
|
25317
|
+
throw new Error(
|
|
25318
|
+
`Invalid Forum config at ${filePath}: put shared ignore rules under .forum/stores/ or personal rules in .forum/usr_ignore.`
|
|
25319
|
+
);
|
|
25130
25320
|
}
|
|
25131
25321
|
return {
|
|
25132
25322
|
...defaultStore ? { defaultStore } : {},
|
|
@@ -25207,7 +25397,7 @@ var normalizeSyncPath = ({
|
|
|
25207
25397
|
value
|
|
25208
25398
|
}) => {
|
|
25209
25399
|
const trimmed = value.trim();
|
|
25210
|
-
if (
|
|
25400
|
+
if (path8.isAbsolute(trimmed)) {
|
|
25211
25401
|
throw new Error(
|
|
25212
25402
|
`Invalid Forum config at ${filePath}: ${fieldName} must be a relative path.`
|
|
25213
25403
|
);
|
|
@@ -25360,16 +25550,16 @@ var parseQualifiedConfigStore = (filePath, fieldName, store) => {
|
|
|
25360
25550
|
return `${segments2[0]}/${segments2[1]}`;
|
|
25361
25551
|
};
|
|
25362
25552
|
var findForumProjectConfig = async (startDir = process.cwd()) => {
|
|
25363
|
-
let current =
|
|
25553
|
+
let current = path8.resolve(startDir);
|
|
25364
25554
|
while (true) {
|
|
25365
25555
|
for (const filename of projectConfigFilenames) {
|
|
25366
|
-
const candidate =
|
|
25556
|
+
const candidate = path8.join(current, filename);
|
|
25367
25557
|
if (await fileExists(candidate)) {
|
|
25368
|
-
const source = await
|
|
25558
|
+
const source = await readFile2(candidate, "utf8");
|
|
25369
25559
|
return parseProjectConfig(candidate, source);
|
|
25370
25560
|
}
|
|
25371
25561
|
}
|
|
25372
|
-
const parent =
|
|
25562
|
+
const parent = path8.dirname(current);
|
|
25373
25563
|
if (parent === current) {
|
|
25374
25564
|
return null;
|
|
25375
25565
|
}
|
|
@@ -25404,28 +25594,8 @@ var writeForumProjectConfig = async (filePath, config2) => {
|
|
|
25404
25594
|
target: rule.target || "."
|
|
25405
25595
|
}));
|
|
25406
25596
|
}
|
|
25407
|
-
await
|
|
25408
|
-
|
|
25409
|
-
|
|
25410
|
-
// src/atomicWriteTextFile.ts
|
|
25411
|
-
import path6 from "path";
|
|
25412
|
-
import { chmod, mkdir as mkdir2, rename, rm, writeFile as writeFile2 } from "fs/promises";
|
|
25413
|
-
var atomicWriteTextFile = async (filePath, text, isExecutable = false) => {
|
|
25414
|
-
const parentDir = path6.dirname(filePath);
|
|
25415
|
-
const tempPath = path6.join(
|
|
25416
|
-
parentDir,
|
|
25417
|
-
`.${path6.basename(filePath)}.${process.pid}.${Date.now()}.tmp`
|
|
25418
|
-
);
|
|
25419
|
-
await mkdir2(parentDir, { recursive: true });
|
|
25420
|
-
try {
|
|
25421
|
-
await writeFile2(tempPath, text, "utf8");
|
|
25422
|
-
await chmod(tempPath, isExecutable ? 493 : 420);
|
|
25423
|
-
await rename(tempPath, filePath);
|
|
25424
|
-
} catch (error51) {
|
|
25425
|
-
await rm(tempPath, { force: true }).catch(() => {
|
|
25426
|
-
});
|
|
25427
|
-
throw error51;
|
|
25428
|
-
}
|
|
25597
|
+
await mkdir3(path8.dirname(filePath), { recursive: true });
|
|
25598
|
+
await writeFile2(filePath, stringify(value), "utf8");
|
|
25429
25599
|
};
|
|
25430
25600
|
|
|
25431
25601
|
// src/markdownStoreLinks.ts
|
|
@@ -25500,10 +25670,8 @@ var rewriteRawUrlsToStorePathLinks = ({
|
|
|
25500
25670
|
};
|
|
25501
25671
|
|
|
25502
25672
|
// src/checkout.ts
|
|
25503
|
-
var reservedRootFiles = new Set(projectConfigFilenames);
|
|
25504
|
-
var reservedRootFileNames = [...reservedRootFiles];
|
|
25505
25673
|
var checkoutFilesManifestFilename = "files.json";
|
|
25506
|
-
var localIgnoreFilename = "
|
|
25674
|
+
var localIgnoreFilename = "usr_ignore";
|
|
25507
25675
|
var gitDirectoryName = ".git";
|
|
25508
25676
|
var defaultConcurrency = 8;
|
|
25509
25677
|
var utf8Decoder = new TextDecoder2("utf-8", { fatal: true });
|
|
@@ -25672,18 +25840,14 @@ var rewriteMarkdownForRemoteStore = ({
|
|
|
25672
25840
|
targets: markdownLinkTargetsFromManifest(manifest),
|
|
25673
25841
|
text
|
|
25674
25842
|
}) : text;
|
|
25675
|
-
var
|
|
25676
|
-
const filename = relativePath.split("/").at(-1) ?? relativePath;
|
|
25677
|
-
return reservedRootFiles.has(filename);
|
|
25678
|
-
};
|
|
25679
|
-
var isReservedCheckoutMetadataPath = (relativePath) => isReservedCheckoutFile(relativePath) || isCheckoutStateDirectoryPath(relativePath) || // `.git/` is the checkout's own VCS metadata — structurally never content,
|
|
25843
|
+
var isReservedCheckoutMetadataPath = (relativePath) => isCheckoutStateDirectoryPath(relativePath) || // `.git/` is the checkout's own VCS metadata — structurally never content,
|
|
25680
25844
|
// like `.forum/`. It is reserved (not an ignore *rule*): there are no
|
|
25681
25845
|
// baked-in ignore patterns, but tooling directories are still never synced.
|
|
25682
25846
|
relativePath === gitDirectoryName || relativePath.startsWith(`${gitDirectoryName}/`);
|
|
25683
25847
|
var reservedCheckoutMetadataMessage = "reserved checkout metadata path; ignored by local sync";
|
|
25684
25848
|
var assertSafeRelativePath2 = (relativePath) => {
|
|
25685
25849
|
const segments2 = relativePath.split("/");
|
|
25686
|
-
if (
|
|
25850
|
+
if (path9.isAbsolute(relativePath) || segments2.some((segment) => segment === "." || segment === "..")) {
|
|
25687
25851
|
throw new Error(`Unsafe checkout path: ${relativePath}`);
|
|
25688
25852
|
}
|
|
25689
25853
|
};
|
|
@@ -25997,8 +26161,8 @@ var createSyncRuleClient = (client, rule) => {
|
|
|
25997
26161
|
}
|
|
25998
26162
|
};
|
|
25999
26163
|
};
|
|
26000
|
-
var syncRuleFileParentPath = (rule) =>
|
|
26001
|
-
var syncRuleRemoteFileParentPath = (rule) =>
|
|
26164
|
+
var syncRuleFileParentPath = (rule) => path9.posix.dirname(addLeadingSlash3(rule.target));
|
|
26165
|
+
var syncRuleRemoteFileParentPath = (rule) => path9.posix.dirname(addLeadingSlash3(rule.path));
|
|
26002
26166
|
var assertSyncRuleFilePath = (storePath, rule) => {
|
|
26003
26167
|
const relativePath = toRelativePath2(storePath);
|
|
26004
26168
|
if (relativePath !== rule.target) {
|
|
@@ -26100,7 +26264,7 @@ var classifySyncRuleRemoteRoot = async (client, storeRef, rule) => {
|
|
|
26100
26264
|
const listing = await client.listDirectoryByRef({
|
|
26101
26265
|
...storeRef,
|
|
26102
26266
|
includeHidden: rule.includeHidden,
|
|
26103
|
-
directoryPath:
|
|
26267
|
+
directoryPath: path9.posix.dirname(remotePath)
|
|
26104
26268
|
});
|
|
26105
26269
|
const entry = listing.entries.find(
|
|
26106
26270
|
(candidate) => candidate.path === remotePath
|
|
@@ -26124,7 +26288,7 @@ var classifySyncRuleLocalTarget = async (rootDir, rule) => {
|
|
|
26124
26288
|
return "directory";
|
|
26125
26289
|
}
|
|
26126
26290
|
try {
|
|
26127
|
-
const details = await lstat(
|
|
26291
|
+
const details = await lstat(path9.join(rootDir, rule.target));
|
|
26128
26292
|
if (details.isFile()) {
|
|
26129
26293
|
return "file";
|
|
26130
26294
|
}
|
|
@@ -26246,34 +26410,32 @@ var normalizeCheckoutIncludePaths = (includePaths) => {
|
|
|
26246
26410
|
}
|
|
26247
26411
|
return normalized;
|
|
26248
26412
|
};
|
|
26249
|
-
var checkoutFilesManifestPath = (rootDir) =>
|
|
26413
|
+
var checkoutFilesManifestPath = (rootDir) => path9.join(
|
|
26250
26414
|
rootDir,
|
|
26251
|
-
resolveCheckoutStateDirectoryName(
|
|
26415
|
+
resolveCheckoutStateDirectoryName(),
|
|
26252
26416
|
checkoutFilesManifestFilename
|
|
26253
26417
|
);
|
|
26254
26418
|
var hashBytes = (bytes) => `sha256:${createHash2("sha256").update(bytes).digest("hex")}`;
|
|
26255
26419
|
var hashText = (text) => hashBytes(Buffer.from(text, "utf8"));
|
|
26256
26420
|
var hashLocalFile = async (filePath) => {
|
|
26257
|
-
return hashBytes(await
|
|
26421
|
+
return hashBytes(await readFile3(filePath));
|
|
26258
26422
|
};
|
|
26259
26423
|
var isExecutableMode = (mode) => (mode & 73) !== 0;
|
|
26260
26424
|
var emptyCheckoutFilesManifest = () => ({
|
|
26261
26425
|
files: {},
|
|
26262
26426
|
references: {},
|
|
26263
26427
|
syncRules: {},
|
|
26264
|
-
ignorePatterns: [],
|
|
26265
26428
|
ignoreOnboardedAt: null,
|
|
26266
26429
|
version: 1
|
|
26267
26430
|
});
|
|
26268
26431
|
var readCheckoutFilesManifest = async (rootDir) => {
|
|
26269
26432
|
try {
|
|
26270
|
-
const raw = await
|
|
26433
|
+
const raw = await readFile3(checkoutFilesManifestPath(rootDir), "utf8");
|
|
26271
26434
|
const parsed = JSON.parse(raw);
|
|
26272
26435
|
return {
|
|
26273
26436
|
files: parsed.files ?? {},
|
|
26274
26437
|
references: parsed.references ?? {},
|
|
26275
26438
|
syncRules: parsed.syncRules ?? {},
|
|
26276
|
-
ignorePatterns: parsed.ignorePatterns ?? [],
|
|
26277
26439
|
ignoreOnboardedAt: parsed.ignoreOnboardedAt ?? null,
|
|
26278
26440
|
version: 1
|
|
26279
26441
|
};
|
|
@@ -26286,12 +26448,12 @@ var readCheckoutFilesManifest = async (rootDir) => {
|
|
|
26286
26448
|
};
|
|
26287
26449
|
var writeCheckoutFilesManifest = async (rootDir, manifest) => {
|
|
26288
26450
|
const filePath = checkoutFilesManifestPath(rootDir);
|
|
26289
|
-
const parentDir =
|
|
26290
|
-
const tempPath =
|
|
26451
|
+
const parentDir = path9.dirname(filePath);
|
|
26452
|
+
const tempPath = path9.join(
|
|
26291
26453
|
parentDir,
|
|
26292
26454
|
`.${checkoutFilesManifestFilename}.${process.pid}.${Date.now()}.tmp`
|
|
26293
26455
|
);
|
|
26294
|
-
await
|
|
26456
|
+
await mkdir4(parentDir, { recursive: true });
|
|
26295
26457
|
try {
|
|
26296
26458
|
await writeFile3(
|
|
26297
26459
|
tempPath,
|
|
@@ -26312,9 +26474,6 @@ var writeCheckoutFilesManifest = async (rootDir, manifest) => {
|
|
|
26312
26474
|
([leftId], [rightId]) => leftId < rightId ? -1 : leftId > rightId ? 1 : 0
|
|
26313
26475
|
)
|
|
26314
26476
|
),
|
|
26315
|
-
ignorePatterns: [...manifest.ignorePatterns].sort(
|
|
26316
|
-
(left, right) => left < right ? -1 : left > right ? 1 : 0
|
|
26317
|
-
),
|
|
26318
26477
|
ignoreOnboardedAt: manifest.ignoreOnboardedAt,
|
|
26319
26478
|
version: 1
|
|
26320
26479
|
},
|
|
@@ -26326,7 +26485,7 @@ var writeCheckoutFilesManifest = async (rootDir, manifest) => {
|
|
|
26326
26485
|
);
|
|
26327
26486
|
await rename2(tempPath, filePath);
|
|
26328
26487
|
} catch (error51) {
|
|
26329
|
-
await
|
|
26488
|
+
await rm3(tempPath, { force: true }).catch(() => {
|
|
26330
26489
|
});
|
|
26331
26490
|
throw error51;
|
|
26332
26491
|
}
|
|
@@ -26377,7 +26536,7 @@ var readFileSnapshot = async (filePath) => {
|
|
|
26377
26536
|
};
|
|
26378
26537
|
var isFileSnapshotEqual = (left, right) => left.size === right.size && left.mtimeMs === right.mtimeMs;
|
|
26379
26538
|
var createIgnoreMatcher = (patterns) => {
|
|
26380
|
-
const matcher =
|
|
26539
|
+
const matcher = ignore2();
|
|
26381
26540
|
matcher.add(patterns);
|
|
26382
26541
|
return matcher;
|
|
26383
26542
|
};
|
|
@@ -26431,7 +26590,7 @@ var deleteLocalFileIfPresent = async (filePath) => {
|
|
|
26431
26590
|
if (!details.isFile()) {
|
|
26432
26591
|
return false;
|
|
26433
26592
|
}
|
|
26434
|
-
await
|
|
26593
|
+
await rm3(filePath, { force: true });
|
|
26435
26594
|
return true;
|
|
26436
26595
|
} catch (error51) {
|
|
26437
26596
|
if (isFileNotFoundError(error51)) {
|
|
@@ -26442,7 +26601,7 @@ var deleteLocalFileIfPresent = async (filePath) => {
|
|
|
26442
26601
|
};
|
|
26443
26602
|
var moveLocalFileIfPresent = async (sourcePath, destinationPath) => {
|
|
26444
26603
|
try {
|
|
26445
|
-
await
|
|
26604
|
+
await mkdir4(path9.dirname(destinationPath), { recursive: true });
|
|
26446
26605
|
await rename2(sourcePath, destinationPath);
|
|
26447
26606
|
return true;
|
|
26448
26607
|
} catch (error51) {
|
|
@@ -26454,7 +26613,7 @@ var moveLocalFileIfPresent = async (sourcePath, destinationPath) => {
|
|
|
26454
26613
|
};
|
|
26455
26614
|
var readLocalFileHashIfPresent = async (rootDir, relativePath) => {
|
|
26456
26615
|
try {
|
|
26457
|
-
return await hashLocalFile(
|
|
26616
|
+
return await hashLocalFile(path9.join(rootDir, relativePath));
|
|
26458
26617
|
} catch (error51) {
|
|
26459
26618
|
if (isFileNotFoundError(error51)) {
|
|
26460
26619
|
return null;
|
|
@@ -26513,7 +26672,7 @@ var reconcileTrackedRemoteDelete = async ({
|
|
|
26513
26672
|
return localFileHash !== null ? "deleted" : "ignored";
|
|
26514
26673
|
}
|
|
26515
26674
|
const deletedLocalFile = await deleteLocalFileIfPresent(
|
|
26516
|
-
|
|
26675
|
+
path9.join(localPath, relativePath)
|
|
26517
26676
|
);
|
|
26518
26677
|
delete manifest.files[relativePath];
|
|
26519
26678
|
return deletedLocalFile ? "deleted" : "ignored";
|
|
@@ -26593,20 +26752,20 @@ var readOnlyCheckoutChangeResults = (changes) => changes.map((change) => ({
|
|
|
26593
26752
|
status: "failed"
|
|
26594
26753
|
}));
|
|
26595
26754
|
var resetCheckoutSyncState = async (rootDir) => {
|
|
26596
|
-
await
|
|
26755
|
+
await rm3(checkoutFilesManifestPath(rootDir), { force: true });
|
|
26597
26756
|
};
|
|
26598
26757
|
var atomicWriteBinaryFile = async (filePath, bytes) => {
|
|
26599
|
-
const parentDir =
|
|
26600
|
-
const tempPath =
|
|
26758
|
+
const parentDir = path9.dirname(filePath);
|
|
26759
|
+
const tempPath = path9.join(
|
|
26601
26760
|
parentDir,
|
|
26602
|
-
`.${
|
|
26761
|
+
`.${path9.basename(filePath)}.${process.pid}.${Date.now()}.tmp`
|
|
26603
26762
|
);
|
|
26604
|
-
await
|
|
26763
|
+
await mkdir4(parentDir, { recursive: true });
|
|
26605
26764
|
try {
|
|
26606
26765
|
await writeFile3(tempPath, bytes);
|
|
26607
26766
|
await rename2(tempPath, filePath);
|
|
26608
26767
|
} catch (error51) {
|
|
26609
|
-
await
|
|
26768
|
+
await rm3(tempPath, { force: true }).catch(() => {
|
|
26610
26769
|
});
|
|
26611
26770
|
throw error51;
|
|
26612
26771
|
}
|
|
@@ -26644,7 +26803,7 @@ var readStableCheckoutFile = async (absolutePath, relativePath, attempts = 3) =>
|
|
|
26644
26803
|
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
26645
26804
|
try {
|
|
26646
26805
|
const before = await readFileSnapshot(absolutePath);
|
|
26647
|
-
const buffer = await
|
|
26806
|
+
const buffer = await readFile3(absolutePath);
|
|
26648
26807
|
const after = await readFileSnapshot(absolutePath);
|
|
26649
26808
|
if (!isFileSnapshotEqual(before, after)) {
|
|
26650
26809
|
sawUnstableRead = true;
|
|
@@ -26704,8 +26863,8 @@ var readStableCheckoutFile = async (absolutePath, relativePath, attempts = 3) =>
|
|
|
26704
26863
|
var walkLocalCheckoutFiles = async (rootDir, directoryPath, includePaths, matcher, scan) => {
|
|
26705
26864
|
const entries = await readdir2(directoryPath, { withFileTypes: true });
|
|
26706
26865
|
for (const entry of entries) {
|
|
26707
|
-
const absolutePath =
|
|
26708
|
-
const relativePath =
|
|
26866
|
+
const absolutePath = path9.join(directoryPath, entry.name);
|
|
26867
|
+
const relativePath = path9.relative(rootDir, absolutePath).split(path9.sep).join("/");
|
|
26709
26868
|
const classification = classifyCheckoutPath(
|
|
26710
26869
|
relativePath,
|
|
26711
26870
|
entry.isDirectory(),
|
|
@@ -26803,7 +26962,7 @@ var readRemoteCheckoutEntry = async (client, storeRef, relativePath) => {
|
|
|
26803
26962
|
const storePath = toStorePath2(relativePath);
|
|
26804
26963
|
const listing = await client.listDirectoryByRef({
|
|
26805
26964
|
...storeRef,
|
|
26806
|
-
directoryPath:
|
|
26965
|
+
directoryPath: path9.posix.dirname(storePath)
|
|
26807
26966
|
});
|
|
26808
26967
|
const entry = listing.entries.find(
|
|
26809
26968
|
(candidate) => candidate.path === storePath
|
|
@@ -26817,7 +26976,7 @@ var readRemoteStoreEntry = async (client, storeRef, relativePath) => {
|
|
|
26817
26976
|
const storePath = toStorePath2(relativePath);
|
|
26818
26977
|
const listing = await client.listDirectoryByRef({
|
|
26819
26978
|
...storeRef,
|
|
26820
|
-
directoryPath:
|
|
26979
|
+
directoryPath: path9.posix.dirname(storePath)
|
|
26821
26980
|
});
|
|
26822
26981
|
return listing.entries.find(
|
|
26823
26982
|
(candidate) => candidate.path === storePath
|
|
@@ -26841,7 +27000,7 @@ var readReferenceSourceForPath = async (client, storeRef, relativePath) => {
|
|
|
26841
27000
|
return void 0;
|
|
26842
27001
|
};
|
|
26843
27002
|
var readLocalCheckoutFile = async (rootDir, relativePath) => {
|
|
26844
|
-
const absolutePath =
|
|
27003
|
+
const absolutePath = path9.join(rootDir, relativePath);
|
|
26845
27004
|
let details;
|
|
26846
27005
|
try {
|
|
26847
27006
|
details = await lstat(absolutePath);
|
|
@@ -27291,7 +27450,7 @@ var joinDirectRootPath = (rootPath, relativePath) => {
|
|
|
27291
27450
|
if (!relativePath) {
|
|
27292
27451
|
return rootPath;
|
|
27293
27452
|
}
|
|
27294
|
-
return
|
|
27453
|
+
return path9.posix.join(rootPath, relativePath);
|
|
27295
27454
|
};
|
|
27296
27455
|
var directStorePath = (relativePath) => relativePath ? toStorePath2(relativePath) : "/";
|
|
27297
27456
|
var relativePathFromDirectRoot = (rootPath, storePath) => {
|
|
@@ -27300,7 +27459,7 @@ var relativePathFromDirectRoot = (rootPath, storePath) => {
|
|
|
27300
27459
|
return relativePath;
|
|
27301
27460
|
}
|
|
27302
27461
|
if (relativePath === rootPath) {
|
|
27303
|
-
return
|
|
27462
|
+
return path9.posix.basename(rootPath);
|
|
27304
27463
|
}
|
|
27305
27464
|
const prefix = `${rootPath}/`;
|
|
27306
27465
|
if (!relativePath.startsWith(prefix)) {
|
|
@@ -27348,22 +27507,26 @@ var updateFileManifestEntry = ({
|
|
|
27348
27507
|
hash: hash2,
|
|
27349
27508
|
manifest,
|
|
27350
27509
|
manifestEntry,
|
|
27351
|
-
path:
|
|
27510
|
+
path: path22,
|
|
27352
27511
|
remoteFile,
|
|
27353
27512
|
source,
|
|
27354
27513
|
syncedAt
|
|
27355
27514
|
}) => {
|
|
27356
|
-
manifest.files[
|
|
27515
|
+
manifest.files[path22] = buildCheckoutFileManifestEntry({
|
|
27357
27516
|
storageClass,
|
|
27358
27517
|
hash: hash2,
|
|
27359
27518
|
manifestEntry,
|
|
27360
|
-
path:
|
|
27519
|
+
path: path22,
|
|
27361
27520
|
remoteFile,
|
|
27362
27521
|
source,
|
|
27363
27522
|
syncedAt
|
|
27364
27523
|
});
|
|
27365
27524
|
};
|
|
27366
27525
|
var reconcileRemoteRenamesBeforePull = async ({
|
|
27526
|
+
client,
|
|
27527
|
+
conflictPolicy,
|
|
27528
|
+
localFiles,
|
|
27529
|
+
storeRef,
|
|
27367
27530
|
dryRun,
|
|
27368
27531
|
files,
|
|
27369
27532
|
force,
|
|
@@ -27375,7 +27538,8 @@ var reconcileRemoteRenamesBeforePull = async ({
|
|
|
27375
27538
|
for (const [relativePath, entry] of Object.entries(manifest.files)) {
|
|
27376
27539
|
manifestPathByRemoteFileId.set(entry.remoteFileId, relativePath);
|
|
27377
27540
|
}
|
|
27378
|
-
for (const
|
|
27541
|
+
for (const remoteFile of files) {
|
|
27542
|
+
const { entry, relativePath } = remoteFile;
|
|
27379
27543
|
if (!entry.id) {
|
|
27380
27544
|
continue;
|
|
27381
27545
|
}
|
|
@@ -27383,18 +27547,40 @@ var reconcileRemoteRenamesBeforePull = async ({
|
|
|
27383
27547
|
if (!manifestPath || manifestPath === relativePath) {
|
|
27384
27548
|
continue;
|
|
27385
27549
|
}
|
|
27386
|
-
const sourcePath =
|
|
27387
|
-
const destinationPath =
|
|
27550
|
+
const sourcePath = path9.join(localPath, manifestPath);
|
|
27551
|
+
const destinationPath = path9.join(localPath, relativePath);
|
|
27388
27552
|
const manifestEntry = manifest.files[manifestPath];
|
|
27389
27553
|
const destinationExists = await pathExists(destinationPath);
|
|
27390
27554
|
const localChanged = await hasTrackedLocalChange({
|
|
27391
27555
|
localPath,
|
|
27392
27556
|
manifestEntry,
|
|
27393
27557
|
relativePath: manifestPath
|
|
27394
|
-
});
|
|
27558
|
+
}) || Boolean(conflictPolicy) && !await pathExists(sourcePath);
|
|
27559
|
+
const localMoveCandidates = conflictPolicy && !await pathExists(sourcePath) ? (localFiles ?? []).filter(
|
|
27560
|
+
(file2) => !manifest.files[file2.relativePath] && file2.hash === manifestEntry.hash
|
|
27561
|
+
) : [];
|
|
27562
|
+
if (conflictPolicy === "local" && (localChanged || destinationExists) && client) {
|
|
27563
|
+
const winnerPath = localMoveCandidates.length === 1 ? localMoveCandidates[0].relativePath : manifestPath;
|
|
27564
|
+
if (!dryRun && relativePath !== winnerPath) {
|
|
27565
|
+
await client.movePathByRef({
|
|
27566
|
+
...storeRef,
|
|
27567
|
+
sourcePath: toStorePath2(relativePath),
|
|
27568
|
+
destinationPath: toStorePath2(winnerPath)
|
|
27569
|
+
});
|
|
27570
|
+
}
|
|
27571
|
+
manifest.files[winnerPath] = {
|
|
27572
|
+
...manifestEntry,
|
|
27573
|
+
remotePath: toStorePath2(winnerPath)
|
|
27574
|
+
};
|
|
27575
|
+
if (winnerPath !== manifestPath) delete manifest.files[manifestPath];
|
|
27576
|
+
remoteFile.conflictWinner = "local";
|
|
27577
|
+
remoteFile.relativePath = winnerPath;
|
|
27578
|
+
remoteFile.entry = { ...entry, path: toStorePath2(winnerPath) };
|
|
27579
|
+
continue;
|
|
27580
|
+
}
|
|
27395
27581
|
const plan = planRemoteRenameBeforePull({
|
|
27396
27582
|
destinationExists,
|
|
27397
|
-
force,
|
|
27583
|
+
force: force || conflictPolicy === "remote",
|
|
27398
27584
|
localChanged
|
|
27399
27585
|
});
|
|
27400
27586
|
if (plan.type === "conflict") {
|
|
@@ -27421,6 +27607,33 @@ var reconcileRemoteRenamesBeforePull = async ({
|
|
|
27421
27607
|
);
|
|
27422
27608
|
continue;
|
|
27423
27609
|
}
|
|
27610
|
+
if (conflictPolicy === "remote" && (localChanged || destinationExists)) {
|
|
27611
|
+
remoteFile.conflictWinner = "remote";
|
|
27612
|
+
for (const candidate of localMoveCandidates) {
|
|
27613
|
+
if (!dryRun)
|
|
27614
|
+
await deleteLocalFileIfPresent(
|
|
27615
|
+
path9.join(localPath, candidate.relativePath)
|
|
27616
|
+
);
|
|
27617
|
+
}
|
|
27618
|
+
}
|
|
27619
|
+
if (conflictPolicy && localFiles) {
|
|
27620
|
+
const source = localFiles.find(
|
|
27621
|
+
(file2) => file2.relativePath === manifestPath
|
|
27622
|
+
);
|
|
27623
|
+
const remaining = localFiles.filter(
|
|
27624
|
+
(file2) => file2.relativePath !== manifestPath && file2.relativePath !== relativePath && !localMoveCandidates.includes(file2)
|
|
27625
|
+
);
|
|
27626
|
+
if (source && !localChanged && !destinationExists)
|
|
27627
|
+
remaining.push({ ...source, relativePath });
|
|
27628
|
+
localFiles.splice(0, localFiles.length, ...remaining);
|
|
27629
|
+
if (dryRun) {
|
|
27630
|
+
manifest.files[relativePath] = {
|
|
27631
|
+
...manifestEntry,
|
|
27632
|
+
remotePath: toStorePath2(relativePath)
|
|
27633
|
+
};
|
|
27634
|
+
delete manifest.files[manifestPath];
|
|
27635
|
+
}
|
|
27636
|
+
}
|
|
27424
27637
|
if (!dryRun) {
|
|
27425
27638
|
if (plan.shouldDeleteDestination) {
|
|
27426
27639
|
await deleteLocalFileIfPresent(destinationPath);
|
|
@@ -27463,6 +27676,9 @@ var localRenameCandidateDestinations = (relativePath, manifest, localFilesByHash
|
|
|
27463
27676
|
var localRenameCandidateSources = (file2, deletePaths, manifest) => deletePaths.filter((relativePath) => manifest.files[relativePath]?.hash === file2.hash).sort();
|
|
27464
27677
|
var preflightLocalRenamesBeforePush = async ({
|
|
27465
27678
|
client,
|
|
27679
|
+
conflictPolicy,
|
|
27680
|
+
remoteFiles,
|
|
27681
|
+
localPath,
|
|
27466
27682
|
deletePaths,
|
|
27467
27683
|
dryRun,
|
|
27468
27684
|
localFiles,
|
|
@@ -27546,6 +27762,41 @@ var preflightLocalRenamesBeforePush = async ({
|
|
|
27546
27762
|
if (!manifestEntry) {
|
|
27547
27763
|
continue;
|
|
27548
27764
|
}
|
|
27765
|
+
const remoteFile = remoteFiles?.find(
|
|
27766
|
+
(file2) => file2.entry.id === manifestEntry.remoteFileId
|
|
27767
|
+
);
|
|
27768
|
+
if (conflictPolicy && remoteFile && localPath && remoteFile.entry.revisionNumber !== manifestEntry.remoteRevisionNumber) {
|
|
27769
|
+
remoteFile.conflictWinner = conflictPolicy;
|
|
27770
|
+
if (conflictPolicy === "local") {
|
|
27771
|
+
if (!dryRun)
|
|
27772
|
+
await client.movePathByRef({
|
|
27773
|
+
...storeRef,
|
|
27774
|
+
sourcePath: toStorePath2(rename5.sourcePath),
|
|
27775
|
+
destinationPath: toStorePath2(rename5.destinationPath)
|
|
27776
|
+
});
|
|
27777
|
+
remoteFile.relativePath = rename5.destinationPath;
|
|
27778
|
+
remoteFile.entry = {
|
|
27779
|
+
...remoteFile.entry,
|
|
27780
|
+
path: toStorePath2(rename5.destinationPath)
|
|
27781
|
+
};
|
|
27782
|
+
manifest.files[rename5.destinationPath] = {
|
|
27783
|
+
...manifestEntry,
|
|
27784
|
+
remotePath: toStorePath2(rename5.destinationPath)
|
|
27785
|
+
};
|
|
27786
|
+
delete manifest.files[rename5.sourcePath];
|
|
27787
|
+
} else {
|
|
27788
|
+
if (!dryRun)
|
|
27789
|
+
await moveLocalFileIfPresent(
|
|
27790
|
+
path9.join(localPath, rename5.destinationPath),
|
|
27791
|
+
path9.join(localPath, rename5.sourcePath)
|
|
27792
|
+
);
|
|
27793
|
+
const movedFile = localFiles.find(
|
|
27794
|
+
(file2) => file2.relativePath === rename5.destinationPath
|
|
27795
|
+
);
|
|
27796
|
+
if (movedFile) movedFile.relativePath = rename5.sourcePath;
|
|
27797
|
+
}
|
|
27798
|
+
continue;
|
|
27799
|
+
}
|
|
27549
27800
|
if (!dryRun) {
|
|
27550
27801
|
await client.movePathByRef({
|
|
27551
27802
|
...storeRef,
|
|
@@ -27572,14 +27823,10 @@ var preflightLocalRenamesBeforePush = async ({
|
|
|
27572
27823
|
remainingDeletePaths
|
|
27573
27824
|
};
|
|
27574
27825
|
};
|
|
27575
|
-
var localIgnoreFilePath = (rootDir) =>
|
|
27576
|
-
rootDir,
|
|
27577
|
-
resolveCheckoutStateDirectoryName(rootDir),
|
|
27578
|
-
localIgnoreFilename
|
|
27579
|
-
);
|
|
27826
|
+
var localIgnoreFilePath = (rootDir) => path9.join(rootDir, resolveCheckoutStateDirectoryName(), localIgnoreFilename);
|
|
27580
27827
|
var readLocalIgnorePatterns = async (rootDir) => {
|
|
27581
27828
|
try {
|
|
27582
|
-
const raw = await
|
|
27829
|
+
const raw = await readFile3(localIgnoreFilePath(rootDir), "utf8");
|
|
27583
27830
|
return parseLocalIgnoreFile(raw);
|
|
27584
27831
|
} catch (error51) {
|
|
27585
27832
|
if (errorCode(error51) === "ENOENT") {
|
|
@@ -27588,20 +27835,6 @@ var readLocalIgnorePatterns = async (rootDir) => {
|
|
|
27588
27835
|
throw error51;
|
|
27589
27836
|
}
|
|
27590
27837
|
};
|
|
27591
|
-
var readStoreIgnoreCache = async (rootDir) => {
|
|
27592
|
-
const manifest = await readCheckoutFilesManifest(rootDir);
|
|
27593
|
-
return manifest.ignorePatterns;
|
|
27594
|
-
};
|
|
27595
|
-
var writeStoreIgnoreCache = async (rootDir, storeIgnorePatterns) => {
|
|
27596
|
-
const manifest = await readCheckoutFilesManifest(rootDir);
|
|
27597
|
-
const ignorePatterns = resolveIgnorePatterns({
|
|
27598
|
-
bakedIn: [],
|
|
27599
|
-
storeSetting: storeIgnorePatterns,
|
|
27600
|
-
localOverride: []
|
|
27601
|
-
});
|
|
27602
|
-
await writeCheckoutFilesManifest(rootDir, { ...manifest, ignorePatterns });
|
|
27603
|
-
return ignorePatterns;
|
|
27604
|
-
};
|
|
27605
27838
|
var readIgnoreOnboardedAt = async (rootDir) => {
|
|
27606
27839
|
const manifest = await readCheckoutFilesManifest(rootDir);
|
|
27607
27840
|
return manifest.ignoreOnboardedAt;
|
|
@@ -27617,22 +27850,29 @@ var resolveCheckoutConfig = async (startDir = process.cwd()) => {
|
|
|
27617
27850
|
const config2 = await findForumProjectConfig(startDir);
|
|
27618
27851
|
if (!config2) {
|
|
27619
27852
|
throw new Error(
|
|
27620
|
-
"No forum.yaml found. Run fm init <store> or fm clone <store> first."
|
|
27853
|
+
"No .forum/sync.yaml found. Run fm init <store> or fm clone <store> first."
|
|
27621
27854
|
);
|
|
27622
27855
|
}
|
|
27623
|
-
const rootDir =
|
|
27624
|
-
const
|
|
27625
|
-
|
|
27626
|
-
|
|
27627
|
-
|
|
27628
|
-
|
|
27629
|
-
|
|
27630
|
-
|
|
27631
|
-
|
|
27632
|
-
|
|
27856
|
+
const rootDir = path9.dirname(path9.dirname(config2.path));
|
|
27857
|
+
const personal = await readLocalIgnorePatterns(rootDir);
|
|
27858
|
+
const ignorePatternsByStore = {};
|
|
27859
|
+
const ignoreMatchersByRule = {};
|
|
27860
|
+
for (const rule of config2.syncRules) {
|
|
27861
|
+
const shared = await readSharedIgnoreFile(sharedIgnorePath(rootDir, rule.store)) ?? [];
|
|
27862
|
+
ignorePatternsByStore[rule.store] = [...shared, ...personal];
|
|
27863
|
+
ignoreMatchersByRule[rule.id] = createCheckoutIgnoreMatcher(
|
|
27864
|
+
rule,
|
|
27865
|
+
shared,
|
|
27866
|
+
personal
|
|
27867
|
+
);
|
|
27868
|
+
}
|
|
27869
|
+
const stores = Object.keys(ignorePatternsByStore);
|
|
27870
|
+
const ignore3 = stores.length === 1 ? ignorePatternsByStore[stores[0]] : personal;
|
|
27633
27871
|
return {
|
|
27634
27872
|
...config2,
|
|
27873
|
+
ignoreMatchersByRule,
|
|
27635
27874
|
ignore: ignore3,
|
|
27875
|
+
ignorePatternsByStore,
|
|
27636
27876
|
configRootDir: rootDir,
|
|
27637
27877
|
rootDir
|
|
27638
27878
|
};
|
|
@@ -27640,8 +27880,8 @@ var resolveCheckoutConfig = async (startDir = process.cwd()) => {
|
|
|
27640
27880
|
var collectLocalCheckoutFiles = async (rootDir, ignorePatterns, syncIncludePaths) => {
|
|
27641
27881
|
return (await scanLocalCheckoutFiles(rootDir, ignorePatterns, syncIncludePaths)).files;
|
|
27642
27882
|
};
|
|
27643
|
-
var scanLocalCheckoutFiles = async (rootDir, ignorePatterns, syncIncludePaths, progress) => {
|
|
27644
|
-
const matcher = createIgnoreMatcher(ignorePatterns);
|
|
27883
|
+
var scanLocalCheckoutFiles = async (rootDir, ignorePatterns, syncIncludePaths, progress, ignoreMatcher) => {
|
|
27884
|
+
const matcher = ignoreMatcher ?? createIgnoreMatcher(ignorePatterns);
|
|
27645
27885
|
const includePaths = normalizeCheckoutIncludePaths(syncIncludePaths);
|
|
27646
27886
|
const scan = {
|
|
27647
27887
|
files: [],
|
|
@@ -27663,18 +27903,76 @@ var scanLocalCheckoutFiles = async (rootDir, ignorePatterns, syncIncludePaths, p
|
|
|
27663
27903
|
);
|
|
27664
27904
|
return scan;
|
|
27665
27905
|
};
|
|
27906
|
+
var ignoreSettingDetail = (change) => {
|
|
27907
|
+
const message = change.action === "conflict" ? `Shared ignore rules changed locally and remotely for ${change.store}. Save your local rules, remove ${change.relativePath}, and sync to restore the store baseline. Then apply your merged rules and sync again.` : `Shared ignore settings: ${change.action} (${change.store})`;
|
|
27908
|
+
if (change.action === "conflict")
|
|
27909
|
+
return checkoutConflictFileResult({
|
|
27910
|
+
relativePath: change.relativePath,
|
|
27911
|
+
message,
|
|
27912
|
+
type: "shared-ignore-conflict"
|
|
27913
|
+
});
|
|
27914
|
+
return checkoutFileResultWithDirection(
|
|
27915
|
+
{
|
|
27916
|
+
relativePath: change.relativePath,
|
|
27917
|
+
message,
|
|
27918
|
+
status: "succeeded",
|
|
27919
|
+
changeType: "updated"
|
|
27920
|
+
},
|
|
27921
|
+
change.action === "publish" ? "upload" : "download"
|
|
27922
|
+
);
|
|
27923
|
+
};
|
|
27666
27924
|
var pullCheckout = async ({
|
|
27667
27925
|
client,
|
|
27668
27926
|
dryRun = false,
|
|
27669
27927
|
filePaths,
|
|
27670
27928
|
force = false,
|
|
27671
27929
|
ignorePatterns,
|
|
27930
|
+
ignoreMatcher,
|
|
27931
|
+
ignoreMatchersByRule,
|
|
27932
|
+
ignoreSettings,
|
|
27933
|
+
ignorePatternsByStore,
|
|
27672
27934
|
localPath,
|
|
27673
27935
|
progress,
|
|
27674
27936
|
storeRef,
|
|
27675
27937
|
syncIncludePaths,
|
|
27676
27938
|
syncRules
|
|
27677
27939
|
}) => {
|
|
27940
|
+
if (syncRules && ignoreSettings) {
|
|
27941
|
+
const settings = await prepareCheckoutIgnore({
|
|
27942
|
+
rootDir: localPath,
|
|
27943
|
+
syncRules,
|
|
27944
|
+
client,
|
|
27945
|
+
dryRun: dryRun || ignoreSettings === "preview"
|
|
27946
|
+
});
|
|
27947
|
+
const conflicts = settings.changes.filter(
|
|
27948
|
+
(change) => change.action === "conflict"
|
|
27949
|
+
);
|
|
27950
|
+
if (conflicts.length)
|
|
27951
|
+
return checkoutResultFromDetails(conflicts.map(ignoreSettingDetail));
|
|
27952
|
+
const result = await pullCheckout({
|
|
27953
|
+
client,
|
|
27954
|
+
dryRun,
|
|
27955
|
+
filePaths,
|
|
27956
|
+
force,
|
|
27957
|
+
ignorePatterns,
|
|
27958
|
+
localPath,
|
|
27959
|
+
progress,
|
|
27960
|
+
storeRef,
|
|
27961
|
+
syncIncludePaths,
|
|
27962
|
+
syncRules,
|
|
27963
|
+
ignorePatternsByStore: settings.patternsByStore,
|
|
27964
|
+
ignoreMatchersByRule: settings.matchersByRule
|
|
27965
|
+
});
|
|
27966
|
+
const changes = dryRun ? settings.changes.filter((change) => change.action !== "publish") : [];
|
|
27967
|
+
Object.assign(
|
|
27968
|
+
result,
|
|
27969
|
+
checkoutResultFromDetails([
|
|
27970
|
+
...result.details,
|
|
27971
|
+
...changes.map(ignoreSettingDetail)
|
|
27972
|
+
])
|
|
27973
|
+
);
|
|
27974
|
+
return result;
|
|
27975
|
+
}
|
|
27678
27976
|
const requestedRelativePaths = normalizeCheckoutFilePaths(filePaths);
|
|
27679
27977
|
if (syncRules) {
|
|
27680
27978
|
await ensureManifestSyncRules(localPath, syncRules, {
|
|
@@ -27715,7 +28013,8 @@ var pullCheckout = async ({
|
|
|
27715
28013
|
dryRun,
|
|
27716
28014
|
filePaths: ruleFilePaths ?? void 0,
|
|
27717
28015
|
force,
|
|
27718
|
-
ignorePatterns,
|
|
28016
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
28017
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
27719
28018
|
localPath,
|
|
27720
28019
|
progress: checkoutProgressWithSyncRuleRemoteRefs(
|
|
27721
28020
|
progress,
|
|
@@ -27746,7 +28045,7 @@ var pullCheckout = async ({
|
|
|
27746
28045
|
);
|
|
27747
28046
|
}
|
|
27748
28047
|
const remoteEntries = [];
|
|
27749
|
-
const matcher = createIgnoreMatcher(ignorePatterns);
|
|
28048
|
+
const matcher = ignoreMatcher ?? createIgnoreMatcher(ignorePatterns);
|
|
27750
28049
|
const includePaths = normalizeCheckoutIncludePaths(syncIncludePaths);
|
|
27751
28050
|
const manifest = await readCheckoutFilesManifest(localPath);
|
|
27752
28051
|
const manifestSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -27857,7 +28156,7 @@ var pullCheckout = async ({
|
|
|
27857
28156
|
}
|
|
27858
28157
|
if (!dryRun) {
|
|
27859
28158
|
const deletedLocalFile = await deleteLocalFileIfPresent(
|
|
27860
|
-
|
|
28159
|
+
path9.join(localPath, relativePath)
|
|
27861
28160
|
);
|
|
27862
28161
|
delete manifest.files[relativePath];
|
|
27863
28162
|
manifest.references[relativePath] = {
|
|
@@ -27942,7 +28241,7 @@ var pullCheckout = async ({
|
|
|
27942
28241
|
);
|
|
27943
28242
|
}
|
|
27944
28243
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
27945
|
-
await atomicWriteBinaryFile(
|
|
28244
|
+
await atomicWriteBinaryFile(path9.join(localPath, relativePath), bytes);
|
|
27946
28245
|
updateFileManifestEntry({
|
|
27947
28246
|
storageClass: "binary",
|
|
27948
28247
|
hash: hashBytes(bytes),
|
|
@@ -27968,7 +28267,7 @@ var pullCheckout = async ({
|
|
|
27968
28267
|
text: remoteFile.content.text
|
|
27969
28268
|
});
|
|
27970
28269
|
await atomicWriteTextFile(
|
|
27971
|
-
|
|
28270
|
+
path9.join(localPath, relativePath),
|
|
27972
28271
|
localText,
|
|
27973
28272
|
remoteFile.isExecutable === true
|
|
27974
28273
|
);
|
|
@@ -28138,7 +28437,7 @@ var pullStoreFiles = async ({
|
|
|
28138
28437
|
if (!remoteFile) {
|
|
28139
28438
|
throw new Error("remote file disappeared while pulling");
|
|
28140
28439
|
}
|
|
28141
|
-
const destinationPath =
|
|
28440
|
+
const destinationPath = path9.join(localPath, targetPath, relativePath);
|
|
28142
28441
|
const changeType = await localPathExists(destinationPath) ? "updated" : "created";
|
|
28143
28442
|
if (remoteFileHasBlobContent(remoteFile)) {
|
|
28144
28443
|
const { downloadUrl } = await client.createFileDownloadUrlByRef({
|
|
@@ -28189,12 +28488,52 @@ var pushCheckout = async ({
|
|
|
28189
28488
|
filePaths,
|
|
28190
28489
|
force,
|
|
28191
28490
|
ignorePatterns,
|
|
28491
|
+
ignoreMatcher,
|
|
28492
|
+
ignoreMatchersByRule,
|
|
28493
|
+
ignoreSettings,
|
|
28494
|
+
ignorePatternsByStore,
|
|
28192
28495
|
localPath,
|
|
28193
28496
|
progress,
|
|
28194
28497
|
storeRef,
|
|
28195
28498
|
syncIncludePaths,
|
|
28196
28499
|
syncRules
|
|
28197
28500
|
}) => {
|
|
28501
|
+
if (syncRules && ignoreSettings) {
|
|
28502
|
+
const settings = await prepareCheckoutIgnore({
|
|
28503
|
+
rootDir: localPath,
|
|
28504
|
+
syncRules,
|
|
28505
|
+
client,
|
|
28506
|
+
dryRun: dryRun || ignoreSettings === "preview"
|
|
28507
|
+
});
|
|
28508
|
+
const conflicts = settings.changes.filter(
|
|
28509
|
+
(change) => change.action === "conflict"
|
|
28510
|
+
);
|
|
28511
|
+
if (conflicts.length)
|
|
28512
|
+
return checkoutResultFromDetails(conflicts.map(ignoreSettingDetail));
|
|
28513
|
+
const result2 = await pushCheckout({
|
|
28514
|
+
client,
|
|
28515
|
+
dryRun,
|
|
28516
|
+
filePaths,
|
|
28517
|
+
force,
|
|
28518
|
+
ignorePatterns,
|
|
28519
|
+
localPath,
|
|
28520
|
+
progress,
|
|
28521
|
+
storeRef,
|
|
28522
|
+
syncIncludePaths,
|
|
28523
|
+
syncRules,
|
|
28524
|
+
ignorePatternsByStore: settings.patternsByStore,
|
|
28525
|
+
ignoreMatchersByRule: settings.matchersByRule
|
|
28526
|
+
});
|
|
28527
|
+
const changes = dryRun ? settings.changes.filter((change) => change.action === "publish") : [];
|
|
28528
|
+
Object.assign(
|
|
28529
|
+
result2,
|
|
28530
|
+
checkoutResultFromDetails([
|
|
28531
|
+
...result2.details,
|
|
28532
|
+
...changes.map(ignoreSettingDetail)
|
|
28533
|
+
])
|
|
28534
|
+
);
|
|
28535
|
+
return result2;
|
|
28536
|
+
}
|
|
28198
28537
|
const requestedRelativePaths = normalizeCheckoutFilePaths(filePaths);
|
|
28199
28538
|
if (syncRules) {
|
|
28200
28539
|
await ensureManifestSyncRules(localPath, syncRules, {
|
|
@@ -28235,7 +28574,8 @@ var pushCheckout = async ({
|
|
|
28235
28574
|
dryRun,
|
|
28236
28575
|
filePaths: ruleFilePaths ?? void 0,
|
|
28237
28576
|
force,
|
|
28238
|
-
ignorePatterns,
|
|
28577
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
28578
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
28239
28579
|
localPath,
|
|
28240
28580
|
progress: checkoutProgressWithSyncRuleRemoteRefs(
|
|
28241
28581
|
progress,
|
|
@@ -28265,14 +28605,20 @@ var pushCheckout = async ({
|
|
|
28265
28605
|
"upload"
|
|
28266
28606
|
);
|
|
28267
28607
|
}
|
|
28268
|
-
const matcher = createIgnoreMatcher(ignorePatterns);
|
|
28608
|
+
const matcher = ignoreMatcher ?? createIgnoreMatcher(ignorePatterns);
|
|
28269
28609
|
const includePaths = normalizeCheckoutIncludePaths(syncIncludePaths);
|
|
28270
28610
|
const scan = requestedRelativePaths ? await scanTargetLocalCheckoutFiles(
|
|
28271
28611
|
localPath,
|
|
28272
28612
|
requestedRelativePaths,
|
|
28273
28613
|
includePaths,
|
|
28274
28614
|
matcher
|
|
28275
|
-
) : await scanLocalCheckoutFiles(
|
|
28615
|
+
) : await scanLocalCheckoutFiles(
|
|
28616
|
+
localPath,
|
|
28617
|
+
ignorePatterns,
|
|
28618
|
+
includePaths,
|
|
28619
|
+
void 0,
|
|
28620
|
+
matcher
|
|
28621
|
+
);
|
|
28276
28622
|
const manifest = await readCheckoutFilesManifest(localPath);
|
|
28277
28623
|
const manifestSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28278
28624
|
const localPaths = new Set(scan.files.map((file2) => file2.relativePath));
|
|
@@ -28532,7 +28878,7 @@ var pullRemoteFileIntoCheckout = async ({
|
|
|
28532
28878
|
);
|
|
28533
28879
|
}
|
|
28534
28880
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
28535
|
-
await atomicWriteBinaryFile(
|
|
28881
|
+
await atomicWriteBinaryFile(path9.join(localPath, relativePath), bytes);
|
|
28536
28882
|
updateFileManifestEntry({
|
|
28537
28883
|
storageClass: "binary",
|
|
28538
28884
|
hash: hashBytes(bytes),
|
|
@@ -28558,7 +28904,7 @@ var pullRemoteFileIntoCheckout = async ({
|
|
|
28558
28904
|
text: remoteFile.content.text
|
|
28559
28905
|
});
|
|
28560
28906
|
await atomicWriteTextFile(
|
|
28561
|
-
|
|
28907
|
+
path9.join(localPath, relativePath),
|
|
28562
28908
|
localText,
|
|
28563
28909
|
remoteFile.isExecutable === true
|
|
28564
28910
|
);
|
|
@@ -28651,7 +28997,7 @@ var remoteFileHash = async ({
|
|
|
28651
28997
|
client,
|
|
28652
28998
|
remoteFile,
|
|
28653
28999
|
storeRef,
|
|
28654
|
-
path:
|
|
29000
|
+
path: path22
|
|
28655
29001
|
}) => {
|
|
28656
29002
|
const textHash = remoteTextHash(remoteFile);
|
|
28657
29003
|
if (textHash) {
|
|
@@ -28662,7 +29008,7 @@ var remoteFileHash = async ({
|
|
|
28662
29008
|
}
|
|
28663
29009
|
const { downloadUrl } = await client.createFileDownloadUrlByRef({
|
|
28664
29010
|
...storeRef,
|
|
28665
|
-
path:
|
|
29011
|
+
path: path22
|
|
28666
29012
|
});
|
|
28667
29013
|
const response = await fetch(downloadUrl);
|
|
28668
29014
|
if (!response.ok) {
|
|
@@ -28812,6 +29158,7 @@ var deleteRemoteFileFromCheckout = async ({
|
|
|
28812
29158
|
};
|
|
28813
29159
|
var executeSyncCheckoutFiles = async ({
|
|
28814
29160
|
client,
|
|
29161
|
+
conflictPolicy,
|
|
28815
29162
|
dryRun,
|
|
28816
29163
|
force,
|
|
28817
29164
|
localPath,
|
|
@@ -28836,6 +29183,7 @@ var executeSyncCheckoutFiles = async ({
|
|
|
28836
29183
|
paths,
|
|
28837
29184
|
(relativePath) => relativePath,
|
|
28838
29185
|
async (relativePath) => syncCheckoutFile({
|
|
29186
|
+
conflictPolicy,
|
|
28839
29187
|
client,
|
|
28840
29188
|
dryRun,
|
|
28841
29189
|
force,
|
|
@@ -28862,6 +29210,7 @@ var ignoredCheckoutFileResult = (ignored) => ({
|
|
|
28862
29210
|
});
|
|
28863
29211
|
var planSyncCheckoutSession = async ({
|
|
28864
29212
|
client,
|
|
29213
|
+
conflictPolicy,
|
|
28865
29214
|
dryRun,
|
|
28866
29215
|
files,
|
|
28867
29216
|
force,
|
|
@@ -28878,6 +29227,10 @@ var planSyncCheckoutSession = async ({
|
|
|
28878
29227
|
remoteFileCount: files.length
|
|
28879
29228
|
});
|
|
28880
29229
|
const remoteRenameConflictDetails = await reconcileRemoteRenamesBeforePull({
|
|
29230
|
+
client,
|
|
29231
|
+
conflictPolicy,
|
|
29232
|
+
localFiles: scan.files,
|
|
29233
|
+
storeRef,
|
|
28881
29234
|
dryRun,
|
|
28882
29235
|
files,
|
|
28883
29236
|
force,
|
|
@@ -28887,7 +29240,7 @@ var planSyncCheckoutSession = async ({
|
|
|
28887
29240
|
const remoteRenameConflictPaths = checkoutDetailPathSet(
|
|
28888
29241
|
remoteRenameConflictDetails
|
|
28889
29242
|
);
|
|
28890
|
-
|
|
29243
|
+
let snapshot = buildSyncCheckoutSnapshot({
|
|
28891
29244
|
includePaths,
|
|
28892
29245
|
isIgnored: (relativePath) => isIgnored(relativePath, false, includePaths, matcher),
|
|
28893
29246
|
localFiles: scan.files,
|
|
@@ -28903,6 +29256,9 @@ var planSyncCheckoutSession = async ({
|
|
|
28903
29256
|
phase: "local-rename-preflight"
|
|
28904
29257
|
});
|
|
28905
29258
|
const structuralPreflight = await preflightLocalRenamesBeforePush({
|
|
29259
|
+
conflictPolicy,
|
|
29260
|
+
remoteFiles: files,
|
|
29261
|
+
localPath,
|
|
28906
29262
|
client,
|
|
28907
29263
|
deletePaths: snapshot.deletePaths,
|
|
28908
29264
|
dryRun,
|
|
@@ -28910,6 +29266,26 @@ var planSyncCheckoutSession = async ({
|
|
|
28910
29266
|
manifest,
|
|
28911
29267
|
storeRef
|
|
28912
29268
|
});
|
|
29269
|
+
if (conflictPolicy) {
|
|
29270
|
+
snapshot = buildSyncCheckoutSnapshot({
|
|
29271
|
+
includePaths,
|
|
29272
|
+
isIgnored: (relativePath) => isIgnored(relativePath, false, includePaths, matcher),
|
|
29273
|
+
localFiles: scan.files,
|
|
29274
|
+
manifestFiles: Object.keys(manifest.files).map((relativePath) => ({
|
|
29275
|
+
relativePath
|
|
29276
|
+
})),
|
|
29277
|
+
remoteBlockedPaths: remoteRenameConflictPaths,
|
|
29278
|
+
remoteFiles: files
|
|
29279
|
+
});
|
|
29280
|
+
}
|
|
29281
|
+
const policyDetails = await resolveAmbiguousSyncMoves({
|
|
29282
|
+
conflictPolicy,
|
|
29283
|
+
dryRun,
|
|
29284
|
+
localPath,
|
|
29285
|
+
manifestFiles: manifest.files,
|
|
29286
|
+
snapshot,
|
|
29287
|
+
structuralPreflight
|
|
29288
|
+
});
|
|
28913
29289
|
const preflightDetails = [
|
|
28914
29290
|
...scan.ignored.map(ignoredCheckoutFileResult),
|
|
28915
29291
|
...scan.unsupported.map(unsupportedCheckoutFileResult)
|
|
@@ -28924,6 +29300,7 @@ var planSyncCheckoutSession = async ({
|
|
|
28924
29300
|
});
|
|
28925
29301
|
return {
|
|
28926
29302
|
explicitDetails: [
|
|
29303
|
+
...withCheckoutDetailsDirection(policyDetails, "download"),
|
|
28927
29304
|
...withCheckoutDetailsDirection(remoteRenameConflictDetails, "download"),
|
|
28928
29305
|
...withCheckoutDetailsDirection(
|
|
28929
29306
|
structuralPreflight.movedDetails,
|
|
@@ -28959,6 +29336,7 @@ var readSyncCheckoutRemoteFiles = async ({
|
|
|
28959
29336
|
};
|
|
28960
29337
|
var scanSyncCheckoutLocalFiles = async ({
|
|
28961
29338
|
ignorePatterns,
|
|
29339
|
+
ignoreMatcher,
|
|
28962
29340
|
includePaths,
|
|
28963
29341
|
localPath,
|
|
28964
29342
|
progress
|
|
@@ -28967,7 +29345,8 @@ var scanSyncCheckoutLocalFiles = async ({
|
|
|
28967
29345
|
localPath,
|
|
28968
29346
|
ignorePatterns,
|
|
28969
29347
|
includePaths,
|
|
28970
|
-
progress
|
|
29348
|
+
progress,
|
|
29349
|
+
ignoreMatcher
|
|
28971
29350
|
);
|
|
28972
29351
|
reportCheckoutProgressEvent(
|
|
28973
29352
|
progress,
|
|
@@ -29021,6 +29400,7 @@ var finalizeSyncCheckoutSession = async ({
|
|
|
29021
29400
|
};
|
|
29022
29401
|
var syncCheckoutFile = async ({
|
|
29023
29402
|
client,
|
|
29403
|
+
conflictPolicy,
|
|
29024
29404
|
dryRun,
|
|
29025
29405
|
force,
|
|
29026
29406
|
isInsideRemoteReference,
|
|
@@ -29035,7 +29415,7 @@ var syncCheckoutFile = async ({
|
|
|
29035
29415
|
const manifestEntry = manifest.files[relativePath];
|
|
29036
29416
|
const remoteKind = remoteFile ? isReferenceEntry(remoteFile.entry) ? "reference" : "file" : "missing";
|
|
29037
29417
|
let remoteVersionChanged = false;
|
|
29038
|
-
if (remoteKind === "file" && remoteFile &&
|
|
29418
|
+
if (remoteKind === "file" && remoteFile && manifestEntry) {
|
|
29039
29419
|
if (typeof remoteFile.entry.revisionNumber === "number") {
|
|
29040
29420
|
remoteVersionChanged = (manifestEntry.remoteRevisionNumber ?? null) !== remoteFile.entry.revisionNumber;
|
|
29041
29421
|
} else {
|
|
@@ -29049,18 +29429,19 @@ var syncCheckoutFile = async ({
|
|
|
29049
29429
|
remoteVersionChanged = (manifestEntry.remoteRevisionNumber ?? null) !== remoteRevisionNumberForConflictCheck(remote);
|
|
29050
29430
|
}
|
|
29051
29431
|
}
|
|
29052
|
-
if (isReferenceManifestEntry(manifestEntry)) {
|
|
29432
|
+
if (isReferenceManifestEntry(manifestEntry) && (!conflictPolicy || remoteKind === "missing")) {
|
|
29053
29433
|
const localHash = localFile?.hash ?? null;
|
|
29054
29434
|
const localChanged = localHash === null || localHash !== manifestEntry.hash;
|
|
29055
29435
|
if (remoteKind === "missing") {
|
|
29056
|
-
if (dryRun) {
|
|
29436
|
+
if (dryRun && !conflictPolicy) {
|
|
29057
29437
|
return withCheckoutWorkerDirection(
|
|
29058
29438
|
localChanged ? "deleted" : "ignored",
|
|
29059
29439
|
"download"
|
|
29060
29440
|
);
|
|
29061
29441
|
}
|
|
29062
29442
|
const result = await reconcileTrackedRemoteDelete({
|
|
29063
|
-
|
|
29443
|
+
dryRun,
|
|
29444
|
+
force: force || conflictPolicy === "remote",
|
|
29064
29445
|
localFileHash: localHash,
|
|
29065
29446
|
localPath,
|
|
29066
29447
|
manifest,
|
|
@@ -29077,7 +29458,7 @@ var syncCheckoutFile = async ({
|
|
|
29077
29458
|
return withCheckoutWorkerDirection(
|
|
29078
29459
|
await deleteRemoteFileFromCheckout({
|
|
29079
29460
|
client,
|
|
29080
|
-
force,
|
|
29461
|
+
force: force || conflictPolicy === "local",
|
|
29081
29462
|
manifest,
|
|
29082
29463
|
manifestEntry,
|
|
29083
29464
|
relativePath,
|
|
@@ -29107,7 +29488,7 @@ var syncCheckoutFile = async ({
|
|
|
29107
29488
|
await pushLocalFileFromCheckout({
|
|
29108
29489
|
client,
|
|
29109
29490
|
file: localFile,
|
|
29110
|
-
force,
|
|
29491
|
+
force: force || conflictPolicy === "local",
|
|
29111
29492
|
manifest,
|
|
29112
29493
|
manifestEntry,
|
|
29113
29494
|
manifestSyncedAt,
|
|
@@ -29190,6 +29571,8 @@ var syncCheckoutFile = async ({
|
|
|
29190
29571
|
}
|
|
29191
29572
|
}
|
|
29192
29573
|
const plan = planSyncCheckoutFile({
|
|
29574
|
+
resolvedConflict: remoteFile?.conflictWinner,
|
|
29575
|
+
conflictPolicy,
|
|
29193
29576
|
force,
|
|
29194
29577
|
localIsExecutable: localFile?.storageClass === "text" ? localFile.isExecutable : false,
|
|
29195
29578
|
localHash: localFile?.hash ?? null,
|
|
@@ -29233,7 +29616,7 @@ var syncCheckoutFile = async ({
|
|
|
29233
29616
|
if (!remoteFile || !isReferenceEntry(remoteFile.entry)) {
|
|
29234
29617
|
throw new Error("planned reference accept without remote reference");
|
|
29235
29618
|
}
|
|
29236
|
-
const deletedLocalFile = !dryRun && (localFile || manifestEntry) ? await deleteLocalFileIfPresent(
|
|
29619
|
+
const deletedLocalFile = !dryRun && (localFile || manifestEntry) ? await deleteLocalFileIfPresent(path9.join(localPath, relativePath)) : false;
|
|
29237
29620
|
if (!dryRun) {
|
|
29238
29621
|
delete manifest.files[relativePath];
|
|
29239
29622
|
manifest.references[relativePath] = {
|
|
@@ -29252,7 +29635,7 @@ var syncCheckoutFile = async ({
|
|
|
29252
29635
|
}
|
|
29253
29636
|
const result = await reconcileTrackedRemoteDelete({
|
|
29254
29637
|
dryRun,
|
|
29255
|
-
force,
|
|
29638
|
+
force: force || conflictPolicy === "remote",
|
|
29256
29639
|
localFileHash: localFile?.hash ?? null,
|
|
29257
29640
|
localPath,
|
|
29258
29641
|
manifest,
|
|
@@ -29262,7 +29645,11 @@ var syncCheckoutFile = async ({
|
|
|
29262
29645
|
return typeof result === "string" || result.status !== "failed" ? withCheckoutWorkerDirection(result, "download") : result;
|
|
29263
29646
|
}
|
|
29264
29647
|
if (plan.type === "pullRemote") {
|
|
29265
|
-
|
|
29648
|
+
const pullEntry = remoteFile?.entry ?? (remotePathExists ? await client.readFileByRef({
|
|
29649
|
+
...storeRef,
|
|
29650
|
+
path: toStorePath2(relativePath)
|
|
29651
|
+
}) : null);
|
|
29652
|
+
if (!pullEntry) {
|
|
29266
29653
|
throw new Error("planned pull without remote file");
|
|
29267
29654
|
}
|
|
29268
29655
|
if (dryRun) {
|
|
@@ -29277,13 +29664,13 @@ var syncCheckoutFile = async ({
|
|
|
29277
29664
|
return withCheckoutWorkerDirection(
|
|
29278
29665
|
await pullRemoteFileIntoCheckout({
|
|
29279
29666
|
client,
|
|
29280
|
-
entry:
|
|
29667
|
+
entry: pullEntry,
|
|
29281
29668
|
localPath,
|
|
29282
29669
|
manifest,
|
|
29283
29670
|
manifestEntry,
|
|
29284
29671
|
manifestSyncedAt,
|
|
29285
29672
|
relativePath,
|
|
29286
|
-
source: remoteFile
|
|
29673
|
+
source: remoteFile?.source,
|
|
29287
29674
|
storeRef
|
|
29288
29675
|
}),
|
|
29289
29676
|
"download"
|
|
@@ -29302,13 +29689,17 @@ var syncCheckoutFile = async ({
|
|
|
29302
29689
|
"upload"
|
|
29303
29690
|
);
|
|
29304
29691
|
}
|
|
29692
|
+
const pushManifestEntry = conflictPolicy === "local" && manifestEntry?.storageClass === "binary" && remoteFile ? {
|
|
29693
|
+
...manifestEntry,
|
|
29694
|
+
remoteRevisionNumber: remoteFile.entry.revisionNumber
|
|
29695
|
+
} : manifestEntry;
|
|
29305
29696
|
return withCheckoutWorkerDirection(
|
|
29306
29697
|
await pushLocalFileFromCheckout({
|
|
29307
29698
|
client,
|
|
29308
29699
|
file: localFile,
|
|
29309
|
-
force,
|
|
29700
|
+
force: force || conflictPolicy === "local",
|
|
29310
29701
|
manifest,
|
|
29311
|
-
manifestEntry,
|
|
29702
|
+
manifestEntry: pushManifestEntry,
|
|
29312
29703
|
manifestSyncedAt,
|
|
29313
29704
|
storeRef
|
|
29314
29705
|
}),
|
|
@@ -29325,7 +29716,7 @@ var syncCheckoutFile = async ({
|
|
|
29325
29716
|
return withCheckoutWorkerDirection(
|
|
29326
29717
|
await deleteRemoteFileFromCheckout({
|
|
29327
29718
|
client,
|
|
29328
|
-
force,
|
|
29719
|
+
force: force || conflictPolicy === "local",
|
|
29329
29720
|
manifest,
|
|
29330
29721
|
manifestEntry,
|
|
29331
29722
|
relativePath,
|
|
@@ -29338,16 +29729,18 @@ var syncCheckoutFile = async ({
|
|
|
29338
29729
|
};
|
|
29339
29730
|
var syncCheckoutRuleFiles = async ({
|
|
29340
29731
|
client,
|
|
29732
|
+
conflictPolicy,
|
|
29341
29733
|
dryRun,
|
|
29342
29734
|
force,
|
|
29343
29735
|
ignorePatterns,
|
|
29736
|
+
ignoreMatcher,
|
|
29344
29737
|
localPath,
|
|
29345
29738
|
progress,
|
|
29346
29739
|
referenceSyncMode,
|
|
29347
29740
|
storeRef,
|
|
29348
29741
|
syncIncludePaths
|
|
29349
29742
|
}) => {
|
|
29350
|
-
const matcher = createIgnoreMatcher(ignorePatterns);
|
|
29743
|
+
const matcher = ignoreMatcher ?? createIgnoreMatcher(ignorePatterns);
|
|
29351
29744
|
const includePaths = normalizeCheckoutIncludePaths(syncIncludePaths);
|
|
29352
29745
|
const manifest = await readCheckoutFilesManifest(localPath);
|
|
29353
29746
|
const manifestSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -29358,12 +29751,14 @@ var syncCheckoutRuleFiles = async ({
|
|
|
29358
29751
|
storeRef
|
|
29359
29752
|
});
|
|
29360
29753
|
const scan = await scanSyncCheckoutLocalFiles({
|
|
29754
|
+
ignoreMatcher,
|
|
29361
29755
|
ignorePatterns,
|
|
29362
29756
|
includePaths,
|
|
29363
29757
|
localPath,
|
|
29364
29758
|
progress
|
|
29365
29759
|
});
|
|
29366
29760
|
const sessionPlan = await planSyncCheckoutSession({
|
|
29761
|
+
conflictPolicy,
|
|
29367
29762
|
client,
|
|
29368
29763
|
dryRun,
|
|
29369
29764
|
files,
|
|
@@ -29385,6 +29780,7 @@ var syncCheckoutRuleFiles = async ({
|
|
|
29385
29780
|
progress?.onTotal?.(explicitDetails.length + paths.length);
|
|
29386
29781
|
reportCheckoutDetails(progress, explicitDetails);
|
|
29387
29782
|
const result = await executeSyncCheckoutFiles({
|
|
29783
|
+
conflictPolicy,
|
|
29388
29784
|
client,
|
|
29389
29785
|
dryRun,
|
|
29390
29786
|
force,
|
|
@@ -29416,9 +29812,14 @@ var syncCheckoutRuleFiles = async ({
|
|
|
29416
29812
|
var syncCheckout = async ({
|
|
29417
29813
|
beforeRuleApply,
|
|
29418
29814
|
client,
|
|
29815
|
+
conflictPolicy,
|
|
29419
29816
|
dryRun = false,
|
|
29420
29817
|
force,
|
|
29421
29818
|
ignorePatterns,
|
|
29819
|
+
ignoreMatcher,
|
|
29820
|
+
ignoreMatchersByRule,
|
|
29821
|
+
ignoreSettings,
|
|
29822
|
+
ignorePatternsByStore,
|
|
29422
29823
|
localPath,
|
|
29423
29824
|
progress,
|
|
29424
29825
|
referenceSyncMode = false,
|
|
@@ -29426,6 +29827,44 @@ var syncCheckout = async ({
|
|
|
29426
29827
|
syncIncludePaths,
|
|
29427
29828
|
syncRules
|
|
29428
29829
|
}) => {
|
|
29830
|
+
if (syncRules && ignoreSettings) {
|
|
29831
|
+
const settings = await prepareCheckoutIgnore({
|
|
29832
|
+
rootDir: localPath,
|
|
29833
|
+
syncRules,
|
|
29834
|
+
client,
|
|
29835
|
+
dryRun: dryRun || ignoreSettings === "preview"
|
|
29836
|
+
});
|
|
29837
|
+
const conflicts = settings.changes.filter(
|
|
29838
|
+
(change) => change.action === "conflict"
|
|
29839
|
+
);
|
|
29840
|
+
if (conflicts.length)
|
|
29841
|
+
return checkoutResultFromDetails(conflicts.map(ignoreSettingDetail));
|
|
29842
|
+
const result = await syncCheckout({
|
|
29843
|
+
beforeRuleApply,
|
|
29844
|
+
client,
|
|
29845
|
+
conflictPolicy,
|
|
29846
|
+
dryRun,
|
|
29847
|
+
force,
|
|
29848
|
+
ignorePatterns,
|
|
29849
|
+
localPath,
|
|
29850
|
+
progress,
|
|
29851
|
+
referenceSyncMode,
|
|
29852
|
+
storeRef,
|
|
29853
|
+
syncIncludePaths,
|
|
29854
|
+
syncRules,
|
|
29855
|
+
ignorePatternsByStore: settings.patternsByStore,
|
|
29856
|
+
ignoreMatchersByRule: settings.matchersByRule
|
|
29857
|
+
});
|
|
29858
|
+
const changes = settings.changes;
|
|
29859
|
+
Object.assign(
|
|
29860
|
+
result,
|
|
29861
|
+
checkoutResultFromDetails([
|
|
29862
|
+
...result.details,
|
|
29863
|
+
...changes.map(ignoreSettingDetail)
|
|
29864
|
+
])
|
|
29865
|
+
);
|
|
29866
|
+
return result;
|
|
29867
|
+
}
|
|
29429
29868
|
if (syncRules) {
|
|
29430
29869
|
reportCheckoutProgressEvent(progress, "Checking checkout sync rules", {
|
|
29431
29870
|
phase: "sync-rules",
|
|
@@ -29525,15 +29964,18 @@ var syncCheckout = async ({
|
|
|
29525
29964
|
client: ruleClient,
|
|
29526
29965
|
dryRun: true,
|
|
29527
29966
|
force,
|
|
29528
|
-
ignorePatterns,
|
|
29967
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
29968
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
29529
29969
|
localPath,
|
|
29530
29970
|
storeRef: ruleStoreRef,
|
|
29531
29971
|
syncIncludePaths: ruleIncludePaths
|
|
29532
29972
|
}) : await syncCheckoutRuleFiles({
|
|
29973
|
+
conflictPolicy,
|
|
29533
29974
|
client: ruleClient,
|
|
29534
29975
|
dryRun: true,
|
|
29535
29976
|
force,
|
|
29536
|
-
ignorePatterns,
|
|
29977
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
29978
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
29537
29979
|
localPath,
|
|
29538
29980
|
referenceSyncMode: isStoreReferenceRule,
|
|
29539
29981
|
storeRef: ruleStoreRef,
|
|
@@ -29557,16 +29999,19 @@ var syncCheckout = async ({
|
|
|
29557
29999
|
client: ruleClient,
|
|
29558
30000
|
dryRun,
|
|
29559
30001
|
force,
|
|
29560
|
-
ignorePatterns,
|
|
30002
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
30003
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
29561
30004
|
localPath,
|
|
29562
30005
|
progress: ruleProgress,
|
|
29563
30006
|
storeRef: ruleStoreRef,
|
|
29564
30007
|
syncIncludePaths: ruleIncludePaths
|
|
29565
30008
|
}) : await syncCheckoutRuleFiles({
|
|
30009
|
+
conflictPolicy,
|
|
29566
30010
|
client: ruleClient,
|
|
29567
30011
|
dryRun,
|
|
29568
30012
|
force,
|
|
29569
|
-
ignorePatterns,
|
|
30013
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
30014
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
29570
30015
|
localPath,
|
|
29571
30016
|
progress: ruleProgress,
|
|
29572
30017
|
referenceSyncMode: isStoreReferenceRule,
|
|
@@ -29621,6 +30066,8 @@ var syncCheckout = async ({
|
|
|
29621
30066
|
);
|
|
29622
30067
|
}
|
|
29623
30068
|
return syncCheckoutRuleFiles({
|
|
30069
|
+
ignoreMatcher,
|
|
30070
|
+
conflictPolicy,
|
|
29624
30071
|
client,
|
|
29625
30072
|
dryRun,
|
|
29626
30073
|
force,
|
|
@@ -29633,16 +30080,16 @@ var syncCheckout = async ({
|
|
|
29633
30080
|
});
|
|
29634
30081
|
};
|
|
29635
30082
|
var ensureCheckoutDirectoryReady = async (directoryPath) => {
|
|
29636
|
-
await
|
|
30083
|
+
await mkdir4(directoryPath, { recursive: true });
|
|
29637
30084
|
const entries = await readdir2(directoryPath);
|
|
29638
30085
|
if (entries.length > 0) {
|
|
29639
30086
|
throw new Error(`Target directory must be empty: ${directoryPath}`);
|
|
29640
30087
|
}
|
|
29641
30088
|
};
|
|
29642
30089
|
var ensureProjectConfigDoesNotExist = async (directoryPath) => {
|
|
29643
|
-
for (const filename of
|
|
30090
|
+
for (const filename of projectConfigFilenames) {
|
|
29644
30091
|
try {
|
|
29645
|
-
const filePath =
|
|
30092
|
+
const filePath = path9.join(directoryPath, filename);
|
|
29646
30093
|
await stat(filePath);
|
|
29647
30094
|
throw new Error(`Forum config already exists: ${filePath}`);
|
|
29648
30095
|
} catch (error51) {
|
|
@@ -29655,142 +30102,40 @@ var ensureProjectConfigDoesNotExist = async (directoryPath) => {
|
|
|
29655
30102
|
};
|
|
29656
30103
|
|
|
29657
30104
|
// src/ignoreCommand.ts
|
|
29658
|
-
|
|
29659
|
-
|
|
29660
|
-
|
|
29661
|
-
var planIgnoreAdd = (pattern, currentPatterns, remoteFilePaths) => {
|
|
29662
|
-
const trimmed = pattern.trim();
|
|
29663
|
-
if (!trimmed) {
|
|
29664
|
-
throw new Error("Ignore pattern cannot be empty.");
|
|
29665
|
-
}
|
|
29666
|
-
const alreadyPresent = currentPatterns.includes(trimmed);
|
|
29667
|
-
const nextPatterns = resolveIgnorePatterns({
|
|
29668
|
-
bakedIn: [],
|
|
29669
|
-
storeSetting: currentPatterns,
|
|
29670
|
-
localOverride: [trimmed]
|
|
29671
|
-
});
|
|
29672
|
-
const matcher = ignore2().add([trimmed]);
|
|
29673
|
-
const matchedRemotePaths = sortPaths(
|
|
29674
|
-
remoteFilePaths.filter((storePath) => {
|
|
29675
|
-
const relative = toRelative(storePath);
|
|
29676
|
-
return Boolean(relative) && matcher.ignores(relative);
|
|
29677
|
-
})
|
|
29678
|
-
);
|
|
29679
|
-
return { pattern: trimmed, alreadyPresent, nextPatterns, matchedRemotePaths };
|
|
29680
|
-
};
|
|
29681
|
-
var collectRemoteFilePaths = async (client, storeRef) => {
|
|
29682
|
-
const listing = await client.listTreeByRef({
|
|
29683
|
-
...storeRef,
|
|
29684
|
-
directoryPath: "/",
|
|
29685
|
-
includeHidden: true
|
|
29686
|
-
});
|
|
29687
|
-
const entries = listing?.entries ?? [];
|
|
29688
|
-
return sortPaths(
|
|
29689
|
-
entries.filter((entry) => entry.type !== "directory").map((entry) => entry.path)
|
|
29690
|
-
);
|
|
29691
|
-
};
|
|
29692
|
-
var executeIgnoreAdd = async (client, storeRef, pattern, currentPatterns, io) => {
|
|
29693
|
-
const remoteFilePaths = await collectRemoteFilePaths(client, storeRef);
|
|
29694
|
-
const plan = planIgnoreAdd(pattern, currentPatterns, remoteFilePaths);
|
|
29695
|
-
let settingUpdated = false;
|
|
29696
|
-
if (!plan.alreadyPresent) {
|
|
29697
|
-
await client.upsertStoreByRef({
|
|
29698
|
-
...storeRef,
|
|
29699
|
-
patch: { ignore: plan.nextPatterns }
|
|
29700
|
-
});
|
|
29701
|
-
settingUpdated = true;
|
|
29702
|
-
}
|
|
29703
|
-
const deletedRemotePaths = [];
|
|
29704
|
-
let deletedRemoteDirectories = [];
|
|
29705
|
-
if (plan.matchedRemotePaths.length > 0 && await io.confirmRemoteDelete(plan)) {
|
|
29706
|
-
for (const storePath of plan.matchedRemotePaths) {
|
|
29707
|
-
await client.deleteFileByRef({ ...storeRef, path: storePath });
|
|
29708
|
-
deletedRemotePaths.push(storePath);
|
|
29709
|
-
}
|
|
29710
|
-
deletedRemoteDirectories = await cleanupRemoteCheckoutDirectories({
|
|
29711
|
-
client,
|
|
29712
|
-
removedPaths: deletedRemotePaths.map(toRelative),
|
|
29713
|
-
storeRef
|
|
29714
|
-
});
|
|
29715
|
-
}
|
|
30105
|
+
var planIgnoreAdd = (pattern, currentPatterns) => {
|
|
30106
|
+
if (!pattern.trim()) throw new Error("Ignore pattern cannot be empty.");
|
|
30107
|
+
const alreadyPresent = currentPatterns.at(-1) === pattern;
|
|
29716
30108
|
return {
|
|
29717
|
-
|
|
29718
|
-
|
|
29719
|
-
|
|
29720
|
-
deletedRemoteDirectories
|
|
30109
|
+
pattern,
|
|
30110
|
+
alreadyPresent,
|
|
30111
|
+
nextPatterns: alreadyPresent ? currentPatterns : [...currentPatterns, pattern]
|
|
29721
30112
|
};
|
|
29722
30113
|
};
|
|
29723
30114
|
var removeIgnorePattern = (pattern, currentPatterns) => {
|
|
29724
|
-
|
|
29725
|
-
|
|
29726
|
-
throw new Error("Ignore pattern cannot be empty.");
|
|
29727
|
-
}
|
|
29728
|
-
const nextPatterns = currentPatterns.filter((current) => current !== trimmed);
|
|
30115
|
+
if (!pattern.trim()) throw new Error("Ignore pattern cannot be empty.");
|
|
30116
|
+
const nextPatterns = currentPatterns.filter((current) => current !== pattern);
|
|
29729
30117
|
return {
|
|
29730
30118
|
nextPatterns,
|
|
29731
30119
|
removed: nextPatterns.length !== currentPatterns.length,
|
|
29732
|
-
pattern
|
|
30120
|
+
pattern
|
|
29733
30121
|
};
|
|
29734
30122
|
};
|
|
29735
|
-
var setIgnorePatterns = (patterns) =>
|
|
29736
|
-
|
|
29737
|
-
|
|
29738
|
-
|
|
29739
|
-
}
|
|
30123
|
+
var setIgnorePatterns = (patterns) => {
|
|
30124
|
+
if (patterns.some((pattern) => !pattern.trim()))
|
|
30125
|
+
throw new Error("Ignore pattern cannot be empty.");
|
|
30126
|
+
return patterns;
|
|
30127
|
+
};
|
|
29740
30128
|
|
|
29741
30129
|
// src/runIgnoreCommand.ts
|
|
29742
30130
|
var runAdd = async (deps) => {
|
|
29743
|
-
const {
|
|
29744
|
-
|
|
29745
|
-
|
|
29746
|
-
|
|
29747
|
-
|
|
29748
|
-
assumeYes,
|
|
29749
|
-
confirmYesNo: confirmYesNo2,
|
|
29750
|
-
renderOutput: renderOutput2,
|
|
29751
|
-
commandNames: commandNames2
|
|
29752
|
-
} = deps;
|
|
29753
|
-
if (!pattern) {
|
|
29754
|
-
throw new Error(`Usage: ${commandNames2} ignore add <pattern>`);
|
|
29755
|
-
}
|
|
29756
|
-
const io = {
|
|
29757
|
-
confirmRemoteDelete: (plan) => confirmYesNo2({
|
|
29758
|
-
assumeYes,
|
|
29759
|
-
nonInteractiveMessage: "Refusing to delete store files without confirmation. Re-run with --yes.",
|
|
29760
|
-
prompt: `Delete ${plan.matchedRemotePaths.length} matching file(s) from the store? [y/N] `
|
|
29761
|
-
})
|
|
29762
|
-
};
|
|
29763
|
-
const result = await executeIgnoreAdd(
|
|
29764
|
-
client,
|
|
29765
|
-
storeRef,
|
|
29766
|
-
pattern,
|
|
29767
|
-
currentPatterns,
|
|
29768
|
-
io
|
|
29769
|
-
);
|
|
29770
|
-
if (result.settingUpdated) {
|
|
29771
|
-
renderOutput2(`Added ignore rule: ${result.plan.pattern}`);
|
|
29772
|
-
} else {
|
|
29773
|
-
renderOutput2(`Ignore rule already present: ${result.plan.pattern}`);
|
|
29774
|
-
}
|
|
29775
|
-
if (result.plan.matchedRemotePaths.length === 0) {
|
|
29776
|
-
renderOutput2("No already-pushed files matched.");
|
|
29777
|
-
} else if (result.deletedRemotePaths.length > 0) {
|
|
29778
|
-
renderOutput2(
|
|
29779
|
-
`Deleted ${result.deletedRemotePaths.length} file(s) from the store.`
|
|
29780
|
-
);
|
|
29781
|
-
} else {
|
|
29782
|
-
renderOutput2("Left already-pushed matches in place.");
|
|
29783
|
-
}
|
|
29784
|
-
if (result.deletedRemoteDirectories.length > 0) {
|
|
29785
|
-
renderOutput2(
|
|
29786
|
-
`Deleted ${result.deletedRemoteDirectories.length} empty director${result.deletedRemoteDirectories.length === 1 ? "y" : "ies"} from the store.`
|
|
29787
|
-
);
|
|
29788
|
-
}
|
|
30131
|
+
const { currentPatterns, pattern, renderOutput: renderOutput2, commandNames: commandNames2 } = deps;
|
|
30132
|
+
if (!pattern) throw new Error(`Usage: ${commandNames2} ignore add <pattern>`);
|
|
30133
|
+
const plan = planIgnoreAdd(pattern, currentPatterns);
|
|
30134
|
+
if (!plan.alreadyPresent) await deps.writePatterns(plan.nextPatterns);
|
|
30135
|
+
renderOutput2(`Added ignore rule: ${plan.pattern}. Run fm sync to publish.`);
|
|
29789
30136
|
};
|
|
29790
30137
|
var runList = async (deps) => {
|
|
29791
|
-
const {
|
|
29792
|
-
const metadata = await client.readStoreByRef(storeRef);
|
|
29793
|
-
const ignore3 = metadata?.ignore ?? [];
|
|
30138
|
+
const { currentPatterns: ignore3, renderOutput: renderOutput2 } = deps;
|
|
29794
30139
|
if (ignore3.length === 0) {
|
|
29795
30140
|
renderOutput2("(no ignore rules)");
|
|
29796
30141
|
return;
|
|
@@ -29801,8 +30146,7 @@ var runList = async (deps) => {
|
|
|
29801
30146
|
};
|
|
29802
30147
|
var runRemove = async (deps) => {
|
|
29803
30148
|
const {
|
|
29804
|
-
|
|
29805
|
-
storeRef,
|
|
30149
|
+
writePatterns,
|
|
29806
30150
|
currentPatterns,
|
|
29807
30151
|
pattern,
|
|
29808
30152
|
renderOutput: renderOutput2,
|
|
@@ -29816,14 +30160,11 @@ var runRemove = async (deps) => {
|
|
|
29816
30160
|
renderOutput2(`Ignore rule not present: ${result.pattern}`);
|
|
29817
30161
|
return;
|
|
29818
30162
|
}
|
|
29819
|
-
await
|
|
29820
|
-
...storeRef,
|
|
29821
|
-
patch: { ignore: result.nextPatterns }
|
|
29822
|
-
});
|
|
30163
|
+
await writePatterns(result.nextPatterns);
|
|
29823
30164
|
renderOutput2(`Removed ignore rule: ${result.pattern}`);
|
|
29824
30165
|
};
|
|
29825
30166
|
var runSet = async (deps) => {
|
|
29826
|
-
const {
|
|
30167
|
+
const { writePatterns, patterns, renderOutput: renderOutput2, commandNames: commandNames2 } = deps;
|
|
29827
30168
|
if (patterns.length === 0) {
|
|
29828
30169
|
throw new Error(`Usage: ${commandNames2} ignore set <pattern>...`);
|
|
29829
30170
|
}
|
|
@@ -29831,24 +30172,17 @@ var runSet = async (deps) => {
|
|
|
29831
30172
|
if (nextPatterns.length === 0) {
|
|
29832
30173
|
throw new Error("Ignore pattern cannot be empty.");
|
|
29833
30174
|
}
|
|
29834
|
-
await
|
|
29835
|
-
...storeRef,
|
|
29836
|
-
patch: { ignore: nextPatterns }
|
|
29837
|
-
});
|
|
30175
|
+
await writePatterns(nextPatterns);
|
|
29838
30176
|
renderOutput2(`Set ${nextPatterns.length} ignore rule(s).`);
|
|
29839
30177
|
};
|
|
29840
30178
|
var runClear = async (deps) => {
|
|
29841
|
-
const {
|
|
29842
|
-
await
|
|
29843
|
-
...storeRef,
|
|
29844
|
-
patch: { ignore: [] }
|
|
29845
|
-
});
|
|
30179
|
+
const { writePatterns, renderOutput: renderOutput2 } = deps;
|
|
30180
|
+
await writePatterns([]);
|
|
29846
30181
|
renderOutput2("Cleared ignore rules.");
|
|
29847
30182
|
};
|
|
29848
30183
|
var runAuto = async (deps) => {
|
|
29849
30184
|
const {
|
|
29850
|
-
|
|
29851
|
-
storeRef,
|
|
30185
|
+
writePatterns,
|
|
29852
30186
|
currentPatterns,
|
|
29853
30187
|
assumeYes,
|
|
29854
30188
|
confirmYesNo: confirmYesNo2,
|
|
@@ -29857,9 +30191,9 @@ var runAuto = async (deps) => {
|
|
|
29857
30191
|
renderOutput: renderOutput2
|
|
29858
30192
|
} = deps;
|
|
29859
30193
|
const analysis = await analyzeLocal();
|
|
29860
|
-
const
|
|
29861
|
-
|
|
29862
|
-
|
|
30194
|
+
const proposed = analysis.proposedPatterns;
|
|
30195
|
+
const alreadyAppended = JSON.stringify(currentPatterns.slice(-proposed.length)) === JSON.stringify(proposed);
|
|
30196
|
+
const additions = alreadyAppended ? [] : proposed;
|
|
29863
30197
|
if (additions.length === 0) {
|
|
29864
30198
|
renderOutput2("Nothing to suggest \u2014 no new junk patterns detected.");
|
|
29865
30199
|
await markOnboarded();
|
|
@@ -29872,19 +30206,18 @@ var runAuto = async (deps) => {
|
|
|
29872
30206
|
const confirmed = await confirmYesNo2({
|
|
29873
30207
|
assumeYes,
|
|
29874
30208
|
nonInteractiveMessage: "Refusing to write ignore rules without confirmation. Re-run with --yes.",
|
|
29875
|
-
prompt: `Add ${additions.length} ignore rule(s) to the
|
|
30209
|
+
prompt: `Add ${additions.length} ignore rule(s) to the shared ignore file? [Y/n] `
|
|
29876
30210
|
});
|
|
29877
30211
|
if (!confirmed) {
|
|
29878
|
-
renderOutput2("Left the
|
|
30212
|
+
renderOutput2("Left the shared ignore file unchanged.");
|
|
29879
30213
|
await markOnboarded();
|
|
29880
30214
|
return;
|
|
29881
30215
|
}
|
|
29882
|
-
await
|
|
29883
|
-
...storeRef,
|
|
29884
|
-
patch: { ignore: [...currentPatterns, ...additions] }
|
|
29885
|
-
});
|
|
30216
|
+
await writePatterns([...currentPatterns, ...additions]);
|
|
29886
30217
|
await markOnboarded();
|
|
29887
|
-
renderOutput2(
|
|
30218
|
+
renderOutput2(
|
|
30219
|
+
`Added ${additions.length} ignore rule(s) locally. Run fm sync to publish.`
|
|
30220
|
+
);
|
|
29888
30221
|
};
|
|
29889
30222
|
var runIgnoreCommand = async (deps) => {
|
|
29890
30223
|
const { subcommand, commandNames: commandNames2 } = deps;
|
|
@@ -29941,8 +30274,7 @@ var warnImminent = (analysis, renderWarning2) => {
|
|
|
29941
30274
|
};
|
|
29942
30275
|
var maybePromptIgnoreSetup = async (deps) => {
|
|
29943
30276
|
const {
|
|
29944
|
-
|
|
29945
|
-
storeRef,
|
|
30277
|
+
writePatterns,
|
|
29946
30278
|
currentPatterns,
|
|
29947
30279
|
analysis,
|
|
29948
30280
|
onboarded,
|
|
@@ -29983,13 +30315,10 @@ var maybePromptIgnoreSetup = async (deps) => {
|
|
|
29983
30315
|
}
|
|
29984
30316
|
const action = await chooseAction(analysis);
|
|
29985
30317
|
if (action === "auto") {
|
|
29986
|
-
await
|
|
29987
|
-
...storeRef,
|
|
29988
|
-
patch: { ignore: analysis.proposedPatterns }
|
|
29989
|
-
});
|
|
30318
|
+
await writePatterns(analysis.proposedPatterns);
|
|
29990
30319
|
await markOnboarded();
|
|
29991
30320
|
renderOutput2(
|
|
29992
|
-
`Added ${analysis.proposedPatterns.length} ignore rule(s)
|
|
30321
|
+
`Added ${analysis.proposedPatterns.length} shared ignore rule(s) locally.`
|
|
29993
30322
|
);
|
|
29994
30323
|
return {
|
|
29995
30324
|
outcome: "auto-applied",
|
|
@@ -30016,10 +30345,10 @@ var maybePromptIgnoreSetup = async (deps) => {
|
|
|
30016
30345
|
|
|
30017
30346
|
// src/collectIgnoreMarkers.ts
|
|
30018
30347
|
import { stat as stat2 } from "fs/promises";
|
|
30019
|
-
import
|
|
30348
|
+
import path10 from "path";
|
|
30020
30349
|
var exists = async (rootDir, rule) => {
|
|
30021
30350
|
try {
|
|
30022
|
-
const stats = await stat2(
|
|
30351
|
+
const stats = await stat2(path10.join(rootDir, rule.marker));
|
|
30023
30352
|
return rule.markerKind === "dir" ? stats.isDirectory() : stats.isFile();
|
|
30024
30353
|
} catch {
|
|
30025
30354
|
return false;
|
|
@@ -30038,11 +30367,11 @@ var collectIgnoreMarkers = async (rootDir, rules = IGNORE_PROPOSAL_RULES) => {
|
|
|
30038
30367
|
};
|
|
30039
30368
|
|
|
30040
30369
|
// src/readGitignorePatterns.ts
|
|
30041
|
-
import { readFile as
|
|
30042
|
-
import
|
|
30370
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
30371
|
+
import path11 from "path";
|
|
30043
30372
|
var readGitignorePatterns = async (rootDir) => {
|
|
30044
30373
|
try {
|
|
30045
|
-
const raw = await
|
|
30374
|
+
const raw = await readFile4(path11.join(rootDir, ".gitignore"), "utf8");
|
|
30046
30375
|
return parseLocalIgnoreFile(raw);
|
|
30047
30376
|
} catch {
|
|
30048
30377
|
return [];
|
|
@@ -30106,9 +30435,9 @@ var createHumanWatchSubscriber = ({
|
|
|
30106
30435
|
return;
|
|
30107
30436
|
}
|
|
30108
30437
|
case "sync.watch.conflict.raised": {
|
|
30109
|
-
const
|
|
30438
|
+
const path22 = String(details.path ?? "");
|
|
30110
30439
|
const suggestions = details.suggestions ?? [];
|
|
30111
|
-
error51(`Conflict: ${
|
|
30440
|
+
error51(`Conflict: ${path22} \u2014 ${event.message ?? "needs attention"}`);
|
|
30112
30441
|
if (suggestions.length > 0) {
|
|
30113
30442
|
error51(` ${formatSuggestions(suggestions)}`);
|
|
30114
30443
|
}
|
|
@@ -30137,10 +30466,10 @@ import notifier from "node-notifier";
|
|
|
30137
30466
|
var createNotifyWatchSubscriber = () => {
|
|
30138
30467
|
return (event) => {
|
|
30139
30468
|
if (event.eventType === "sync.watch.conflict.raised") {
|
|
30140
|
-
const
|
|
30469
|
+
const path22 = event.details?.path;
|
|
30141
30470
|
notifier.notify({
|
|
30142
30471
|
title: "Forum sync conflict",
|
|
30143
|
-
message: typeof
|
|
30472
|
+
message: typeof path22 === "string" ? `${path22} needs attention` : event.message ?? "A file needs attention"
|
|
30144
30473
|
});
|
|
30145
30474
|
return;
|
|
30146
30475
|
}
|
|
@@ -30256,10 +30585,10 @@ var createConflictTracker = () => {
|
|
|
30256
30585
|
);
|
|
30257
30586
|
const raised = current.filter((conflict) => !active.has(conflict.path));
|
|
30258
30587
|
const cleared = [...active.keys()].filter(
|
|
30259
|
-
(
|
|
30588
|
+
(path22) => !currentByPath.has(path22)
|
|
30260
30589
|
);
|
|
30261
|
-
for (const
|
|
30262
|
-
active.delete(
|
|
30590
|
+
for (const path22 of cleared) {
|
|
30591
|
+
active.delete(path22);
|
|
30263
30592
|
}
|
|
30264
30593
|
for (const conflict of current) {
|
|
30265
30594
|
active.set(conflict.path, conflict);
|
|
@@ -30270,13 +30599,13 @@ var createConflictTracker = () => {
|
|
|
30270
30599
|
};
|
|
30271
30600
|
|
|
30272
30601
|
// src/watch/conflictResolutionHints.ts
|
|
30273
|
-
var keepLocal = (
|
|
30602
|
+
var keepLocal = (path22) => ({
|
|
30274
30603
|
label: "Keep local",
|
|
30275
|
-
command: `fm push --force ${
|
|
30604
|
+
command: `fm push --force ${path22}`
|
|
30276
30605
|
});
|
|
30277
|
-
var acceptRemote = (
|
|
30606
|
+
var acceptRemote = (path22) => ({
|
|
30278
30607
|
label: "Accept remote",
|
|
30279
|
-
command: `fm pull --force ${
|
|
30608
|
+
command: `fm pull --force ${path22}`
|
|
30280
30609
|
});
|
|
30281
30610
|
var review = (label, command) => ({
|
|
30282
30611
|
label,
|
|
@@ -30292,23 +30621,23 @@ var forceResolvableTypes = /* @__PURE__ */ new Set([
|
|
|
30292
30621
|
"reference-local-file",
|
|
30293
30622
|
"read-only-local-change"
|
|
30294
30623
|
]);
|
|
30295
|
-
var conflictResolutionSuggestions = (conflictType,
|
|
30624
|
+
var conflictResolutionSuggestions = (conflictType, path22) => {
|
|
30296
30625
|
if (forceResolvableTypes.has(conflictType)) {
|
|
30297
|
-
return [keepLocal(
|
|
30626
|
+
return [keepLocal(path22), acceptRemote(path22)];
|
|
30298
30627
|
}
|
|
30299
|
-
return [review("Review", `fm status ${
|
|
30628
|
+
return [review("Review", `fm status ${path22}`)];
|
|
30300
30629
|
};
|
|
30301
30630
|
|
|
30302
30631
|
// src/watch/extractWatchConflicts.ts
|
|
30303
30632
|
var toWatchConflict = (issue2) => {
|
|
30304
|
-
const { path:
|
|
30633
|
+
const { path: path22, message, relatedPaths } = issue2.details.details;
|
|
30305
30634
|
const conflictType = issue2.details.type;
|
|
30306
30635
|
return {
|
|
30307
|
-
path:
|
|
30636
|
+
path: path22,
|
|
30308
30637
|
conflictType,
|
|
30309
30638
|
message,
|
|
30310
30639
|
relatedPaths: relatedPaths ?? [],
|
|
30311
|
-
suggestions: conflictResolutionSuggestions(conflictType,
|
|
30640
|
+
suggestions: conflictResolutionSuggestions(conflictType, path22)
|
|
30312
30641
|
};
|
|
30313
30642
|
};
|
|
30314
30643
|
var extractWatchConflicts = (result) => {
|
|
@@ -30399,9 +30728,9 @@ var createCheckoutWatcher = ({
|
|
|
30399
30728
|
})
|
|
30400
30729
|
);
|
|
30401
30730
|
}
|
|
30402
|
-
for (const
|
|
30731
|
+
for (const path22 of cleared) {
|
|
30403
30732
|
bus.emit(
|
|
30404
|
-
watchEvent("sync.watch.conflict.cleared", void 0, { path:
|
|
30733
|
+
watchEvent("sync.watch.conflict.cleared", void 0, { path: path22 })
|
|
30405
30734
|
);
|
|
30406
30735
|
}
|
|
30407
30736
|
bus.emit(
|
|
@@ -30619,7 +30948,7 @@ var runSyncWatchDirectory = async (options2) => {
|
|
|
30619
30948
|
};
|
|
30620
30949
|
|
|
30621
30950
|
// src/watch/fleetStatusSubscriber.ts
|
|
30622
|
-
import
|
|
30951
|
+
import path12 from "path";
|
|
30623
30952
|
var STATUS_BADGE = {
|
|
30624
30953
|
starting: "\u2026",
|
|
30625
30954
|
clean: "\u2713",
|
|
@@ -30637,15 +30966,15 @@ var STATUS_COLOR = {
|
|
|
30637
30966
|
var deriveLabels = (rootDirs) => {
|
|
30638
30967
|
const counts = /* @__PURE__ */ new Map();
|
|
30639
30968
|
for (const dir of rootDirs) {
|
|
30640
|
-
const base =
|
|
30969
|
+
const base = path12.basename(dir);
|
|
30641
30970
|
counts.set(base, (counts.get(base) ?? 0) + 1);
|
|
30642
30971
|
}
|
|
30643
30972
|
const labels = /* @__PURE__ */ new Map();
|
|
30644
30973
|
for (const dir of rootDirs) {
|
|
30645
|
-
const base =
|
|
30974
|
+
const base = path12.basename(dir);
|
|
30646
30975
|
labels.set(
|
|
30647
30976
|
dir,
|
|
30648
|
-
(counts.get(base) ?? 0) > 1 ?
|
|
30977
|
+
(counts.get(base) ?? 0) > 1 ? path12.join(path12.basename(path12.dirname(dir)), base) : base
|
|
30649
30978
|
);
|
|
30650
30979
|
}
|
|
30651
30980
|
return labels;
|
|
@@ -30744,7 +31073,7 @@ var createFleetStatusSubscriber = (rootDirs, { write, isTty }) => {
|
|
|
30744
31073
|
};
|
|
30745
31074
|
|
|
30746
31075
|
// src/watch/discoverCheckouts.ts
|
|
30747
|
-
import
|
|
31076
|
+
import path13 from "path";
|
|
30748
31077
|
import { readdir as readdir3, stat as stat3 } from "fs/promises";
|
|
30749
31078
|
var pathExists2 = async (candidate) => {
|
|
30750
31079
|
try {
|
|
@@ -30757,7 +31086,7 @@ var pathExists2 = async (candidate) => {
|
|
|
30757
31086
|
var isCheckoutDir = async (dir) => {
|
|
30758
31087
|
let hasStateDirectory = false;
|
|
30759
31088
|
for (const name of checkoutStateDirectoryNames) {
|
|
30760
|
-
if (await pathExists2(
|
|
31089
|
+
if (await pathExists2(path13.join(dir, name))) {
|
|
30761
31090
|
hasStateDirectory = true;
|
|
30762
31091
|
break;
|
|
30763
31092
|
}
|
|
@@ -30766,7 +31095,7 @@ var isCheckoutDir = async (dir) => {
|
|
|
30766
31095
|
return false;
|
|
30767
31096
|
}
|
|
30768
31097
|
for (const filename of projectConfigFilenames) {
|
|
30769
|
-
if (await pathExists2(
|
|
31098
|
+
if (await pathExists2(path13.join(dir, filename))) {
|
|
30770
31099
|
return true;
|
|
30771
31100
|
}
|
|
30772
31101
|
}
|
|
@@ -30781,10 +31110,10 @@ var readSubdirectories = async (dir) => {
|
|
|
30781
31110
|
}
|
|
30782
31111
|
return entries.filter(
|
|
30783
31112
|
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules"
|
|
30784
|
-
).map((entry) =>
|
|
31113
|
+
).map((entry) => path13.join(dir, entry.name));
|
|
30785
31114
|
};
|
|
30786
31115
|
var discoverCheckouts = async (rootPath) => {
|
|
30787
|
-
const root =
|
|
31116
|
+
const root = path13.resolve(rootPath);
|
|
30788
31117
|
const found = [];
|
|
30789
31118
|
const visit = async (dir) => {
|
|
30790
31119
|
if (await isCheckoutDir(dir)) {
|
|
@@ -30799,51 +31128,27 @@ var discoverCheckouts = async (rootPath) => {
|
|
|
30799
31128
|
};
|
|
30800
31129
|
|
|
30801
31130
|
// src/watch/isIgnoredWatchPath.ts
|
|
30802
|
-
import
|
|
30803
|
-
var ignoredWatchSegments = /* @__PURE__ */ new Set([
|
|
30804
|
-
".forum",
|
|
30805
|
-
".doctrine",
|
|
30806
|
-
".git",
|
|
30807
|
-
"node_modules",
|
|
30808
|
-
// Standard build/cache junk — never source content, and the usual offenders
|
|
30809
|
-
// for high-churn writes during a build or test run.
|
|
30810
|
-
".cache",
|
|
30811
|
-
".next",
|
|
30812
|
-
".nuxt",
|
|
30813
|
-
".turbo",
|
|
30814
|
-
".svelte-kit",
|
|
30815
|
-
"dist",
|
|
30816
|
-
"build",
|
|
30817
|
-
"coverage",
|
|
30818
|
-
"out"
|
|
30819
|
-
]);
|
|
30820
|
-
var ignoredRootFiles = /* @__PURE__ */ new Set([
|
|
30821
|
-
"forum.yaml",
|
|
30822
|
-
"forum.yml",
|
|
30823
|
-
"doctrine.yaml",
|
|
30824
|
-
"doctrine.yml"
|
|
30825
|
-
]);
|
|
31131
|
+
import path14 from "path";
|
|
30826
31132
|
var isIgnoredWatchPath = (filename) => {
|
|
30827
|
-
if (!filename)
|
|
30828
|
-
|
|
30829
|
-
|
|
30830
|
-
|
|
30831
|
-
const
|
|
30832
|
-
if (
|
|
30833
|
-
|
|
30834
|
-
|
|
30835
|
-
return segments2.length === 1 && ignoredRootFiles.has(segments2[0]);
|
|
31133
|
+
if (!filename) return false;
|
|
31134
|
+
const relativePath = String(filename).split(path14.sep).join("/");
|
|
31135
|
+
const segments2 = relativePath.split("/").filter(Boolean);
|
|
31136
|
+
if (segments2.includes(".git")) return true;
|
|
31137
|
+
const metadataIndex = segments2.indexOf(".forum");
|
|
31138
|
+
if (metadataIndex === -1) return false;
|
|
31139
|
+
const metadataPath = segments2.slice(metadataIndex + 1).join("/");
|
|
31140
|
+
return !(metadataPath === "usr_ignore" || metadataPath === "sync.yaml" || /^stores\/[^/]+\/ignore$/.test(metadataPath));
|
|
30836
31141
|
};
|
|
30837
31142
|
|
|
30838
31143
|
// src/watch/readPathsFile.ts
|
|
30839
|
-
import { readFile as
|
|
31144
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
30840
31145
|
var readPathsFile = async (file2) => {
|
|
30841
|
-
const contents = await
|
|
31146
|
+
const contents = await readFile5(file2, "utf8");
|
|
30842
31147
|
return contents.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
30843
31148
|
};
|
|
30844
31149
|
|
|
30845
31150
|
// src/watch/resolveWatchWorkingSet.ts
|
|
30846
|
-
import
|
|
31151
|
+
import path15 from "path";
|
|
30847
31152
|
var resolveWatchWorkingSet = async ({ watchPaths, pathsFile }, resolvers) => {
|
|
30848
31153
|
const explicitPaths = [...watchPaths];
|
|
30849
31154
|
if (pathsFile !== null) {
|
|
@@ -30866,7 +31171,7 @@ var resolveWatchWorkingSet = async ({ watchPaths, pathsFile }, resolvers) => {
|
|
|
30866
31171
|
const entries = [];
|
|
30867
31172
|
const errors = [];
|
|
30868
31173
|
for (const rawPath of explicitPaths) {
|
|
30869
|
-
const resolved =
|
|
31174
|
+
const resolved = path15.resolve(rawPath);
|
|
30870
31175
|
if (seen.has(resolved)) {
|
|
30871
31176
|
continue;
|
|
30872
31177
|
}
|
|
@@ -31102,6 +31407,10 @@ var createStoreClient = ({
|
|
|
31102
31407
|
createStore: (input) => call("stores.create", () => trpc.stores.create.mutate(input)),
|
|
31103
31408
|
deleteStore: (input) => call("stores.delete", () => trpc.stores.delete.mutate(input)),
|
|
31104
31409
|
readStoreByRef: (input) => call("stores.readByRef", () => trpc.stores.readByRef.query(input)),
|
|
31410
|
+
syncStoreIgnoreByRef: (input) => call(
|
|
31411
|
+
"stores.syncIgnoreByRef",
|
|
31412
|
+
() => trpc.stores.syncIgnoreByRef.mutate(input)
|
|
31413
|
+
),
|
|
31105
31414
|
upsertStoreByRef: (input) => call("stores.upsertByRef", () => trpc.stores.upsertByRef.mutate(input)),
|
|
31106
31415
|
deleteFileByRef: (input) => call(
|
|
31107
31416
|
"files.deleteFileByRef",
|
|
@@ -31233,10 +31542,9 @@ var createClient = (config2) => {
|
|
|
31233
31542
|
|
|
31234
31543
|
// src/state.ts
|
|
31235
31544
|
import { homedir } from "os";
|
|
31236
|
-
import
|
|
31237
|
-
import {
|
|
31545
|
+
import path16 from "path";
|
|
31546
|
+
import { mkdir as mkdir5, readFile as readFile6, rename as rename3, writeFile as writeFile4 } from "fs/promises";
|
|
31238
31547
|
var DEFAULT_STATE_DIRNAME = ".forum";
|
|
31239
|
-
var LEGACY_STATE_DIRNAME = ".doctrine";
|
|
31240
31548
|
var DEFAULT_POLL_INTERVAL_MS = 4e3;
|
|
31241
31549
|
var DEFAULT_API_BASE_URL = "https://api.forumlabs.net";
|
|
31242
31550
|
var DEFAULT_CONFIG = {
|
|
@@ -31244,49 +31552,32 @@ var DEFAULT_CONFIG = {
|
|
|
31244
31552
|
pollIntervalMs: DEFAULT_POLL_INTERVAL_MS,
|
|
31245
31553
|
forceWrites: false
|
|
31246
31554
|
};
|
|
31247
|
-
var
|
|
31248
|
-
var
|
|
31249
|
-
var configPath = (stateDir) => path14.join(stateDir, "config.json");
|
|
31555
|
+
var defaultStateDir = () => path16.join(homedir(), DEFAULT_STATE_DIRNAME);
|
|
31556
|
+
var configPath = (stateDir) => path16.join(stateDir, "config.json");
|
|
31250
31557
|
var ensureStateDir = async (stateDir) => {
|
|
31251
|
-
await
|
|
31558
|
+
await mkdir5(stateDir, { recursive: true });
|
|
31252
31559
|
};
|
|
31253
31560
|
var readJson = async (filePath, fallback) => {
|
|
31254
31561
|
try {
|
|
31255
|
-
const raw = await
|
|
31562
|
+
const raw = await readFile6(filePath, "utf8");
|
|
31256
31563
|
return JSON.parse(raw);
|
|
31257
31564
|
} catch {
|
|
31258
31565
|
return fallback;
|
|
31259
31566
|
}
|
|
31260
31567
|
};
|
|
31261
|
-
var fileExists2 = async (filePath) => {
|
|
31262
|
-
try {
|
|
31263
|
-
await access2(filePath);
|
|
31264
|
-
return true;
|
|
31265
|
-
} catch {
|
|
31266
|
-
return false;
|
|
31267
|
-
}
|
|
31268
|
-
};
|
|
31269
|
-
var readConfigSourcePath = async (stateDir) => {
|
|
31270
|
-
const currentPath = configPath(stateDir);
|
|
31271
|
-
if (stateDir !== defaultStateDir() || await fileExists2(currentPath)) {
|
|
31272
|
-
return currentPath;
|
|
31273
|
-
}
|
|
31274
|
-
const legacyPath = configPath(legacyStateDir());
|
|
31275
|
-
return await fileExists2(legacyPath) ? legacyPath : currentPath;
|
|
31276
|
-
};
|
|
31277
31568
|
var writeJsonAtomic = async (filePath, value) => {
|
|
31278
|
-
const parentDir =
|
|
31279
|
-
const tempPath =
|
|
31569
|
+
const parentDir = path16.dirname(filePath);
|
|
31570
|
+
const tempPath = path16.join(
|
|
31280
31571
|
parentDir,
|
|
31281
|
-
`.${
|
|
31572
|
+
`.${path16.basename(filePath)}.${process.pid}.${Date.now()}.tmp`
|
|
31282
31573
|
);
|
|
31283
|
-
await
|
|
31574
|
+
await mkdir5(parentDir, { recursive: true });
|
|
31284
31575
|
await writeFile4(tempPath, JSON.stringify(value, null, 2), "utf8");
|
|
31285
31576
|
await rename3(tempPath, filePath);
|
|
31286
31577
|
};
|
|
31287
31578
|
var readConfig = async (stateDir) => {
|
|
31288
31579
|
const config2 = await readJson(
|
|
31289
|
-
|
|
31580
|
+
configPath(stateDir),
|
|
31290
31581
|
DEFAULT_CONFIG
|
|
31291
31582
|
);
|
|
31292
31583
|
return {
|
|
@@ -31301,28 +31592,28 @@ var writeConfig = async (stateDir, config2) => {
|
|
|
31301
31592
|
|
|
31302
31593
|
// src/skillIntegration.ts
|
|
31303
31594
|
import { constants } from "fs";
|
|
31304
|
-
import { access as
|
|
31595
|
+
import { access as access2 } from "fs/promises";
|
|
31305
31596
|
import os from "os";
|
|
31306
|
-
import
|
|
31597
|
+
import path19 from "path";
|
|
31307
31598
|
import Enquirer from "enquirer";
|
|
31308
31599
|
|
|
31309
31600
|
// src/skillProviders/claude.ts
|
|
31310
|
-
import
|
|
31601
|
+
import path17 from "path";
|
|
31311
31602
|
var claudeSkillProvider = {
|
|
31312
31603
|
id: "claude",
|
|
31313
|
-
globalRootCandidates: (home) => [
|
|
31314
|
-
localRoot: (projectDir) =>
|
|
31604
|
+
globalRootCandidates: (home) => [path17.join(home, ".claude", "skills")],
|
|
31605
|
+
localRoot: (projectDir) => path17.join(projectDir, ".claude", "skills")
|
|
31315
31606
|
};
|
|
31316
31607
|
|
|
31317
31608
|
// src/skillProviders/codex.ts
|
|
31318
|
-
import
|
|
31609
|
+
import path18 from "path";
|
|
31319
31610
|
var codexSkillProvider = {
|
|
31320
31611
|
id: "codex",
|
|
31321
31612
|
globalRootCandidates: (home) => [
|
|
31322
|
-
|
|
31323
|
-
|
|
31613
|
+
path18.join(home, ".codex", "skills"),
|
|
31614
|
+
path18.join(home, ".agents", "skills")
|
|
31324
31615
|
],
|
|
31325
|
-
localRoot: (projectDir) =>
|
|
31616
|
+
localRoot: (projectDir) => path18.join(projectDir, ".codex", "skills")
|
|
31326
31617
|
};
|
|
31327
31618
|
|
|
31328
31619
|
// src/skillProviders/registry.ts
|
|
@@ -31343,13 +31634,13 @@ var expandHomePath = (input) => {
|
|
|
31343
31634
|
return process.env.HOME || os.homedir();
|
|
31344
31635
|
}
|
|
31345
31636
|
if (input.startsWith("~/")) {
|
|
31346
|
-
return
|
|
31637
|
+
return path19.join(process.env.HOME || os.homedir(), input.slice(2));
|
|
31347
31638
|
}
|
|
31348
31639
|
return input;
|
|
31349
31640
|
};
|
|
31350
31641
|
var pathExists3 = async (filePath) => {
|
|
31351
31642
|
try {
|
|
31352
|
-
await
|
|
31643
|
+
await access2(filePath);
|
|
31353
31644
|
return true;
|
|
31354
31645
|
} catch {
|
|
31355
31646
|
return false;
|
|
@@ -31860,13 +32151,13 @@ var editEncryptedText = async ({
|
|
|
31860
32151
|
|
|
31861
32152
|
// src/openInEditor.ts
|
|
31862
32153
|
import { spawn } from "child_process";
|
|
31863
|
-
import { mkdtemp, readFile as
|
|
32154
|
+
import { mkdtemp, readFile as readFile7, rm as rm4, writeFile as writeFile5 } from "fs/promises";
|
|
31864
32155
|
import { tmpdir } from "os";
|
|
31865
|
-
import
|
|
32156
|
+
import path20 from "path";
|
|
31866
32157
|
var openInEditor = async (currentText, { extension = "" } = {}) => {
|
|
31867
32158
|
const editor = process.env.EDITOR?.trim() || "vi";
|
|
31868
|
-
const dir = await mkdtemp(
|
|
31869
|
-
const tempPath =
|
|
32159
|
+
const dir = await mkdtemp(path20.join(tmpdir(), "fm-edit-"));
|
|
32160
|
+
const tempPath = path20.join(dir, `edit${extension}`);
|
|
31870
32161
|
try {
|
|
31871
32162
|
await writeFile5(tempPath, currentText, "utf8");
|
|
31872
32163
|
const exitCode = await new Promise((resolve, reject) => {
|
|
@@ -31881,9 +32172,9 @@ var openInEditor = async (currentText, { extension = "" } = {}) => {
|
|
|
31881
32172
|
if (exitCode !== 0) {
|
|
31882
32173
|
return null;
|
|
31883
32174
|
}
|
|
31884
|
-
return await
|
|
32175
|
+
return await readFile7(tempPath, "utf8");
|
|
31885
32176
|
} finally {
|
|
31886
|
-
await
|
|
32177
|
+
await rm4(dir, { force: true, recursive: true }).catch(() => {
|
|
31887
32178
|
});
|
|
31888
32179
|
}
|
|
31889
32180
|
};
|
|
@@ -32025,7 +32316,7 @@ Usage:
|
|
|
32025
32316
|
fm push [filePath] [--token <jwt>] [--force] [--yes|-y] [--dry-run|-d] [--verbose|--debug]
|
|
32026
32317
|
fm status [--token <jwt>] [--json]
|
|
32027
32318
|
fm s [--token <jwt>] [--json]
|
|
32028
|
-
fm sync [--token <jwt>] [--force] [--yes|-y] [--verbose] [--watch] [--readonly]
|
|
32319
|
+
fm sync [--token <jwt>] [--conflict|-c local|remote] [--force] [--yes|-y] [--verbose] [--watch] [--readonly]
|
|
32029
32320
|
fm sync --watch [<path>] [--notify] [--json] [--readonly]
|
|
32030
32321
|
fm sync --watch <path...> [--paths-file <file>] [--notify] [--json]
|
|
32031
32322
|
fm sync --dry-run|-d [--token <jwt>] [--json]
|
|
@@ -32057,7 +32348,7 @@ Usage:
|
|
|
32057
32348
|
fm --version
|
|
32058
32349
|
|
|
32059
32350
|
Store creation:
|
|
32060
|
-
fm store create <storeId> creates in defaults.store's workspace from forum.yaml when present, otherwise in the authenticated workspace.
|
|
32351
|
+
fm store create <storeId> creates in defaults.store's workspace from .forum/sync.yaml when present, otherwise in the authenticated workspace.
|
|
32061
32352
|
fm store create <workspace/storeId> creates in that explicitly selected workspace.
|
|
32062
32353
|
|
|
32063
32354
|
Auth:
|
|
@@ -32075,7 +32366,7 @@ Output:
|
|
|
32075
32366
|
`;
|
|
32076
32367
|
var readCliVersion = async () => {
|
|
32077
32368
|
const packageJson = JSON.parse(
|
|
32078
|
-
await
|
|
32369
|
+
await readFile8(new URL("../package.json", import.meta.url), "utf8")
|
|
32079
32370
|
);
|
|
32080
32371
|
return typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
32081
32372
|
};
|
|
@@ -32116,6 +32407,7 @@ var parseArgvCommandName = (argv) => {
|
|
|
32116
32407
|
var parseArgs = (argv) => {
|
|
32117
32408
|
const positional = [];
|
|
32118
32409
|
const shouldParseDirectPullMapping = argv.includes("pull") && argv.includes("--direct");
|
|
32410
|
+
const isSyncCommand = parseArgvCommandName(argv) === "sync";
|
|
32119
32411
|
const isCatCommand = parseArgvCommandName(argv) === "cat";
|
|
32120
32412
|
let token = null;
|
|
32121
32413
|
const storeFilters = [];
|
|
@@ -32135,6 +32427,7 @@ var parseArgs = (argv) => {
|
|
|
32135
32427
|
let stateDir = defaultStateDir();
|
|
32136
32428
|
let pollIntervalMs = null;
|
|
32137
32429
|
let dryRun = false;
|
|
32430
|
+
let conflictPolicy;
|
|
32138
32431
|
let force = false;
|
|
32139
32432
|
let direct = false;
|
|
32140
32433
|
let json2 = false;
|
|
@@ -32181,7 +32474,7 @@ var parseArgs = (argv) => {
|
|
|
32181
32474
|
continue;
|
|
32182
32475
|
}
|
|
32183
32476
|
if (current === "--file" || current === "-f") {
|
|
32184
|
-
inputFilePath = next ?
|
|
32477
|
+
inputFilePath = next ? path21.resolve(next) : inputFilePath;
|
|
32185
32478
|
index += 1;
|
|
32186
32479
|
continue;
|
|
32187
32480
|
}
|
|
@@ -32246,7 +32539,7 @@ var parseArgs = (argv) => {
|
|
|
32246
32539
|
if (!next) {
|
|
32247
32540
|
throw new Error("--target-dir requires a path.");
|
|
32248
32541
|
}
|
|
32249
|
-
skillTargetDir =
|
|
32542
|
+
skillTargetDir = path21.resolve(expandHomePath(next));
|
|
32250
32543
|
index += 1;
|
|
32251
32544
|
continue;
|
|
32252
32545
|
}
|
|
@@ -32258,7 +32551,7 @@ var parseArgs = (argv) => {
|
|
|
32258
32551
|
continue;
|
|
32259
32552
|
}
|
|
32260
32553
|
if (current === "--state-dir") {
|
|
32261
|
-
stateDir =
|
|
32554
|
+
stateDir = path21.resolve(next ?? stateDir);
|
|
32262
32555
|
index += 1;
|
|
32263
32556
|
continue;
|
|
32264
32557
|
}
|
|
@@ -32266,12 +32559,12 @@ var parseArgs = (argv) => {
|
|
|
32266
32559
|
if (!next) {
|
|
32267
32560
|
throw new Error("--paths-file requires a file path.");
|
|
32268
32561
|
}
|
|
32269
|
-
pathsFile =
|
|
32562
|
+
pathsFile = path21.resolve(expandHomePath(next));
|
|
32270
32563
|
index += 1;
|
|
32271
32564
|
continue;
|
|
32272
32565
|
}
|
|
32273
32566
|
if (current.startsWith("--paths-file=")) {
|
|
32274
|
-
pathsFile =
|
|
32567
|
+
pathsFile = path21.resolve(
|
|
32275
32568
|
expandHomePath(current.slice("--paths-file=".length))
|
|
32276
32569
|
);
|
|
32277
32570
|
continue;
|
|
@@ -32285,6 +32578,15 @@ var parseArgs = (argv) => {
|
|
|
32285
32578
|
openBrowser = false;
|
|
32286
32579
|
continue;
|
|
32287
32580
|
}
|
|
32581
|
+
if (isSyncCommand && (current === "-c" || current === "--conflict" || current.startsWith("--conflict="))) {
|
|
32582
|
+
const value = current.startsWith("--conflict=") ? current.slice("--conflict=".length) : next;
|
|
32583
|
+
if (value !== "local" && value !== "remote") {
|
|
32584
|
+
throw new Error("--conflict requires local or remote.");
|
|
32585
|
+
}
|
|
32586
|
+
conflictPolicy = value;
|
|
32587
|
+
if (!current.startsWith("--conflict=")) index += 1;
|
|
32588
|
+
continue;
|
|
32589
|
+
}
|
|
32288
32590
|
if (current === "--force") {
|
|
32289
32591
|
force = true;
|
|
32290
32592
|
continue;
|
|
@@ -32337,6 +32639,7 @@ var parseArgs = (argv) => {
|
|
|
32337
32639
|
}
|
|
32338
32640
|
return {
|
|
32339
32641
|
args: positional,
|
|
32642
|
+
conflictPolicy,
|
|
32340
32643
|
token,
|
|
32341
32644
|
storeFilters,
|
|
32342
32645
|
searchLimit,
|
|
@@ -32459,10 +32762,10 @@ var listDirectoryEntries = async (listDirectory, directoryPath) => {
|
|
|
32459
32762
|
if (left.type !== "directory" && right.type === "directory") {
|
|
32460
32763
|
return 1;
|
|
32461
32764
|
}
|
|
32462
|
-
return
|
|
32765
|
+
return path21.basename(left.path).localeCompare(path21.basename(right.path));
|
|
32463
32766
|
}).forEach((entry) => {
|
|
32464
32767
|
const suffix = entry.type === "directory" ? "/" : "";
|
|
32465
|
-
renderOutput(`${
|
|
32768
|
+
renderOutput(`${path21.basename(entry.path)}${suffix}`);
|
|
32466
32769
|
});
|
|
32467
32770
|
};
|
|
32468
32771
|
var listStores = async (listStoresMetadata) => {
|
|
@@ -32757,7 +33060,7 @@ var normalizeSkillAgents = (inputs) => {
|
|
|
32757
33060
|
return [...new Set(inputs.map(normalizeSkillAgent))];
|
|
32758
33061
|
};
|
|
32759
33062
|
var normalizeRemoteSkillPath = (input) => {
|
|
32760
|
-
const normalized =
|
|
33063
|
+
const normalized = path21.posix.normalize(`/${input.trim()}`);
|
|
32761
33064
|
if (normalized === "/") {
|
|
32762
33065
|
throw new Error("Skill path must not be the store root.");
|
|
32763
33066
|
}
|
|
@@ -32767,11 +33070,11 @@ var normalizeRemoteSkillPath = (input) => {
|
|
|
32767
33070
|
return normalized;
|
|
32768
33071
|
};
|
|
32769
33072
|
var parentRemotePath = (filePath) => {
|
|
32770
|
-
const parent =
|
|
33073
|
+
const parent = path21.posix.dirname(filePath);
|
|
32771
33074
|
return parent === "." ? "/" : parent;
|
|
32772
33075
|
};
|
|
32773
33076
|
var joinRemotePath = (left, right) => {
|
|
32774
|
-
return
|
|
33077
|
+
return path21.posix.join(left, right).replace(/\/+/g, "/");
|
|
32775
33078
|
};
|
|
32776
33079
|
var readRemoteSkillTextFile = async (filePath, storeRef, client) => {
|
|
32777
33080
|
const file2 = await client.readFileByRef({ ...storeRef, path: filePath });
|
|
@@ -32833,7 +33136,7 @@ var collectRemoteSkillFiles = async ({
|
|
|
32833
33136
|
`Skill contains unsupported ${entry.type} entry: ${entry.path}`
|
|
32834
33137
|
);
|
|
32835
33138
|
}
|
|
32836
|
-
const relativePath =
|
|
33139
|
+
const relativePath = path21.posix.relative(rootPath, entry.path);
|
|
32837
33140
|
if (!relativePath || relativePath.startsWith("..")) {
|
|
32838
33141
|
throw new Error(
|
|
32839
33142
|
`Unexpected skill entry outside skill root: ${entry.path}`
|
|
@@ -32847,7 +33150,7 @@ var collectRemoteSkillFiles = async ({
|
|
|
32847
33150
|
};
|
|
32848
33151
|
var resolveRemoteSkillRoot = async (inputPath, storeRef, client) => {
|
|
32849
33152
|
const normalizedPath = normalizeRemoteSkillPath(inputPath);
|
|
32850
|
-
if (
|
|
33153
|
+
if (path21.posix.basename(normalizedPath) === "SKILL.md") {
|
|
32851
33154
|
await readRemoteSkillTextFile(normalizedPath, storeRef, client);
|
|
32852
33155
|
return {
|
|
32853
33156
|
rootPath: parentRemotePath(normalizedPath),
|
|
@@ -32927,7 +33230,7 @@ var resolveSkillInstallTargets = async ({
|
|
|
32927
33230
|
return {
|
|
32928
33231
|
agent,
|
|
32929
33232
|
rootDir,
|
|
32930
|
-
targetDir:
|
|
33233
|
+
targetDir: path21.join(rootDir, skillName)
|
|
32931
33234
|
};
|
|
32932
33235
|
})
|
|
32933
33236
|
);
|
|
@@ -32966,24 +33269,24 @@ var formatSkillTarget = (target, existingTargetDirs) => {
|
|
|
32966
33269
|
return ` ${target.agent.padEnd(7)} ${target.targetDir}${suffix}`;
|
|
32967
33270
|
};
|
|
32968
33271
|
var writeSkillFiles = async (target, files, replaceExisting) => {
|
|
32969
|
-
const temporaryDirectory =
|
|
33272
|
+
const temporaryDirectory = path21.join(
|
|
32970
33273
|
target.rootDir,
|
|
32971
|
-
`.${
|
|
33274
|
+
`.${path21.basename(target.targetDir)}.tmp-${process.pid}-${Date.now()}`
|
|
32972
33275
|
);
|
|
32973
|
-
await
|
|
32974
|
-
await
|
|
33276
|
+
await rm5(temporaryDirectory, { recursive: true, force: true });
|
|
33277
|
+
await mkdir6(temporaryDirectory, { recursive: true });
|
|
32975
33278
|
try {
|
|
32976
33279
|
for (const file2 of files) {
|
|
32977
|
-
const localPath =
|
|
32978
|
-
await
|
|
33280
|
+
const localPath = path21.join(temporaryDirectory, file2.relativePath);
|
|
33281
|
+
await mkdir6(path21.dirname(localPath), { recursive: true });
|
|
32979
33282
|
await writeFile6(localPath, file2.bytes);
|
|
32980
33283
|
}
|
|
32981
33284
|
if (replaceExisting) {
|
|
32982
|
-
await
|
|
33285
|
+
await rm5(target.targetDir, { recursive: true, force: true });
|
|
32983
33286
|
}
|
|
32984
33287
|
await rename4(temporaryDirectory, target.targetDir);
|
|
32985
33288
|
} catch (error51) {
|
|
32986
|
-
await
|
|
33289
|
+
await rm5(temporaryDirectory, { recursive: true, force: true });
|
|
32987
33290
|
throw error51;
|
|
32988
33291
|
}
|
|
32989
33292
|
};
|
|
@@ -33026,7 +33329,7 @@ var installSkillBundle = async ({
|
|
|
33026
33329
|
throw new Error("Aborted skill install.");
|
|
33027
33330
|
}
|
|
33028
33331
|
for (const target of targets) {
|
|
33029
|
-
await
|
|
33332
|
+
await mkdir6(target.rootDir, { recursive: true });
|
|
33030
33333
|
}
|
|
33031
33334
|
for (const target of targets) {
|
|
33032
33335
|
await writeSkillFiles(
|
|
@@ -33058,7 +33361,7 @@ var readRemoteSkillBundle = async ({
|
|
|
33058
33361
|
client
|
|
33059
33362
|
);
|
|
33060
33363
|
const metadata = parseSkillMetadata(skillMarkdown);
|
|
33061
|
-
const rootName =
|
|
33364
|
+
const rootName = path21.posix.basename(rootPath);
|
|
33062
33365
|
if (metadata.name !== rootName) {
|
|
33063
33366
|
throw new Error(
|
|
33064
33367
|
`SKILL.md name "${metadata.name}" must match skill directory "${rootName}".`
|
|
@@ -33238,7 +33541,7 @@ var readWriteTextInput = async (inlineText, inputFilePath) => {
|
|
|
33238
33541
|
throw new Error("Provide either inline text or --file, not both.");
|
|
33239
33542
|
}
|
|
33240
33543
|
if (inputFilePath) {
|
|
33241
|
-
return
|
|
33544
|
+
return readFile8(inputFilePath, "utf8");
|
|
33242
33545
|
}
|
|
33243
33546
|
return inlineText ?? null;
|
|
33244
33547
|
};
|
|
@@ -33254,7 +33557,7 @@ var readRemoteTextFile = async (filePath, storeRef, client) => {
|
|
|
33254
33557
|
return text;
|
|
33255
33558
|
};
|
|
33256
33559
|
var normalizeRemotePath = (input) => {
|
|
33257
|
-
const normalized =
|
|
33560
|
+
const normalized = path21.posix.normalize(`/${input.trim()}`);
|
|
33258
33561
|
if (normalized.includes("\0")) {
|
|
33259
33562
|
throw new Error("Path contains an invalid null byte.");
|
|
33260
33563
|
}
|
|
@@ -33548,7 +33851,7 @@ var diffRemoteFiles = async ({
|
|
|
33548
33851
|
storeRef
|
|
33549
33852
|
}) => {
|
|
33550
33853
|
const leftText = await readRemoteTextFile(leftPath, storeRef, client);
|
|
33551
|
-
const rightText = localRight ? await
|
|
33854
|
+
const rightText = localRight ? await readFile8(path21.resolve(rightPath), "utf8") : await readRemoteTextFile(rightPath, storeRef, client);
|
|
33552
33855
|
return buildUnifiedDiff({
|
|
33553
33856
|
leftLabel: leftPath,
|
|
33554
33857
|
leftText,
|
|
@@ -33615,8 +33918,8 @@ var copyRemotePath = async (args, storeRef, client) => {
|
|
|
33615
33918
|
(entry) => entry.path.startsWith(`${normalizedSource}/`)
|
|
33616
33919
|
);
|
|
33617
33920
|
for (const entry of descendants) {
|
|
33618
|
-
const relativePath =
|
|
33619
|
-
const targetPath =
|
|
33921
|
+
const relativePath = path21.posix.relative(normalizedSource, entry.path);
|
|
33922
|
+
const targetPath = path21.posix.join(normalizedDestination, relativePath);
|
|
33620
33923
|
if (entry.type === "directory") {
|
|
33621
33924
|
await createRemoteDirectory(targetPath, storeRef, client);
|
|
33622
33925
|
continue;
|
|
@@ -33811,19 +34114,19 @@ var runDecryptCommand = async (rest, parsed, client) => {
|
|
|
33811
34114
|
);
|
|
33812
34115
|
};
|
|
33813
34116
|
var runEditCommand = async (rest, parsed, client) => {
|
|
33814
|
-
const filePath = parsed.inputFilePath ?? (rest[0] ?
|
|
34117
|
+
const filePath = parsed.inputFilePath ?? (rest[0] ? path21.resolve(rest[0]) : null);
|
|
33815
34118
|
if (!filePath) {
|
|
33816
34119
|
throw new Error(
|
|
33817
34120
|
`Usage: ${commandNames} edit (<localPath>|--file|-f <localPath>) [--password <password>] [--token <jwt>]`
|
|
33818
34121
|
);
|
|
33819
34122
|
}
|
|
33820
|
-
const encryptedText = await
|
|
34123
|
+
const encryptedText = await readFile8(filePath, "utf8");
|
|
33821
34124
|
const [password, userEncryption] = await Promise.all([
|
|
33822
34125
|
readEncryptionPassword(parsed),
|
|
33823
34126
|
readUserEncryption(client)
|
|
33824
34127
|
]);
|
|
33825
34128
|
const result = await editEncryptedText({
|
|
33826
|
-
edit: (currentPlaintext) => openInEditor(currentPlaintext, { extension:
|
|
34129
|
+
edit: (currentPlaintext) => openInEditor(currentPlaintext, { extension: path21.extname(filePath) }),
|
|
33827
34130
|
encryptedText,
|
|
33828
34131
|
password,
|
|
33829
34132
|
userEncryption: userEncryption.userEncryption
|
|
@@ -33899,10 +34202,10 @@ var runEncryptAddRecipientCommand = async (rest, parsed, client) => {
|
|
|
33899
34202
|
`);
|
|
33900
34203
|
renderOutput(result.encryptedText);
|
|
33901
34204
|
};
|
|
33902
|
-
var defaultEncryptionMigrationBackupPath = () =>
|
|
33903
|
-
var readEncryptionMigrationBackup = async (backupPath) => JSON.parse(await
|
|
34205
|
+
var defaultEncryptionMigrationBackupPath = () => path21.resolve(process.cwd(), "doctrine-encryption-migration.json");
|
|
34206
|
+
var readEncryptionMigrationBackup = async (backupPath) => JSON.parse(await readFile8(backupPath, "utf8"));
|
|
33904
34207
|
var writeEncryptionMigrationBackup = async (backupPath, backup) => {
|
|
33905
|
-
await
|
|
34208
|
+
await mkdir6(path21.dirname(backupPath), { recursive: true });
|
|
33906
34209
|
await writeFile6(backupPath, `${JSON.stringify(backup, null, 2)}
|
|
33907
34210
|
`, "utf8");
|
|
33908
34211
|
};
|
|
@@ -34190,7 +34493,7 @@ var runEncryptionMigrateCommand = async (rest, parsed, client) => {
|
|
|
34190
34493
|
`Usage: ${commandNames} encryption migrate [backup-file] [--store <storeId>] [--password <password>] [--dry-run] [--yes]`
|
|
34191
34494
|
);
|
|
34192
34495
|
}
|
|
34193
|
-
const backupPath =
|
|
34496
|
+
const backupPath = path21.resolve(
|
|
34194
34497
|
rest[1] ?? defaultEncryptionMigrationBackupPath()
|
|
34195
34498
|
);
|
|
34196
34499
|
const password = await readEncryptionPassword(parsed);
|
|
@@ -34265,7 +34568,7 @@ var doesRemoteQueryMatchPath = (query, filePath) => {
|
|
|
34265
34568
|
if (query.startsWith("/")) {
|
|
34266
34569
|
return normalizedPath === query;
|
|
34267
34570
|
}
|
|
34268
|
-
const filename =
|
|
34571
|
+
const filename = path21.basename(filePath).toLowerCase();
|
|
34269
34572
|
return filename === query || normalizedPath === query || filename.includes(query) || normalizedPath.includes(query);
|
|
34270
34573
|
};
|
|
34271
34574
|
var queryRemoteFiles = async (query, storeFilters, client) => {
|
|
@@ -34337,7 +34640,7 @@ var printRemoteQueryMatches = (matches) => {
|
|
|
34337
34640
|
});
|
|
34338
34641
|
};
|
|
34339
34642
|
var normalizeRemoteDirectoryPath = (input) => {
|
|
34340
|
-
const normalized =
|
|
34643
|
+
const normalized = path21.posix.normalize(`/${input.trim()}`);
|
|
34341
34644
|
if (normalized.includes("\0")) {
|
|
34342
34645
|
throw new Error("Path contains an invalid null byte.");
|
|
34343
34646
|
}
|
|
@@ -34457,12 +34760,12 @@ var labelFromTreeDirectoryPath = (directoryPath) => {
|
|
|
34457
34760
|
if (directoryPath === "/") {
|
|
34458
34761
|
return "./";
|
|
34459
34762
|
}
|
|
34460
|
-
return `${
|
|
34763
|
+
return `${path21.posix.basename(directoryPath)}/`;
|
|
34461
34764
|
};
|
|
34462
34765
|
var doesTreeFilterMatchDirectory = (filter, directoryPath) => {
|
|
34463
34766
|
const normalizedFilter = filter.trim().toLowerCase();
|
|
34464
34767
|
const normalizedPath = directoryPath.toLowerCase();
|
|
34465
|
-
const basename3 =
|
|
34768
|
+
const basename3 = path21.posix.basename(directoryPath).toLowerCase();
|
|
34466
34769
|
return basename3.includes(normalizedFilter) || normalizedPath.includes(normalizedFilter);
|
|
34467
34770
|
};
|
|
34468
34771
|
var resolveTreeDirectoryPath = async ({
|
|
@@ -34517,7 +34820,7 @@ var printRemoteTreeChildren = async ({
|
|
|
34517
34820
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
34518
34821
|
const suffix = entry.type === "directory" ? "/" : "";
|
|
34519
34822
|
lines.push(
|
|
34520
|
-
`${prefix}${connector}${
|
|
34823
|
+
`${prefix}${connector}${path21.posix.basename(entry.path)}${suffix}`
|
|
34521
34824
|
);
|
|
34522
34825
|
if (entry.type === "directory") {
|
|
34523
34826
|
await printRemoteTreeChildren({
|
|
@@ -34856,7 +35159,7 @@ var parseRootStorePath = (storePathInput) => {
|
|
|
34856
35159
|
var parseNewStorePath = (storePathInput) => {
|
|
34857
35160
|
return parseRootStorePath(storePathInput);
|
|
34858
35161
|
};
|
|
34859
|
-
var storeCreateSyntaxMessage = "Store ref must be a store ID like 'my-store' or a qualified ref like 'workspace/my-store'. Unqualified store IDs use defaults.store from forum.yaml when present, otherwise the authenticated workspace.";
|
|
35162
|
+
var storeCreateSyntaxMessage = "Store ref must be a store ID like 'my-store' or a qualified ref like 'workspace/my-store'. Unqualified store IDs use defaults.store from .forum/sync.yaml when present, otherwise the authenticated workspace.";
|
|
34860
35163
|
var parseStoreCreateInput = async (storePathInput) => {
|
|
34861
35164
|
const segments2 = storePathInput.split("/").map((segment) => segment.trim()).filter(Boolean);
|
|
34862
35165
|
if (segments2.length === 2) {
|
|
@@ -35129,9 +35432,9 @@ var shouldPrintCheckoutDetail = (detail, verbose) => {
|
|
|
35129
35432
|
var formatCheckoutDetail = (detail, options2) => {
|
|
35130
35433
|
const status = checkoutStatusLabel(detail, options2);
|
|
35131
35434
|
const direction = checkoutDirectionLabel(detail);
|
|
35132
|
-
const
|
|
35435
|
+
const path22 = formatCheckoutDetailPath(detail, options2.syncRules);
|
|
35133
35436
|
const reason = styleText.dim(checkoutDetailMessage(detail));
|
|
35134
|
-
return direction ? `${direction} ${status} ${
|
|
35437
|
+
return direction ? `${direction} ${status} ${path22} ${reason}` : `${status} ${path22} ${reason}`;
|
|
35135
35438
|
};
|
|
35136
35439
|
var formatCheckoutDetailPath = (detail, syncRules) => {
|
|
35137
35440
|
const localPath = formatLocalCheckoutPath(detail.relativePath);
|
|
@@ -35343,9 +35646,9 @@ var checkoutReportGroups = (details, options2) => {
|
|
|
35343
35646
|
);
|
|
35344
35647
|
};
|
|
35345
35648
|
var checkoutReportDetailLine = (detail, options2) => {
|
|
35346
|
-
const
|
|
35649
|
+
const path22 = formatCheckoutDetailPath(detail, options2.syncRules);
|
|
35347
35650
|
const message = detail.status === "failed" || detail.status === "skipped" || detail.status === "ignored" ? detail.message ?? checkoutDetailMessage(detail) : "";
|
|
35348
|
-
return message ? ` ${
|
|
35651
|
+
return message ? ` ${path22} ${styleText.dim(message)}` : ` ${path22}`;
|
|
35349
35652
|
};
|
|
35350
35653
|
var checkoutReportGroupBlock = ({
|
|
35351
35654
|
dryRun,
|
|
@@ -35472,13 +35775,13 @@ var statusChangeKind = (detail) => {
|
|
|
35472
35775
|
var formatStatusChange = (detail, syncRules) => {
|
|
35473
35776
|
const kind = statusChangeKind(detail);
|
|
35474
35777
|
const tone = kind === "deleted" ? "error" : kind === "added" ? "ok" : "warn";
|
|
35475
|
-
const
|
|
35476
|
-
return ` ${styleText.color(tone, kind.padEnd(8))} ${
|
|
35778
|
+
const path22 = formatCheckoutDetailPath(detail, syncRules);
|
|
35779
|
+
return ` ${styleText.color(tone, kind.padEnd(8))} ${path22}`;
|
|
35477
35780
|
};
|
|
35478
35781
|
var formatStatusBlock = (detail, syncRules) => {
|
|
35479
35782
|
const message = detail.message ? ` ${styleText.dim(detail.message)}` : "";
|
|
35480
|
-
const
|
|
35481
|
-
return ` ${styleText.color("error", "blocked ".padEnd(8))} ${
|
|
35783
|
+
const path22 = formatCheckoutDetailPath(detail, syncRules);
|
|
35784
|
+
return ` ${styleText.color("error", "blocked ".padEnd(8))} ${path22}${message}`;
|
|
35482
35785
|
};
|
|
35483
35786
|
var actionableStatusDetails = (result) => result.details.filter(
|
|
35484
35787
|
(detail) => detail.status === "succeeded" || detail.status === "deleted"
|
|
@@ -35611,7 +35914,7 @@ var assertCheckoutSyncEnabled = (checkout) => {
|
|
|
35611
35914
|
return;
|
|
35612
35915
|
}
|
|
35613
35916
|
throw new Error(
|
|
35614
|
-
"Checkout sync is not configured in forum.yaml. Use fm config sync add --target <path> to enable local file sync."
|
|
35917
|
+
"Checkout sync is not configured in .forum/sync.yaml. Use fm config sync add --target <path> to enable local file sync."
|
|
35615
35918
|
);
|
|
35616
35919
|
};
|
|
35617
35920
|
var warnReadonlyCheckoutPush = (checkout, force) => {
|
|
@@ -35619,7 +35922,7 @@ var warnReadonlyCheckoutPush = (checkout, force) => {
|
|
|
35619
35922
|
return;
|
|
35620
35923
|
}
|
|
35621
35924
|
renderWarning(
|
|
35622
|
-
"Warning: forum.yaml has sync.readonly enabled. This manual push can write local files back to the store. Rerun with --force to bypass this reminder."
|
|
35925
|
+
"Warning: .forum/sync.yaml has sync.readonly enabled. This manual push can write local files back to the store. Rerun with --force to bypass this reminder."
|
|
35623
35926
|
);
|
|
35624
35927
|
};
|
|
35625
35928
|
var referenceStructuralChangeLabel = (detail) => {
|
|
@@ -35678,20 +35981,26 @@ var confirmCheckoutReferenceStructuralWrites = async ({
|
|
|
35678
35981
|
yes
|
|
35679
35982
|
}) => {
|
|
35680
35983
|
const result = operation === "sync" ? await syncCheckout({
|
|
35984
|
+
ignoreSettings: "sync",
|
|
35681
35985
|
client,
|
|
35682
35986
|
dryRun: true,
|
|
35683
35987
|
force,
|
|
35684
35988
|
ignorePatterns: checkout.ignore,
|
|
35989
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
35990
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35685
35991
|
localPath: checkout.rootDir,
|
|
35686
35992
|
progress,
|
|
35687
35993
|
storeRef: {},
|
|
35688
35994
|
syncRules: checkout.syncRules
|
|
35689
35995
|
}) : await pushCheckout({
|
|
35996
|
+
ignoreSettings: "preview",
|
|
35690
35997
|
client,
|
|
35691
35998
|
dryRun: true,
|
|
35692
35999
|
filePaths,
|
|
35693
36000
|
force,
|
|
35694
36001
|
ignorePatterns: checkout.ignore,
|
|
36002
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36003
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35695
36004
|
localPath: checkout.rootDir,
|
|
35696
36005
|
progress,
|
|
35697
36006
|
storeRef: {},
|
|
@@ -35736,12 +36045,18 @@ var runCheckoutOperation = async ({
|
|
|
35736
36045
|
filePaths,
|
|
35737
36046
|
force,
|
|
35738
36047
|
ignorePatterns: checkout.ignore,
|
|
36048
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36049
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35739
36050
|
localPath: checkout.rootDir,
|
|
35740
36051
|
progress,
|
|
35741
36052
|
storeRef: {},
|
|
35742
36053
|
syncRules: checkout.syncRules
|
|
35743
36054
|
};
|
|
35744
|
-
const result = operation === "pull" ? await pullCheckout(commonInput) : await pushCheckout({
|
|
36055
|
+
const result = operation === "pull" ? await pullCheckout({ ...commonInput, ignoreSettings: "preview" }) : await pushCheckout({
|
|
36056
|
+
ignoreSettings: "preview",
|
|
36057
|
+
...commonInput,
|
|
36058
|
+
dryRun
|
|
36059
|
+
});
|
|
35745
36060
|
formatCheckoutResult(labels.summaryVerb, result, {
|
|
35746
36061
|
detailsRendered: Boolean(progress),
|
|
35747
36062
|
dryRun,
|
|
@@ -35835,6 +36150,7 @@ var assertCheckoutReadyForReadOnlyPull = async (checkout) => {
|
|
|
35835
36150
|
};
|
|
35836
36151
|
var runCheckoutPullThenPush = async ({
|
|
35837
36152
|
checkout,
|
|
36153
|
+
conflictPolicy,
|
|
35838
36154
|
client,
|
|
35839
36155
|
force,
|
|
35840
36156
|
verbose,
|
|
@@ -35852,6 +36168,8 @@ var runCheckoutPullThenPush = async ({
|
|
|
35852
36168
|
}
|
|
35853
36169
|
progress?.start?.();
|
|
35854
36170
|
const result = await syncCheckout({
|
|
36171
|
+
ignoreSettings: "sync",
|
|
36172
|
+
conflictPolicy,
|
|
35855
36173
|
beforeRuleApply: async ({ result: rulePlan }) => {
|
|
35856
36174
|
await confirmReferenceStructuralWrites(
|
|
35857
36175
|
referenceStructuralWriteDetails(rulePlan),
|
|
@@ -35861,6 +36179,8 @@ var runCheckoutPullThenPush = async ({
|
|
|
35861
36179
|
client,
|
|
35862
36180
|
force,
|
|
35863
36181
|
ignorePatterns: checkout.ignore,
|
|
36182
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36183
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35864
36184
|
localPath: checkout.rootDir,
|
|
35865
36185
|
progress,
|
|
35866
36186
|
storeRef: {},
|
|
@@ -35887,10 +36207,13 @@ var assertGitSyncHasNoPushPlan = async ({
|
|
|
35887
36207
|
force
|
|
35888
36208
|
}) => {
|
|
35889
36209
|
const result = await pushCheckout({
|
|
36210
|
+
ignoreSettings: "preview",
|
|
35890
36211
|
client,
|
|
35891
36212
|
dryRun: true,
|
|
35892
36213
|
force,
|
|
35893
36214
|
ignorePatterns: checkout.ignore,
|
|
36215
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36216
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35894
36217
|
localPath: checkout.rootDir,
|
|
35895
36218
|
storeRef: {},
|
|
35896
36219
|
syncRules: checkout.syncRules
|
|
@@ -35914,16 +36237,6 @@ var assertGitSyncHasNoPushPlan = async ({
|
|
|
35914
36237
|
].join("\n")
|
|
35915
36238
|
);
|
|
35916
36239
|
};
|
|
35917
|
-
var refreshStoreIgnoreCache = async (checkout, client) => {
|
|
35918
|
-
const storeRef = await resolveProjectStoreRef();
|
|
35919
|
-
if (!storeRef) {
|
|
35920
|
-
return null;
|
|
35921
|
-
}
|
|
35922
|
-
const metadata = await client.readStoreByRef(storeRef);
|
|
35923
|
-
const storeIgnore = metadata?.ignore ?? [];
|
|
35924
|
-
await writeStoreIgnoreCache(checkout.rootDir, storeIgnore);
|
|
35925
|
-
return { storeIgnore, storeRef };
|
|
35926
|
-
};
|
|
35927
36240
|
var analyzeLocalIgnore = async (checkout) => {
|
|
35928
36241
|
const [files, presentMarkers, gitignorePatterns] = await Promise.all([
|
|
35929
36242
|
collectLocalCheckoutFiles(checkout.rootDir, []),
|
|
@@ -35954,17 +36267,30 @@ var promptIgnoreAction = async () => {
|
|
|
35954
36267
|
};
|
|
35955
36268
|
var isInteractiveTty = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
35956
36269
|
var runIgnoreSetupGate = async (checkout, client, assumeYes) => {
|
|
35957
|
-
const
|
|
35958
|
-
if (!
|
|
35959
|
-
|
|
35960
|
-
|
|
35961
|
-
|
|
35962
|
-
|
|
35963
|
-
|
|
36270
|
+
const storeRef = await resolveProjectStoreRef();
|
|
36271
|
+
if (!storeRef) return;
|
|
36272
|
+
const sharedFilePath = sharedIgnorePath(
|
|
36273
|
+
checkout.rootDir,
|
|
36274
|
+
`${storeRef.workspaceSlug}/${storeRef.storeSlug}`
|
|
36275
|
+
);
|
|
36276
|
+
let storeIgnore = await readSharedIgnoreFile(sharedFilePath);
|
|
36277
|
+
if (storeIgnore === null) {
|
|
36278
|
+
const metadata = await client.readStoreByRef(storeRef);
|
|
36279
|
+
if (!metadata) throw new Error("Store not found for ignore setup.");
|
|
36280
|
+
const restored = await reconcileSharedIgnoreFile({
|
|
36281
|
+
rootDir: checkout.rootDir,
|
|
36282
|
+
sharedFilePath,
|
|
36283
|
+
store: `${storeRef.workspaceSlug}/${storeRef.storeSlug}`,
|
|
36284
|
+
remote: metadata.ignore ?? [],
|
|
36285
|
+
publish: async () => {
|
|
36286
|
+
}
|
|
36287
|
+
});
|
|
36288
|
+
storeIgnore = restored.patterns;
|
|
35964
36289
|
}
|
|
36290
|
+
if (storeIgnore.length > 0) return;
|
|
35965
36291
|
await maybePromptIgnoreSetup({
|
|
35966
36292
|
assumeYes,
|
|
35967
|
-
|
|
36293
|
+
writePatterns: (patterns) => writeSharedIgnoreFile(sharedFilePath, patterns),
|
|
35968
36294
|
analysis: await analyzeLocalIgnore(checkout),
|
|
35969
36295
|
onboarded: await readIgnoreOnboardedAt(checkout.rootDir) !== null,
|
|
35970
36296
|
currentPatterns: storeIgnore,
|
|
@@ -35972,11 +36298,11 @@ var runIgnoreSetupGate = async (checkout, client, assumeYes) => {
|
|
|
35972
36298
|
chooseAction: promptIgnoreAction,
|
|
35973
36299
|
markOnboarded: () => markIgnoreOnboarded(checkout.rootDir),
|
|
35974
36300
|
renderOutput,
|
|
35975
|
-
renderWarning
|
|
35976
|
-
storeRef
|
|
36301
|
+
renderWarning
|
|
35977
36302
|
});
|
|
35978
36303
|
};
|
|
35979
36304
|
var runCheckoutSyncOnce = async ({
|
|
36305
|
+
conflictPolicy,
|
|
35980
36306
|
client,
|
|
35981
36307
|
force,
|
|
35982
36308
|
verbose,
|
|
@@ -35984,17 +36310,27 @@ var runCheckoutSyncOnce = async ({
|
|
|
35984
36310
|
}) => {
|
|
35985
36311
|
const checkout = await resolveCheckoutConfig();
|
|
35986
36312
|
assertCheckoutSyncEnabled(checkout);
|
|
35987
|
-
await runCheckoutPullThenPush({
|
|
36313
|
+
await runCheckoutPullThenPush({
|
|
36314
|
+
checkout,
|
|
36315
|
+
client,
|
|
36316
|
+
conflictPolicy,
|
|
36317
|
+
force,
|
|
36318
|
+
verbose,
|
|
36319
|
+
yes
|
|
36320
|
+
});
|
|
35988
36321
|
};
|
|
35989
36322
|
var DEFAULT_FULL_SYNC_INTERVAL_MS = 5 * 60 * 1e3;
|
|
35990
36323
|
var runCheckoutSyncCollecting = async ({
|
|
35991
36324
|
checkout,
|
|
36325
|
+
conflictPolicy,
|
|
35992
36326
|
client,
|
|
35993
36327
|
force,
|
|
35994
36328
|
yes = false
|
|
35995
36329
|
}) => {
|
|
35996
36330
|
assertCheckoutSyncEnabled(checkout);
|
|
35997
36331
|
return syncCheckout({
|
|
36332
|
+
ignoreSettings: "sync",
|
|
36333
|
+
conflictPolicy,
|
|
35998
36334
|
beforeRuleApply: async ({ result }) => {
|
|
35999
36335
|
await confirmReferenceStructuralWrites(
|
|
36000
36336
|
referenceStructuralWriteDetails(result),
|
|
@@ -36004,6 +36340,8 @@ var runCheckoutSyncCollecting = async ({
|
|
|
36004
36340
|
client,
|
|
36005
36341
|
force,
|
|
36006
36342
|
ignorePatterns: checkout.ignore,
|
|
36343
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36344
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
36007
36345
|
localPath: checkout.rootDir,
|
|
36008
36346
|
storeRef: {},
|
|
36009
36347
|
syncRules: checkout.syncRules
|
|
@@ -36030,14 +36368,15 @@ var runCheckoutStatus = async ({
|
|
|
36030
36368
|
}) => {
|
|
36031
36369
|
const initialCheckout = await resolveCheckoutConfig();
|
|
36032
36370
|
assertCheckoutSyncEnabled(initialCheckout);
|
|
36033
|
-
|
|
36034
|
-
const checkout = await resolveCheckoutConfig();
|
|
36035
|
-
assertCheckoutSyncEnabled(checkout);
|
|
36371
|
+
const checkout = initialCheckout;
|
|
36036
36372
|
const pullResult = await pullCheckout({
|
|
36373
|
+
ignoreSettings: "preview",
|
|
36037
36374
|
client,
|
|
36038
36375
|
dryRun: true,
|
|
36039
36376
|
force,
|
|
36040
36377
|
ignorePatterns: checkout.ignore,
|
|
36378
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36379
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
36041
36380
|
localPath: checkout.rootDir,
|
|
36042
36381
|
storeRef: {},
|
|
36043
36382
|
syncRules: checkout.syncRules
|
|
@@ -36080,10 +36419,13 @@ var runCheckoutStatus = async ({
|
|
|
36080
36419
|
return;
|
|
36081
36420
|
}
|
|
36082
36421
|
const pushResult = await pushCheckout({
|
|
36422
|
+
ignoreSettings: "preview",
|
|
36083
36423
|
client,
|
|
36084
36424
|
dryRun: true,
|
|
36085
36425
|
force,
|
|
36086
36426
|
ignorePatterns: checkout.ignore,
|
|
36427
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36428
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
36087
36429
|
localPath: checkout.rootDir,
|
|
36088
36430
|
storeRef: {},
|
|
36089
36431
|
syncRules: checkout.syncRules
|
|
@@ -36096,18 +36438,18 @@ var runCheckoutStatus = async ({
|
|
|
36096
36438
|
});
|
|
36097
36439
|
};
|
|
36098
36440
|
var isCheckoutStateGitPath = isCheckoutStateDirectoryPath;
|
|
36099
|
-
var checkoutFilesManifestPath2 = (
|
|
36441
|
+
var checkoutFilesManifestPath2 = () => `${resolveCheckoutStateDirectoryName()}/files.json`;
|
|
36100
36442
|
var isInsideOrEqual = (parentPath, childPath2) => {
|
|
36101
|
-
const relativePath =
|
|
36102
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
36443
|
+
const relativePath = path21.relative(parentPath, childPath2);
|
|
36444
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path21.isAbsolute(relativePath);
|
|
36103
36445
|
};
|
|
36104
36446
|
var resolveSyncTargetPaths = (checkout) => checkout.syncRules.map(
|
|
36105
|
-
(rule) =>
|
|
36447
|
+
(rule) => path21.resolve(checkout.rootDir, rule.target || ".")
|
|
36106
36448
|
);
|
|
36107
|
-
var resolveCheckoutManifestGitPath = (checkout, gitRoot) =>
|
|
36449
|
+
var resolveCheckoutManifestGitPath = (checkout, gitRoot) => path21.relative(
|
|
36108
36450
|
gitRoot,
|
|
36109
|
-
|
|
36110
|
-
) || checkoutFilesManifestPath2(
|
|
36451
|
+
path21.join(checkout.rootDir, checkoutFilesManifestPath2())
|
|
36452
|
+
) || checkoutFilesManifestPath2();
|
|
36111
36453
|
var stageCheckoutManifest = async ({
|
|
36112
36454
|
checkout,
|
|
36113
36455
|
gitRoot
|
|
@@ -36132,7 +36474,7 @@ var assertGitChangesStayInSyncTargets = async ({
|
|
|
36132
36474
|
if (isCheckoutStateGitPath(entry.path)) {
|
|
36133
36475
|
return false;
|
|
36134
36476
|
}
|
|
36135
|
-
const absolutePath =
|
|
36477
|
+
const absolutePath = path21.resolve(gitRoot, entry.path);
|
|
36136
36478
|
return !allowedPaths.some(
|
|
36137
36479
|
(allowedPath) => isInsideOrEqual(allowedPath, absolutePath)
|
|
36138
36480
|
);
|
|
@@ -36154,7 +36496,7 @@ var stageGitSyncTargets = async ({
|
|
|
36154
36496
|
}) => {
|
|
36155
36497
|
const targetPaths = [];
|
|
36156
36498
|
for (const targetPath of resolveSyncTargetPaths(checkout)) {
|
|
36157
|
-
const relativePath =
|
|
36499
|
+
const relativePath = path21.relative(gitRoot, targetPath) || ".";
|
|
36158
36500
|
const tracked = await runGit(gitRoot, ["ls-files", "--", relativePath]);
|
|
36159
36501
|
if (await pathExists3(targetPath) || tracked.stdout.trim()) {
|
|
36160
36502
|
targetPaths.push(relativePath);
|
|
@@ -36196,7 +36538,7 @@ var runGitSyncCommand = async ({
|
|
|
36196
36538
|
assertCheckoutSyncEnabled(checkout);
|
|
36197
36539
|
if (!checkout.gitSyncCommitMessage) {
|
|
36198
36540
|
throw new Error(
|
|
36199
|
-
"No Git sync commit message configured. Add git.commit-message to forum.yaml."
|
|
36541
|
+
"No Git sync commit message configured. Add git.commit-message to .forum/sync.yaml."
|
|
36200
36542
|
);
|
|
36201
36543
|
}
|
|
36202
36544
|
const gitRoot = await resolveGitRoot(checkout.rootDir);
|
|
@@ -36229,6 +36571,7 @@ var runCheckoutReadOnlyPullOnce = async ({
|
|
|
36229
36571
|
};
|
|
36230
36572
|
var buildCheckoutWatchEntry = ({
|
|
36231
36573
|
checkout,
|
|
36574
|
+
conflictPolicy,
|
|
36232
36575
|
client,
|
|
36233
36576
|
force,
|
|
36234
36577
|
yes
|
|
@@ -36237,10 +36580,17 @@ var buildCheckoutWatchEntry = ({
|
|
|
36237
36580
|
rootDir: checkout.rootDir,
|
|
36238
36581
|
startMessage: `Watching ${checkout.rootDir}`,
|
|
36239
36582
|
storeRefs: changesFeedStoreRefsForCheckout(checkout),
|
|
36240
|
-
syncOnce: () => runCheckoutSyncCollecting({
|
|
36583
|
+
syncOnce: async () => runCheckoutSyncCollecting({
|
|
36584
|
+
checkout: await resolveCheckoutConfig(checkout.rootDir),
|
|
36585
|
+
client,
|
|
36586
|
+
conflictPolicy,
|
|
36587
|
+
force,
|
|
36588
|
+
yes
|
|
36589
|
+
})
|
|
36241
36590
|
});
|
|
36242
36591
|
var resolveExplicitCheckoutEntry = async ({
|
|
36243
36592
|
checkoutPath,
|
|
36593
|
+
conflictPolicy,
|
|
36244
36594
|
client,
|
|
36245
36595
|
force,
|
|
36246
36596
|
yes
|
|
@@ -36248,13 +36598,20 @@ var resolveExplicitCheckoutEntry = async ({
|
|
|
36248
36598
|
const checkout = await resolveCheckoutConfig(checkoutPath);
|
|
36249
36599
|
if (checkout.rootDir !== checkoutPath) {
|
|
36250
36600
|
throw new Error(
|
|
36251
|
-
`${checkoutPath} is not a Forum checkout (no forum.yaml here).`
|
|
36601
|
+
`${checkoutPath} is not a Forum checkout (no .forum/sync.yaml here).`
|
|
36252
36602
|
);
|
|
36253
36603
|
}
|
|
36254
36604
|
assertCheckoutSyncEnabled(checkout);
|
|
36255
|
-
return buildCheckoutWatchEntry({
|
|
36605
|
+
return buildCheckoutWatchEntry({
|
|
36606
|
+
checkout,
|
|
36607
|
+
client,
|
|
36608
|
+
conflictPolicy,
|
|
36609
|
+
force,
|
|
36610
|
+
yes
|
|
36611
|
+
});
|
|
36256
36612
|
};
|
|
36257
36613
|
var resolveDiscoveredCheckoutEntries = async ({
|
|
36614
|
+
conflictPolicy,
|
|
36258
36615
|
client,
|
|
36259
36616
|
force,
|
|
36260
36617
|
rootPath,
|
|
@@ -36270,7 +36627,9 @@ var resolveDiscoveredCheckoutEntries = async ({
|
|
|
36270
36627
|
if (checkout.syncRules.length === 0) {
|
|
36271
36628
|
continue;
|
|
36272
36629
|
}
|
|
36273
|
-
entries.push(
|
|
36630
|
+
entries.push(
|
|
36631
|
+
buildCheckoutWatchEntry({ checkout, client, conflictPolicy, force, yes })
|
|
36632
|
+
);
|
|
36274
36633
|
}
|
|
36275
36634
|
if (entries.length === 0) {
|
|
36276
36635
|
throw new Error(
|
|
@@ -36280,6 +36639,7 @@ var resolveDiscoveredCheckoutEntries = async ({
|
|
|
36280
36639
|
return entries;
|
|
36281
36640
|
};
|
|
36282
36641
|
var runCheckoutSyncWatch = async ({
|
|
36642
|
+
conflictPolicy,
|
|
36283
36643
|
client,
|
|
36284
36644
|
force,
|
|
36285
36645
|
intervalMs,
|
|
@@ -36352,12 +36712,30 @@ var runCheckoutSyncWatch = async ({
|
|
|
36352
36712
|
{ watchPaths, pathsFile },
|
|
36353
36713
|
{
|
|
36354
36714
|
readPathsFile,
|
|
36355
|
-
resolveDiscoveredEntries: (rootPath) => resolveDiscoveredCheckoutEntries({
|
|
36356
|
-
|
|
36715
|
+
resolveDiscoveredEntries: (rootPath) => resolveDiscoveredCheckoutEntries({
|
|
36716
|
+
client,
|
|
36717
|
+
conflictPolicy,
|
|
36718
|
+
force,
|
|
36719
|
+
rootPath,
|
|
36720
|
+
yes
|
|
36721
|
+
}),
|
|
36722
|
+
resolveExplicitEntry: (checkoutPath) => resolveExplicitCheckoutEntry({
|
|
36723
|
+
checkoutPath,
|
|
36724
|
+
client,
|
|
36725
|
+
conflictPolicy,
|
|
36726
|
+
force,
|
|
36727
|
+
yes
|
|
36728
|
+
}),
|
|
36357
36729
|
resolveSingleCheckoutEntry: async () => {
|
|
36358
36730
|
const checkout = await resolveCheckoutConfig();
|
|
36359
36731
|
assertCheckoutSyncEnabled(checkout);
|
|
36360
|
-
return buildCheckoutWatchEntry({
|
|
36732
|
+
return buildCheckoutWatchEntry({
|
|
36733
|
+
checkout,
|
|
36734
|
+
client,
|
|
36735
|
+
conflictPolicy,
|
|
36736
|
+
force,
|
|
36737
|
+
yes
|
|
36738
|
+
});
|
|
36361
36739
|
}
|
|
36362
36740
|
}
|
|
36363
36741
|
);
|
|
@@ -36414,11 +36792,11 @@ var resolveReadableStore = async (storeInput, client) => {
|
|
|
36414
36792
|
var writeCheckoutConfig = async (directoryPath, metadata, workspaceSlug, options2 = {}) => {
|
|
36415
36793
|
if (!workspaceSlug) {
|
|
36416
36794
|
throw new Error(
|
|
36417
|
-
`Store ${metadata.slug} is missing a workspace slug and cannot be written to forum.yaml.`
|
|
36795
|
+
`Store ${metadata.slug} is missing a workspace slug and cannot be written to .forum/sync.yaml.`
|
|
36418
36796
|
);
|
|
36419
36797
|
}
|
|
36420
36798
|
await writeForumProjectConfig(
|
|
36421
|
-
|
|
36799
|
+
path21.join(directoryPath, defaultProjectConfigFilename),
|
|
36422
36800
|
{
|
|
36423
36801
|
syncRules: [
|
|
36424
36802
|
{
|
|
@@ -36434,6 +36812,18 @@ var writeCheckoutConfig = async (directoryPath, metadata, workspaceSlug, options
|
|
|
36434
36812
|
]
|
|
36435
36813
|
}
|
|
36436
36814
|
);
|
|
36815
|
+
await reconcileSharedIgnoreFile({
|
|
36816
|
+
rootDir: directoryPath,
|
|
36817
|
+
sharedFilePath: sharedIgnorePath(
|
|
36818
|
+
directoryPath,
|
|
36819
|
+
`${workspaceSlug}/${metadata.slug}`
|
|
36820
|
+
),
|
|
36821
|
+
store: `${workspaceSlug}/${metadata.slug}`,
|
|
36822
|
+
remote: metadata.ignore ?? [],
|
|
36823
|
+
publish: async () => {
|
|
36824
|
+
throw new Error("Initialization cannot publish ignore rules.");
|
|
36825
|
+
}
|
|
36826
|
+
});
|
|
36437
36827
|
};
|
|
36438
36828
|
var normalizeProjectConfigPath = (value, fieldName, allowCurrentDirectory = false) => {
|
|
36439
36829
|
const trimmed = value.trim().replace(/^\/+/, "").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
@@ -36443,7 +36833,7 @@ var normalizeProjectConfigPath = (value, fieldName, allowCurrentDirectory = fals
|
|
|
36443
36833
|
}
|
|
36444
36834
|
throw new Error(`${fieldName} must be a non-empty relative path.`);
|
|
36445
36835
|
}
|
|
36446
|
-
if (
|
|
36836
|
+
if (path21.isAbsolute(value)) {
|
|
36447
36837
|
throw new Error(`${fieldName} must be a relative path.`);
|
|
36448
36838
|
}
|
|
36449
36839
|
const segments2 = trimmed.split("/");
|
|
@@ -36496,7 +36886,7 @@ var runProjectConfigSyncCommand = async (mode, args) => {
|
|
|
36496
36886
|
const projectConfig = await findForumProjectConfig();
|
|
36497
36887
|
if (!projectConfig) {
|
|
36498
36888
|
throw new Error(
|
|
36499
|
-
"No forum.yaml found. Run fm init <store> before configuring project sync."
|
|
36889
|
+
"No .forum/sync.yaml found. Run fm init <store> before configuring project sync."
|
|
36500
36890
|
);
|
|
36501
36891
|
}
|
|
36502
36892
|
if (mode === "clear") {
|
|
@@ -36599,7 +36989,7 @@ var runProjectConfigSyncCommand = async (mode, args) => {
|
|
|
36599
36989
|
var runProjectConfigValidateCommand = async () => {
|
|
36600
36990
|
const projectConfig = await findForumProjectConfig();
|
|
36601
36991
|
if (!projectConfig) {
|
|
36602
|
-
throw new Error("No forum.yaml found.");
|
|
36992
|
+
throw new Error("No .forum/sync.yaml found.");
|
|
36603
36993
|
}
|
|
36604
36994
|
renderOutput(`Valid Forum config: ${projectConfig.path}`);
|
|
36605
36995
|
renderOutput(
|
|
@@ -36609,7 +36999,7 @@ var runProjectConfigValidateCommand = async () => {
|
|
|
36609
36999
|
var runProjectConfigStandardizeCommand = async () => {
|
|
36610
37000
|
const projectConfig = await findForumProjectConfig();
|
|
36611
37001
|
if (!projectConfig) {
|
|
36612
|
-
throw new Error("No forum.yaml found.");
|
|
37002
|
+
throw new Error("No .forum/sync.yaml found.");
|
|
36613
37003
|
}
|
|
36614
37004
|
await writeForumProjectConfig(projectConfig.path, {
|
|
36615
37005
|
defaultStore: projectConfig.defaultStore,
|
|
@@ -36625,7 +37015,7 @@ var defaultCloneDirectoryName = (storeId) => {
|
|
|
36625
37015
|
var fsErrorCode = (error51) => error51 instanceof Error && "code" in error51 ? String(error51.code ?? "") : "";
|
|
36626
37016
|
var ensureGitMetadataExists = async (directoryPath) => {
|
|
36627
37017
|
try {
|
|
36628
|
-
await lstat2(
|
|
37018
|
+
await lstat2(path21.join(directoryPath, ".git"));
|
|
36629
37019
|
} catch (error51) {
|
|
36630
37020
|
if (fsErrorCode(error51) === "ENOENT") {
|
|
36631
37021
|
throw new Error(
|
|
@@ -36663,8 +37053,8 @@ var confirmGitMetadataDeletion = async (localPath, assumeYes) => {
|
|
|
36663
37053
|
"Refusing to delete .git without interactive confirmation. Rerun with --yes to confirm in a non-interactive shell."
|
|
36664
37054
|
);
|
|
36665
37055
|
}
|
|
36666
|
-
const gitPath =
|
|
36667
|
-
const gitignorePath =
|
|
37056
|
+
const gitPath = path21.join(localPath, ".git");
|
|
37057
|
+
const gitignorePath = path21.join(localPath, ".gitignore");
|
|
36668
37058
|
const confirmationPhrase = "DELETE GIT";
|
|
36669
37059
|
renderWarning("");
|
|
36670
37060
|
renderWarning("DANGER: Forum is about to remove Git from this checkout.");
|
|
@@ -36706,11 +37096,11 @@ var runGitConvertCommand = async ({
|
|
|
36706
37096
|
const { created, metadata, workspaceSlug, storeRef } = await resolveOrCreateConversionStore(storeInput, client);
|
|
36707
37097
|
if (!workspaceSlug) {
|
|
36708
37098
|
throw new Error(
|
|
36709
|
-
`Store ${metadata.slug} is missing a workspace slug and cannot be written to forum.yaml.`
|
|
37099
|
+
`Store ${metadata.slug} is missing a workspace slug and cannot be written to .forum/sync.yaml.`
|
|
36710
37100
|
);
|
|
36711
37101
|
}
|
|
36712
37102
|
await writeForumProjectConfig(
|
|
36713
|
-
|
|
37103
|
+
path21.join(localPath, defaultProjectConfigFilename),
|
|
36714
37104
|
{
|
|
36715
37105
|
syncRules: [
|
|
36716
37106
|
{
|
|
@@ -36725,14 +37115,24 @@ var runGitConvertCommand = async ({
|
|
|
36725
37115
|
]
|
|
36726
37116
|
}
|
|
36727
37117
|
);
|
|
36728
|
-
|
|
36729
|
-
|
|
36730
|
-
|
|
36731
|
-
|
|
36732
|
-
|
|
36733
|
-
|
|
37118
|
+
await reconcileSharedIgnoreFile({
|
|
37119
|
+
rootDir: localPath,
|
|
37120
|
+
sharedFilePath: sharedIgnorePath(
|
|
37121
|
+
localPath,
|
|
37122
|
+
`${workspaceSlug}/${metadata.slug}`
|
|
37123
|
+
),
|
|
37124
|
+
store: `${workspaceSlug}/${metadata.slug}`,
|
|
37125
|
+
remote: metadata.ignore ?? [],
|
|
37126
|
+
publish: async () => {
|
|
37127
|
+
}
|
|
37128
|
+
});
|
|
37129
|
+
await writeSharedIgnoreFile(
|
|
37130
|
+
sharedIgnorePath(localPath, `${workspaceSlug}/${metadata.slug}`),
|
|
37131
|
+
[...metadata.ignore ?? [], ...ignorePatterns]
|
|
37132
|
+
);
|
|
36734
37133
|
const conversionIgnorePatterns = [...ignorePatterns, ".gitignore"];
|
|
36735
37134
|
await pushCheckout({
|
|
37135
|
+
ignoreSettings: "preview",
|
|
36736
37136
|
client,
|
|
36737
37137
|
dryRun: true,
|
|
36738
37138
|
force,
|
|
@@ -36741,6 +37141,7 @@ var runGitConvertCommand = async ({
|
|
|
36741
37141
|
storeRef
|
|
36742
37142
|
});
|
|
36743
37143
|
const result = await pushCheckout({
|
|
37144
|
+
ignoreSettings: "preview",
|
|
36744
37145
|
client,
|
|
36745
37146
|
force,
|
|
36746
37147
|
ignorePatterns: conversionIgnorePatterns,
|
|
@@ -36761,8 +37162,8 @@ var runGitConvertCommand = async ({
|
|
|
36761
37162
|
"Aborted before deleting Git metadata. The Forum push completed, but .git and .gitignore were left in place."
|
|
36762
37163
|
);
|
|
36763
37164
|
}
|
|
36764
|
-
await
|
|
36765
|
-
await
|
|
37165
|
+
await rm5(path21.join(localPath, ".gitignore"), { force: true });
|
|
37166
|
+
await rm5(path21.join(localPath, ".git"), { recursive: true, force: true });
|
|
36766
37167
|
renderOutput(
|
|
36767
37168
|
`${created ? "Created" : "Using existing"} store ${metadata.slug}`
|
|
36768
37169
|
);
|
|
@@ -36880,7 +37281,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
36880
37281
|
}
|
|
36881
37282
|
if (command === "hash" && parsed.local) {
|
|
36882
37283
|
const filePath = rest[0];
|
|
36883
|
-
renderOutput(await hashLocalFile(
|
|
37284
|
+
renderOutput(await hashLocalFile(path21.resolve(filePath)));
|
|
36884
37285
|
return;
|
|
36885
37286
|
}
|
|
36886
37287
|
const config2 = await resolveConfig(parsed);
|
|
@@ -37154,26 +37555,45 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37154
37555
|
const subcommand = rest[0];
|
|
37155
37556
|
const checkout = await resolveCheckoutConfig();
|
|
37156
37557
|
assertCheckoutSyncEnabled(checkout);
|
|
37157
|
-
const
|
|
37158
|
-
|
|
37558
|
+
const stores = [...new Set(checkout.syncRules.map((rule2) => rule2.store))];
|
|
37559
|
+
const requested = parsed.storeFilters;
|
|
37560
|
+
const candidates = requested.length ? stores.filter(
|
|
37561
|
+
(store2) => requested.includes(store2) || requested.includes(store2.split("/").at(-1))
|
|
37562
|
+
) : stores;
|
|
37563
|
+
if (candidates.length !== 1)
|
|
37159
37564
|
throw new Error(
|
|
37160
|
-
"
|
|
37565
|
+
"Select one configured store with fm ignore --store workspace/store."
|
|
37161
37566
|
);
|
|
37567
|
+
const store = candidates[0];
|
|
37568
|
+
const rule = checkout.syncRules.find((entry) => entry.store === store);
|
|
37569
|
+
const sharedFilePath = sharedIgnorePath(checkout.rootDir, store);
|
|
37570
|
+
let currentPatterns = await readSharedIgnoreFile(sharedFilePath);
|
|
37571
|
+
if (currentPatterns === null) {
|
|
37572
|
+
const metadata = await client.readStoreByRef({
|
|
37573
|
+
workspaceSlug: rule.storeOwner,
|
|
37574
|
+
storeSlug: rule.storeSlug
|
|
37575
|
+
});
|
|
37576
|
+
if (!metadata) throw new Error(`Store not found: ${store}`);
|
|
37577
|
+
await reconcileSharedIgnoreFile({
|
|
37578
|
+
rootDir: checkout.rootDir,
|
|
37579
|
+
sharedFilePath,
|
|
37580
|
+
store,
|
|
37581
|
+
remote: metadata.ignore ?? [],
|
|
37582
|
+
publish: async () => {
|
|
37583
|
+
}
|
|
37584
|
+
});
|
|
37585
|
+
currentPatterns = metadata.ignore ?? [];
|
|
37162
37586
|
}
|
|
37163
|
-
const metadata = await client.readStoreByRef(storeRef);
|
|
37164
|
-
const currentPatterns = metadata?.ignore ?? [];
|
|
37165
37587
|
await runIgnoreCommand({
|
|
37166
|
-
|
|
37167
|
-
client,
|
|
37588
|
+
writePatterns: (patterns) => writeSharedIgnoreFile(sharedFilePath, patterns),
|
|
37168
37589
|
commandNames,
|
|
37169
37590
|
confirmYesNo,
|
|
37170
|
-
currentPatterns,
|
|
37591
|
+
currentPatterns: currentPatterns ?? [],
|
|
37171
37592
|
analyzeLocal: () => analyzeLocalIgnore(checkout),
|
|
37172
37593
|
markOnboarded: () => markIgnoreOnboarded(checkout.rootDir),
|
|
37173
37594
|
pattern: rest[1],
|
|
37174
37595
|
patterns: rest.slice(1),
|
|
37175
37596
|
renderOutput,
|
|
37176
|
-
storeRef,
|
|
37177
37597
|
subcommand,
|
|
37178
37598
|
assumeYes: parsed.yes
|
|
37179
37599
|
});
|
|
@@ -37252,7 +37672,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37252
37672
|
}
|
|
37253
37673
|
const checkout = await resolveCheckoutConfig();
|
|
37254
37674
|
assertCheckoutSyncEnabled(checkout);
|
|
37255
|
-
await runIgnoreSetupGate(checkout, client, parsed.yes);
|
|
37675
|
+
if (!parsed.dryRun) await runIgnoreSetupGate(checkout, client, parsed.yes);
|
|
37256
37676
|
await runCheckoutPush({
|
|
37257
37677
|
checkout,
|
|
37258
37678
|
client,
|
|
@@ -37265,12 +37685,41 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37265
37685
|
return;
|
|
37266
37686
|
}
|
|
37267
37687
|
if (command === "sync") {
|
|
37688
|
+
if (parsed.conflictPolicy && (parsed.force || parsed.readonly)) {
|
|
37689
|
+
throw new Error(
|
|
37690
|
+
"--conflict cannot be combined with --force or --readonly."
|
|
37691
|
+
);
|
|
37692
|
+
}
|
|
37268
37693
|
if (rest[0] === "reset") {
|
|
37269
37694
|
const checkout = await resolveCheckoutConfig();
|
|
37270
37695
|
await resetCheckoutSyncState(checkout.rootDir);
|
|
37271
37696
|
renderOutput("Cleared local checkout sync state.");
|
|
37272
37697
|
return;
|
|
37273
37698
|
}
|
|
37699
|
+
if (parsed.dryRun && parsed.conflictPolicy) {
|
|
37700
|
+
const checkout = await resolveCheckoutConfig();
|
|
37701
|
+
assertCheckoutSyncEnabled(checkout);
|
|
37702
|
+
const result = await syncCheckout({
|
|
37703
|
+
ignoreSettings: "sync",
|
|
37704
|
+
client,
|
|
37705
|
+
conflictPolicy: parsed.conflictPolicy,
|
|
37706
|
+
dryRun: true,
|
|
37707
|
+
force: false,
|
|
37708
|
+
ignorePatterns: checkout.ignore,
|
|
37709
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
37710
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
37711
|
+
localPath: checkout.rootDir,
|
|
37712
|
+
storeRef: {},
|
|
37713
|
+
syncRules: checkout.syncRules
|
|
37714
|
+
});
|
|
37715
|
+
if (parsed.json) renderOutput({ type: "checkout-sync-plan", ...result });
|
|
37716
|
+
else
|
|
37717
|
+
formatCheckoutResult("Planned", result, {
|
|
37718
|
+
syncRules: checkout.syncRules,
|
|
37719
|
+
verbose: parsed.verbose
|
|
37720
|
+
});
|
|
37721
|
+
return;
|
|
37722
|
+
}
|
|
37274
37723
|
if (parsed.dryRun) {
|
|
37275
37724
|
await withActivity(
|
|
37276
37725
|
"Checking status",
|
|
@@ -37284,6 +37733,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37284
37733
|
}
|
|
37285
37734
|
if (parsed.watch) {
|
|
37286
37735
|
await runCheckoutSyncWatch({
|
|
37736
|
+
conflictPolicy: parsed.conflictPolicy,
|
|
37287
37737
|
client,
|
|
37288
37738
|
force: parsed.force,
|
|
37289
37739
|
intervalMs: config2.pollIntervalMs,
|
|
@@ -37311,6 +37761,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37311
37761
|
}
|
|
37312
37762
|
await runIgnoreSetupGate(await resolveCheckoutConfig(), client, parsed.yes);
|
|
37313
37763
|
await runCheckoutSyncOnce({
|
|
37764
|
+
conflictPolicy: parsed.conflictPolicy,
|
|
37314
37765
|
client,
|
|
37315
37766
|
force: parsed.force,
|
|
37316
37767
|
verbose: parsed.verbose,
|
|
@@ -37352,8 +37803,8 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37352
37803
|
`Usage: ${commandNames} clone <storeId> [localPath] [--readonly]`
|
|
37353
37804
|
);
|
|
37354
37805
|
}
|
|
37355
|
-
const localPath =
|
|
37356
|
-
rest[1] ??
|
|
37806
|
+
const localPath = path21.resolve(
|
|
37807
|
+
rest[1] ?? path21.join(process.cwd(), defaultCloneDirectoryName(remoteInput))
|
|
37357
37808
|
);
|
|
37358
37809
|
const { metadata, workspaceSlug, storeRef } = await resolveReadableStore(
|
|
37359
37810
|
remoteInput,
|
|
@@ -37371,14 +37822,17 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37371
37822
|
verbose: parsed.verbose
|
|
37372
37823
|
});
|
|
37373
37824
|
const result = await pullCheckout({
|
|
37825
|
+
ignoreSettings: "preview",
|
|
37374
37826
|
client,
|
|
37375
37827
|
ignorePatterns: checkout.ignore,
|
|
37828
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
37829
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
37376
37830
|
localPath: checkout.rootDir,
|
|
37377
37831
|
progress,
|
|
37378
37832
|
storeRef,
|
|
37379
37833
|
syncRules: checkout.syncRules
|
|
37380
37834
|
});
|
|
37381
|
-
renderOutput(`Cloned store ${metadata.slug} to ${
|
|
37835
|
+
renderOutput(`Cloned store ${metadata.slug} to ${path21.resolve(localPath)}`);
|
|
37382
37836
|
formatCheckoutResult("Pulled", result, {
|
|
37383
37837
|
detailsRendered: Boolean(progress),
|
|
37384
37838
|
verbose: parsed.verbose
|