@mp-lb/forum-cli 0.1.2 → 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 +1567 -954
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1753,18 +1753,365 @@ 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
|
-
import { createInterface } from "readline/promises";
|
|
2114
|
+
import { createInterface as createInterface2 } from "readline/promises";
|
|
1768
2115
|
import { pathToFileURL } from "url";
|
|
1769
2116
|
import { parse as parseYaml } from "yaml";
|
|
1770
2117
|
|
|
@@ -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),
|
|
@@ -18345,7 +18692,9 @@ var listSearchReconciliationStoresInputSchema = external_exports.object({
|
|
|
18345
18692
|
limit: external_exports.number().int().min(1).max(500).default(100),
|
|
18346
18693
|
touchedAfter: external_exports.string().datetime()
|
|
18347
18694
|
});
|
|
18348
|
-
var listOwnStoresInputSchema = external_exports.object({
|
|
18695
|
+
var listOwnStoresInputSchema = external_exports.object({
|
|
18696
|
+
workspaceId: external_exports.string().trim().min(1).optional()
|
|
18697
|
+
});
|
|
18349
18698
|
var readStoreMetadataInputSchema = external_exports.object({
|
|
18350
18699
|
workspaceId: storeWorkspaceIdSchema,
|
|
18351
18700
|
storeId: storeIdSchema
|
|
@@ -18432,10 +18781,15 @@ var pinnedStoreIdsValueSchema = external_exports.array(storePreferenceIdSchema);
|
|
|
18432
18781
|
var recentStoresValueSchema = external_exports.array(recentStoreVisitSchema);
|
|
18433
18782
|
var pinnedStoreIdsSchema = pinnedStoreIdsValueSchema.default([]);
|
|
18434
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
|
+
);
|
|
18435
18788
|
var userPreferencesSchema = external_exports.object({
|
|
18436
18789
|
id: storeOwnerIdSchema,
|
|
18437
18790
|
pinnedStoreIds: pinnedStoreIdsSchema,
|
|
18438
18791
|
recentStores: recentStoresSchema,
|
|
18792
|
+
createTypeLastUsedAt: createTypeLastUsedAtSchema.default({}),
|
|
18439
18793
|
recentStoresEnabled: external_exports.boolean().default(true),
|
|
18440
18794
|
showHomeWelcomeBanner: external_exports.boolean().default(true),
|
|
18441
18795
|
showHiddenFiles: external_exports.boolean().default(false),
|
|
@@ -18455,6 +18809,7 @@ var userPreferencesSchema = external_exports.object({
|
|
|
18455
18809
|
var userPreferencesUpdateSchema = external_exports.object({
|
|
18456
18810
|
pinnedStoreIds: pinnedStoreIdsValueSchema,
|
|
18457
18811
|
recentStores: recentStoresValueSchema,
|
|
18812
|
+
createTypeLastUsedAt: createTypeLastUsedAtSchema,
|
|
18458
18813
|
recentStoresEnabled: external_exports.boolean(),
|
|
18459
18814
|
showHomeWelcomeBanner: external_exports.boolean(),
|
|
18460
18815
|
showHiddenFiles: external_exports.boolean(),
|
|
@@ -19187,21 +19542,21 @@ var isKey = (value) => /^\w*$/.test(value);
|
|
|
19187
19542
|
var isUndefined = (val) => val === void 0;
|
|
19188
19543
|
var compact = (value) => Array.isArray(value) ? value.filter(Boolean) : [];
|
|
19189
19544
|
var stringToPath = (input) => compact(input.replace(/["|']|\]/g, "").split(/\.|\[/));
|
|
19190
|
-
var get = (object2,
|
|
19191
|
-
if (!
|
|
19545
|
+
var get = (object2, path22, defaultValue) => {
|
|
19546
|
+
if (!path22 || !isObject2(object2)) {
|
|
19192
19547
|
return defaultValue;
|
|
19193
19548
|
}
|
|
19194
|
-
const paths = isKey(
|
|
19549
|
+
const paths = isKey(path22) ? [path22] : stringToPath(path22);
|
|
19195
19550
|
const result = paths.reduce((result2, key) => {
|
|
19196
19551
|
return isNullOrUndefined(result2) ? void 0 : result2[key];
|
|
19197
19552
|
}, object2);
|
|
19198
|
-
return isUndefined(result) || result === object2 ? isUndefined(object2[
|
|
19553
|
+
return isUndefined(result) || result === object2 ? isUndefined(object2[path22]) ? defaultValue : object2[path22] : result;
|
|
19199
19554
|
};
|
|
19200
19555
|
var isBoolean = (value) => typeof value === "boolean";
|
|
19201
19556
|
var isFunction = (value) => typeof value === "function";
|
|
19202
|
-
var set2 = (object2,
|
|
19557
|
+
var set2 = (object2, path22, value) => {
|
|
19203
19558
|
let index = -1;
|
|
19204
|
-
const tempPath = isKey(
|
|
19559
|
+
const tempPath = isKey(path22) ? [path22] : stringToPath(path22);
|
|
19205
19560
|
const length = tempPath.length;
|
|
19206
19561
|
const lastIndex = length - 1;
|
|
19207
19562
|
while (++index < length) {
|
|
@@ -19399,12 +19754,12 @@ function isEmptyArray(obj) {
|
|
|
19399
19754
|
}
|
|
19400
19755
|
return true;
|
|
19401
19756
|
}
|
|
19402
|
-
function unset(object2,
|
|
19403
|
-
if (isString(
|
|
19404
|
-
delete object2[
|
|
19757
|
+
function unset(object2, path22) {
|
|
19758
|
+
if (isString(path22) && Object.prototype.hasOwnProperty.call(object2, path22)) {
|
|
19759
|
+
delete object2[path22];
|
|
19405
19760
|
return object2;
|
|
19406
19761
|
}
|
|
19407
|
-
const paths = Array.isArray(
|
|
19762
|
+
const paths = Array.isArray(path22) ? path22 : isKey(path22) ? [path22] : stringToPath(path22);
|
|
19408
19763
|
const childObject = paths.length === 1 ? object2 : baseGet(object2, paths);
|
|
19409
19764
|
const index = paths.length - 1;
|
|
19410
19765
|
const key = paths[index];
|
|
@@ -23129,7 +23484,7 @@ var publicActionSubmitResultSchema = external_exports.unknown();
|
|
|
23129
23484
|
|
|
23130
23485
|
// ../../packages/core/src/widgetRuntime.ts
|
|
23131
23486
|
var widgetRuntimeOutputPathSchema = storePathSchema.refine(
|
|
23132
|
-
(
|
|
23487
|
+
(path22) => path22 !== "/",
|
|
23133
23488
|
{
|
|
23134
23489
|
message: "Path must not be the root directory."
|
|
23135
23490
|
}
|
|
@@ -23179,7 +23534,7 @@ var widgetRuntimeCompleteAttachmentUploadInputSchema = storeRefSchema.safeExtend
|
|
|
23179
23534
|
treeVisibility: external_exports.enum(["visible", "hidden"]).optional(),
|
|
23180
23535
|
uploadIntentId: external_exports.string().trim().min(1)
|
|
23181
23536
|
});
|
|
23182
|
-
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("//"), {
|
|
23183
23538
|
message: "Link path must be a relative application path."
|
|
23184
23539
|
});
|
|
23185
23540
|
var widgetRuntimeCreateSigningLinkInputSchema = storeRefSchema.safeExtend({
|
|
@@ -23230,168 +23585,10 @@ var storeMemberSchema = external_exports.object({
|
|
|
23230
23585
|
createdAt: external_exports.string().datetime().default(() => (/* @__PURE__ */ new Date()).toISOString())
|
|
23231
23586
|
});
|
|
23232
23587
|
|
|
23233
|
-
// ../../packages/core/src/storeIgnore.ts
|
|
23234
|
-
var segments = (relativePath) => relativePath.split("/").filter(Boolean);
|
|
23235
|
-
var basename = (relativePath) => {
|
|
23236
|
-
const parts = segments(relativePath);
|
|
23237
|
-
return parts[parts.length - 1] ?? "";
|
|
23238
|
-
};
|
|
23239
|
-
var dirRule = (name) => ({
|
|
23240
|
-
label: name,
|
|
23241
|
-
pattern: `${name}/`,
|
|
23242
|
-
matches: (relativePath) => segments(relativePath).slice(0, -1).includes(name)
|
|
23243
|
-
});
|
|
23244
|
-
var ENV_EXAMPLE_SUFFIXES = [".example", ".sample", ".template", ".dist"];
|
|
23245
|
-
var envRule = {
|
|
23246
|
-
label: ".env",
|
|
23247
|
-
pattern: ".env",
|
|
23248
|
-
matches: (relativePath) => {
|
|
23249
|
-
const name = basename(relativePath);
|
|
23250
|
-
if (name !== ".env" && !name.startsWith(".env.")) {
|
|
23251
|
-
return false;
|
|
23252
|
-
}
|
|
23253
|
-
return !ENV_EXAMPLE_SUFFIXES.some((suffix) => name.endsWith(suffix));
|
|
23254
|
-
}
|
|
23255
|
-
};
|
|
23256
|
-
var logRule = {
|
|
23257
|
-
label: "*.log",
|
|
23258
|
-
pattern: "*.log",
|
|
23259
|
-
matches: (relativePath) => basename(relativePath).endsWith(".log")
|
|
23260
|
-
};
|
|
23261
|
-
var vitepressRule = {
|
|
23262
|
-
label: ".vitepress/cache",
|
|
23263
|
-
pattern: ".vitepress/cache/",
|
|
23264
|
-
matches: (relativePath) => relativePath.includes(".vitepress/cache/") || relativePath.includes(".vitepress/dist/")
|
|
23265
|
-
};
|
|
23266
|
-
var KNOWN_JUNK_RULES = [
|
|
23267
|
-
dirRule("node_modules"),
|
|
23268
|
-
dirRule("dist"),
|
|
23269
|
-
dirRule("build"),
|
|
23270
|
-
dirRule(".next"),
|
|
23271
|
-
dirRule(".nuxt"),
|
|
23272
|
-
dirRule(".svelte-kit"),
|
|
23273
|
-
dirRule(".turbo"),
|
|
23274
|
-
dirRule(".cache"),
|
|
23275
|
-
dirRule("coverage"),
|
|
23276
|
-
dirRule("target"),
|
|
23277
|
-
dirRule("__pycache__"),
|
|
23278
|
-
dirRule(".venv"),
|
|
23279
|
-
vitepressRule,
|
|
23280
|
-
envRule,
|
|
23281
|
-
logRule
|
|
23282
|
-
];
|
|
23283
|
-
var detectJunk = (paths, rules = KNOWN_JUNK_RULES) => {
|
|
23284
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
23285
|
-
for (const path20 of paths) {
|
|
23286
|
-
const rule = rules.find((candidate) => candidate.matches(path20));
|
|
23287
|
-
if (!rule) continue;
|
|
23288
|
-
const existing = grouped.get(rule);
|
|
23289
|
-
if (existing) existing.push(path20);
|
|
23290
|
-
else grouped.set(rule, [path20]);
|
|
23291
|
-
}
|
|
23292
|
-
return rules.filter((rule) => grouped.has(rule)).map((rule) => ({
|
|
23293
|
-
rule,
|
|
23294
|
-
paths: [...grouped.get(rule) ?? []].sort(
|
|
23295
|
-
(left, right) => left < right ? -1 : left > right ? 1 : 0
|
|
23296
|
-
)
|
|
23297
|
-
}));
|
|
23298
|
-
};
|
|
23299
|
-
var IGNORE_PROPOSAL_RULES = [
|
|
23300
|
-
{ marker: "package.json", markerKind: "file", patterns: ["node_modules/"] },
|
|
23301
|
-
{ marker: ".vitepress", markerKind: "dir", patterns: [".vitepress/cache/"] },
|
|
23302
|
-
{ marker: "next.config.js", markerKind: "file", patterns: [".next/"] },
|
|
23303
|
-
{ marker: "next.config.mjs", markerKind: "file", patterns: [".next/"] },
|
|
23304
|
-
{ marker: "Cargo.toml", markerKind: "file", patterns: ["target/"] },
|
|
23305
|
-
{
|
|
23306
|
-
marker: "pyproject.toml",
|
|
23307
|
-
markerKind: "file",
|
|
23308
|
-
patterns: ["__pycache__/", ".venv/"]
|
|
23309
|
-
}
|
|
23310
|
-
];
|
|
23311
|
-
var analyzeIgnoreSignals = ({
|
|
23312
|
-
presentPaths,
|
|
23313
|
-
presentMarkers,
|
|
23314
|
-
gitignorePatterns = [],
|
|
23315
|
-
rules = KNOWN_JUNK_RULES,
|
|
23316
|
-
proposalRules = IGNORE_PROPOSAL_RULES
|
|
23317
|
-
}) => {
|
|
23318
|
-
const findings = [];
|
|
23319
|
-
const seen = /* @__PURE__ */ new Set();
|
|
23320
|
-
const add = (finding) => {
|
|
23321
|
-
if (seen.has(finding.pattern)) return;
|
|
23322
|
-
seen.add(finding.pattern);
|
|
23323
|
-
findings.push(finding);
|
|
23324
|
-
};
|
|
23325
|
-
for (const group of detectJunk(presentPaths, rules)) {
|
|
23326
|
-
add({
|
|
23327
|
-
source: "present",
|
|
23328
|
-
severity: "imminent",
|
|
23329
|
-
label: group.rule.label,
|
|
23330
|
-
pattern: group.rule.pattern,
|
|
23331
|
-
matchedPaths: group.paths
|
|
23332
|
-
});
|
|
23333
|
-
}
|
|
23334
|
-
for (const rule of proposalRules) {
|
|
23335
|
-
if (!presentMarkers.has(rule.marker)) continue;
|
|
23336
|
-
for (const pattern of rule.patterns) {
|
|
23337
|
-
add({
|
|
23338
|
-
source: "marker",
|
|
23339
|
-
severity: "predicted",
|
|
23340
|
-
label: `${rule.marker} \u2192 ${pattern}`,
|
|
23341
|
-
pattern,
|
|
23342
|
-
matchedPaths: []
|
|
23343
|
-
});
|
|
23344
|
-
}
|
|
23345
|
-
}
|
|
23346
|
-
for (const pattern of gitignorePatterns) {
|
|
23347
|
-
const trimmed = pattern.trim();
|
|
23348
|
-
if (!trimmed) continue;
|
|
23349
|
-
add({
|
|
23350
|
-
source: "gitignore",
|
|
23351
|
-
severity: "predicted",
|
|
23352
|
-
label: trimmed,
|
|
23353
|
-
pattern: trimmed,
|
|
23354
|
-
matchedPaths: []
|
|
23355
|
-
});
|
|
23356
|
-
}
|
|
23357
|
-
const maxSeverity = findings.some(
|
|
23358
|
-
(finding) => finding.severity === "imminent"
|
|
23359
|
-
) ? "imminent" : findings.length > 0 ? "predicted" : null;
|
|
23360
|
-
return {
|
|
23361
|
-
findings,
|
|
23362
|
-
proposedPatterns: findings.map((finding) => finding.pattern),
|
|
23363
|
-
maxSeverity
|
|
23364
|
-
};
|
|
23365
|
-
};
|
|
23366
|
-
var resolveIgnorePatterns = ({
|
|
23367
|
-
bakedIn,
|
|
23368
|
-
storeSetting,
|
|
23369
|
-
localOverride
|
|
23370
|
-
}) => {
|
|
23371
|
-
const seen = /* @__PURE__ */ new Set();
|
|
23372
|
-
const resolved = [];
|
|
23373
|
-
for (const pattern of [...bakedIn, ...storeSetting, ...localOverride]) {
|
|
23374
|
-
const trimmed = pattern.trim();
|
|
23375
|
-
if (!trimmed || seen.has(trimmed)) continue;
|
|
23376
|
-
seen.add(trimmed);
|
|
23377
|
-
resolved.push(trimmed);
|
|
23378
|
-
}
|
|
23379
|
-
return resolved;
|
|
23380
|
-
};
|
|
23381
|
-
var parseLocalIgnoreFile = (text) => {
|
|
23382
|
-
const patterns = [];
|
|
23383
|
-
for (const rawLine of text.split(/\r?\n/)) {
|
|
23384
|
-
const line = rawLine.trim();
|
|
23385
|
-
if (!line || line.startsWith("#")) continue;
|
|
23386
|
-
patterns.push(line);
|
|
23387
|
-
}
|
|
23388
|
-
return patterns;
|
|
23389
|
-
};
|
|
23390
|
-
|
|
23391
23588
|
// ../../packages/store-tree/src/patterns.ts
|
|
23392
23589
|
var escapeRegex2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23393
|
-
var basename2 = (
|
|
23394
|
-
const segments2 =
|
|
23590
|
+
var basename2 = (path22) => {
|
|
23591
|
+
const segments2 = path22.split("/").filter(Boolean);
|
|
23395
23592
|
return segments2[segments2.length - 1] ?? "";
|
|
23396
23593
|
};
|
|
23397
23594
|
var normalizeStorePathPattern = (pattern) => pattern.trim();
|
|
@@ -23409,7 +23606,7 @@ var storePathPatternToRegex = (pattern) => {
|
|
|
23409
23606
|
return new RegExp(source, "i");
|
|
23410
23607
|
};
|
|
23411
23608
|
var doesStorePathPatternMatch = ({
|
|
23412
|
-
path:
|
|
23609
|
+
path: path22,
|
|
23413
23610
|
pattern,
|
|
23414
23611
|
mode = "path"
|
|
23415
23612
|
}) => {
|
|
@@ -23417,7 +23614,7 @@ var doesStorePathPatternMatch = ({
|
|
|
23417
23614
|
if (!normalizedPattern) {
|
|
23418
23615
|
return true;
|
|
23419
23616
|
}
|
|
23420
|
-
const normalizedPath = normalizeStorePath(
|
|
23617
|
+
const normalizedPath = normalizeStorePath(path22);
|
|
23421
23618
|
const target = mode === "basename" ? basename2(normalizedPath) : normalizedPath;
|
|
23422
23619
|
if (patternHasWildcard(normalizedPattern)) {
|
|
23423
23620
|
return storePathPatternToRegex(normalizedPattern).test(target);
|
|
@@ -23449,9 +23646,21 @@ var storeRootPathFromId2 = (storeId) => {
|
|
|
23449
23646
|
return `/${normalizeStoreId2(storeId)}`;
|
|
23450
23647
|
};
|
|
23451
23648
|
|
|
23452
|
-
// src/
|
|
23649
|
+
// src/openInBrowser.ts
|
|
23453
23650
|
import { execFile } from "child_process";
|
|
23454
23651
|
import { promisify } from "util";
|
|
23652
|
+
var execFileAsync = promisify(execFile);
|
|
23653
|
+
var openInBrowser = async (url2) => {
|
|
23654
|
+
if (process.platform === "darwin") {
|
|
23655
|
+
await execFileAsync("open", [url2]);
|
|
23656
|
+
return;
|
|
23657
|
+
}
|
|
23658
|
+
if (process.platform === "win32") {
|
|
23659
|
+
await execFileAsync("cmd", ["/c", "start", "", url2]);
|
|
23660
|
+
return;
|
|
23661
|
+
}
|
|
23662
|
+
await execFileAsync("xdg-open", [url2]);
|
|
23663
|
+
};
|
|
23455
23664
|
|
|
23456
23665
|
// src/render.ts
|
|
23457
23666
|
var options = {
|
|
@@ -23493,8 +23702,8 @@ var isIssueRecord = (value) => {
|
|
|
23493
23702
|
return isRecord2(value) && typeof value.message === "string";
|
|
23494
23703
|
};
|
|
23495
23704
|
var formatIssue = (issue2) => {
|
|
23496
|
-
const
|
|
23497
|
-
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;
|
|
23498
23707
|
};
|
|
23499
23708
|
var formatIssueArray = (issues) => {
|
|
23500
23709
|
if (!issues.every(isIssueRecord)) {
|
|
@@ -23775,19 +23984,28 @@ var withActivity = async (label, run) => {
|
|
|
23775
23984
|
}
|
|
23776
23985
|
};
|
|
23777
23986
|
|
|
23987
|
+
// src/waitForLoginBrowser.ts
|
|
23988
|
+
import { createInterface } from "readline";
|
|
23989
|
+
var waitForLoginBrowser = () => new Promise((resolve, reject) => {
|
|
23990
|
+
const prompt = createInterface({
|
|
23991
|
+
input: process.stdin,
|
|
23992
|
+
output: process.stderr
|
|
23993
|
+
});
|
|
23994
|
+
const cancel = () => {
|
|
23995
|
+
reject(new Error("Login cancelled. Run `fm auth login` again."));
|
|
23996
|
+
prompt.close();
|
|
23997
|
+
};
|
|
23998
|
+
prompt.once("SIGINT", cancel);
|
|
23999
|
+
prompt.once("close", cancel);
|
|
24000
|
+
prompt.question("Press Enter to open the browser... ", () => {
|
|
24001
|
+
prompt.removeListener("close", cancel);
|
|
24002
|
+
prompt.removeListener("SIGINT", cancel);
|
|
24003
|
+
prompt.close();
|
|
24004
|
+
resolve();
|
|
24005
|
+
});
|
|
24006
|
+
});
|
|
24007
|
+
|
|
23778
24008
|
// src/auth.ts
|
|
23779
|
-
var execFileAsync = promisify(execFile);
|
|
23780
|
-
var openInBrowser = async (url2) => {
|
|
23781
|
-
if (process.platform === "darwin") {
|
|
23782
|
-
await execFileAsync("open", [url2]);
|
|
23783
|
-
return;
|
|
23784
|
-
}
|
|
23785
|
-
if (process.platform === "win32") {
|
|
23786
|
-
await execFileAsync("cmd", ["/c", "start", "", url2]);
|
|
23787
|
-
return;
|
|
23788
|
-
}
|
|
23789
|
-
await execFileAsync("xdg-open", [url2]);
|
|
23790
|
-
};
|
|
23791
24009
|
var interactiveLogin = async ({
|
|
23792
24010
|
apiBaseUrl,
|
|
23793
24011
|
timeoutMs = 2 * 60 * 1e3,
|
|
@@ -23806,10 +24024,11 @@ var interactiveLogin = async ({
|
|
|
23806
24024
|
throw new Error(`Failed to start auth flow: ${message}`);
|
|
23807
24025
|
}
|
|
23808
24026
|
const session = await startResponse.json();
|
|
23809
|
-
renderOutput(`
|
|
23810
|
-
renderOutput(`
|
|
24027
|
+
renderOutput(`First, copy this code: ${session.userCode}`);
|
|
24028
|
+
renderOutput(`Open this URL and enter the code: ${session.verificationUrl}`);
|
|
23811
24029
|
renderOutput(`This code expires at: ${session.expiresAt}`);
|
|
23812
|
-
if (openBrowser) {
|
|
24030
|
+
if (openBrowser && process.stdin.isTTY && process.stderr.isTTY) {
|
|
24031
|
+
await waitForLoginBrowser();
|
|
23813
24032
|
void openInBrowser(session.verificationUrl).catch(() => {
|
|
23814
24033
|
renderOutput(
|
|
23815
24034
|
"Could not open browser automatically. Open the URL manually."
|
|
@@ -23957,7 +24176,7 @@ var buildContentChangedConflictExplainer = (issues) => {
|
|
|
23957
24176
|
body: [
|
|
23958
24177
|
pathSubject(
|
|
23959
24178
|
paths,
|
|
23960
|
-
(
|
|
24179
|
+
(path22) => `${path22} changed both locally and remotely.`,
|
|
23961
24180
|
(count) => `${count} files changed both locally and remotely.`
|
|
23962
24181
|
),
|
|
23963
24182
|
"Forum left these files alone because either overwrite direction could lose work."
|
|
@@ -23989,7 +24208,7 @@ var buildLocalDeleteRemoteChangeExplainer = (issues) => {
|
|
|
23989
24208
|
body: [
|
|
23990
24209
|
pathSubject(
|
|
23991
24210
|
paths,
|
|
23992
|
-
(
|
|
24211
|
+
(path22) => `${path22} was deleted locally, but the remote file changed.`,
|
|
23993
24212
|
(count) => `${count} files were deleted locally, but changed remotely.`
|
|
23994
24213
|
),
|
|
23995
24214
|
"Forum did not delete newer remote work automatically."
|
|
@@ -24021,7 +24240,7 @@ var buildMoveDestinationConflictExplainer = (issues) => {
|
|
|
24021
24240
|
body: [
|
|
24022
24241
|
pathSubject(
|
|
24023
24242
|
paths,
|
|
24024
|
-
(
|
|
24243
|
+
(path22) => `${path22} is the destination of a remote move, but already exists locally.`,
|
|
24025
24244
|
(count) => `${count} paths are remote move destinations that already exist locally.`
|
|
24026
24245
|
),
|
|
24027
24246
|
"Forum synced unrelated files but left these paths alone."
|
|
@@ -24056,7 +24275,7 @@ var buildMoveRemoteChangeConflictExplainer = (issues) => {
|
|
|
24056
24275
|
body: [
|
|
24057
24276
|
pathSubject(
|
|
24058
24277
|
paths,
|
|
24059
|
-
(
|
|
24278
|
+
(path22) => `${path22} was involved in a move while the other side changed it.`,
|
|
24060
24279
|
(count) => `${count} files were involved in moves while the other side changed them.`
|
|
24061
24280
|
),
|
|
24062
24281
|
"Forum did not combine the move and content change automatically."
|
|
@@ -24088,7 +24307,7 @@ var buildMoveMoveConflictExplainer = (issues) => {
|
|
|
24088
24307
|
body: [
|
|
24089
24308
|
pathSubject(
|
|
24090
24309
|
paths,
|
|
24091
|
-
(
|
|
24310
|
+
(path22) => `${path22} moved locally and remotely to different paths.`,
|
|
24092
24311
|
(count) => `${count} files moved locally and remotely to different paths.`
|
|
24093
24312
|
),
|
|
24094
24313
|
"Forum left these moves unresolved because choosing a path automatically could hide work."
|
|
@@ -24120,7 +24339,7 @@ var buildDeleteMoveConflictExplainer = (issues) => {
|
|
|
24120
24339
|
body: [
|
|
24121
24340
|
pathSubject(
|
|
24122
24341
|
paths,
|
|
24123
|
-
(
|
|
24342
|
+
(path22) => `${path22} was deleted on one side and moved on the other.`,
|
|
24124
24343
|
(count) => `${count} files were deleted on one side and moved on the other.`
|
|
24125
24344
|
),
|
|
24126
24345
|
"Forum did not choose between delete and move automatically."
|
|
@@ -24152,7 +24371,7 @@ var buildReferenceLocalFileConflictExplainer = (issues) => {
|
|
|
24152
24371
|
body: [
|
|
24153
24372
|
pathSubject(
|
|
24154
24373
|
paths,
|
|
24155
|
-
(
|
|
24374
|
+
(path22) => `${path22} is now a remote reference, but the local file has changes.`,
|
|
24156
24375
|
(count) => `${count} paths are now remote references, but local files have changes.`
|
|
24157
24376
|
),
|
|
24158
24377
|
"Forum left the local files alone because replacing them would discard local work."
|
|
@@ -24184,7 +24403,7 @@ var buildUnsupportedLocalEntryExplainer = (issues) => {
|
|
|
24184
24403
|
body: [
|
|
24185
24404
|
pathSubject(
|
|
24186
24405
|
paths,
|
|
24187
|
-
(
|
|
24406
|
+
(path22) => `${path22} is an unsupported local filesystem entry.`,
|
|
24188
24407
|
(count) => `${count} local filesystem entries are unsupported.`
|
|
24189
24408
|
),
|
|
24190
24409
|
"Forum skipped these paths and continued with unrelated files where it could."
|
|
@@ -24216,7 +24435,7 @@ var buildReadOnlyLocalChangeExplainer = (issues) => {
|
|
|
24216
24435
|
body: [
|
|
24217
24436
|
pathSubject(
|
|
24218
24437
|
paths,
|
|
24219
|
-
(
|
|
24438
|
+
(path22) => `${path22} has local changes, but its sync rule is read-only.`,
|
|
24220
24439
|
(count) => `${count} files have local changes, but their sync rules are read-only.`
|
|
24221
24440
|
),
|
|
24222
24441
|
"Forum left these files alone so remote updates cannot overwrite local work."
|
|
@@ -24313,7 +24532,7 @@ var checkoutConflictIssuesFromResult = (result) => checkoutIssuesFromResult(resu
|
|
|
24313
24532
|
(issue2) => issue2.type === "conflict"
|
|
24314
24533
|
);
|
|
24315
24534
|
var formatCheckoutExplainer = (explainer) => {
|
|
24316
|
-
const pathLines = explainer.paths.length <= 1 ? [] : ["", ...formatPathList(explainer.paths).map((
|
|
24535
|
+
const pathLines = explainer.paths.length <= 1 ? [] : ["", ...formatPathList(explainer.paths).map((path22) => ` ${path22}`)];
|
|
24317
24536
|
const actionLines = explainer.actions.map(
|
|
24318
24537
|
(action) => `${styleText.bold(`${action.label}:`)} ${action.text}`
|
|
24319
24538
|
);
|
|
@@ -24337,7 +24556,7 @@ var formatCheckoutExplainers = (result) => {
|
|
|
24337
24556
|
|
|
24338
24557
|
// src/gitIntegration.ts
|
|
24339
24558
|
import { execFile as execFile2 } from "child_process";
|
|
24340
|
-
import
|
|
24559
|
+
import path4 from "path";
|
|
24341
24560
|
import { promisify as promisify2 } from "util";
|
|
24342
24561
|
var execFileAsync2 = promisify2(execFile2);
|
|
24343
24562
|
var gitErrorMessage = (error51) => {
|
|
@@ -24362,7 +24581,7 @@ var runGit = async (cwd, args) => {
|
|
|
24362
24581
|
};
|
|
24363
24582
|
var resolveGitRoot = async (cwd) => {
|
|
24364
24583
|
const result = await runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
24365
|
-
return
|
|
24584
|
+
return path4.resolve(cwd, result.stdout.trim());
|
|
24366
24585
|
};
|
|
24367
24586
|
var readGitStatusEntries = async (gitRoot) => {
|
|
24368
24587
|
const result = await runGit(gitRoot, [
|
|
@@ -24442,59 +24661,80 @@ var commitGitChanges = async (gitRoot, message) => {
|
|
|
24442
24661
|
};
|
|
24443
24662
|
|
|
24444
24663
|
// src/checkoutNaming.ts
|
|
24445
|
-
|
|
24446
|
-
|
|
24447
|
-
var
|
|
24448
|
-
"forum.yaml",
|
|
24449
|
-
"forum.yml",
|
|
24450
|
-
"doctrine.yaml",
|
|
24451
|
-
"doctrine.yml"
|
|
24452
|
-
];
|
|
24453
|
-
var defaultProjectConfigFilename = "forum.yaml";
|
|
24454
|
-
var checkoutStateDirectoryNames = [".forum", ".doctrine"];
|
|
24664
|
+
var defaultProjectConfigFilename = ".forum/sync.yaml";
|
|
24665
|
+
var projectConfigFilenames = [defaultProjectConfigFilename];
|
|
24666
|
+
var checkoutStateDirectoryNames = [".forum"];
|
|
24455
24667
|
var defaultCheckoutStateDirectoryName = ".forum";
|
|
24456
|
-
var resolveCheckoutStateDirectoryName = (
|
|
24457
|
-
|
|
24458
|
-
|
|
24459
|
-
|
|
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
|
+
}
|
|
24460
24702
|
}
|
|
24461
24703
|
}
|
|
24462
|
-
|
|
24704
|
+
structuralPreflight.blockedDetails = [];
|
|
24705
|
+
return details;
|
|
24463
24706
|
};
|
|
24464
|
-
var isCheckoutStateDirectoryPath = (relativePath) => checkoutStateDirectoryNames.some(
|
|
24465
|
-
(name) => relativePath === name || relativePath.startsWith(`${name}/`)
|
|
24466
|
-
);
|
|
24467
24707
|
|
|
24468
24708
|
// src/checkout.ts
|
|
24469
24709
|
import { createHash as createHash2 } from "crypto";
|
|
24470
|
-
import
|
|
24710
|
+
import path9 from "path";
|
|
24471
24711
|
import {
|
|
24472
24712
|
lstat,
|
|
24473
|
-
mkdir as
|
|
24713
|
+
mkdir as mkdir4,
|
|
24474
24714
|
readdir as readdir2,
|
|
24475
|
-
readFile as
|
|
24715
|
+
readFile as readFile3,
|
|
24476
24716
|
rename as rename2,
|
|
24477
|
-
rm as
|
|
24717
|
+
rm as rm3,
|
|
24478
24718
|
stat,
|
|
24479
24719
|
writeFile as writeFile3
|
|
24480
24720
|
} from "fs/promises";
|
|
24481
24721
|
import { TextDecoder as TextDecoder2 } from "util";
|
|
24482
|
-
import
|
|
24722
|
+
import ignore2 from "ignore";
|
|
24483
24723
|
|
|
24484
24724
|
// src/buildCheckoutFileManifestEntry.ts
|
|
24485
|
-
var toManifestRemotePath = (
|
|
24725
|
+
var toManifestRemotePath = (path22) => path22.startsWith("/") ? path22 : `/${path22}`;
|
|
24486
24726
|
var buildCheckoutFileManifestEntry = ({
|
|
24487
24727
|
storageClass,
|
|
24488
24728
|
hash: hash2,
|
|
24489
24729
|
manifestEntry,
|
|
24490
|
-
path:
|
|
24730
|
+
path: path22,
|
|
24491
24731
|
remoteFile,
|
|
24492
24732
|
source,
|
|
24493
24733
|
syncedAt
|
|
24494
24734
|
}) => {
|
|
24495
24735
|
const remoteFileId = remoteFile.id ?? remoteFile._id ?? manifestEntry?.remoteFileId;
|
|
24496
24736
|
if (!remoteFileId) {
|
|
24497
|
-
throw new Error(`Remote file ${
|
|
24737
|
+
throw new Error(`Remote file ${path22} did not include a file id`);
|
|
24498
24738
|
}
|
|
24499
24739
|
return {
|
|
24500
24740
|
storageClass,
|
|
@@ -24502,7 +24742,7 @@ var buildCheckoutFileManifestEntry = ({
|
|
|
24502
24742
|
isExecutable: storageClass === "text" ? remoteFile.isExecutable === true || void 0 : void 0,
|
|
24503
24743
|
lastSyncedAt: syncedAt,
|
|
24504
24744
|
remoteFileId,
|
|
24505
|
-
remotePath: remoteFile.path ?? manifestEntry?.remotePath ?? toManifestRemotePath(
|
|
24745
|
+
remotePath: remoteFile.path ?? manifestEntry?.remotePath ?? toManifestRemotePath(path22),
|
|
24506
24746
|
remoteUpdatedAt: remoteFile.updatedAt ?? null,
|
|
24507
24747
|
remoteRevisionNumber: remoteFile.revisionNumber ?? null,
|
|
24508
24748
|
...source ? { source } : {}
|
|
@@ -24604,14 +24844,14 @@ var buildSyncCheckoutSnapshot = ({
|
|
|
24604
24844
|
};
|
|
24605
24845
|
|
|
24606
24846
|
// src/checkoutDirectories.ts
|
|
24607
|
-
import
|
|
24608
|
-
import { mkdir, readdir, rmdir } from "fs/promises";
|
|
24847
|
+
import path6 from "path";
|
|
24848
|
+
import { mkdir as mkdir2, readdir, rmdir } from "fs/promises";
|
|
24609
24849
|
var parentDirectoriesForPath = (relativePath) => {
|
|
24610
24850
|
const directories = [];
|
|
24611
|
-
let directory =
|
|
24851
|
+
let directory = path6.posix.dirname(relativePath);
|
|
24612
24852
|
while (directory && directory !== ".") {
|
|
24613
24853
|
directories.push(directory);
|
|
24614
|
-
directory =
|
|
24854
|
+
directory = path6.posix.dirname(directory);
|
|
24615
24855
|
}
|
|
24616
24856
|
return directories;
|
|
24617
24857
|
};
|
|
@@ -24636,7 +24876,7 @@ var prepareCheckoutDirectories = async ({
|
|
|
24636
24876
|
const directories = checkoutParentDirectories(relativePaths);
|
|
24637
24877
|
await Promise.all(
|
|
24638
24878
|
directories.map(
|
|
24639
|
-
(directory) =>
|
|
24879
|
+
(directory) => mkdir2(path6.join(localPath, directory), { recursive: true })
|
|
24640
24880
|
)
|
|
24641
24881
|
);
|
|
24642
24882
|
return directories;
|
|
@@ -24650,7 +24890,7 @@ var cleanupCheckoutDirectories = async ({
|
|
|
24650
24890
|
if (checkoutStateDirectoryNames.includes(directory)) {
|
|
24651
24891
|
continue;
|
|
24652
24892
|
}
|
|
24653
|
-
const absolutePath =
|
|
24893
|
+
const absolutePath = path6.join(localPath, directory);
|
|
24654
24894
|
try {
|
|
24655
24895
|
const entries = await readdir(absolutePath);
|
|
24656
24896
|
if (entries.length > 0) {
|
|
@@ -24673,13 +24913,13 @@ var cleanupCheckoutDirectories = async ({
|
|
|
24673
24913
|
};
|
|
24674
24914
|
|
|
24675
24915
|
// src/planRemoteDirectoryCleanup.ts
|
|
24676
|
-
import
|
|
24916
|
+
import path7 from "path";
|
|
24677
24917
|
var ancestorDirectories = (relativePath) => {
|
|
24678
24918
|
const directories = [];
|
|
24679
|
-
let directory =
|
|
24919
|
+
let directory = path7.posix.dirname(relativePath);
|
|
24680
24920
|
while (directory && directory !== ".") {
|
|
24681
24921
|
directories.push(directory);
|
|
24682
|
-
directory =
|
|
24922
|
+
directory = path7.posix.dirname(directory);
|
|
24683
24923
|
}
|
|
24684
24924
|
return directories;
|
|
24685
24925
|
};
|
|
@@ -24696,7 +24936,7 @@ var planRemoteDirectoryCleanup = (removedPaths) => {
|
|
|
24696
24936
|
};
|
|
24697
24937
|
|
|
24698
24938
|
// src/cleanupRemoteCheckoutDirectories.ts
|
|
24699
|
-
var
|
|
24939
|
+
var addLeadingSlash2 = (relativePath) => relativePath ? `/${relativePath}` : "/";
|
|
24700
24940
|
var cleanupRemoteCheckoutDirectories = async ({
|
|
24701
24941
|
client,
|
|
24702
24942
|
removedPaths,
|
|
@@ -24704,7 +24944,7 @@ var cleanupRemoteCheckoutDirectories = async ({
|
|
|
24704
24944
|
}) => {
|
|
24705
24945
|
const removed = [];
|
|
24706
24946
|
for (const directory of planRemoteDirectoryCleanup(removedPaths)) {
|
|
24707
|
-
const directoryPath =
|
|
24947
|
+
const directoryPath = addLeadingSlash2(directory);
|
|
24708
24948
|
try {
|
|
24709
24949
|
const listing = await client.listDirectoryByRef({
|
|
24710
24950
|
...storeRef,
|
|
@@ -24727,53 +24967,6 @@ var cleanupRemoteCheckoutDirectories = async ({
|
|
|
24727
24967
|
return removed;
|
|
24728
24968
|
};
|
|
24729
24969
|
|
|
24730
|
-
// src/mapSyncRulePath.ts
|
|
24731
|
-
var assertSafeRelativePath = (relativePath) => {
|
|
24732
|
-
const segments2 = relativePath.split("/");
|
|
24733
|
-
if (relativePath.startsWith("/") || segments2.some((segment) => segment === "." || segment === "..")) {
|
|
24734
|
-
throw new Error(`Unsafe checkout path: ${relativePath}`);
|
|
24735
|
-
}
|
|
24736
|
-
};
|
|
24737
|
-
var toRelativePath = (storePath) => {
|
|
24738
|
-
const relativePath = storePath.replace(/^\/+/, "");
|
|
24739
|
-
assertSafeRelativePath(relativePath);
|
|
24740
|
-
return relativePath;
|
|
24741
|
-
};
|
|
24742
|
-
var joinRelativePath = (...parts) => parts.flatMap((part) => part.split("/")).filter(Boolean).join("/");
|
|
24743
|
-
var addLeadingSlash2 = (relativePath) => relativePath ? `/${relativePath}` : "/";
|
|
24744
|
-
var stripSyncRuleTarget = (localRelativePath, rule) => {
|
|
24745
|
-
if (!rule.target) {
|
|
24746
|
-
return localRelativePath;
|
|
24747
|
-
}
|
|
24748
|
-
if (localRelativePath === rule.target) {
|
|
24749
|
-
return "";
|
|
24750
|
-
}
|
|
24751
|
-
if (!localRelativePath.startsWith(`${rule.target}/`)) {
|
|
24752
|
-
return null;
|
|
24753
|
-
}
|
|
24754
|
-
return localRelativePath.slice(rule.target.length + 1);
|
|
24755
|
-
};
|
|
24756
|
-
var mapLocalPathToSyncRuleRemotePath = (localStorePath, rule) => {
|
|
24757
|
-
const localRelativePath = toRelativePath(localStorePath);
|
|
24758
|
-
const ruleRelativePath = stripSyncRuleTarget(localRelativePath, rule);
|
|
24759
|
-
if (ruleRelativePath === null) {
|
|
24760
|
-
throw new Error(
|
|
24761
|
-
`Path is outside sync rule target ${rule.target || "."}: ${localRelativePath}`
|
|
24762
|
-
);
|
|
24763
|
-
}
|
|
24764
|
-
return addLeadingSlash2(joinRelativePath(rule.path, ruleRelativePath));
|
|
24765
|
-
};
|
|
24766
|
-
var mapRemotePathToSyncRuleLocalPath = (remoteStorePath, rule) => {
|
|
24767
|
-
const remoteRelativePath = toRelativePath(remoteStorePath);
|
|
24768
|
-
if (rule.path && remoteRelativePath !== rule.path && !remoteRelativePath.startsWith(`${rule.path}/`)) {
|
|
24769
|
-
throw new Error(
|
|
24770
|
-
`Remote path is outside sync rule path ${rule.path}: ${remoteRelativePath}`
|
|
24771
|
-
);
|
|
24772
|
-
}
|
|
24773
|
-
const ruleRelativePath = rule.path ? remoteRelativePath === rule.path ? "" : remoteRelativePath.slice(rule.path.length + 1) : remoteRelativePath;
|
|
24774
|
-
return addLeadingSlash2(joinRelativePath(rule.target, ruleRelativePath));
|
|
24775
|
-
};
|
|
24776
|
-
|
|
24777
24970
|
// src/planSyncCheckoutPaths.ts
|
|
24778
24971
|
var detailRelatedPaths = (detail) => [
|
|
24779
24972
|
detail.relativePath,
|
|
@@ -24947,6 +25140,8 @@ var planRemoteRenameBeforePull = ({
|
|
|
24947
25140
|
|
|
24948
25141
|
// src/planSyncCheckoutFile.ts
|
|
24949
25142
|
var planSyncCheckoutFile = ({
|
|
25143
|
+
conflictPolicy,
|
|
25144
|
+
resolvedConflict,
|
|
24950
25145
|
force,
|
|
24951
25146
|
localIsExecutable = false,
|
|
24952
25147
|
localHash,
|
|
@@ -24959,6 +25154,34 @@ var planSyncCheckoutFile = ({
|
|
|
24959
25154
|
}) => {
|
|
24960
25155
|
const hasLocal = localHash !== null;
|
|
24961
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
|
+
}
|
|
24962
25185
|
if (remoteKind === "reference") {
|
|
24963
25186
|
if (!force && (hasManifest || hasLocal)) {
|
|
24964
25187
|
return {
|
|
@@ -25014,7 +25237,6 @@ var planSyncCheckoutFile = ({
|
|
|
25014
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"
|
|
25015
25238
|
};
|
|
25016
25239
|
}
|
|
25017
|
-
const localChanged = localHash !== manifestHash || localIsExecutable !== manifestIsExecutable;
|
|
25018
25240
|
if (!force && localChanged && remoteVersionChanged) {
|
|
25019
25241
|
return {
|
|
25020
25242
|
type: "conflict",
|
|
@@ -25057,19 +25279,9 @@ var selectCheckoutFilePathsForSyncRule = ({
|
|
|
25057
25279
|
|
|
25058
25280
|
// src/projectConfig.ts
|
|
25059
25281
|
import { createHash } from "crypto";
|
|
25060
|
-
import
|
|
25061
|
-
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";
|
|
25062
25284
|
import { parse as parse3, stringify } from "yaml";
|
|
25063
|
-
var warnedLegacyIgnorePaths = /* @__PURE__ */ new Set();
|
|
25064
|
-
var warnLegacyIgnoreField = (filePath) => {
|
|
25065
|
-
if (warnedLegacyIgnorePaths.has(filePath)) {
|
|
25066
|
-
return;
|
|
25067
|
-
}
|
|
25068
|
-
warnedLegacyIgnorePaths.add(filePath);
|
|
25069
|
-
renderWarning(
|
|
25070
|
-
`ignore in ${filePath} is no longer used; move these to the store with \`fm ignore add\`, or to .forum/ignore`
|
|
25071
|
-
);
|
|
25072
|
-
};
|
|
25073
25285
|
var fileExists = async (filePath) => {
|
|
25074
25286
|
try {
|
|
25075
25287
|
await access(filePath);
|
|
@@ -25102,7 +25314,9 @@ var parseProjectConfig = (filePath, source) => {
|
|
|
25102
25314
|
);
|
|
25103
25315
|
}
|
|
25104
25316
|
if (ignore3 !== void 0) {
|
|
25105
|
-
|
|
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
|
+
);
|
|
25106
25320
|
}
|
|
25107
25321
|
return {
|
|
25108
25322
|
...defaultStore ? { defaultStore } : {},
|
|
@@ -25183,7 +25397,7 @@ var normalizeSyncPath = ({
|
|
|
25183
25397
|
value
|
|
25184
25398
|
}) => {
|
|
25185
25399
|
const trimmed = value.trim();
|
|
25186
|
-
if (
|
|
25400
|
+
if (path8.isAbsolute(trimmed)) {
|
|
25187
25401
|
throw new Error(
|
|
25188
25402
|
`Invalid Forum config at ${filePath}: ${fieldName} must be a relative path.`
|
|
25189
25403
|
);
|
|
@@ -25336,16 +25550,16 @@ var parseQualifiedConfigStore = (filePath, fieldName, store) => {
|
|
|
25336
25550
|
return `${segments2[0]}/${segments2[1]}`;
|
|
25337
25551
|
};
|
|
25338
25552
|
var findForumProjectConfig = async (startDir = process.cwd()) => {
|
|
25339
|
-
let current =
|
|
25553
|
+
let current = path8.resolve(startDir);
|
|
25340
25554
|
while (true) {
|
|
25341
25555
|
for (const filename of projectConfigFilenames) {
|
|
25342
|
-
const candidate =
|
|
25556
|
+
const candidate = path8.join(current, filename);
|
|
25343
25557
|
if (await fileExists(candidate)) {
|
|
25344
|
-
const source = await
|
|
25558
|
+
const source = await readFile2(candidate, "utf8");
|
|
25345
25559
|
return parseProjectConfig(candidate, source);
|
|
25346
25560
|
}
|
|
25347
25561
|
}
|
|
25348
|
-
const parent =
|
|
25562
|
+
const parent = path8.dirname(current);
|
|
25349
25563
|
if (parent === current) {
|
|
25350
25564
|
return null;
|
|
25351
25565
|
}
|
|
@@ -25380,35 +25594,84 @@ var writeForumProjectConfig = async (filePath, config2) => {
|
|
|
25380
25594
|
target: rule.target || "."
|
|
25381
25595
|
}));
|
|
25382
25596
|
}
|
|
25383
|
-
await
|
|
25597
|
+
await mkdir3(path8.dirname(filePath), { recursive: true });
|
|
25598
|
+
await writeFile2(filePath, stringify(value), "utf8");
|
|
25384
25599
|
};
|
|
25385
25600
|
|
|
25386
|
-
// src/
|
|
25387
|
-
|
|
25388
|
-
|
|
25389
|
-
var
|
|
25390
|
-
const
|
|
25391
|
-
const
|
|
25392
|
-
|
|
25393
|
-
|
|
25394
|
-
|
|
25395
|
-
|
|
25601
|
+
// src/markdownStoreLinks.ts
|
|
25602
|
+
var markdownExtensions = /* @__PURE__ */ new Set([".md", ".markdown", ".mdx"]);
|
|
25603
|
+
var inlineLinkDestinationPattern = /(\]\()([^)\s]+)(\))/g;
|
|
25604
|
+
var normalizeStorePath2 = (value) => {
|
|
25605
|
+
const withoutFragment = value.split("#", 1)[0] ?? value;
|
|
25606
|
+
const withoutQuery = withoutFragment.split("?", 1)[0] ?? withoutFragment;
|
|
25607
|
+
return withoutQuery.startsWith("/") ? withoutQuery : `/${withoutQuery}`;
|
|
25608
|
+
};
|
|
25609
|
+
var normalizeFileExtension = (pathValue) => {
|
|
25610
|
+
const basename3 = pathValue.split("/").at(-1) ?? pathValue;
|
|
25611
|
+
const dotIndex = basename3.lastIndexOf(".");
|
|
25612
|
+
return dotIndex >= 0 ? basename3.slice(dotIndex).toLowerCase() : "";
|
|
25613
|
+
};
|
|
25614
|
+
var isMarkdownStorePath = (pathValue) => markdownExtensions.has(normalizeFileExtension(pathValue));
|
|
25615
|
+
var encodeRawFileUrl = (baseUrl, fileId) => `${baseUrl.replace(/\/+$/, "")}/raw-file/${encodeURIComponent(fileId)}`;
|
|
25616
|
+
var decodeRawFileId = (href) => {
|
|
25617
|
+
let url2;
|
|
25396
25618
|
try {
|
|
25397
|
-
|
|
25398
|
-
|
|
25399
|
-
|
|
25400
|
-
}
|
|
25401
|
-
|
|
25402
|
-
|
|
25403
|
-
|
|
25619
|
+
url2 = new URL(href);
|
|
25620
|
+
} catch {
|
|
25621
|
+
return null;
|
|
25622
|
+
}
|
|
25623
|
+
const segments2 = url2.pathname.split("/").filter(Boolean);
|
|
25624
|
+
if (segments2.length !== 2 || segments2[0] !== "raw-file") {
|
|
25625
|
+
return null;
|
|
25626
|
+
}
|
|
25627
|
+
try {
|
|
25628
|
+
return decodeURIComponent(segments2[1] ?? "");
|
|
25629
|
+
} catch {
|
|
25630
|
+
return null;
|
|
25404
25631
|
}
|
|
25405
25632
|
};
|
|
25633
|
+
var rewriteMarkdownLinkDestinations = (markdown, rewriteDestination) => markdown.replace(
|
|
25634
|
+
inlineLinkDestinationPattern,
|
|
25635
|
+
(_match, prefix, destination, suffix) => `${prefix}${rewriteDestination(destination)}${suffix}`
|
|
25636
|
+
);
|
|
25637
|
+
var rewriteStorePathLinksToRawUrls = ({
|
|
25638
|
+
rawFileBaseUrl: rawFileBaseUrl2,
|
|
25639
|
+
targets,
|
|
25640
|
+
text
|
|
25641
|
+
}) => {
|
|
25642
|
+
const targetByStorePath = new Map(
|
|
25643
|
+
targets.map((target) => [normalizeStorePath2(target.storePath), target])
|
|
25644
|
+
);
|
|
25645
|
+
return rewriteMarkdownLinkDestinations(text, (destination) => {
|
|
25646
|
+
if (!destination.startsWith("/") || destination.startsWith("//")) {
|
|
25647
|
+
return destination;
|
|
25648
|
+
}
|
|
25649
|
+
const target = targetByStorePath.get(normalizeStorePath2(destination));
|
|
25650
|
+
return target ? encodeRawFileUrl(rawFileBaseUrl2, target.fileId) : destination;
|
|
25651
|
+
});
|
|
25652
|
+
};
|
|
25653
|
+
var rewriteRawUrlsToStorePathLinks = ({
|
|
25654
|
+
targets,
|
|
25655
|
+
text
|
|
25656
|
+
}) => {
|
|
25657
|
+
const storePathByFileId = new Map(
|
|
25658
|
+
targets.map((target) => [
|
|
25659
|
+
target.fileId,
|
|
25660
|
+
normalizeStorePath2(target.storePath)
|
|
25661
|
+
])
|
|
25662
|
+
);
|
|
25663
|
+
return rewriteMarkdownLinkDestinations(text, (destination) => {
|
|
25664
|
+
const fileId = decodeRawFileId(destination);
|
|
25665
|
+
if (!fileId) {
|
|
25666
|
+
return destination;
|
|
25667
|
+
}
|
|
25668
|
+
return storePathByFileId.get(fileId) ?? destination;
|
|
25669
|
+
});
|
|
25670
|
+
};
|
|
25406
25671
|
|
|
25407
25672
|
// src/checkout.ts
|
|
25408
|
-
var reservedRootFiles = new Set(projectConfigFilenames);
|
|
25409
|
-
var reservedRootFileNames = [...reservedRootFiles];
|
|
25410
25673
|
var checkoutFilesManifestFilename = "files.json";
|
|
25411
|
-
var localIgnoreFilename = "
|
|
25674
|
+
var localIgnoreFilename = "usr_ignore";
|
|
25412
25675
|
var gitDirectoryName = ".git";
|
|
25413
25676
|
var defaultConcurrency = 8;
|
|
25414
25677
|
var utf8Decoder = new TextDecoder2("utf-8", { fatal: true });
|
|
@@ -25542,18 +25805,49 @@ var checkoutEchoSuppressionPathsForWorkerValue = (value) => {
|
|
|
25542
25805
|
};
|
|
25543
25806
|
var compareRelativePath3 = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
25544
25807
|
var remoteEntrySource = (entry) => entry.__forumSource;
|
|
25545
|
-
var
|
|
25546
|
-
|
|
25547
|
-
|
|
25548
|
-
|
|
25549
|
-
|
|
25808
|
+
var remoteEntryStorePath = (entry) => entry.__forumStorePath ?? entry.path;
|
|
25809
|
+
var markdownLinkTargetsFromEntries = (entries) => entries.map(
|
|
25810
|
+
({ entry }) => entry.id ? {
|
|
25811
|
+
fileId: entry.id,
|
|
25812
|
+
storePath: remoteEntryStorePath(entry)
|
|
25813
|
+
} : null
|
|
25814
|
+
).filter((target) => Boolean(target));
|
|
25815
|
+
var markdownLinkTargetsFromManifest = (manifest) => Object.values(manifest.files).map(
|
|
25816
|
+
(entry) => entry.remoteFileId && entry.remotePath ? {
|
|
25817
|
+
fileId: entry.remoteFileId,
|
|
25818
|
+
storePath: entry.remotePath
|
|
25819
|
+
} : null
|
|
25820
|
+
).filter((target) => Boolean(target));
|
|
25821
|
+
var rawFileBaseUrl = (client) => {
|
|
25822
|
+
const probeId = "__forum_probe__";
|
|
25823
|
+
return client.createRawFileUrl(probeId).replace(new RegExp(`/raw-file/${probeId}$`), "");
|
|
25824
|
+
};
|
|
25825
|
+
var rewriteMarkdownForLocalCheckout = ({
|
|
25826
|
+
client,
|
|
25827
|
+
relativePath,
|
|
25828
|
+
targets,
|
|
25829
|
+
text
|
|
25830
|
+
}) => isMarkdownStorePath(relativePath) && text.includes("](/") ? rewriteStorePathLinksToRawUrls({
|
|
25831
|
+
rawFileBaseUrl: rawFileBaseUrl(client),
|
|
25832
|
+
targets,
|
|
25833
|
+
text
|
|
25834
|
+
}) : text;
|
|
25835
|
+
var rewriteMarkdownForRemoteStore = ({
|
|
25836
|
+
manifest,
|
|
25837
|
+
relativePath,
|
|
25838
|
+
text
|
|
25839
|
+
}) => isMarkdownStorePath(relativePath) ? rewriteRawUrlsToStorePathLinks({
|
|
25840
|
+
targets: markdownLinkTargetsFromManifest(manifest),
|
|
25841
|
+
text
|
|
25842
|
+
}) : text;
|
|
25843
|
+
var isReservedCheckoutMetadataPath = (relativePath) => isCheckoutStateDirectoryPath(relativePath) || // `.git/` is the checkout's own VCS metadata — structurally never content,
|
|
25550
25844
|
// like `.forum/`. It is reserved (not an ignore *rule*): there are no
|
|
25551
25845
|
// baked-in ignore patterns, but tooling directories are still never synced.
|
|
25552
25846
|
relativePath === gitDirectoryName || relativePath.startsWith(`${gitDirectoryName}/`);
|
|
25553
25847
|
var reservedCheckoutMetadataMessage = "reserved checkout metadata path; ignored by local sync";
|
|
25554
25848
|
var assertSafeRelativePath2 = (relativePath) => {
|
|
25555
25849
|
const segments2 = relativePath.split("/");
|
|
25556
|
-
if (
|
|
25850
|
+
if (path9.isAbsolute(relativePath) || segments2.some((segment) => segment === "." || segment === "..")) {
|
|
25557
25851
|
throw new Error(`Unsafe checkout path: ${relativePath}`);
|
|
25558
25852
|
}
|
|
25559
25853
|
};
|
|
@@ -25708,6 +26002,7 @@ var createSyncRuleClient = (client, rule) => {
|
|
|
25708
26002
|
};
|
|
25709
26003
|
const mapListingEntries = (entries, remoteRoot) => entries.map((entry) => ({
|
|
25710
26004
|
...entry,
|
|
26005
|
+
__forumStorePath: entry.path,
|
|
25711
26006
|
...remoteRoot.displayStore ? {
|
|
25712
26007
|
__forumRemoteRef: {
|
|
25713
26008
|
...remoteRoot.displayStore,
|
|
@@ -25866,8 +26161,8 @@ var createSyncRuleClient = (client, rule) => {
|
|
|
25866
26161
|
}
|
|
25867
26162
|
};
|
|
25868
26163
|
};
|
|
25869
|
-
var syncRuleFileParentPath = (rule) =>
|
|
25870
|
-
var syncRuleRemoteFileParentPath = (rule) =>
|
|
26164
|
+
var syncRuleFileParentPath = (rule) => path9.posix.dirname(addLeadingSlash3(rule.target));
|
|
26165
|
+
var syncRuleRemoteFileParentPath = (rule) => path9.posix.dirname(addLeadingSlash3(rule.path));
|
|
25871
26166
|
var assertSyncRuleFilePath = (storePath, rule) => {
|
|
25872
26167
|
const relativePath = toRelativePath2(storePath);
|
|
25873
26168
|
if (relativePath !== rule.target) {
|
|
@@ -25928,6 +26223,7 @@ var createSyncRuleFileClient = (client, rule) => {
|
|
|
25928
26223
|
...listing,
|
|
25929
26224
|
entries: listing.entries.filter((entry) => entry.path === remotePath).map((entry) => ({
|
|
25930
26225
|
...entry,
|
|
26226
|
+
__forumStorePath: entry.path,
|
|
25931
26227
|
path: localPathForEntry
|
|
25932
26228
|
}))
|
|
25933
26229
|
};
|
|
@@ -25945,6 +26241,7 @@ var createSyncRuleFileClient = (client, rule) => {
|
|
|
25945
26241
|
...listing,
|
|
25946
26242
|
entries: listing.entries.filter((entry) => entry.path === remotePath).map((entry) => ({
|
|
25947
26243
|
...entry,
|
|
26244
|
+
__forumStorePath: entry.path,
|
|
25948
26245
|
path: localPathForEntry
|
|
25949
26246
|
}))
|
|
25950
26247
|
};
|
|
@@ -25967,7 +26264,7 @@ var classifySyncRuleRemoteRoot = async (client, storeRef, rule) => {
|
|
|
25967
26264
|
const listing = await client.listDirectoryByRef({
|
|
25968
26265
|
...storeRef,
|
|
25969
26266
|
includeHidden: rule.includeHidden,
|
|
25970
|
-
directoryPath:
|
|
26267
|
+
directoryPath: path9.posix.dirname(remotePath)
|
|
25971
26268
|
});
|
|
25972
26269
|
const entry = listing.entries.find(
|
|
25973
26270
|
(candidate) => candidate.path === remotePath
|
|
@@ -25991,7 +26288,7 @@ var classifySyncRuleLocalTarget = async (rootDir, rule) => {
|
|
|
25991
26288
|
return "directory";
|
|
25992
26289
|
}
|
|
25993
26290
|
try {
|
|
25994
|
-
const details = await lstat(
|
|
26291
|
+
const details = await lstat(path9.join(rootDir, rule.target));
|
|
25995
26292
|
if (details.isFile()) {
|
|
25996
26293
|
return "file";
|
|
25997
26294
|
}
|
|
@@ -26113,34 +26410,32 @@ var normalizeCheckoutIncludePaths = (includePaths) => {
|
|
|
26113
26410
|
}
|
|
26114
26411
|
return normalized;
|
|
26115
26412
|
};
|
|
26116
|
-
var checkoutFilesManifestPath = (rootDir) =>
|
|
26413
|
+
var checkoutFilesManifestPath = (rootDir) => path9.join(
|
|
26117
26414
|
rootDir,
|
|
26118
|
-
resolveCheckoutStateDirectoryName(
|
|
26415
|
+
resolveCheckoutStateDirectoryName(),
|
|
26119
26416
|
checkoutFilesManifestFilename
|
|
26120
26417
|
);
|
|
26121
26418
|
var hashBytes = (bytes) => `sha256:${createHash2("sha256").update(bytes).digest("hex")}`;
|
|
26122
26419
|
var hashText = (text) => hashBytes(Buffer.from(text, "utf8"));
|
|
26123
26420
|
var hashLocalFile = async (filePath) => {
|
|
26124
|
-
return hashBytes(await
|
|
26421
|
+
return hashBytes(await readFile3(filePath));
|
|
26125
26422
|
};
|
|
26126
26423
|
var isExecutableMode = (mode) => (mode & 73) !== 0;
|
|
26127
26424
|
var emptyCheckoutFilesManifest = () => ({
|
|
26128
26425
|
files: {},
|
|
26129
26426
|
references: {},
|
|
26130
26427
|
syncRules: {},
|
|
26131
|
-
ignorePatterns: [],
|
|
26132
26428
|
ignoreOnboardedAt: null,
|
|
26133
26429
|
version: 1
|
|
26134
26430
|
});
|
|
26135
26431
|
var readCheckoutFilesManifest = async (rootDir) => {
|
|
26136
26432
|
try {
|
|
26137
|
-
const raw = await
|
|
26433
|
+
const raw = await readFile3(checkoutFilesManifestPath(rootDir), "utf8");
|
|
26138
26434
|
const parsed = JSON.parse(raw);
|
|
26139
26435
|
return {
|
|
26140
26436
|
files: parsed.files ?? {},
|
|
26141
26437
|
references: parsed.references ?? {},
|
|
26142
26438
|
syncRules: parsed.syncRules ?? {},
|
|
26143
|
-
ignorePatterns: parsed.ignorePatterns ?? [],
|
|
26144
26439
|
ignoreOnboardedAt: parsed.ignoreOnboardedAt ?? null,
|
|
26145
26440
|
version: 1
|
|
26146
26441
|
};
|
|
@@ -26153,12 +26448,12 @@ var readCheckoutFilesManifest = async (rootDir) => {
|
|
|
26153
26448
|
};
|
|
26154
26449
|
var writeCheckoutFilesManifest = async (rootDir, manifest) => {
|
|
26155
26450
|
const filePath = checkoutFilesManifestPath(rootDir);
|
|
26156
|
-
const parentDir =
|
|
26157
|
-
const tempPath =
|
|
26451
|
+
const parentDir = path9.dirname(filePath);
|
|
26452
|
+
const tempPath = path9.join(
|
|
26158
26453
|
parentDir,
|
|
26159
26454
|
`.${checkoutFilesManifestFilename}.${process.pid}.${Date.now()}.tmp`
|
|
26160
26455
|
);
|
|
26161
|
-
await
|
|
26456
|
+
await mkdir4(parentDir, { recursive: true });
|
|
26162
26457
|
try {
|
|
26163
26458
|
await writeFile3(
|
|
26164
26459
|
tempPath,
|
|
@@ -26179,9 +26474,6 @@ var writeCheckoutFilesManifest = async (rootDir, manifest) => {
|
|
|
26179
26474
|
([leftId], [rightId]) => leftId < rightId ? -1 : leftId > rightId ? 1 : 0
|
|
26180
26475
|
)
|
|
26181
26476
|
),
|
|
26182
|
-
ignorePatterns: [...manifest.ignorePatterns].sort(
|
|
26183
|
-
(left, right) => left < right ? -1 : left > right ? 1 : 0
|
|
26184
|
-
),
|
|
26185
26477
|
ignoreOnboardedAt: manifest.ignoreOnboardedAt,
|
|
26186
26478
|
version: 1
|
|
26187
26479
|
},
|
|
@@ -26193,7 +26485,7 @@ var writeCheckoutFilesManifest = async (rootDir, manifest) => {
|
|
|
26193
26485
|
);
|
|
26194
26486
|
await rename2(tempPath, filePath);
|
|
26195
26487
|
} catch (error51) {
|
|
26196
|
-
await
|
|
26488
|
+
await rm3(tempPath, { force: true }).catch(() => {
|
|
26197
26489
|
});
|
|
26198
26490
|
throw error51;
|
|
26199
26491
|
}
|
|
@@ -26244,7 +26536,7 @@ var readFileSnapshot = async (filePath) => {
|
|
|
26244
26536
|
};
|
|
26245
26537
|
var isFileSnapshotEqual = (left, right) => left.size === right.size && left.mtimeMs === right.mtimeMs;
|
|
26246
26538
|
var createIgnoreMatcher = (patterns) => {
|
|
26247
|
-
const matcher =
|
|
26539
|
+
const matcher = ignore2();
|
|
26248
26540
|
matcher.add(patterns);
|
|
26249
26541
|
return matcher;
|
|
26250
26542
|
};
|
|
@@ -26298,7 +26590,7 @@ var deleteLocalFileIfPresent = async (filePath) => {
|
|
|
26298
26590
|
if (!details.isFile()) {
|
|
26299
26591
|
return false;
|
|
26300
26592
|
}
|
|
26301
|
-
await
|
|
26593
|
+
await rm3(filePath, { force: true });
|
|
26302
26594
|
return true;
|
|
26303
26595
|
} catch (error51) {
|
|
26304
26596
|
if (isFileNotFoundError(error51)) {
|
|
@@ -26309,7 +26601,7 @@ var deleteLocalFileIfPresent = async (filePath) => {
|
|
|
26309
26601
|
};
|
|
26310
26602
|
var moveLocalFileIfPresent = async (sourcePath, destinationPath) => {
|
|
26311
26603
|
try {
|
|
26312
|
-
await
|
|
26604
|
+
await mkdir4(path9.dirname(destinationPath), { recursive: true });
|
|
26313
26605
|
await rename2(sourcePath, destinationPath);
|
|
26314
26606
|
return true;
|
|
26315
26607
|
} catch (error51) {
|
|
@@ -26321,7 +26613,7 @@ var moveLocalFileIfPresent = async (sourcePath, destinationPath) => {
|
|
|
26321
26613
|
};
|
|
26322
26614
|
var readLocalFileHashIfPresent = async (rootDir, relativePath) => {
|
|
26323
26615
|
try {
|
|
26324
|
-
return await hashLocalFile(
|
|
26616
|
+
return await hashLocalFile(path9.join(rootDir, relativePath));
|
|
26325
26617
|
} catch (error51) {
|
|
26326
26618
|
if (isFileNotFoundError(error51)) {
|
|
26327
26619
|
return null;
|
|
@@ -26380,7 +26672,7 @@ var reconcileTrackedRemoteDelete = async ({
|
|
|
26380
26672
|
return localFileHash !== null ? "deleted" : "ignored";
|
|
26381
26673
|
}
|
|
26382
26674
|
const deletedLocalFile = await deleteLocalFileIfPresent(
|
|
26383
|
-
|
|
26675
|
+
path9.join(localPath, relativePath)
|
|
26384
26676
|
);
|
|
26385
26677
|
delete manifest.files[relativePath];
|
|
26386
26678
|
return deletedLocalFile ? "deleted" : "ignored";
|
|
@@ -26460,20 +26752,20 @@ var readOnlyCheckoutChangeResults = (changes) => changes.map((change) => ({
|
|
|
26460
26752
|
status: "failed"
|
|
26461
26753
|
}));
|
|
26462
26754
|
var resetCheckoutSyncState = async (rootDir) => {
|
|
26463
|
-
await
|
|
26755
|
+
await rm3(checkoutFilesManifestPath(rootDir), { force: true });
|
|
26464
26756
|
};
|
|
26465
26757
|
var atomicWriteBinaryFile = async (filePath, bytes) => {
|
|
26466
|
-
const parentDir =
|
|
26467
|
-
const tempPath =
|
|
26758
|
+
const parentDir = path9.dirname(filePath);
|
|
26759
|
+
const tempPath = path9.join(
|
|
26468
26760
|
parentDir,
|
|
26469
|
-
`.${
|
|
26761
|
+
`.${path9.basename(filePath)}.${process.pid}.${Date.now()}.tmp`
|
|
26470
26762
|
);
|
|
26471
|
-
await
|
|
26763
|
+
await mkdir4(parentDir, { recursive: true });
|
|
26472
26764
|
try {
|
|
26473
26765
|
await writeFile3(tempPath, bytes);
|
|
26474
26766
|
await rename2(tempPath, filePath);
|
|
26475
26767
|
} catch (error51) {
|
|
26476
|
-
await
|
|
26768
|
+
await rm3(tempPath, { force: true }).catch(() => {
|
|
26477
26769
|
});
|
|
26478
26770
|
throw error51;
|
|
26479
26771
|
}
|
|
@@ -26511,7 +26803,7 @@ var readStableCheckoutFile = async (absolutePath, relativePath, attempts = 3) =>
|
|
|
26511
26803
|
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
26512
26804
|
try {
|
|
26513
26805
|
const before = await readFileSnapshot(absolutePath);
|
|
26514
|
-
const buffer = await
|
|
26806
|
+
const buffer = await readFile3(absolutePath);
|
|
26515
26807
|
const after = await readFileSnapshot(absolutePath);
|
|
26516
26808
|
if (!isFileSnapshotEqual(before, after)) {
|
|
26517
26809
|
sawUnstableRead = true;
|
|
@@ -26571,8 +26863,8 @@ var readStableCheckoutFile = async (absolutePath, relativePath, attempts = 3) =>
|
|
|
26571
26863
|
var walkLocalCheckoutFiles = async (rootDir, directoryPath, includePaths, matcher, scan) => {
|
|
26572
26864
|
const entries = await readdir2(directoryPath, { withFileTypes: true });
|
|
26573
26865
|
for (const entry of entries) {
|
|
26574
|
-
const absolutePath =
|
|
26575
|
-
const relativePath =
|
|
26866
|
+
const absolutePath = path9.join(directoryPath, entry.name);
|
|
26867
|
+
const relativePath = path9.relative(rootDir, absolutePath).split(path9.sep).join("/");
|
|
26576
26868
|
const classification = classifyCheckoutPath(
|
|
26577
26869
|
relativePath,
|
|
26578
26870
|
entry.isDirectory(),
|
|
@@ -26670,7 +26962,7 @@ var readRemoteCheckoutEntry = async (client, storeRef, relativePath) => {
|
|
|
26670
26962
|
const storePath = toStorePath2(relativePath);
|
|
26671
26963
|
const listing = await client.listDirectoryByRef({
|
|
26672
26964
|
...storeRef,
|
|
26673
|
-
directoryPath:
|
|
26965
|
+
directoryPath: path9.posix.dirname(storePath)
|
|
26674
26966
|
});
|
|
26675
26967
|
const entry = listing.entries.find(
|
|
26676
26968
|
(candidate) => candidate.path === storePath
|
|
@@ -26684,7 +26976,7 @@ var readRemoteStoreEntry = async (client, storeRef, relativePath) => {
|
|
|
26684
26976
|
const storePath = toStorePath2(relativePath);
|
|
26685
26977
|
const listing = await client.listDirectoryByRef({
|
|
26686
26978
|
...storeRef,
|
|
26687
|
-
directoryPath:
|
|
26979
|
+
directoryPath: path9.posix.dirname(storePath)
|
|
26688
26980
|
});
|
|
26689
26981
|
return listing.entries.find(
|
|
26690
26982
|
(candidate) => candidate.path === storePath
|
|
@@ -26708,7 +27000,7 @@ var readReferenceSourceForPath = async (client, storeRef, relativePath) => {
|
|
|
26708
27000
|
return void 0;
|
|
26709
27001
|
};
|
|
26710
27002
|
var readLocalCheckoutFile = async (rootDir, relativePath) => {
|
|
26711
|
-
const absolutePath =
|
|
27003
|
+
const absolutePath = path9.join(rootDir, relativePath);
|
|
26712
27004
|
let details;
|
|
26713
27005
|
try {
|
|
26714
27006
|
details = await lstat(absolutePath);
|
|
@@ -27158,7 +27450,7 @@ var joinDirectRootPath = (rootPath, relativePath) => {
|
|
|
27158
27450
|
if (!relativePath) {
|
|
27159
27451
|
return rootPath;
|
|
27160
27452
|
}
|
|
27161
|
-
return
|
|
27453
|
+
return path9.posix.join(rootPath, relativePath);
|
|
27162
27454
|
};
|
|
27163
27455
|
var directStorePath = (relativePath) => relativePath ? toStorePath2(relativePath) : "/";
|
|
27164
27456
|
var relativePathFromDirectRoot = (rootPath, storePath) => {
|
|
@@ -27167,7 +27459,7 @@ var relativePathFromDirectRoot = (rootPath, storePath) => {
|
|
|
27167
27459
|
return relativePath;
|
|
27168
27460
|
}
|
|
27169
27461
|
if (relativePath === rootPath) {
|
|
27170
|
-
return
|
|
27462
|
+
return path9.posix.basename(rootPath);
|
|
27171
27463
|
}
|
|
27172
27464
|
const prefix = `${rootPath}/`;
|
|
27173
27465
|
if (!relativePath.startsWith(prefix)) {
|
|
@@ -27215,22 +27507,26 @@ var updateFileManifestEntry = ({
|
|
|
27215
27507
|
hash: hash2,
|
|
27216
27508
|
manifest,
|
|
27217
27509
|
manifestEntry,
|
|
27218
|
-
path:
|
|
27510
|
+
path: path22,
|
|
27219
27511
|
remoteFile,
|
|
27220
27512
|
source,
|
|
27221
27513
|
syncedAt
|
|
27222
27514
|
}) => {
|
|
27223
|
-
manifest.files[
|
|
27515
|
+
manifest.files[path22] = buildCheckoutFileManifestEntry({
|
|
27224
27516
|
storageClass,
|
|
27225
27517
|
hash: hash2,
|
|
27226
27518
|
manifestEntry,
|
|
27227
|
-
path:
|
|
27519
|
+
path: path22,
|
|
27228
27520
|
remoteFile,
|
|
27229
27521
|
source,
|
|
27230
27522
|
syncedAt
|
|
27231
27523
|
});
|
|
27232
27524
|
};
|
|
27233
27525
|
var reconcileRemoteRenamesBeforePull = async ({
|
|
27526
|
+
client,
|
|
27527
|
+
conflictPolicy,
|
|
27528
|
+
localFiles,
|
|
27529
|
+
storeRef,
|
|
27234
27530
|
dryRun,
|
|
27235
27531
|
files,
|
|
27236
27532
|
force,
|
|
@@ -27242,7 +27538,8 @@ var reconcileRemoteRenamesBeforePull = async ({
|
|
|
27242
27538
|
for (const [relativePath, entry] of Object.entries(manifest.files)) {
|
|
27243
27539
|
manifestPathByRemoteFileId.set(entry.remoteFileId, relativePath);
|
|
27244
27540
|
}
|
|
27245
|
-
for (const
|
|
27541
|
+
for (const remoteFile of files) {
|
|
27542
|
+
const { entry, relativePath } = remoteFile;
|
|
27246
27543
|
if (!entry.id) {
|
|
27247
27544
|
continue;
|
|
27248
27545
|
}
|
|
@@ -27250,18 +27547,40 @@ var reconcileRemoteRenamesBeforePull = async ({
|
|
|
27250
27547
|
if (!manifestPath || manifestPath === relativePath) {
|
|
27251
27548
|
continue;
|
|
27252
27549
|
}
|
|
27253
|
-
const sourcePath =
|
|
27254
|
-
const destinationPath =
|
|
27550
|
+
const sourcePath = path9.join(localPath, manifestPath);
|
|
27551
|
+
const destinationPath = path9.join(localPath, relativePath);
|
|
27255
27552
|
const manifestEntry = manifest.files[manifestPath];
|
|
27256
27553
|
const destinationExists = await pathExists(destinationPath);
|
|
27257
27554
|
const localChanged = await hasTrackedLocalChange({
|
|
27258
27555
|
localPath,
|
|
27259
27556
|
manifestEntry,
|
|
27260
27557
|
relativePath: manifestPath
|
|
27261
|
-
});
|
|
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
|
+
}
|
|
27262
27581
|
const plan = planRemoteRenameBeforePull({
|
|
27263
27582
|
destinationExists,
|
|
27264
|
-
force,
|
|
27583
|
+
force: force || conflictPolicy === "remote",
|
|
27265
27584
|
localChanged
|
|
27266
27585
|
});
|
|
27267
27586
|
if (plan.type === "conflict") {
|
|
@@ -27288,6 +27607,33 @@ var reconcileRemoteRenamesBeforePull = async ({
|
|
|
27288
27607
|
);
|
|
27289
27608
|
continue;
|
|
27290
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
|
+
}
|
|
27291
27637
|
if (!dryRun) {
|
|
27292
27638
|
if (plan.shouldDeleteDestination) {
|
|
27293
27639
|
await deleteLocalFileIfPresent(destinationPath);
|
|
@@ -27330,6 +27676,9 @@ var localRenameCandidateDestinations = (relativePath, manifest, localFilesByHash
|
|
|
27330
27676
|
var localRenameCandidateSources = (file2, deletePaths, manifest) => deletePaths.filter((relativePath) => manifest.files[relativePath]?.hash === file2.hash).sort();
|
|
27331
27677
|
var preflightLocalRenamesBeforePush = async ({
|
|
27332
27678
|
client,
|
|
27679
|
+
conflictPolicy,
|
|
27680
|
+
remoteFiles,
|
|
27681
|
+
localPath,
|
|
27333
27682
|
deletePaths,
|
|
27334
27683
|
dryRun,
|
|
27335
27684
|
localFiles,
|
|
@@ -27413,6 +27762,41 @@ var preflightLocalRenamesBeforePush = async ({
|
|
|
27413
27762
|
if (!manifestEntry) {
|
|
27414
27763
|
continue;
|
|
27415
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
|
+
}
|
|
27416
27800
|
if (!dryRun) {
|
|
27417
27801
|
await client.movePathByRef({
|
|
27418
27802
|
...storeRef,
|
|
@@ -27439,14 +27823,10 @@ var preflightLocalRenamesBeforePush = async ({
|
|
|
27439
27823
|
remainingDeletePaths
|
|
27440
27824
|
};
|
|
27441
27825
|
};
|
|
27442
|
-
var localIgnoreFilePath = (rootDir) =>
|
|
27443
|
-
rootDir,
|
|
27444
|
-
resolveCheckoutStateDirectoryName(rootDir),
|
|
27445
|
-
localIgnoreFilename
|
|
27446
|
-
);
|
|
27826
|
+
var localIgnoreFilePath = (rootDir) => path9.join(rootDir, resolveCheckoutStateDirectoryName(), localIgnoreFilename);
|
|
27447
27827
|
var readLocalIgnorePatterns = async (rootDir) => {
|
|
27448
27828
|
try {
|
|
27449
|
-
const raw = await
|
|
27829
|
+
const raw = await readFile3(localIgnoreFilePath(rootDir), "utf8");
|
|
27450
27830
|
return parseLocalIgnoreFile(raw);
|
|
27451
27831
|
} catch (error51) {
|
|
27452
27832
|
if (errorCode(error51) === "ENOENT") {
|
|
@@ -27455,20 +27835,6 @@ var readLocalIgnorePatterns = async (rootDir) => {
|
|
|
27455
27835
|
throw error51;
|
|
27456
27836
|
}
|
|
27457
27837
|
};
|
|
27458
|
-
var readStoreIgnoreCache = async (rootDir) => {
|
|
27459
|
-
const manifest = await readCheckoutFilesManifest(rootDir);
|
|
27460
|
-
return manifest.ignorePatterns;
|
|
27461
|
-
};
|
|
27462
|
-
var writeStoreIgnoreCache = async (rootDir, storeIgnorePatterns) => {
|
|
27463
|
-
const manifest = await readCheckoutFilesManifest(rootDir);
|
|
27464
|
-
const ignorePatterns = resolveIgnorePatterns({
|
|
27465
|
-
bakedIn: [],
|
|
27466
|
-
storeSetting: storeIgnorePatterns,
|
|
27467
|
-
localOverride: []
|
|
27468
|
-
});
|
|
27469
|
-
await writeCheckoutFilesManifest(rootDir, { ...manifest, ignorePatterns });
|
|
27470
|
-
return ignorePatterns;
|
|
27471
|
-
};
|
|
27472
27838
|
var readIgnoreOnboardedAt = async (rootDir) => {
|
|
27473
27839
|
const manifest = await readCheckoutFilesManifest(rootDir);
|
|
27474
27840
|
return manifest.ignoreOnboardedAt;
|
|
@@ -27484,22 +27850,29 @@ var resolveCheckoutConfig = async (startDir = process.cwd()) => {
|
|
|
27484
27850
|
const config2 = await findForumProjectConfig(startDir);
|
|
27485
27851
|
if (!config2) {
|
|
27486
27852
|
throw new Error(
|
|
27487
|
-
"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."
|
|
27488
27854
|
);
|
|
27489
27855
|
}
|
|
27490
|
-
const rootDir =
|
|
27491
|
-
const
|
|
27492
|
-
|
|
27493
|
-
|
|
27494
|
-
|
|
27495
|
-
|
|
27496
|
-
|
|
27497
|
-
|
|
27498
|
-
|
|
27499
|
-
|
|
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;
|
|
27500
27871
|
return {
|
|
27501
27872
|
...config2,
|
|
27873
|
+
ignoreMatchersByRule,
|
|
27502
27874
|
ignore: ignore3,
|
|
27875
|
+
ignorePatternsByStore,
|
|
27503
27876
|
configRootDir: rootDir,
|
|
27504
27877
|
rootDir
|
|
27505
27878
|
};
|
|
@@ -27507,8 +27880,8 @@ var resolveCheckoutConfig = async (startDir = process.cwd()) => {
|
|
|
27507
27880
|
var collectLocalCheckoutFiles = async (rootDir, ignorePatterns, syncIncludePaths) => {
|
|
27508
27881
|
return (await scanLocalCheckoutFiles(rootDir, ignorePatterns, syncIncludePaths)).files;
|
|
27509
27882
|
};
|
|
27510
|
-
var scanLocalCheckoutFiles = async (rootDir, ignorePatterns, syncIncludePaths, progress) => {
|
|
27511
|
-
const matcher = createIgnoreMatcher(ignorePatterns);
|
|
27883
|
+
var scanLocalCheckoutFiles = async (rootDir, ignorePatterns, syncIncludePaths, progress, ignoreMatcher) => {
|
|
27884
|
+
const matcher = ignoreMatcher ?? createIgnoreMatcher(ignorePatterns);
|
|
27512
27885
|
const includePaths = normalizeCheckoutIncludePaths(syncIncludePaths);
|
|
27513
27886
|
const scan = {
|
|
27514
27887
|
files: [],
|
|
@@ -27530,18 +27903,76 @@ var scanLocalCheckoutFiles = async (rootDir, ignorePatterns, syncIncludePaths, p
|
|
|
27530
27903
|
);
|
|
27531
27904
|
return scan;
|
|
27532
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
|
+
};
|
|
27533
27924
|
var pullCheckout = async ({
|
|
27534
27925
|
client,
|
|
27535
27926
|
dryRun = false,
|
|
27536
27927
|
filePaths,
|
|
27537
27928
|
force = false,
|
|
27538
27929
|
ignorePatterns,
|
|
27930
|
+
ignoreMatcher,
|
|
27931
|
+
ignoreMatchersByRule,
|
|
27932
|
+
ignoreSettings,
|
|
27933
|
+
ignorePatternsByStore,
|
|
27539
27934
|
localPath,
|
|
27540
27935
|
progress,
|
|
27541
27936
|
storeRef,
|
|
27542
27937
|
syncIncludePaths,
|
|
27543
27938
|
syncRules
|
|
27544
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
|
+
}
|
|
27545
27976
|
const requestedRelativePaths = normalizeCheckoutFilePaths(filePaths);
|
|
27546
27977
|
if (syncRules) {
|
|
27547
27978
|
await ensureManifestSyncRules(localPath, syncRules, {
|
|
@@ -27582,7 +28013,8 @@ var pullCheckout = async ({
|
|
|
27582
28013
|
dryRun,
|
|
27583
28014
|
filePaths: ruleFilePaths ?? void 0,
|
|
27584
28015
|
force,
|
|
27585
|
-
ignorePatterns,
|
|
28016
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
28017
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
27586
28018
|
localPath,
|
|
27587
28019
|
progress: checkoutProgressWithSyncRuleRemoteRefs(
|
|
27588
28020
|
progress,
|
|
@@ -27613,7 +28045,7 @@ var pullCheckout = async ({
|
|
|
27613
28045
|
);
|
|
27614
28046
|
}
|
|
27615
28047
|
const remoteEntries = [];
|
|
27616
|
-
const matcher = createIgnoreMatcher(ignorePatterns);
|
|
28048
|
+
const matcher = ignoreMatcher ?? createIgnoreMatcher(ignorePatterns);
|
|
27617
28049
|
const includePaths = normalizeCheckoutIncludePaths(syncIncludePaths);
|
|
27618
28050
|
const manifest = await readCheckoutFilesManifest(localPath);
|
|
27619
28051
|
const manifestSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -27662,6 +28094,7 @@ var pullCheckout = async ({
|
|
|
27662
28094
|
const files = remoteEntries.filter(
|
|
27663
28095
|
(file2) => isCheckoutPathIncluded2(file2.relativePath, false, includePaths)
|
|
27664
28096
|
);
|
|
28097
|
+
const markdownLinkTargets = markdownLinkTargetsFromEntries(files);
|
|
27665
28098
|
const remotePaths = new Set(files.map((file2) => file2.relativePath));
|
|
27666
28099
|
const remoteRenameConflictDetails = dryRun ? [] : await reconcileRemoteRenamesBeforePull({
|
|
27667
28100
|
dryRun,
|
|
@@ -27723,7 +28156,7 @@ var pullCheckout = async ({
|
|
|
27723
28156
|
}
|
|
27724
28157
|
if (!dryRun) {
|
|
27725
28158
|
const deletedLocalFile = await deleteLocalFileIfPresent(
|
|
27726
|
-
|
|
28159
|
+
path9.join(localPath, relativePath)
|
|
27727
28160
|
);
|
|
27728
28161
|
delete manifest.files[relativePath];
|
|
27729
28162
|
manifest.references[relativePath] = {
|
|
@@ -27808,7 +28241,7 @@ var pullCheckout = async ({
|
|
|
27808
28241
|
);
|
|
27809
28242
|
}
|
|
27810
28243
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
27811
|
-
await atomicWriteBinaryFile(
|
|
28244
|
+
await atomicWriteBinaryFile(path9.join(localPath, relativePath), bytes);
|
|
27812
28245
|
updateFileManifestEntry({
|
|
27813
28246
|
storageClass: "binary",
|
|
27814
28247
|
hash: hashBytes(bytes),
|
|
@@ -27827,14 +28260,20 @@ var pullCheckout = async ({
|
|
|
27827
28260
|
if (!remoteFile?.content || !("text" in remoteFile.content)) {
|
|
27828
28261
|
throw new Error("remote file did not include text content");
|
|
27829
28262
|
}
|
|
28263
|
+
const localText = rewriteMarkdownForLocalCheckout({
|
|
28264
|
+
client,
|
|
28265
|
+
relativePath,
|
|
28266
|
+
targets: markdownLinkTargets,
|
|
28267
|
+
text: remoteFile.content.text
|
|
28268
|
+
});
|
|
27830
28269
|
await atomicWriteTextFile(
|
|
27831
|
-
|
|
27832
|
-
|
|
28270
|
+
path9.join(localPath, relativePath),
|
|
28271
|
+
localText,
|
|
27833
28272
|
remoteFile.isExecutable === true
|
|
27834
28273
|
);
|
|
27835
28274
|
updateFileManifestEntry({
|
|
27836
28275
|
storageClass: "text",
|
|
27837
|
-
hash: hashText(
|
|
28276
|
+
hash: hashText(localText),
|
|
27838
28277
|
manifest,
|
|
27839
28278
|
path: relativePath,
|
|
27840
28279
|
remoteFile,
|
|
@@ -27980,6 +28419,7 @@ var pullStoreFiles = async ({
|
|
|
27980
28419
|
}
|
|
27981
28420
|
const downloadProgress = withCheckoutProgressDirection(progress, "download");
|
|
27982
28421
|
downloadProgress?.onTotal?.(files.length + missingRemoteDetails.length);
|
|
28422
|
+
const markdownLinkTargets = markdownLinkTargetsFromEntries(files);
|
|
27983
28423
|
return runInParallel(
|
|
27984
28424
|
files,
|
|
27985
28425
|
(file2) => file2.relativePath,
|
|
@@ -27997,7 +28437,7 @@ var pullStoreFiles = async ({
|
|
|
27997
28437
|
if (!remoteFile) {
|
|
27998
28438
|
throw new Error("remote file disappeared while pulling");
|
|
27999
28439
|
}
|
|
28000
|
-
const destinationPath =
|
|
28440
|
+
const destinationPath = path9.join(localPath, targetPath, relativePath);
|
|
28001
28441
|
const changeType = await localPathExists(destinationPath) ? "updated" : "created";
|
|
28002
28442
|
if (remoteFileHasBlobContent(remoteFile)) {
|
|
28003
28443
|
const { downloadUrl } = await client.createFileDownloadUrlByRef({
|
|
@@ -28017,9 +28457,15 @@ var pullStoreFiles = async ({
|
|
|
28017
28457
|
if (!remoteFile.content || !("text" in remoteFile.content)) {
|
|
28018
28458
|
throw new Error("remote file did not include text content");
|
|
28019
28459
|
}
|
|
28460
|
+
const localText = rewriteMarkdownForLocalCheckout({
|
|
28461
|
+
client,
|
|
28462
|
+
relativePath,
|
|
28463
|
+
targets: markdownLinkTargets,
|
|
28464
|
+
text: remoteFile.content.text
|
|
28465
|
+
});
|
|
28020
28466
|
await atomicWriteTextFile(
|
|
28021
28467
|
destinationPath,
|
|
28022
|
-
|
|
28468
|
+
localText,
|
|
28023
28469
|
remoteFile.isExecutable === true
|
|
28024
28470
|
);
|
|
28025
28471
|
return { changeType, status: "succeeded" };
|
|
@@ -28042,12 +28488,52 @@ var pushCheckout = async ({
|
|
|
28042
28488
|
filePaths,
|
|
28043
28489
|
force,
|
|
28044
28490
|
ignorePatterns,
|
|
28491
|
+
ignoreMatcher,
|
|
28492
|
+
ignoreMatchersByRule,
|
|
28493
|
+
ignoreSettings,
|
|
28494
|
+
ignorePatternsByStore,
|
|
28045
28495
|
localPath,
|
|
28046
28496
|
progress,
|
|
28047
28497
|
storeRef,
|
|
28048
28498
|
syncIncludePaths,
|
|
28049
28499
|
syncRules
|
|
28050
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
|
+
}
|
|
28051
28537
|
const requestedRelativePaths = normalizeCheckoutFilePaths(filePaths);
|
|
28052
28538
|
if (syncRules) {
|
|
28053
28539
|
await ensureManifestSyncRules(localPath, syncRules, {
|
|
@@ -28088,7 +28574,8 @@ var pushCheckout = async ({
|
|
|
28088
28574
|
dryRun,
|
|
28089
28575
|
filePaths: ruleFilePaths ?? void 0,
|
|
28090
28576
|
force,
|
|
28091
|
-
ignorePatterns,
|
|
28577
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
28578
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
28092
28579
|
localPath,
|
|
28093
28580
|
progress: checkoutProgressWithSyncRuleRemoteRefs(
|
|
28094
28581
|
progress,
|
|
@@ -28118,14 +28605,20 @@ var pushCheckout = async ({
|
|
|
28118
28605
|
"upload"
|
|
28119
28606
|
);
|
|
28120
28607
|
}
|
|
28121
|
-
const matcher = createIgnoreMatcher(ignorePatterns);
|
|
28608
|
+
const matcher = ignoreMatcher ?? createIgnoreMatcher(ignorePatterns);
|
|
28122
28609
|
const includePaths = normalizeCheckoutIncludePaths(syncIncludePaths);
|
|
28123
28610
|
const scan = requestedRelativePaths ? await scanTargetLocalCheckoutFiles(
|
|
28124
28611
|
localPath,
|
|
28125
28612
|
requestedRelativePaths,
|
|
28126
28613
|
includePaths,
|
|
28127
28614
|
matcher
|
|
28128
|
-
) : await scanLocalCheckoutFiles(
|
|
28615
|
+
) : await scanLocalCheckoutFiles(
|
|
28616
|
+
localPath,
|
|
28617
|
+
ignorePatterns,
|
|
28618
|
+
includePaths,
|
|
28619
|
+
void 0,
|
|
28620
|
+
matcher
|
|
28621
|
+
);
|
|
28129
28622
|
const manifest = await readCheckoutFilesManifest(localPath);
|
|
28130
28623
|
const manifestSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28131
28624
|
const localPaths = new Set(scan.files.map((file2) => file2.relativePath));
|
|
@@ -28273,7 +28766,11 @@ var pushCheckout = async ({
|
|
|
28273
28766
|
relativePath: file2.relativePath,
|
|
28274
28767
|
remoteRevisionNumber: manifestEntry?.remoteRevisionNumber,
|
|
28275
28768
|
storeRef,
|
|
28276
|
-
text:
|
|
28769
|
+
text: rewriteMarkdownForRemoteStore({
|
|
28770
|
+
manifest,
|
|
28771
|
+
relativePath: file2.relativePath,
|
|
28772
|
+
text: file2.text
|
|
28773
|
+
})
|
|
28277
28774
|
});
|
|
28278
28775
|
const pushed = await client.writeTextFileByRef(writeInput);
|
|
28279
28776
|
updateFileManifestEntry({
|
|
@@ -28381,7 +28878,7 @@ var pullRemoteFileIntoCheckout = async ({
|
|
|
28381
28878
|
);
|
|
28382
28879
|
}
|
|
28383
28880
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
28384
|
-
await atomicWriteBinaryFile(
|
|
28881
|
+
await atomicWriteBinaryFile(path9.join(localPath, relativePath), bytes);
|
|
28385
28882
|
updateFileManifestEntry({
|
|
28386
28883
|
storageClass: "binary",
|
|
28387
28884
|
hash: hashBytes(bytes),
|
|
@@ -28400,14 +28897,20 @@ var pullRemoteFileIntoCheckout = async ({
|
|
|
28400
28897
|
if (!remoteFile.content || !("text" in remoteFile.content)) {
|
|
28401
28898
|
throw new Error("remote file did not include text content");
|
|
28402
28899
|
}
|
|
28900
|
+
const localText = rewriteMarkdownForLocalCheckout({
|
|
28901
|
+
client,
|
|
28902
|
+
relativePath,
|
|
28903
|
+
targets: markdownLinkTargetsFromManifest(manifest),
|
|
28904
|
+
text: remoteFile.content.text
|
|
28905
|
+
});
|
|
28403
28906
|
await atomicWriteTextFile(
|
|
28404
|
-
|
|
28405
|
-
|
|
28907
|
+
path9.join(localPath, relativePath),
|
|
28908
|
+
localText,
|
|
28406
28909
|
remoteFile.isExecutable === true
|
|
28407
28910
|
);
|
|
28408
28911
|
updateFileManifestEntry({
|
|
28409
28912
|
storageClass: "text",
|
|
28410
|
-
hash: hashText(
|
|
28913
|
+
hash: hashText(localText),
|
|
28411
28914
|
manifest,
|
|
28412
28915
|
path: relativePath,
|
|
28413
28916
|
remoteFile,
|
|
@@ -28448,7 +28951,11 @@ var pushLocalFileFromCheckout = async ({
|
|
|
28448
28951
|
relativePath: file2.relativePath,
|
|
28449
28952
|
remoteRevisionNumber: manifestEntry?.remoteRevisionNumber,
|
|
28450
28953
|
storeRef,
|
|
28451
|
-
text:
|
|
28954
|
+
text: rewriteMarkdownForRemoteStore({
|
|
28955
|
+
manifest,
|
|
28956
|
+
relativePath: file2.relativePath,
|
|
28957
|
+
text: file2.text
|
|
28958
|
+
})
|
|
28452
28959
|
})
|
|
28453
28960
|
);
|
|
28454
28961
|
updateFileManifestEntry({
|
|
@@ -28490,7 +28997,7 @@ var remoteFileHash = async ({
|
|
|
28490
28997
|
client,
|
|
28491
28998
|
remoteFile,
|
|
28492
28999
|
storeRef,
|
|
28493
|
-
path:
|
|
29000
|
+
path: path22
|
|
28494
29001
|
}) => {
|
|
28495
29002
|
const textHash = remoteTextHash(remoteFile);
|
|
28496
29003
|
if (textHash) {
|
|
@@ -28501,7 +29008,7 @@ var remoteFileHash = async ({
|
|
|
28501
29008
|
}
|
|
28502
29009
|
const { downloadUrl } = await client.createFileDownloadUrlByRef({
|
|
28503
29010
|
...storeRef,
|
|
28504
|
-
path:
|
|
29011
|
+
path: path22
|
|
28505
29012
|
});
|
|
28506
29013
|
const response = await fetch(downloadUrl);
|
|
28507
29014
|
if (!response.ok) {
|
|
@@ -28651,6 +29158,7 @@ var deleteRemoteFileFromCheckout = async ({
|
|
|
28651
29158
|
};
|
|
28652
29159
|
var executeSyncCheckoutFiles = async ({
|
|
28653
29160
|
client,
|
|
29161
|
+
conflictPolicy,
|
|
28654
29162
|
dryRun,
|
|
28655
29163
|
force,
|
|
28656
29164
|
localPath,
|
|
@@ -28675,6 +29183,7 @@ var executeSyncCheckoutFiles = async ({
|
|
|
28675
29183
|
paths,
|
|
28676
29184
|
(relativePath) => relativePath,
|
|
28677
29185
|
async (relativePath) => syncCheckoutFile({
|
|
29186
|
+
conflictPolicy,
|
|
28678
29187
|
client,
|
|
28679
29188
|
dryRun,
|
|
28680
29189
|
force,
|
|
@@ -28701,6 +29210,7 @@ var ignoredCheckoutFileResult = (ignored) => ({
|
|
|
28701
29210
|
});
|
|
28702
29211
|
var planSyncCheckoutSession = async ({
|
|
28703
29212
|
client,
|
|
29213
|
+
conflictPolicy,
|
|
28704
29214
|
dryRun,
|
|
28705
29215
|
files,
|
|
28706
29216
|
force,
|
|
@@ -28717,6 +29227,10 @@ var planSyncCheckoutSession = async ({
|
|
|
28717
29227
|
remoteFileCount: files.length
|
|
28718
29228
|
});
|
|
28719
29229
|
const remoteRenameConflictDetails = await reconcileRemoteRenamesBeforePull({
|
|
29230
|
+
client,
|
|
29231
|
+
conflictPolicy,
|
|
29232
|
+
localFiles: scan.files,
|
|
29233
|
+
storeRef,
|
|
28720
29234
|
dryRun,
|
|
28721
29235
|
files,
|
|
28722
29236
|
force,
|
|
@@ -28726,7 +29240,7 @@ var planSyncCheckoutSession = async ({
|
|
|
28726
29240
|
const remoteRenameConflictPaths = checkoutDetailPathSet(
|
|
28727
29241
|
remoteRenameConflictDetails
|
|
28728
29242
|
);
|
|
28729
|
-
|
|
29243
|
+
let snapshot = buildSyncCheckoutSnapshot({
|
|
28730
29244
|
includePaths,
|
|
28731
29245
|
isIgnored: (relativePath) => isIgnored(relativePath, false, includePaths, matcher),
|
|
28732
29246
|
localFiles: scan.files,
|
|
@@ -28742,6 +29256,9 @@ var planSyncCheckoutSession = async ({
|
|
|
28742
29256
|
phase: "local-rename-preflight"
|
|
28743
29257
|
});
|
|
28744
29258
|
const structuralPreflight = await preflightLocalRenamesBeforePush({
|
|
29259
|
+
conflictPolicy,
|
|
29260
|
+
remoteFiles: files,
|
|
29261
|
+
localPath,
|
|
28745
29262
|
client,
|
|
28746
29263
|
deletePaths: snapshot.deletePaths,
|
|
28747
29264
|
dryRun,
|
|
@@ -28749,6 +29266,26 @@ var planSyncCheckoutSession = async ({
|
|
|
28749
29266
|
manifest,
|
|
28750
29267
|
storeRef
|
|
28751
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
|
+
});
|
|
28752
29289
|
const preflightDetails = [
|
|
28753
29290
|
...scan.ignored.map(ignoredCheckoutFileResult),
|
|
28754
29291
|
...scan.unsupported.map(unsupportedCheckoutFileResult)
|
|
@@ -28763,6 +29300,7 @@ var planSyncCheckoutSession = async ({
|
|
|
28763
29300
|
});
|
|
28764
29301
|
return {
|
|
28765
29302
|
explicitDetails: [
|
|
29303
|
+
...withCheckoutDetailsDirection(policyDetails, "download"),
|
|
28766
29304
|
...withCheckoutDetailsDirection(remoteRenameConflictDetails, "download"),
|
|
28767
29305
|
...withCheckoutDetailsDirection(
|
|
28768
29306
|
structuralPreflight.movedDetails,
|
|
@@ -28798,6 +29336,7 @@ var readSyncCheckoutRemoteFiles = async ({
|
|
|
28798
29336
|
};
|
|
28799
29337
|
var scanSyncCheckoutLocalFiles = async ({
|
|
28800
29338
|
ignorePatterns,
|
|
29339
|
+
ignoreMatcher,
|
|
28801
29340
|
includePaths,
|
|
28802
29341
|
localPath,
|
|
28803
29342
|
progress
|
|
@@ -28806,7 +29345,8 @@ var scanSyncCheckoutLocalFiles = async ({
|
|
|
28806
29345
|
localPath,
|
|
28807
29346
|
ignorePatterns,
|
|
28808
29347
|
includePaths,
|
|
28809
|
-
progress
|
|
29348
|
+
progress,
|
|
29349
|
+
ignoreMatcher
|
|
28810
29350
|
);
|
|
28811
29351
|
reportCheckoutProgressEvent(
|
|
28812
29352
|
progress,
|
|
@@ -28860,6 +29400,7 @@ var finalizeSyncCheckoutSession = async ({
|
|
|
28860
29400
|
};
|
|
28861
29401
|
var syncCheckoutFile = async ({
|
|
28862
29402
|
client,
|
|
29403
|
+
conflictPolicy,
|
|
28863
29404
|
dryRun,
|
|
28864
29405
|
force,
|
|
28865
29406
|
isInsideRemoteReference,
|
|
@@ -28874,7 +29415,7 @@ var syncCheckoutFile = async ({
|
|
|
28874
29415
|
const manifestEntry = manifest.files[relativePath];
|
|
28875
29416
|
const remoteKind = remoteFile ? isReferenceEntry(remoteFile.entry) ? "reference" : "file" : "missing";
|
|
28876
29417
|
let remoteVersionChanged = false;
|
|
28877
|
-
if (remoteKind === "file" && remoteFile &&
|
|
29418
|
+
if (remoteKind === "file" && remoteFile && manifestEntry) {
|
|
28878
29419
|
if (typeof remoteFile.entry.revisionNumber === "number") {
|
|
28879
29420
|
remoteVersionChanged = (manifestEntry.remoteRevisionNumber ?? null) !== remoteFile.entry.revisionNumber;
|
|
28880
29421
|
} else {
|
|
@@ -28888,18 +29429,19 @@ var syncCheckoutFile = async ({
|
|
|
28888
29429
|
remoteVersionChanged = (manifestEntry.remoteRevisionNumber ?? null) !== remoteRevisionNumberForConflictCheck(remote);
|
|
28889
29430
|
}
|
|
28890
29431
|
}
|
|
28891
|
-
if (isReferenceManifestEntry(manifestEntry)) {
|
|
29432
|
+
if (isReferenceManifestEntry(manifestEntry) && (!conflictPolicy || remoteKind === "missing")) {
|
|
28892
29433
|
const localHash = localFile?.hash ?? null;
|
|
28893
29434
|
const localChanged = localHash === null || localHash !== manifestEntry.hash;
|
|
28894
29435
|
if (remoteKind === "missing") {
|
|
28895
|
-
if (dryRun) {
|
|
29436
|
+
if (dryRun && !conflictPolicy) {
|
|
28896
29437
|
return withCheckoutWorkerDirection(
|
|
28897
29438
|
localChanged ? "deleted" : "ignored",
|
|
28898
29439
|
"download"
|
|
28899
29440
|
);
|
|
28900
29441
|
}
|
|
28901
29442
|
const result = await reconcileTrackedRemoteDelete({
|
|
28902
|
-
|
|
29443
|
+
dryRun,
|
|
29444
|
+
force: force || conflictPolicy === "remote",
|
|
28903
29445
|
localFileHash: localHash,
|
|
28904
29446
|
localPath,
|
|
28905
29447
|
manifest,
|
|
@@ -28916,7 +29458,7 @@ var syncCheckoutFile = async ({
|
|
|
28916
29458
|
return withCheckoutWorkerDirection(
|
|
28917
29459
|
await deleteRemoteFileFromCheckout({
|
|
28918
29460
|
client,
|
|
28919
|
-
force,
|
|
29461
|
+
force: force || conflictPolicy === "local",
|
|
28920
29462
|
manifest,
|
|
28921
29463
|
manifestEntry,
|
|
28922
29464
|
relativePath,
|
|
@@ -28946,7 +29488,7 @@ var syncCheckoutFile = async ({
|
|
|
28946
29488
|
await pushLocalFileFromCheckout({
|
|
28947
29489
|
client,
|
|
28948
29490
|
file: localFile,
|
|
28949
|
-
force,
|
|
29491
|
+
force: force || conflictPolicy === "local",
|
|
28950
29492
|
manifest,
|
|
28951
29493
|
manifestEntry,
|
|
28952
29494
|
manifestSyncedAt,
|
|
@@ -29029,6 +29571,8 @@ var syncCheckoutFile = async ({
|
|
|
29029
29571
|
}
|
|
29030
29572
|
}
|
|
29031
29573
|
const plan = planSyncCheckoutFile({
|
|
29574
|
+
resolvedConflict: remoteFile?.conflictWinner,
|
|
29575
|
+
conflictPolicy,
|
|
29032
29576
|
force,
|
|
29033
29577
|
localIsExecutable: localFile?.storageClass === "text" ? localFile.isExecutable : false,
|
|
29034
29578
|
localHash: localFile?.hash ?? null,
|
|
@@ -29072,7 +29616,7 @@ var syncCheckoutFile = async ({
|
|
|
29072
29616
|
if (!remoteFile || !isReferenceEntry(remoteFile.entry)) {
|
|
29073
29617
|
throw new Error("planned reference accept without remote reference");
|
|
29074
29618
|
}
|
|
29075
|
-
const deletedLocalFile = !dryRun && (localFile || manifestEntry) ? await deleteLocalFileIfPresent(
|
|
29619
|
+
const deletedLocalFile = !dryRun && (localFile || manifestEntry) ? await deleteLocalFileIfPresent(path9.join(localPath, relativePath)) : false;
|
|
29076
29620
|
if (!dryRun) {
|
|
29077
29621
|
delete manifest.files[relativePath];
|
|
29078
29622
|
manifest.references[relativePath] = {
|
|
@@ -29091,7 +29635,7 @@ var syncCheckoutFile = async ({
|
|
|
29091
29635
|
}
|
|
29092
29636
|
const result = await reconcileTrackedRemoteDelete({
|
|
29093
29637
|
dryRun,
|
|
29094
|
-
force,
|
|
29638
|
+
force: force || conflictPolicy === "remote",
|
|
29095
29639
|
localFileHash: localFile?.hash ?? null,
|
|
29096
29640
|
localPath,
|
|
29097
29641
|
manifest,
|
|
@@ -29101,7 +29645,11 @@ var syncCheckoutFile = async ({
|
|
|
29101
29645
|
return typeof result === "string" || result.status !== "failed" ? withCheckoutWorkerDirection(result, "download") : result;
|
|
29102
29646
|
}
|
|
29103
29647
|
if (plan.type === "pullRemote") {
|
|
29104
|
-
|
|
29648
|
+
const pullEntry = remoteFile?.entry ?? (remotePathExists ? await client.readFileByRef({
|
|
29649
|
+
...storeRef,
|
|
29650
|
+
path: toStorePath2(relativePath)
|
|
29651
|
+
}) : null);
|
|
29652
|
+
if (!pullEntry) {
|
|
29105
29653
|
throw new Error("planned pull without remote file");
|
|
29106
29654
|
}
|
|
29107
29655
|
if (dryRun) {
|
|
@@ -29116,13 +29664,13 @@ var syncCheckoutFile = async ({
|
|
|
29116
29664
|
return withCheckoutWorkerDirection(
|
|
29117
29665
|
await pullRemoteFileIntoCheckout({
|
|
29118
29666
|
client,
|
|
29119
|
-
entry:
|
|
29667
|
+
entry: pullEntry,
|
|
29120
29668
|
localPath,
|
|
29121
29669
|
manifest,
|
|
29122
29670
|
manifestEntry,
|
|
29123
29671
|
manifestSyncedAt,
|
|
29124
29672
|
relativePath,
|
|
29125
|
-
source: remoteFile
|
|
29673
|
+
source: remoteFile?.source,
|
|
29126
29674
|
storeRef
|
|
29127
29675
|
}),
|
|
29128
29676
|
"download"
|
|
@@ -29141,13 +29689,17 @@ var syncCheckoutFile = async ({
|
|
|
29141
29689
|
"upload"
|
|
29142
29690
|
);
|
|
29143
29691
|
}
|
|
29692
|
+
const pushManifestEntry = conflictPolicy === "local" && manifestEntry?.storageClass === "binary" && remoteFile ? {
|
|
29693
|
+
...manifestEntry,
|
|
29694
|
+
remoteRevisionNumber: remoteFile.entry.revisionNumber
|
|
29695
|
+
} : manifestEntry;
|
|
29144
29696
|
return withCheckoutWorkerDirection(
|
|
29145
29697
|
await pushLocalFileFromCheckout({
|
|
29146
29698
|
client,
|
|
29147
29699
|
file: localFile,
|
|
29148
|
-
force,
|
|
29700
|
+
force: force || conflictPolicy === "local",
|
|
29149
29701
|
manifest,
|
|
29150
|
-
manifestEntry,
|
|
29702
|
+
manifestEntry: pushManifestEntry,
|
|
29151
29703
|
manifestSyncedAt,
|
|
29152
29704
|
storeRef
|
|
29153
29705
|
}),
|
|
@@ -29164,7 +29716,7 @@ var syncCheckoutFile = async ({
|
|
|
29164
29716
|
return withCheckoutWorkerDirection(
|
|
29165
29717
|
await deleteRemoteFileFromCheckout({
|
|
29166
29718
|
client,
|
|
29167
|
-
force,
|
|
29719
|
+
force: force || conflictPolicy === "local",
|
|
29168
29720
|
manifest,
|
|
29169
29721
|
manifestEntry,
|
|
29170
29722
|
relativePath,
|
|
@@ -29177,16 +29729,18 @@ var syncCheckoutFile = async ({
|
|
|
29177
29729
|
};
|
|
29178
29730
|
var syncCheckoutRuleFiles = async ({
|
|
29179
29731
|
client,
|
|
29732
|
+
conflictPolicy,
|
|
29180
29733
|
dryRun,
|
|
29181
29734
|
force,
|
|
29182
29735
|
ignorePatterns,
|
|
29736
|
+
ignoreMatcher,
|
|
29183
29737
|
localPath,
|
|
29184
29738
|
progress,
|
|
29185
29739
|
referenceSyncMode,
|
|
29186
29740
|
storeRef,
|
|
29187
29741
|
syncIncludePaths
|
|
29188
29742
|
}) => {
|
|
29189
|
-
const matcher = createIgnoreMatcher(ignorePatterns);
|
|
29743
|
+
const matcher = ignoreMatcher ?? createIgnoreMatcher(ignorePatterns);
|
|
29190
29744
|
const includePaths = normalizeCheckoutIncludePaths(syncIncludePaths);
|
|
29191
29745
|
const manifest = await readCheckoutFilesManifest(localPath);
|
|
29192
29746
|
const manifestSyncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -29197,12 +29751,14 @@ var syncCheckoutRuleFiles = async ({
|
|
|
29197
29751
|
storeRef
|
|
29198
29752
|
});
|
|
29199
29753
|
const scan = await scanSyncCheckoutLocalFiles({
|
|
29754
|
+
ignoreMatcher,
|
|
29200
29755
|
ignorePatterns,
|
|
29201
29756
|
includePaths,
|
|
29202
29757
|
localPath,
|
|
29203
29758
|
progress
|
|
29204
29759
|
});
|
|
29205
29760
|
const sessionPlan = await planSyncCheckoutSession({
|
|
29761
|
+
conflictPolicy,
|
|
29206
29762
|
client,
|
|
29207
29763
|
dryRun,
|
|
29208
29764
|
files,
|
|
@@ -29224,6 +29780,7 @@ var syncCheckoutRuleFiles = async ({
|
|
|
29224
29780
|
progress?.onTotal?.(explicitDetails.length + paths.length);
|
|
29225
29781
|
reportCheckoutDetails(progress, explicitDetails);
|
|
29226
29782
|
const result = await executeSyncCheckoutFiles({
|
|
29783
|
+
conflictPolicy,
|
|
29227
29784
|
client,
|
|
29228
29785
|
dryRun,
|
|
29229
29786
|
force,
|
|
@@ -29255,9 +29812,14 @@ var syncCheckoutRuleFiles = async ({
|
|
|
29255
29812
|
var syncCheckout = async ({
|
|
29256
29813
|
beforeRuleApply,
|
|
29257
29814
|
client,
|
|
29815
|
+
conflictPolicy,
|
|
29258
29816
|
dryRun = false,
|
|
29259
29817
|
force,
|
|
29260
29818
|
ignorePatterns,
|
|
29819
|
+
ignoreMatcher,
|
|
29820
|
+
ignoreMatchersByRule,
|
|
29821
|
+
ignoreSettings,
|
|
29822
|
+
ignorePatternsByStore,
|
|
29261
29823
|
localPath,
|
|
29262
29824
|
progress,
|
|
29263
29825
|
referenceSyncMode = false,
|
|
@@ -29265,6 +29827,44 @@ var syncCheckout = async ({
|
|
|
29265
29827
|
syncIncludePaths,
|
|
29266
29828
|
syncRules
|
|
29267
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
|
+
}
|
|
29268
29868
|
if (syncRules) {
|
|
29269
29869
|
reportCheckoutProgressEvent(progress, "Checking checkout sync rules", {
|
|
29270
29870
|
phase: "sync-rules",
|
|
@@ -29364,15 +29964,18 @@ var syncCheckout = async ({
|
|
|
29364
29964
|
client: ruleClient,
|
|
29365
29965
|
dryRun: true,
|
|
29366
29966
|
force,
|
|
29367
|
-
ignorePatterns,
|
|
29967
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
29968
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
29368
29969
|
localPath,
|
|
29369
29970
|
storeRef: ruleStoreRef,
|
|
29370
29971
|
syncIncludePaths: ruleIncludePaths
|
|
29371
29972
|
}) : await syncCheckoutRuleFiles({
|
|
29973
|
+
conflictPolicy,
|
|
29372
29974
|
client: ruleClient,
|
|
29373
29975
|
dryRun: true,
|
|
29374
29976
|
force,
|
|
29375
|
-
ignorePatterns,
|
|
29977
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
29978
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
29376
29979
|
localPath,
|
|
29377
29980
|
referenceSyncMode: isStoreReferenceRule,
|
|
29378
29981
|
storeRef: ruleStoreRef,
|
|
@@ -29396,16 +29999,19 @@ var syncCheckout = async ({
|
|
|
29396
29999
|
client: ruleClient,
|
|
29397
30000
|
dryRun,
|
|
29398
30001
|
force,
|
|
29399
|
-
ignorePatterns,
|
|
30002
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
30003
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
29400
30004
|
localPath,
|
|
29401
30005
|
progress: ruleProgress,
|
|
29402
30006
|
storeRef: ruleStoreRef,
|
|
29403
30007
|
syncIncludePaths: ruleIncludePaths
|
|
29404
30008
|
}) : await syncCheckoutRuleFiles({
|
|
30009
|
+
conflictPolicy,
|
|
29405
30010
|
client: ruleClient,
|
|
29406
30011
|
dryRun,
|
|
29407
30012
|
force,
|
|
29408
|
-
ignorePatterns,
|
|
30013
|
+
ignorePatterns: ignorePatternsByStore?.[rule.store] ?? ignorePatterns,
|
|
30014
|
+
ignoreMatcher: ignoreMatchersByRule?.[rule.id],
|
|
29409
30015
|
localPath,
|
|
29410
30016
|
progress: ruleProgress,
|
|
29411
30017
|
referenceSyncMode: isStoreReferenceRule,
|
|
@@ -29460,6 +30066,8 @@ var syncCheckout = async ({
|
|
|
29460
30066
|
);
|
|
29461
30067
|
}
|
|
29462
30068
|
return syncCheckoutRuleFiles({
|
|
30069
|
+
ignoreMatcher,
|
|
30070
|
+
conflictPolicy,
|
|
29463
30071
|
client,
|
|
29464
30072
|
dryRun,
|
|
29465
30073
|
force,
|
|
@@ -29472,16 +30080,16 @@ var syncCheckout = async ({
|
|
|
29472
30080
|
});
|
|
29473
30081
|
};
|
|
29474
30082
|
var ensureCheckoutDirectoryReady = async (directoryPath) => {
|
|
29475
|
-
await
|
|
30083
|
+
await mkdir4(directoryPath, { recursive: true });
|
|
29476
30084
|
const entries = await readdir2(directoryPath);
|
|
29477
30085
|
if (entries.length > 0) {
|
|
29478
30086
|
throw new Error(`Target directory must be empty: ${directoryPath}`);
|
|
29479
30087
|
}
|
|
29480
30088
|
};
|
|
29481
30089
|
var ensureProjectConfigDoesNotExist = async (directoryPath) => {
|
|
29482
|
-
for (const filename of
|
|
30090
|
+
for (const filename of projectConfigFilenames) {
|
|
29483
30091
|
try {
|
|
29484
|
-
const filePath =
|
|
30092
|
+
const filePath = path9.join(directoryPath, filename);
|
|
29485
30093
|
await stat(filePath);
|
|
29486
30094
|
throw new Error(`Forum config already exists: ${filePath}`);
|
|
29487
30095
|
} catch (error51) {
|
|
@@ -29494,142 +30102,40 @@ var ensureProjectConfigDoesNotExist = async (directoryPath) => {
|
|
|
29494
30102
|
};
|
|
29495
30103
|
|
|
29496
30104
|
// src/ignoreCommand.ts
|
|
29497
|
-
|
|
29498
|
-
|
|
29499
|
-
|
|
29500
|
-
var planIgnoreAdd = (pattern, currentPatterns, remoteFilePaths) => {
|
|
29501
|
-
const trimmed = pattern.trim();
|
|
29502
|
-
if (!trimmed) {
|
|
29503
|
-
throw new Error("Ignore pattern cannot be empty.");
|
|
29504
|
-
}
|
|
29505
|
-
const alreadyPresent = currentPatterns.includes(trimmed);
|
|
29506
|
-
const nextPatterns = resolveIgnorePatterns({
|
|
29507
|
-
bakedIn: [],
|
|
29508
|
-
storeSetting: currentPatterns,
|
|
29509
|
-
localOverride: [trimmed]
|
|
29510
|
-
});
|
|
29511
|
-
const matcher = ignore2().add([trimmed]);
|
|
29512
|
-
const matchedRemotePaths = sortPaths(
|
|
29513
|
-
remoteFilePaths.filter((storePath) => {
|
|
29514
|
-
const relative = toRelative(storePath);
|
|
29515
|
-
return Boolean(relative) && matcher.ignores(relative);
|
|
29516
|
-
})
|
|
29517
|
-
);
|
|
29518
|
-
return { pattern: trimmed, alreadyPresent, nextPatterns, matchedRemotePaths };
|
|
29519
|
-
};
|
|
29520
|
-
var collectRemoteFilePaths = async (client, storeRef) => {
|
|
29521
|
-
const listing = await client.listTreeByRef({
|
|
29522
|
-
...storeRef,
|
|
29523
|
-
directoryPath: "/",
|
|
29524
|
-
includeHidden: true
|
|
29525
|
-
});
|
|
29526
|
-
const entries = listing?.entries ?? [];
|
|
29527
|
-
return sortPaths(
|
|
29528
|
-
entries.filter((entry) => entry.type !== "directory").map((entry) => entry.path)
|
|
29529
|
-
);
|
|
29530
|
-
};
|
|
29531
|
-
var executeIgnoreAdd = async (client, storeRef, pattern, currentPatterns, io) => {
|
|
29532
|
-
const remoteFilePaths = await collectRemoteFilePaths(client, storeRef);
|
|
29533
|
-
const plan = planIgnoreAdd(pattern, currentPatterns, remoteFilePaths);
|
|
29534
|
-
let settingUpdated = false;
|
|
29535
|
-
if (!plan.alreadyPresent) {
|
|
29536
|
-
await client.upsertStoreByRef({
|
|
29537
|
-
...storeRef,
|
|
29538
|
-
patch: { ignore: plan.nextPatterns }
|
|
29539
|
-
});
|
|
29540
|
-
settingUpdated = true;
|
|
29541
|
-
}
|
|
29542
|
-
const deletedRemotePaths = [];
|
|
29543
|
-
let deletedRemoteDirectories = [];
|
|
29544
|
-
if (plan.matchedRemotePaths.length > 0 && await io.confirmRemoteDelete(plan)) {
|
|
29545
|
-
for (const storePath of plan.matchedRemotePaths) {
|
|
29546
|
-
await client.deleteFileByRef({ ...storeRef, path: storePath });
|
|
29547
|
-
deletedRemotePaths.push(storePath);
|
|
29548
|
-
}
|
|
29549
|
-
deletedRemoteDirectories = await cleanupRemoteCheckoutDirectories({
|
|
29550
|
-
client,
|
|
29551
|
-
removedPaths: deletedRemotePaths.map(toRelative),
|
|
29552
|
-
storeRef
|
|
29553
|
-
});
|
|
29554
|
-
}
|
|
30105
|
+
var planIgnoreAdd = (pattern, currentPatterns) => {
|
|
30106
|
+
if (!pattern.trim()) throw new Error("Ignore pattern cannot be empty.");
|
|
30107
|
+
const alreadyPresent = currentPatterns.at(-1) === pattern;
|
|
29555
30108
|
return {
|
|
29556
|
-
|
|
29557
|
-
|
|
29558
|
-
|
|
29559
|
-
deletedRemoteDirectories
|
|
30109
|
+
pattern,
|
|
30110
|
+
alreadyPresent,
|
|
30111
|
+
nextPatterns: alreadyPresent ? currentPatterns : [...currentPatterns, pattern]
|
|
29560
30112
|
};
|
|
29561
30113
|
};
|
|
29562
30114
|
var removeIgnorePattern = (pattern, currentPatterns) => {
|
|
29563
|
-
|
|
29564
|
-
|
|
29565
|
-
throw new Error("Ignore pattern cannot be empty.");
|
|
29566
|
-
}
|
|
29567
|
-
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);
|
|
29568
30117
|
return {
|
|
29569
30118
|
nextPatterns,
|
|
29570
30119
|
removed: nextPatterns.length !== currentPatterns.length,
|
|
29571
|
-
pattern
|
|
30120
|
+
pattern
|
|
29572
30121
|
};
|
|
29573
30122
|
};
|
|
29574
|
-
var setIgnorePatterns = (patterns) =>
|
|
29575
|
-
|
|
29576
|
-
|
|
29577
|
-
|
|
29578
|
-
}
|
|
30123
|
+
var setIgnorePatterns = (patterns) => {
|
|
30124
|
+
if (patterns.some((pattern) => !pattern.trim()))
|
|
30125
|
+
throw new Error("Ignore pattern cannot be empty.");
|
|
30126
|
+
return patterns;
|
|
30127
|
+
};
|
|
29579
30128
|
|
|
29580
30129
|
// src/runIgnoreCommand.ts
|
|
29581
30130
|
var runAdd = async (deps) => {
|
|
29582
|
-
const {
|
|
29583
|
-
|
|
29584
|
-
|
|
29585
|
-
|
|
29586
|
-
|
|
29587
|
-
assumeYes,
|
|
29588
|
-
confirmYesNo: confirmYesNo2,
|
|
29589
|
-
renderOutput: renderOutput2,
|
|
29590
|
-
commandNames: commandNames2
|
|
29591
|
-
} = deps;
|
|
29592
|
-
if (!pattern) {
|
|
29593
|
-
throw new Error(`Usage: ${commandNames2} ignore add <pattern>`);
|
|
29594
|
-
}
|
|
29595
|
-
const io = {
|
|
29596
|
-
confirmRemoteDelete: (plan) => confirmYesNo2({
|
|
29597
|
-
assumeYes,
|
|
29598
|
-
nonInteractiveMessage: "Refusing to delete store files without confirmation. Re-run with --yes.",
|
|
29599
|
-
prompt: `Delete ${plan.matchedRemotePaths.length} matching file(s) from the store? [y/N] `
|
|
29600
|
-
})
|
|
29601
|
-
};
|
|
29602
|
-
const result = await executeIgnoreAdd(
|
|
29603
|
-
client,
|
|
29604
|
-
storeRef,
|
|
29605
|
-
pattern,
|
|
29606
|
-
currentPatterns,
|
|
29607
|
-
io
|
|
29608
|
-
);
|
|
29609
|
-
if (result.settingUpdated) {
|
|
29610
|
-
renderOutput2(`Added ignore rule: ${result.plan.pattern}`);
|
|
29611
|
-
} else {
|
|
29612
|
-
renderOutput2(`Ignore rule already present: ${result.plan.pattern}`);
|
|
29613
|
-
}
|
|
29614
|
-
if (result.plan.matchedRemotePaths.length === 0) {
|
|
29615
|
-
renderOutput2("No already-pushed files matched.");
|
|
29616
|
-
} else if (result.deletedRemotePaths.length > 0) {
|
|
29617
|
-
renderOutput2(
|
|
29618
|
-
`Deleted ${result.deletedRemotePaths.length} file(s) from the store.`
|
|
29619
|
-
);
|
|
29620
|
-
} else {
|
|
29621
|
-
renderOutput2("Left already-pushed matches in place.");
|
|
29622
|
-
}
|
|
29623
|
-
if (result.deletedRemoteDirectories.length > 0) {
|
|
29624
|
-
renderOutput2(
|
|
29625
|
-
`Deleted ${result.deletedRemoteDirectories.length} empty director${result.deletedRemoteDirectories.length === 1 ? "y" : "ies"} from the store.`
|
|
29626
|
-
);
|
|
29627
|
-
}
|
|
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.`);
|
|
29628
30136
|
};
|
|
29629
30137
|
var runList = async (deps) => {
|
|
29630
|
-
const {
|
|
29631
|
-
const metadata = await client.readStoreByRef(storeRef);
|
|
29632
|
-
const ignore3 = metadata?.ignore ?? [];
|
|
30138
|
+
const { currentPatterns: ignore3, renderOutput: renderOutput2 } = deps;
|
|
29633
30139
|
if (ignore3.length === 0) {
|
|
29634
30140
|
renderOutput2("(no ignore rules)");
|
|
29635
30141
|
return;
|
|
@@ -29640,8 +30146,7 @@ var runList = async (deps) => {
|
|
|
29640
30146
|
};
|
|
29641
30147
|
var runRemove = async (deps) => {
|
|
29642
30148
|
const {
|
|
29643
|
-
|
|
29644
|
-
storeRef,
|
|
30149
|
+
writePatterns,
|
|
29645
30150
|
currentPatterns,
|
|
29646
30151
|
pattern,
|
|
29647
30152
|
renderOutput: renderOutput2,
|
|
@@ -29655,14 +30160,11 @@ var runRemove = async (deps) => {
|
|
|
29655
30160
|
renderOutput2(`Ignore rule not present: ${result.pattern}`);
|
|
29656
30161
|
return;
|
|
29657
30162
|
}
|
|
29658
|
-
await
|
|
29659
|
-
...storeRef,
|
|
29660
|
-
patch: { ignore: result.nextPatterns }
|
|
29661
|
-
});
|
|
30163
|
+
await writePatterns(result.nextPatterns);
|
|
29662
30164
|
renderOutput2(`Removed ignore rule: ${result.pattern}`);
|
|
29663
30165
|
};
|
|
29664
30166
|
var runSet = async (deps) => {
|
|
29665
|
-
const {
|
|
30167
|
+
const { writePatterns, patterns, renderOutput: renderOutput2, commandNames: commandNames2 } = deps;
|
|
29666
30168
|
if (patterns.length === 0) {
|
|
29667
30169
|
throw new Error(`Usage: ${commandNames2} ignore set <pattern>...`);
|
|
29668
30170
|
}
|
|
@@ -29670,24 +30172,17 @@ var runSet = async (deps) => {
|
|
|
29670
30172
|
if (nextPatterns.length === 0) {
|
|
29671
30173
|
throw new Error("Ignore pattern cannot be empty.");
|
|
29672
30174
|
}
|
|
29673
|
-
await
|
|
29674
|
-
...storeRef,
|
|
29675
|
-
patch: { ignore: nextPatterns }
|
|
29676
|
-
});
|
|
30175
|
+
await writePatterns(nextPatterns);
|
|
29677
30176
|
renderOutput2(`Set ${nextPatterns.length} ignore rule(s).`);
|
|
29678
30177
|
};
|
|
29679
30178
|
var runClear = async (deps) => {
|
|
29680
|
-
const {
|
|
29681
|
-
await
|
|
29682
|
-
...storeRef,
|
|
29683
|
-
patch: { ignore: [] }
|
|
29684
|
-
});
|
|
30179
|
+
const { writePatterns, renderOutput: renderOutput2 } = deps;
|
|
30180
|
+
await writePatterns([]);
|
|
29685
30181
|
renderOutput2("Cleared ignore rules.");
|
|
29686
30182
|
};
|
|
29687
30183
|
var runAuto = async (deps) => {
|
|
29688
30184
|
const {
|
|
29689
|
-
|
|
29690
|
-
storeRef,
|
|
30185
|
+
writePatterns,
|
|
29691
30186
|
currentPatterns,
|
|
29692
30187
|
assumeYes,
|
|
29693
30188
|
confirmYesNo: confirmYesNo2,
|
|
@@ -29696,9 +30191,9 @@ var runAuto = async (deps) => {
|
|
|
29696
30191
|
renderOutput: renderOutput2
|
|
29697
30192
|
} = deps;
|
|
29698
30193
|
const analysis = await analyzeLocal();
|
|
29699
|
-
const
|
|
29700
|
-
|
|
29701
|
-
|
|
30194
|
+
const proposed = analysis.proposedPatterns;
|
|
30195
|
+
const alreadyAppended = JSON.stringify(currentPatterns.slice(-proposed.length)) === JSON.stringify(proposed);
|
|
30196
|
+
const additions = alreadyAppended ? [] : proposed;
|
|
29702
30197
|
if (additions.length === 0) {
|
|
29703
30198
|
renderOutput2("Nothing to suggest \u2014 no new junk patterns detected.");
|
|
29704
30199
|
await markOnboarded();
|
|
@@ -29711,19 +30206,18 @@ var runAuto = async (deps) => {
|
|
|
29711
30206
|
const confirmed = await confirmYesNo2({
|
|
29712
30207
|
assumeYes,
|
|
29713
30208
|
nonInteractiveMessage: "Refusing to write ignore rules without confirmation. Re-run with --yes.",
|
|
29714
|
-
prompt: `Add ${additions.length} ignore rule(s) to the
|
|
30209
|
+
prompt: `Add ${additions.length} ignore rule(s) to the shared ignore file? [Y/n] `
|
|
29715
30210
|
});
|
|
29716
30211
|
if (!confirmed) {
|
|
29717
|
-
renderOutput2("Left the
|
|
30212
|
+
renderOutput2("Left the shared ignore file unchanged.");
|
|
29718
30213
|
await markOnboarded();
|
|
29719
30214
|
return;
|
|
29720
30215
|
}
|
|
29721
|
-
await
|
|
29722
|
-
...storeRef,
|
|
29723
|
-
patch: { ignore: [...currentPatterns, ...additions] }
|
|
29724
|
-
});
|
|
30216
|
+
await writePatterns([...currentPatterns, ...additions]);
|
|
29725
30217
|
await markOnboarded();
|
|
29726
|
-
renderOutput2(
|
|
30218
|
+
renderOutput2(
|
|
30219
|
+
`Added ${additions.length} ignore rule(s) locally. Run fm sync to publish.`
|
|
30220
|
+
);
|
|
29727
30221
|
};
|
|
29728
30222
|
var runIgnoreCommand = async (deps) => {
|
|
29729
30223
|
const { subcommand, commandNames: commandNames2 } = deps;
|
|
@@ -29780,8 +30274,7 @@ var warnImminent = (analysis, renderWarning2) => {
|
|
|
29780
30274
|
};
|
|
29781
30275
|
var maybePromptIgnoreSetup = async (deps) => {
|
|
29782
30276
|
const {
|
|
29783
|
-
|
|
29784
|
-
storeRef,
|
|
30277
|
+
writePatterns,
|
|
29785
30278
|
currentPatterns,
|
|
29786
30279
|
analysis,
|
|
29787
30280
|
onboarded,
|
|
@@ -29822,13 +30315,10 @@ var maybePromptIgnoreSetup = async (deps) => {
|
|
|
29822
30315
|
}
|
|
29823
30316
|
const action = await chooseAction(analysis);
|
|
29824
30317
|
if (action === "auto") {
|
|
29825
|
-
await
|
|
29826
|
-
...storeRef,
|
|
29827
|
-
patch: { ignore: analysis.proposedPatterns }
|
|
29828
|
-
});
|
|
30318
|
+
await writePatterns(analysis.proposedPatterns);
|
|
29829
30319
|
await markOnboarded();
|
|
29830
30320
|
renderOutput2(
|
|
29831
|
-
`Added ${analysis.proposedPatterns.length} ignore rule(s)
|
|
30321
|
+
`Added ${analysis.proposedPatterns.length} shared ignore rule(s) locally.`
|
|
29832
30322
|
);
|
|
29833
30323
|
return {
|
|
29834
30324
|
outcome: "auto-applied",
|
|
@@ -29855,10 +30345,10 @@ var maybePromptIgnoreSetup = async (deps) => {
|
|
|
29855
30345
|
|
|
29856
30346
|
// src/collectIgnoreMarkers.ts
|
|
29857
30347
|
import { stat as stat2 } from "fs/promises";
|
|
29858
|
-
import
|
|
30348
|
+
import path10 from "path";
|
|
29859
30349
|
var exists = async (rootDir, rule) => {
|
|
29860
30350
|
try {
|
|
29861
|
-
const stats = await stat2(
|
|
30351
|
+
const stats = await stat2(path10.join(rootDir, rule.marker));
|
|
29862
30352
|
return rule.markerKind === "dir" ? stats.isDirectory() : stats.isFile();
|
|
29863
30353
|
} catch {
|
|
29864
30354
|
return false;
|
|
@@ -29877,11 +30367,11 @@ var collectIgnoreMarkers = async (rootDir, rules = IGNORE_PROPOSAL_RULES) => {
|
|
|
29877
30367
|
};
|
|
29878
30368
|
|
|
29879
30369
|
// src/readGitignorePatterns.ts
|
|
29880
|
-
import { readFile as
|
|
29881
|
-
import
|
|
30370
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
30371
|
+
import path11 from "path";
|
|
29882
30372
|
var readGitignorePatterns = async (rootDir) => {
|
|
29883
30373
|
try {
|
|
29884
|
-
const raw = await
|
|
30374
|
+
const raw = await readFile4(path11.join(rootDir, ".gitignore"), "utf8");
|
|
29885
30375
|
return parseLocalIgnoreFile(raw);
|
|
29886
30376
|
} catch {
|
|
29887
30377
|
return [];
|
|
@@ -29945,9 +30435,9 @@ var createHumanWatchSubscriber = ({
|
|
|
29945
30435
|
return;
|
|
29946
30436
|
}
|
|
29947
30437
|
case "sync.watch.conflict.raised": {
|
|
29948
|
-
const
|
|
30438
|
+
const path22 = String(details.path ?? "");
|
|
29949
30439
|
const suggestions = details.suggestions ?? [];
|
|
29950
|
-
error51(`Conflict: ${
|
|
30440
|
+
error51(`Conflict: ${path22} \u2014 ${event.message ?? "needs attention"}`);
|
|
29951
30441
|
if (suggestions.length > 0) {
|
|
29952
30442
|
error51(` ${formatSuggestions(suggestions)}`);
|
|
29953
30443
|
}
|
|
@@ -29976,10 +30466,10 @@ import notifier from "node-notifier";
|
|
|
29976
30466
|
var createNotifyWatchSubscriber = () => {
|
|
29977
30467
|
return (event) => {
|
|
29978
30468
|
if (event.eventType === "sync.watch.conflict.raised") {
|
|
29979
|
-
const
|
|
30469
|
+
const path22 = event.details?.path;
|
|
29980
30470
|
notifier.notify({
|
|
29981
30471
|
title: "Forum sync conflict",
|
|
29982
|
-
message: typeof
|
|
30472
|
+
message: typeof path22 === "string" ? `${path22} needs attention` : event.message ?? "A file needs attention"
|
|
29983
30473
|
});
|
|
29984
30474
|
return;
|
|
29985
30475
|
}
|
|
@@ -30095,10 +30585,10 @@ var createConflictTracker = () => {
|
|
|
30095
30585
|
);
|
|
30096
30586
|
const raised = current.filter((conflict) => !active.has(conflict.path));
|
|
30097
30587
|
const cleared = [...active.keys()].filter(
|
|
30098
|
-
(
|
|
30588
|
+
(path22) => !currentByPath.has(path22)
|
|
30099
30589
|
);
|
|
30100
|
-
for (const
|
|
30101
|
-
active.delete(
|
|
30590
|
+
for (const path22 of cleared) {
|
|
30591
|
+
active.delete(path22);
|
|
30102
30592
|
}
|
|
30103
30593
|
for (const conflict of current) {
|
|
30104
30594
|
active.set(conflict.path, conflict);
|
|
@@ -30109,13 +30599,13 @@ var createConflictTracker = () => {
|
|
|
30109
30599
|
};
|
|
30110
30600
|
|
|
30111
30601
|
// src/watch/conflictResolutionHints.ts
|
|
30112
|
-
var keepLocal = (
|
|
30602
|
+
var keepLocal = (path22) => ({
|
|
30113
30603
|
label: "Keep local",
|
|
30114
|
-
command: `fm push --force ${
|
|
30604
|
+
command: `fm push --force ${path22}`
|
|
30115
30605
|
});
|
|
30116
|
-
var acceptRemote = (
|
|
30606
|
+
var acceptRemote = (path22) => ({
|
|
30117
30607
|
label: "Accept remote",
|
|
30118
|
-
command: `fm pull --force ${
|
|
30608
|
+
command: `fm pull --force ${path22}`
|
|
30119
30609
|
});
|
|
30120
30610
|
var review = (label, command) => ({
|
|
30121
30611
|
label,
|
|
@@ -30131,23 +30621,23 @@ var forceResolvableTypes = /* @__PURE__ */ new Set([
|
|
|
30131
30621
|
"reference-local-file",
|
|
30132
30622
|
"read-only-local-change"
|
|
30133
30623
|
]);
|
|
30134
|
-
var conflictResolutionSuggestions = (conflictType,
|
|
30624
|
+
var conflictResolutionSuggestions = (conflictType, path22) => {
|
|
30135
30625
|
if (forceResolvableTypes.has(conflictType)) {
|
|
30136
|
-
return [keepLocal(
|
|
30626
|
+
return [keepLocal(path22), acceptRemote(path22)];
|
|
30137
30627
|
}
|
|
30138
|
-
return [review("Review", `fm status ${
|
|
30628
|
+
return [review("Review", `fm status ${path22}`)];
|
|
30139
30629
|
};
|
|
30140
30630
|
|
|
30141
30631
|
// src/watch/extractWatchConflicts.ts
|
|
30142
30632
|
var toWatchConflict = (issue2) => {
|
|
30143
|
-
const { path:
|
|
30633
|
+
const { path: path22, message, relatedPaths } = issue2.details.details;
|
|
30144
30634
|
const conflictType = issue2.details.type;
|
|
30145
30635
|
return {
|
|
30146
|
-
path:
|
|
30636
|
+
path: path22,
|
|
30147
30637
|
conflictType,
|
|
30148
30638
|
message,
|
|
30149
30639
|
relatedPaths: relatedPaths ?? [],
|
|
30150
|
-
suggestions: conflictResolutionSuggestions(conflictType,
|
|
30640
|
+
suggestions: conflictResolutionSuggestions(conflictType, path22)
|
|
30151
30641
|
};
|
|
30152
30642
|
};
|
|
30153
30643
|
var extractWatchConflicts = (result) => {
|
|
@@ -30238,9 +30728,9 @@ var createCheckoutWatcher = ({
|
|
|
30238
30728
|
})
|
|
30239
30729
|
);
|
|
30240
30730
|
}
|
|
30241
|
-
for (const
|
|
30731
|
+
for (const path22 of cleared) {
|
|
30242
30732
|
bus.emit(
|
|
30243
|
-
watchEvent("sync.watch.conflict.cleared", void 0, { path:
|
|
30733
|
+
watchEvent("sync.watch.conflict.cleared", void 0, { path: path22 })
|
|
30244
30734
|
);
|
|
30245
30735
|
}
|
|
30246
30736
|
bus.emit(
|
|
@@ -30458,7 +30948,7 @@ var runSyncWatchDirectory = async (options2) => {
|
|
|
30458
30948
|
};
|
|
30459
30949
|
|
|
30460
30950
|
// src/watch/fleetStatusSubscriber.ts
|
|
30461
|
-
import
|
|
30951
|
+
import path12 from "path";
|
|
30462
30952
|
var STATUS_BADGE = {
|
|
30463
30953
|
starting: "\u2026",
|
|
30464
30954
|
clean: "\u2713",
|
|
@@ -30476,15 +30966,15 @@ var STATUS_COLOR = {
|
|
|
30476
30966
|
var deriveLabels = (rootDirs) => {
|
|
30477
30967
|
const counts = /* @__PURE__ */ new Map();
|
|
30478
30968
|
for (const dir of rootDirs) {
|
|
30479
|
-
const base =
|
|
30969
|
+
const base = path12.basename(dir);
|
|
30480
30970
|
counts.set(base, (counts.get(base) ?? 0) + 1);
|
|
30481
30971
|
}
|
|
30482
30972
|
const labels = /* @__PURE__ */ new Map();
|
|
30483
30973
|
for (const dir of rootDirs) {
|
|
30484
|
-
const base =
|
|
30974
|
+
const base = path12.basename(dir);
|
|
30485
30975
|
labels.set(
|
|
30486
30976
|
dir,
|
|
30487
|
-
(counts.get(base) ?? 0) > 1 ?
|
|
30977
|
+
(counts.get(base) ?? 0) > 1 ? path12.join(path12.basename(path12.dirname(dir)), base) : base
|
|
30488
30978
|
);
|
|
30489
30979
|
}
|
|
30490
30980
|
return labels;
|
|
@@ -30583,7 +31073,7 @@ var createFleetStatusSubscriber = (rootDirs, { write, isTty }) => {
|
|
|
30583
31073
|
};
|
|
30584
31074
|
|
|
30585
31075
|
// src/watch/discoverCheckouts.ts
|
|
30586
|
-
import
|
|
31076
|
+
import path13 from "path";
|
|
30587
31077
|
import { readdir as readdir3, stat as stat3 } from "fs/promises";
|
|
30588
31078
|
var pathExists2 = async (candidate) => {
|
|
30589
31079
|
try {
|
|
@@ -30596,7 +31086,7 @@ var pathExists2 = async (candidate) => {
|
|
|
30596
31086
|
var isCheckoutDir = async (dir) => {
|
|
30597
31087
|
let hasStateDirectory = false;
|
|
30598
31088
|
for (const name of checkoutStateDirectoryNames) {
|
|
30599
|
-
if (await pathExists2(
|
|
31089
|
+
if (await pathExists2(path13.join(dir, name))) {
|
|
30600
31090
|
hasStateDirectory = true;
|
|
30601
31091
|
break;
|
|
30602
31092
|
}
|
|
@@ -30605,7 +31095,7 @@ var isCheckoutDir = async (dir) => {
|
|
|
30605
31095
|
return false;
|
|
30606
31096
|
}
|
|
30607
31097
|
for (const filename of projectConfigFilenames) {
|
|
30608
|
-
if (await pathExists2(
|
|
31098
|
+
if (await pathExists2(path13.join(dir, filename))) {
|
|
30609
31099
|
return true;
|
|
30610
31100
|
}
|
|
30611
31101
|
}
|
|
@@ -30620,10 +31110,10 @@ var readSubdirectories = async (dir) => {
|
|
|
30620
31110
|
}
|
|
30621
31111
|
return entries.filter(
|
|
30622
31112
|
(entry) => entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules"
|
|
30623
|
-
).map((entry) =>
|
|
31113
|
+
).map((entry) => path13.join(dir, entry.name));
|
|
30624
31114
|
};
|
|
30625
31115
|
var discoverCheckouts = async (rootPath) => {
|
|
30626
|
-
const root =
|
|
31116
|
+
const root = path13.resolve(rootPath);
|
|
30627
31117
|
const found = [];
|
|
30628
31118
|
const visit = async (dir) => {
|
|
30629
31119
|
if (await isCheckoutDir(dir)) {
|
|
@@ -30638,51 +31128,27 @@ var discoverCheckouts = async (rootPath) => {
|
|
|
30638
31128
|
};
|
|
30639
31129
|
|
|
30640
31130
|
// src/watch/isIgnoredWatchPath.ts
|
|
30641
|
-
import
|
|
30642
|
-
var ignoredWatchSegments = /* @__PURE__ */ new Set([
|
|
30643
|
-
".forum",
|
|
30644
|
-
".doctrine",
|
|
30645
|
-
".git",
|
|
30646
|
-
"node_modules",
|
|
30647
|
-
// Standard build/cache junk — never source content, and the usual offenders
|
|
30648
|
-
// for high-churn writes during a build or test run.
|
|
30649
|
-
".cache",
|
|
30650
|
-
".next",
|
|
30651
|
-
".nuxt",
|
|
30652
|
-
".turbo",
|
|
30653
|
-
".svelte-kit",
|
|
30654
|
-
"dist",
|
|
30655
|
-
"build",
|
|
30656
|
-
"coverage",
|
|
30657
|
-
"out"
|
|
30658
|
-
]);
|
|
30659
|
-
var ignoredRootFiles = /* @__PURE__ */ new Set([
|
|
30660
|
-
"forum.yaml",
|
|
30661
|
-
"forum.yml",
|
|
30662
|
-
"doctrine.yaml",
|
|
30663
|
-
"doctrine.yml"
|
|
30664
|
-
]);
|
|
31131
|
+
import path14 from "path";
|
|
30665
31132
|
var isIgnoredWatchPath = (filename) => {
|
|
30666
|
-
if (!filename)
|
|
30667
|
-
|
|
30668
|
-
|
|
30669
|
-
|
|
30670
|
-
const
|
|
30671
|
-
if (
|
|
30672
|
-
|
|
30673
|
-
|
|
30674
|
-
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));
|
|
30675
31141
|
};
|
|
30676
31142
|
|
|
30677
31143
|
// src/watch/readPathsFile.ts
|
|
30678
|
-
import { readFile as
|
|
31144
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
30679
31145
|
var readPathsFile = async (file2) => {
|
|
30680
|
-
const contents = await
|
|
31146
|
+
const contents = await readFile5(file2, "utf8");
|
|
30681
31147
|
return contents.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
30682
31148
|
};
|
|
30683
31149
|
|
|
30684
31150
|
// src/watch/resolveWatchWorkingSet.ts
|
|
30685
|
-
import
|
|
31151
|
+
import path15 from "path";
|
|
30686
31152
|
var resolveWatchWorkingSet = async ({ watchPaths, pathsFile }, resolvers) => {
|
|
30687
31153
|
const explicitPaths = [...watchPaths];
|
|
30688
31154
|
if (pathsFile !== null) {
|
|
@@ -30705,7 +31171,7 @@ var resolveWatchWorkingSet = async ({ watchPaths, pathsFile }, resolvers) => {
|
|
|
30705
31171
|
const entries = [];
|
|
30706
31172
|
const errors = [];
|
|
30707
31173
|
for (const rawPath of explicitPaths) {
|
|
30708
|
-
const resolved =
|
|
31174
|
+
const resolved = path15.resolve(rawPath);
|
|
30709
31175
|
if (seen.has(resolved)) {
|
|
30710
31176
|
continue;
|
|
30711
31177
|
}
|
|
@@ -30936,10 +31402,15 @@ var createStoreClient = ({
|
|
|
30936
31402
|
{ retryDelayMs: transientRetryDelayMs }
|
|
30937
31403
|
);
|
|
30938
31404
|
return {
|
|
31405
|
+
createRawFileUrl: (fileId) => `${apiBaseUrl.replace(/\/+$/, "")}/raw-file/${encodeURIComponent(fileId)}`,
|
|
30939
31406
|
listStores: () => call("stores.list", () => trpc.stores.list.query({})),
|
|
30940
31407
|
createStore: (input) => call("stores.create", () => trpc.stores.create.mutate(input)),
|
|
30941
31408
|
deleteStore: (input) => call("stores.delete", () => trpc.stores.delete.mutate(input)),
|
|
30942
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
|
+
),
|
|
30943
31414
|
upsertStoreByRef: (input) => call("stores.upsertByRef", () => trpc.stores.upsertByRef.mutate(input)),
|
|
30944
31415
|
deleteFileByRef: (input) => call(
|
|
30945
31416
|
"files.deleteFileByRef",
|
|
@@ -31071,10 +31542,9 @@ var createClient = (config2) => {
|
|
|
31071
31542
|
|
|
31072
31543
|
// src/state.ts
|
|
31073
31544
|
import { homedir } from "os";
|
|
31074
|
-
import
|
|
31075
|
-
import {
|
|
31545
|
+
import path16 from "path";
|
|
31546
|
+
import { mkdir as mkdir5, readFile as readFile6, rename as rename3, writeFile as writeFile4 } from "fs/promises";
|
|
31076
31547
|
var DEFAULT_STATE_DIRNAME = ".forum";
|
|
31077
|
-
var LEGACY_STATE_DIRNAME = ".doctrine";
|
|
31078
31548
|
var DEFAULT_POLL_INTERVAL_MS = 4e3;
|
|
31079
31549
|
var DEFAULT_API_BASE_URL = "https://api.forumlabs.net";
|
|
31080
31550
|
var DEFAULT_CONFIG = {
|
|
@@ -31082,49 +31552,32 @@ var DEFAULT_CONFIG = {
|
|
|
31082
31552
|
pollIntervalMs: DEFAULT_POLL_INTERVAL_MS,
|
|
31083
31553
|
forceWrites: false
|
|
31084
31554
|
};
|
|
31085
|
-
var
|
|
31086
|
-
var
|
|
31087
|
-
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");
|
|
31088
31557
|
var ensureStateDir = async (stateDir) => {
|
|
31089
|
-
await
|
|
31558
|
+
await mkdir5(stateDir, { recursive: true });
|
|
31090
31559
|
};
|
|
31091
31560
|
var readJson = async (filePath, fallback) => {
|
|
31092
31561
|
try {
|
|
31093
|
-
const raw = await
|
|
31562
|
+
const raw = await readFile6(filePath, "utf8");
|
|
31094
31563
|
return JSON.parse(raw);
|
|
31095
31564
|
} catch {
|
|
31096
31565
|
return fallback;
|
|
31097
31566
|
}
|
|
31098
31567
|
};
|
|
31099
|
-
var fileExists2 = async (filePath) => {
|
|
31100
|
-
try {
|
|
31101
|
-
await access2(filePath);
|
|
31102
|
-
return true;
|
|
31103
|
-
} catch {
|
|
31104
|
-
return false;
|
|
31105
|
-
}
|
|
31106
|
-
};
|
|
31107
|
-
var readConfigSourcePath = async (stateDir) => {
|
|
31108
|
-
const currentPath = configPath(stateDir);
|
|
31109
|
-
if (stateDir !== defaultStateDir() || await fileExists2(currentPath)) {
|
|
31110
|
-
return currentPath;
|
|
31111
|
-
}
|
|
31112
|
-
const legacyPath = configPath(legacyStateDir());
|
|
31113
|
-
return await fileExists2(legacyPath) ? legacyPath : currentPath;
|
|
31114
|
-
};
|
|
31115
31568
|
var writeJsonAtomic = async (filePath, value) => {
|
|
31116
|
-
const parentDir =
|
|
31117
|
-
const tempPath =
|
|
31569
|
+
const parentDir = path16.dirname(filePath);
|
|
31570
|
+
const tempPath = path16.join(
|
|
31118
31571
|
parentDir,
|
|
31119
|
-
`.${
|
|
31572
|
+
`.${path16.basename(filePath)}.${process.pid}.${Date.now()}.tmp`
|
|
31120
31573
|
);
|
|
31121
|
-
await
|
|
31574
|
+
await mkdir5(parentDir, { recursive: true });
|
|
31122
31575
|
await writeFile4(tempPath, JSON.stringify(value, null, 2), "utf8");
|
|
31123
31576
|
await rename3(tempPath, filePath);
|
|
31124
31577
|
};
|
|
31125
31578
|
var readConfig = async (stateDir) => {
|
|
31126
31579
|
const config2 = await readJson(
|
|
31127
|
-
|
|
31580
|
+
configPath(stateDir),
|
|
31128
31581
|
DEFAULT_CONFIG
|
|
31129
31582
|
);
|
|
31130
31583
|
return {
|
|
@@ -31139,28 +31592,28 @@ var writeConfig = async (stateDir, config2) => {
|
|
|
31139
31592
|
|
|
31140
31593
|
// src/skillIntegration.ts
|
|
31141
31594
|
import { constants } from "fs";
|
|
31142
|
-
import { access as
|
|
31595
|
+
import { access as access2 } from "fs/promises";
|
|
31143
31596
|
import os from "os";
|
|
31144
|
-
import
|
|
31597
|
+
import path19 from "path";
|
|
31145
31598
|
import Enquirer from "enquirer";
|
|
31146
31599
|
|
|
31147
31600
|
// src/skillProviders/claude.ts
|
|
31148
|
-
import
|
|
31601
|
+
import path17 from "path";
|
|
31149
31602
|
var claudeSkillProvider = {
|
|
31150
31603
|
id: "claude",
|
|
31151
|
-
globalRootCandidates: (home) => [
|
|
31152
|
-
localRoot: (projectDir) =>
|
|
31604
|
+
globalRootCandidates: (home) => [path17.join(home, ".claude", "skills")],
|
|
31605
|
+
localRoot: (projectDir) => path17.join(projectDir, ".claude", "skills")
|
|
31153
31606
|
};
|
|
31154
31607
|
|
|
31155
31608
|
// src/skillProviders/codex.ts
|
|
31156
|
-
import
|
|
31609
|
+
import path18 from "path";
|
|
31157
31610
|
var codexSkillProvider = {
|
|
31158
31611
|
id: "codex",
|
|
31159
31612
|
globalRootCandidates: (home) => [
|
|
31160
|
-
|
|
31161
|
-
|
|
31613
|
+
path18.join(home, ".codex", "skills"),
|
|
31614
|
+
path18.join(home, ".agents", "skills")
|
|
31162
31615
|
],
|
|
31163
|
-
localRoot: (projectDir) =>
|
|
31616
|
+
localRoot: (projectDir) => path18.join(projectDir, ".codex", "skills")
|
|
31164
31617
|
};
|
|
31165
31618
|
|
|
31166
31619
|
// src/skillProviders/registry.ts
|
|
@@ -31181,13 +31634,13 @@ var expandHomePath = (input) => {
|
|
|
31181
31634
|
return process.env.HOME || os.homedir();
|
|
31182
31635
|
}
|
|
31183
31636
|
if (input.startsWith("~/")) {
|
|
31184
|
-
return
|
|
31637
|
+
return path19.join(process.env.HOME || os.homedir(), input.slice(2));
|
|
31185
31638
|
}
|
|
31186
31639
|
return input;
|
|
31187
31640
|
};
|
|
31188
31641
|
var pathExists3 = async (filePath) => {
|
|
31189
31642
|
try {
|
|
31190
|
-
await
|
|
31643
|
+
await access2(filePath);
|
|
31191
31644
|
return true;
|
|
31192
31645
|
} catch {
|
|
31193
31646
|
return false;
|
|
@@ -31698,33 +32151,84 @@ var editEncryptedText = async ({
|
|
|
31698
32151
|
|
|
31699
32152
|
// src/openInEditor.ts
|
|
31700
32153
|
import { spawn } from "child_process";
|
|
31701
|
-
import { mkdtemp, readFile as
|
|
32154
|
+
import { mkdtemp, readFile as readFile7, rm as rm4, writeFile as writeFile5 } from "fs/promises";
|
|
31702
32155
|
import { tmpdir } from "os";
|
|
31703
|
-
import
|
|
32156
|
+
import path20 from "path";
|
|
31704
32157
|
var openInEditor = async (currentText, { extension = "" } = {}) => {
|
|
31705
32158
|
const editor = process.env.EDITOR?.trim() || "vi";
|
|
31706
|
-
const dir = await mkdtemp(
|
|
31707
|
-
const tempPath =
|
|
32159
|
+
const dir = await mkdtemp(path20.join(tmpdir(), "fm-edit-"));
|
|
32160
|
+
const tempPath = path20.join(dir, `edit${extension}`);
|
|
31708
32161
|
try {
|
|
31709
32162
|
await writeFile5(tempPath, currentText, "utf8");
|
|
31710
32163
|
const exitCode = await new Promise((resolve, reject) => {
|
|
31711
|
-
const child = spawn(
|
|
31712
|
-
|
|
31713
|
-
|
|
31714
|
-
|
|
32164
|
+
const child = spawn(
|
|
32165
|
+
"/bin/sh",
|
|
32166
|
+
["-c", `exec ${editor} "$1"`, "fm-editor", tempPath],
|
|
32167
|
+
{ stdio: "inherit" }
|
|
32168
|
+
);
|
|
31715
32169
|
child.on("error", reject);
|
|
31716
|
-
child.on("exit", (code) => resolve(code ??
|
|
32170
|
+
child.on("exit", (code) => resolve(code ?? 1));
|
|
31717
32171
|
});
|
|
31718
32172
|
if (exitCode !== 0) {
|
|
31719
32173
|
return null;
|
|
31720
32174
|
}
|
|
31721
|
-
return await
|
|
32175
|
+
return await readFile7(tempPath, "utf8");
|
|
31722
32176
|
} finally {
|
|
31723
|
-
await
|
|
32177
|
+
await rm4(dir, { force: true, recursive: true }).catch(() => {
|
|
31724
32178
|
});
|
|
31725
32179
|
}
|
|
31726
32180
|
};
|
|
31727
32181
|
|
|
32182
|
+
// src/readHiddenLine.ts
|
|
32183
|
+
var readHiddenLine = async (prompt) => {
|
|
32184
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
32185
|
+
throw new Error(
|
|
32186
|
+
"Missing encryption password. Provide --password or DOCTRINE_ENCRYPTION_PASSWORD."
|
|
32187
|
+
);
|
|
32188
|
+
}
|
|
32189
|
+
return new Promise((resolve, reject) => {
|
|
32190
|
+
const stdin = process.stdin;
|
|
32191
|
+
const stdout = process.stdout;
|
|
32192
|
+
const wasRaw = stdin.isRaw;
|
|
32193
|
+
let value = "";
|
|
32194
|
+
const cleanup = () => {
|
|
32195
|
+
stdin.off("data", readChunk);
|
|
32196
|
+
stdin.pause();
|
|
32197
|
+
stdin.setRawMode(wasRaw);
|
|
32198
|
+
stdout.write("\n");
|
|
32199
|
+
};
|
|
32200
|
+
const finish = () => {
|
|
32201
|
+
cleanup();
|
|
32202
|
+
resolve(value);
|
|
32203
|
+
};
|
|
32204
|
+
const cancel = () => {
|
|
32205
|
+
cleanup();
|
|
32206
|
+
reject(new Error("Encryption password prompt cancelled."));
|
|
32207
|
+
};
|
|
32208
|
+
const readChunk = (chunk) => {
|
|
32209
|
+
for (const byte of chunk) {
|
|
32210
|
+
if (byte === 3) {
|
|
32211
|
+
cancel();
|
|
32212
|
+
return;
|
|
32213
|
+
}
|
|
32214
|
+
if (byte === 13 || byte === 10) {
|
|
32215
|
+
finish();
|
|
32216
|
+
return;
|
|
32217
|
+
}
|
|
32218
|
+
if (byte === 127) {
|
|
32219
|
+
value = value.slice(0, -1);
|
|
32220
|
+
continue;
|
|
32221
|
+
}
|
|
32222
|
+
value += String.fromCharCode(byte);
|
|
32223
|
+
}
|
|
32224
|
+
};
|
|
32225
|
+
stdin.setRawMode(true);
|
|
32226
|
+
stdin.on("data", readChunk);
|
|
32227
|
+
stdin.resume();
|
|
32228
|
+
stdout.write(prompt);
|
|
32229
|
+
});
|
|
32230
|
+
};
|
|
32231
|
+
|
|
31728
32232
|
// src/resolveDecryptAuthMode.ts
|
|
31729
32233
|
var resolveDecryptAuthMode = ({
|
|
31730
32234
|
encryptionPassword,
|
|
@@ -31812,7 +32316,7 @@ Usage:
|
|
|
31812
32316
|
fm push [filePath] [--token <jwt>] [--force] [--yes|-y] [--dry-run|-d] [--verbose|--debug]
|
|
31813
32317
|
fm status [--token <jwt>] [--json]
|
|
31814
32318
|
fm s [--token <jwt>] [--json]
|
|
31815
|
-
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]
|
|
31816
32320
|
fm sync --watch [<path>] [--notify] [--json] [--readonly]
|
|
31817
32321
|
fm sync --watch <path...> [--paths-file <file>] [--notify] [--json]
|
|
31818
32322
|
fm sync --dry-run|-d [--token <jwt>] [--json]
|
|
@@ -31844,7 +32348,7 @@ Usage:
|
|
|
31844
32348
|
fm --version
|
|
31845
32349
|
|
|
31846
32350
|
Store creation:
|
|
31847
|
-
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.
|
|
31848
32352
|
fm store create <workspace/storeId> creates in that explicitly selected workspace.
|
|
31849
32353
|
|
|
31850
32354
|
Auth:
|
|
@@ -31862,7 +32366,7 @@ Output:
|
|
|
31862
32366
|
`;
|
|
31863
32367
|
var readCliVersion = async () => {
|
|
31864
32368
|
const packageJson = JSON.parse(
|
|
31865
|
-
await
|
|
32369
|
+
await readFile8(new URL("../package.json", import.meta.url), "utf8")
|
|
31866
32370
|
);
|
|
31867
32371
|
return typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
31868
32372
|
};
|
|
@@ -31903,6 +32407,7 @@ var parseArgvCommandName = (argv) => {
|
|
|
31903
32407
|
var parseArgs = (argv) => {
|
|
31904
32408
|
const positional = [];
|
|
31905
32409
|
const shouldParseDirectPullMapping = argv.includes("pull") && argv.includes("--direct");
|
|
32410
|
+
const isSyncCommand = parseArgvCommandName(argv) === "sync";
|
|
31906
32411
|
const isCatCommand = parseArgvCommandName(argv) === "cat";
|
|
31907
32412
|
let token = null;
|
|
31908
32413
|
const storeFilters = [];
|
|
@@ -31922,6 +32427,7 @@ var parseArgs = (argv) => {
|
|
|
31922
32427
|
let stateDir = defaultStateDir();
|
|
31923
32428
|
let pollIntervalMs = null;
|
|
31924
32429
|
let dryRun = false;
|
|
32430
|
+
let conflictPolicy;
|
|
31925
32431
|
let force = false;
|
|
31926
32432
|
let direct = false;
|
|
31927
32433
|
let json2 = false;
|
|
@@ -31968,7 +32474,7 @@ var parseArgs = (argv) => {
|
|
|
31968
32474
|
continue;
|
|
31969
32475
|
}
|
|
31970
32476
|
if (current === "--file" || current === "-f") {
|
|
31971
|
-
inputFilePath = next ?
|
|
32477
|
+
inputFilePath = next ? path21.resolve(next) : inputFilePath;
|
|
31972
32478
|
index += 1;
|
|
31973
32479
|
continue;
|
|
31974
32480
|
}
|
|
@@ -32033,7 +32539,7 @@ var parseArgs = (argv) => {
|
|
|
32033
32539
|
if (!next) {
|
|
32034
32540
|
throw new Error("--target-dir requires a path.");
|
|
32035
32541
|
}
|
|
32036
|
-
skillTargetDir =
|
|
32542
|
+
skillTargetDir = path21.resolve(expandHomePath(next));
|
|
32037
32543
|
index += 1;
|
|
32038
32544
|
continue;
|
|
32039
32545
|
}
|
|
@@ -32045,7 +32551,7 @@ var parseArgs = (argv) => {
|
|
|
32045
32551
|
continue;
|
|
32046
32552
|
}
|
|
32047
32553
|
if (current === "--state-dir") {
|
|
32048
|
-
stateDir =
|
|
32554
|
+
stateDir = path21.resolve(next ?? stateDir);
|
|
32049
32555
|
index += 1;
|
|
32050
32556
|
continue;
|
|
32051
32557
|
}
|
|
@@ -32053,12 +32559,12 @@ var parseArgs = (argv) => {
|
|
|
32053
32559
|
if (!next) {
|
|
32054
32560
|
throw new Error("--paths-file requires a file path.");
|
|
32055
32561
|
}
|
|
32056
|
-
pathsFile =
|
|
32562
|
+
pathsFile = path21.resolve(expandHomePath(next));
|
|
32057
32563
|
index += 1;
|
|
32058
32564
|
continue;
|
|
32059
32565
|
}
|
|
32060
32566
|
if (current.startsWith("--paths-file=")) {
|
|
32061
|
-
pathsFile =
|
|
32567
|
+
pathsFile = path21.resolve(
|
|
32062
32568
|
expandHomePath(current.slice("--paths-file=".length))
|
|
32063
32569
|
);
|
|
32064
32570
|
continue;
|
|
@@ -32072,6 +32578,15 @@ var parseArgs = (argv) => {
|
|
|
32072
32578
|
openBrowser = false;
|
|
32073
32579
|
continue;
|
|
32074
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
|
+
}
|
|
32075
32590
|
if (current === "--force") {
|
|
32076
32591
|
force = true;
|
|
32077
32592
|
continue;
|
|
@@ -32124,6 +32639,7 @@ var parseArgs = (argv) => {
|
|
|
32124
32639
|
}
|
|
32125
32640
|
return {
|
|
32126
32641
|
args: positional,
|
|
32642
|
+
conflictPolicy,
|
|
32127
32643
|
token,
|
|
32128
32644
|
storeFilters,
|
|
32129
32645
|
searchLimit,
|
|
@@ -32246,10 +32762,10 @@ var listDirectoryEntries = async (listDirectory, directoryPath) => {
|
|
|
32246
32762
|
if (left.type !== "directory" && right.type === "directory") {
|
|
32247
32763
|
return 1;
|
|
32248
32764
|
}
|
|
32249
|
-
return
|
|
32765
|
+
return path21.basename(left.path).localeCompare(path21.basename(right.path));
|
|
32250
32766
|
}).forEach((entry) => {
|
|
32251
32767
|
const suffix = entry.type === "directory" ? "/" : "";
|
|
32252
|
-
renderOutput(`${
|
|
32768
|
+
renderOutput(`${path21.basename(entry.path)}${suffix}`);
|
|
32253
32769
|
});
|
|
32254
32770
|
};
|
|
32255
32771
|
var listStores = async (listStoresMetadata) => {
|
|
@@ -32544,7 +33060,7 @@ var normalizeSkillAgents = (inputs) => {
|
|
|
32544
33060
|
return [...new Set(inputs.map(normalizeSkillAgent))];
|
|
32545
33061
|
};
|
|
32546
33062
|
var normalizeRemoteSkillPath = (input) => {
|
|
32547
|
-
const normalized =
|
|
33063
|
+
const normalized = path21.posix.normalize(`/${input.trim()}`);
|
|
32548
33064
|
if (normalized === "/") {
|
|
32549
33065
|
throw new Error("Skill path must not be the store root.");
|
|
32550
33066
|
}
|
|
@@ -32554,11 +33070,11 @@ var normalizeRemoteSkillPath = (input) => {
|
|
|
32554
33070
|
return normalized;
|
|
32555
33071
|
};
|
|
32556
33072
|
var parentRemotePath = (filePath) => {
|
|
32557
|
-
const parent =
|
|
33073
|
+
const parent = path21.posix.dirname(filePath);
|
|
32558
33074
|
return parent === "." ? "/" : parent;
|
|
32559
33075
|
};
|
|
32560
33076
|
var joinRemotePath = (left, right) => {
|
|
32561
|
-
return
|
|
33077
|
+
return path21.posix.join(left, right).replace(/\/+/g, "/");
|
|
32562
33078
|
};
|
|
32563
33079
|
var readRemoteSkillTextFile = async (filePath, storeRef, client) => {
|
|
32564
33080
|
const file2 = await client.readFileByRef({ ...storeRef, path: filePath });
|
|
@@ -32620,7 +33136,7 @@ var collectRemoteSkillFiles = async ({
|
|
|
32620
33136
|
`Skill contains unsupported ${entry.type} entry: ${entry.path}`
|
|
32621
33137
|
);
|
|
32622
33138
|
}
|
|
32623
|
-
const relativePath =
|
|
33139
|
+
const relativePath = path21.posix.relative(rootPath, entry.path);
|
|
32624
33140
|
if (!relativePath || relativePath.startsWith("..")) {
|
|
32625
33141
|
throw new Error(
|
|
32626
33142
|
`Unexpected skill entry outside skill root: ${entry.path}`
|
|
@@ -32634,7 +33150,7 @@ var collectRemoteSkillFiles = async ({
|
|
|
32634
33150
|
};
|
|
32635
33151
|
var resolveRemoteSkillRoot = async (inputPath, storeRef, client) => {
|
|
32636
33152
|
const normalizedPath = normalizeRemoteSkillPath(inputPath);
|
|
32637
|
-
if (
|
|
33153
|
+
if (path21.posix.basename(normalizedPath) === "SKILL.md") {
|
|
32638
33154
|
await readRemoteSkillTextFile(normalizedPath, storeRef, client);
|
|
32639
33155
|
return {
|
|
32640
33156
|
rootPath: parentRemotePath(normalizedPath),
|
|
@@ -32714,7 +33230,7 @@ var resolveSkillInstallTargets = async ({
|
|
|
32714
33230
|
return {
|
|
32715
33231
|
agent,
|
|
32716
33232
|
rootDir,
|
|
32717
|
-
targetDir:
|
|
33233
|
+
targetDir: path21.join(rootDir, skillName)
|
|
32718
33234
|
};
|
|
32719
33235
|
})
|
|
32720
33236
|
);
|
|
@@ -32730,7 +33246,7 @@ var confirmYesNo = async ({
|
|
|
32730
33246
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
32731
33247
|
throw new Error(nonInteractiveMessage);
|
|
32732
33248
|
}
|
|
32733
|
-
const readline =
|
|
33249
|
+
const readline = createInterface2({
|
|
32734
33250
|
input: process.stdin,
|
|
32735
33251
|
output: process.stdout
|
|
32736
33252
|
});
|
|
@@ -32753,24 +33269,24 @@ var formatSkillTarget = (target, existingTargetDirs) => {
|
|
|
32753
33269
|
return ` ${target.agent.padEnd(7)} ${target.targetDir}${suffix}`;
|
|
32754
33270
|
};
|
|
32755
33271
|
var writeSkillFiles = async (target, files, replaceExisting) => {
|
|
32756
|
-
const temporaryDirectory =
|
|
33272
|
+
const temporaryDirectory = path21.join(
|
|
32757
33273
|
target.rootDir,
|
|
32758
|
-
`.${
|
|
33274
|
+
`.${path21.basename(target.targetDir)}.tmp-${process.pid}-${Date.now()}`
|
|
32759
33275
|
);
|
|
32760
|
-
await
|
|
32761
|
-
await
|
|
33276
|
+
await rm5(temporaryDirectory, { recursive: true, force: true });
|
|
33277
|
+
await mkdir6(temporaryDirectory, { recursive: true });
|
|
32762
33278
|
try {
|
|
32763
33279
|
for (const file2 of files) {
|
|
32764
|
-
const localPath =
|
|
32765
|
-
await
|
|
33280
|
+
const localPath = path21.join(temporaryDirectory, file2.relativePath);
|
|
33281
|
+
await mkdir6(path21.dirname(localPath), { recursive: true });
|
|
32766
33282
|
await writeFile6(localPath, file2.bytes);
|
|
32767
33283
|
}
|
|
32768
33284
|
if (replaceExisting) {
|
|
32769
|
-
await
|
|
33285
|
+
await rm5(target.targetDir, { recursive: true, force: true });
|
|
32770
33286
|
}
|
|
32771
33287
|
await rename4(temporaryDirectory, target.targetDir);
|
|
32772
33288
|
} catch (error51) {
|
|
32773
|
-
await
|
|
33289
|
+
await rm5(temporaryDirectory, { recursive: true, force: true });
|
|
32774
33290
|
throw error51;
|
|
32775
33291
|
}
|
|
32776
33292
|
};
|
|
@@ -32813,7 +33329,7 @@ var installSkillBundle = async ({
|
|
|
32813
33329
|
throw new Error("Aborted skill install.");
|
|
32814
33330
|
}
|
|
32815
33331
|
for (const target of targets) {
|
|
32816
|
-
await
|
|
33332
|
+
await mkdir6(target.rootDir, { recursive: true });
|
|
32817
33333
|
}
|
|
32818
33334
|
for (const target of targets) {
|
|
32819
33335
|
await writeSkillFiles(
|
|
@@ -32845,7 +33361,7 @@ var readRemoteSkillBundle = async ({
|
|
|
32845
33361
|
client
|
|
32846
33362
|
);
|
|
32847
33363
|
const metadata = parseSkillMetadata(skillMarkdown);
|
|
32848
|
-
const rootName =
|
|
33364
|
+
const rootName = path21.posix.basename(rootPath);
|
|
32849
33365
|
if (metadata.name !== rootName) {
|
|
32850
33366
|
throw new Error(
|
|
32851
33367
|
`SKILL.md name "${metadata.name}" must match skill directory "${rootName}".`
|
|
@@ -33025,7 +33541,7 @@ var readWriteTextInput = async (inlineText, inputFilePath) => {
|
|
|
33025
33541
|
throw new Error("Provide either inline text or --file, not both.");
|
|
33026
33542
|
}
|
|
33027
33543
|
if (inputFilePath) {
|
|
33028
|
-
return
|
|
33544
|
+
return readFile8(inputFilePath, "utf8");
|
|
33029
33545
|
}
|
|
33030
33546
|
return inlineText ?? null;
|
|
33031
33547
|
};
|
|
@@ -33041,7 +33557,7 @@ var readRemoteTextFile = async (filePath, storeRef, client) => {
|
|
|
33041
33557
|
return text;
|
|
33042
33558
|
};
|
|
33043
33559
|
var normalizeRemotePath = (input) => {
|
|
33044
|
-
const normalized =
|
|
33560
|
+
const normalized = path21.posix.normalize(`/${input.trim()}`);
|
|
33045
33561
|
if (normalized.includes("\0")) {
|
|
33046
33562
|
throw new Error("Path contains an invalid null byte.");
|
|
33047
33563
|
}
|
|
@@ -33335,7 +33851,7 @@ var diffRemoteFiles = async ({
|
|
|
33335
33851
|
storeRef
|
|
33336
33852
|
}) => {
|
|
33337
33853
|
const leftText = await readRemoteTextFile(leftPath, storeRef, client);
|
|
33338
|
-
const rightText = localRight ? await
|
|
33854
|
+
const rightText = localRight ? await readFile8(path21.resolve(rightPath), "utf8") : await readRemoteTextFile(rightPath, storeRef, client);
|
|
33339
33855
|
return buildUnifiedDiff({
|
|
33340
33856
|
leftLabel: leftPath,
|
|
33341
33857
|
leftText,
|
|
@@ -33402,8 +33918,8 @@ var copyRemotePath = async (args, storeRef, client) => {
|
|
|
33402
33918
|
(entry) => entry.path.startsWith(`${normalizedSource}/`)
|
|
33403
33919
|
);
|
|
33404
33920
|
for (const entry of descendants) {
|
|
33405
|
-
const relativePath =
|
|
33406
|
-
const targetPath =
|
|
33921
|
+
const relativePath = path21.posix.relative(normalizedSource, entry.path);
|
|
33922
|
+
const targetPath = path21.posix.join(normalizedDestination, relativePath);
|
|
33407
33923
|
if (entry.type === "directory") {
|
|
33408
33924
|
await createRemoteDirectory(targetPath, storeRef, client);
|
|
33409
33925
|
continue;
|
|
@@ -33533,53 +34049,6 @@ var readCommandTextInput = async (inlineText, inputFilePath) => {
|
|
|
33533
34049
|
}
|
|
33534
34050
|
return null;
|
|
33535
34051
|
};
|
|
33536
|
-
var readHiddenLine = async (prompt) => {
|
|
33537
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
33538
|
-
throw new Error(
|
|
33539
|
-
"Missing encryption password. Provide --password or DOCTRINE_ENCRYPTION_PASSWORD."
|
|
33540
|
-
);
|
|
33541
|
-
}
|
|
33542
|
-
return new Promise((resolve, reject) => {
|
|
33543
|
-
const stdin = process.stdin;
|
|
33544
|
-
const stdout = process.stdout;
|
|
33545
|
-
const wasRaw = stdin.isRaw;
|
|
33546
|
-
let value = "";
|
|
33547
|
-
const cleanup = () => {
|
|
33548
|
-
stdin.off("data", readChunk);
|
|
33549
|
-
stdin.setRawMode(wasRaw);
|
|
33550
|
-
stdout.write("\n");
|
|
33551
|
-
};
|
|
33552
|
-
const finish = () => {
|
|
33553
|
-
cleanup();
|
|
33554
|
-
resolve(value);
|
|
33555
|
-
};
|
|
33556
|
-
const cancel = () => {
|
|
33557
|
-
cleanup();
|
|
33558
|
-
reject(new Error("Encryption password prompt cancelled."));
|
|
33559
|
-
};
|
|
33560
|
-
const readChunk = (chunk) => {
|
|
33561
|
-
for (const byte of chunk) {
|
|
33562
|
-
if (byte === 3) {
|
|
33563
|
-
cancel();
|
|
33564
|
-
return;
|
|
33565
|
-
}
|
|
33566
|
-
if (byte === 13 || byte === 10) {
|
|
33567
|
-
finish();
|
|
33568
|
-
return;
|
|
33569
|
-
}
|
|
33570
|
-
if (byte === 127) {
|
|
33571
|
-
value = value.slice(0, -1);
|
|
33572
|
-
continue;
|
|
33573
|
-
}
|
|
33574
|
-
value += String.fromCharCode(byte);
|
|
33575
|
-
}
|
|
33576
|
-
};
|
|
33577
|
-
stdout.write(prompt);
|
|
33578
|
-
stdin.setRawMode(true);
|
|
33579
|
-
stdin.resume();
|
|
33580
|
-
stdin.on("data", readChunk);
|
|
33581
|
-
});
|
|
33582
|
-
};
|
|
33583
34052
|
var readEncryptionPassword = async (parsed) => {
|
|
33584
34053
|
const password = parsed.encryptionPassword ?? process.env.DOCTRINE_ENCRYPTION_PASSWORD;
|
|
33585
34054
|
if (password) {
|
|
@@ -33645,19 +34114,19 @@ var runDecryptCommand = async (rest, parsed, client) => {
|
|
|
33645
34114
|
);
|
|
33646
34115
|
};
|
|
33647
34116
|
var runEditCommand = async (rest, parsed, client) => {
|
|
33648
|
-
const filePath = parsed.inputFilePath ?? (rest[0] ?
|
|
34117
|
+
const filePath = parsed.inputFilePath ?? (rest[0] ? path21.resolve(rest[0]) : null);
|
|
33649
34118
|
if (!filePath) {
|
|
33650
34119
|
throw new Error(
|
|
33651
34120
|
`Usage: ${commandNames} edit (<localPath>|--file|-f <localPath>) [--password <password>] [--token <jwt>]`
|
|
33652
34121
|
);
|
|
33653
34122
|
}
|
|
33654
|
-
const encryptedText = await
|
|
34123
|
+
const encryptedText = await readFile8(filePath, "utf8");
|
|
33655
34124
|
const [password, userEncryption] = await Promise.all([
|
|
33656
34125
|
readEncryptionPassword(parsed),
|
|
33657
34126
|
readUserEncryption(client)
|
|
33658
34127
|
]);
|
|
33659
34128
|
const result = await editEncryptedText({
|
|
33660
|
-
edit: (currentPlaintext) => openInEditor(currentPlaintext, { extension:
|
|
34129
|
+
edit: (currentPlaintext) => openInEditor(currentPlaintext, { extension: path21.extname(filePath) }),
|
|
33661
34130
|
encryptedText,
|
|
33662
34131
|
password,
|
|
33663
34132
|
userEncryption: userEncryption.userEncryption
|
|
@@ -33733,10 +34202,10 @@ var runEncryptAddRecipientCommand = async (rest, parsed, client) => {
|
|
|
33733
34202
|
`);
|
|
33734
34203
|
renderOutput(result.encryptedText);
|
|
33735
34204
|
};
|
|
33736
|
-
var defaultEncryptionMigrationBackupPath = () =>
|
|
33737
|
-
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"));
|
|
33738
34207
|
var writeEncryptionMigrationBackup = async (backupPath, backup) => {
|
|
33739
|
-
await
|
|
34208
|
+
await mkdir6(path21.dirname(backupPath), { recursive: true });
|
|
33740
34209
|
await writeFile6(backupPath, `${JSON.stringify(backup, null, 2)}
|
|
33741
34210
|
`, "utf8");
|
|
33742
34211
|
};
|
|
@@ -33753,7 +34222,7 @@ var confirmEncryptionMigration = async ({
|
|
|
33753
34222
|
"Refusing to migrate encryption without interactive confirmation. Rerun with --yes to confirm in a non-interactive shell."
|
|
33754
34223
|
);
|
|
33755
34224
|
}
|
|
33756
|
-
const readline =
|
|
34225
|
+
const readline = createInterface2({
|
|
33757
34226
|
input: process.stdin,
|
|
33758
34227
|
output: process.stdout
|
|
33759
34228
|
});
|
|
@@ -34024,7 +34493,7 @@ var runEncryptionMigrateCommand = async (rest, parsed, client) => {
|
|
|
34024
34493
|
`Usage: ${commandNames} encryption migrate [backup-file] [--store <storeId>] [--password <password>] [--dry-run] [--yes]`
|
|
34025
34494
|
);
|
|
34026
34495
|
}
|
|
34027
|
-
const backupPath =
|
|
34496
|
+
const backupPath = path21.resolve(
|
|
34028
34497
|
rest[1] ?? defaultEncryptionMigrationBackupPath()
|
|
34029
34498
|
);
|
|
34030
34499
|
const password = await readEncryptionPassword(parsed);
|
|
@@ -34099,7 +34568,7 @@ var doesRemoteQueryMatchPath = (query, filePath) => {
|
|
|
34099
34568
|
if (query.startsWith("/")) {
|
|
34100
34569
|
return normalizedPath === query;
|
|
34101
34570
|
}
|
|
34102
|
-
const filename =
|
|
34571
|
+
const filename = path21.basename(filePath).toLowerCase();
|
|
34103
34572
|
return filename === query || normalizedPath === query || filename.includes(query) || normalizedPath.includes(query);
|
|
34104
34573
|
};
|
|
34105
34574
|
var queryRemoteFiles = async (query, storeFilters, client) => {
|
|
@@ -34171,7 +34640,7 @@ var printRemoteQueryMatches = (matches) => {
|
|
|
34171
34640
|
});
|
|
34172
34641
|
};
|
|
34173
34642
|
var normalizeRemoteDirectoryPath = (input) => {
|
|
34174
|
-
const normalized =
|
|
34643
|
+
const normalized = path21.posix.normalize(`/${input.trim()}`);
|
|
34175
34644
|
if (normalized.includes("\0")) {
|
|
34176
34645
|
throw new Error("Path contains an invalid null byte.");
|
|
34177
34646
|
}
|
|
@@ -34291,12 +34760,12 @@ var labelFromTreeDirectoryPath = (directoryPath) => {
|
|
|
34291
34760
|
if (directoryPath === "/") {
|
|
34292
34761
|
return "./";
|
|
34293
34762
|
}
|
|
34294
|
-
return `${
|
|
34763
|
+
return `${path21.posix.basename(directoryPath)}/`;
|
|
34295
34764
|
};
|
|
34296
34765
|
var doesTreeFilterMatchDirectory = (filter, directoryPath) => {
|
|
34297
34766
|
const normalizedFilter = filter.trim().toLowerCase();
|
|
34298
34767
|
const normalizedPath = directoryPath.toLowerCase();
|
|
34299
|
-
const basename3 =
|
|
34768
|
+
const basename3 = path21.posix.basename(directoryPath).toLowerCase();
|
|
34300
34769
|
return basename3.includes(normalizedFilter) || normalizedPath.includes(normalizedFilter);
|
|
34301
34770
|
};
|
|
34302
34771
|
var resolveTreeDirectoryPath = async ({
|
|
@@ -34351,7 +34820,7 @@ var printRemoteTreeChildren = async ({
|
|
|
34351
34820
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
34352
34821
|
const suffix = entry.type === "directory" ? "/" : "";
|
|
34353
34822
|
lines.push(
|
|
34354
|
-
`${prefix}${connector}${
|
|
34823
|
+
`${prefix}${connector}${path21.posix.basename(entry.path)}${suffix}`
|
|
34355
34824
|
);
|
|
34356
34825
|
if (entry.type === "directory") {
|
|
34357
34826
|
await printRemoteTreeChildren({
|
|
@@ -34680,12 +35149,6 @@ var unsetConfigValue = async (parsed, key) => {
|
|
|
34680
35149
|
});
|
|
34681
35150
|
renderOutput(`Reset poll-interval-ms to ${DEFAULT_POLL_INTERVAL_MS}`);
|
|
34682
35151
|
};
|
|
34683
|
-
var ensureToken = (token) => {
|
|
34684
|
-
if (!token) {
|
|
34685
|
-
throw new Error("Missing auth token. Provide --token or DOCTRINE_TOKEN.");
|
|
34686
|
-
}
|
|
34687
|
-
return token;
|
|
34688
|
-
};
|
|
34689
35152
|
var parseRootStorePath = (storePathInput) => {
|
|
34690
35153
|
const storeId = normalizeStoreId2(storePathInput);
|
|
34691
35154
|
return {
|
|
@@ -34696,7 +35159,7 @@ var parseRootStorePath = (storePathInput) => {
|
|
|
34696
35159
|
var parseNewStorePath = (storePathInput) => {
|
|
34697
35160
|
return parseRootStorePath(storePathInput);
|
|
34698
35161
|
};
|
|
34699
|
-
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.";
|
|
34700
35163
|
var parseStoreCreateInput = async (storePathInput) => {
|
|
34701
35164
|
const segments2 = storePathInput.split("/").map((segment) => segment.trim()).filter(Boolean);
|
|
34702
35165
|
if (segments2.length === 2) {
|
|
@@ -34969,9 +35432,9 @@ var shouldPrintCheckoutDetail = (detail, verbose) => {
|
|
|
34969
35432
|
var formatCheckoutDetail = (detail, options2) => {
|
|
34970
35433
|
const status = checkoutStatusLabel(detail, options2);
|
|
34971
35434
|
const direction = checkoutDirectionLabel(detail);
|
|
34972
|
-
const
|
|
35435
|
+
const path22 = formatCheckoutDetailPath(detail, options2.syncRules);
|
|
34973
35436
|
const reason = styleText.dim(checkoutDetailMessage(detail));
|
|
34974
|
-
return direction ? `${direction} ${status} ${
|
|
35437
|
+
return direction ? `${direction} ${status} ${path22} ${reason}` : `${status} ${path22} ${reason}`;
|
|
34975
35438
|
};
|
|
34976
35439
|
var formatCheckoutDetailPath = (detail, syncRules) => {
|
|
34977
35440
|
const localPath = formatLocalCheckoutPath(detail.relativePath);
|
|
@@ -35183,9 +35646,9 @@ var checkoutReportGroups = (details, options2) => {
|
|
|
35183
35646
|
);
|
|
35184
35647
|
};
|
|
35185
35648
|
var checkoutReportDetailLine = (detail, options2) => {
|
|
35186
|
-
const
|
|
35649
|
+
const path22 = formatCheckoutDetailPath(detail, options2.syncRules);
|
|
35187
35650
|
const message = detail.status === "failed" || detail.status === "skipped" || detail.status === "ignored" ? detail.message ?? checkoutDetailMessage(detail) : "";
|
|
35188
|
-
return message ? ` ${
|
|
35651
|
+
return message ? ` ${path22} ${styleText.dim(message)}` : ` ${path22}`;
|
|
35189
35652
|
};
|
|
35190
35653
|
var checkoutReportGroupBlock = ({
|
|
35191
35654
|
dryRun,
|
|
@@ -35312,13 +35775,13 @@ var statusChangeKind = (detail) => {
|
|
|
35312
35775
|
var formatStatusChange = (detail, syncRules) => {
|
|
35313
35776
|
const kind = statusChangeKind(detail);
|
|
35314
35777
|
const tone = kind === "deleted" ? "error" : kind === "added" ? "ok" : "warn";
|
|
35315
|
-
const
|
|
35316
|
-
return ` ${styleText.color(tone, kind.padEnd(8))} ${
|
|
35778
|
+
const path22 = formatCheckoutDetailPath(detail, syncRules);
|
|
35779
|
+
return ` ${styleText.color(tone, kind.padEnd(8))} ${path22}`;
|
|
35317
35780
|
};
|
|
35318
35781
|
var formatStatusBlock = (detail, syncRules) => {
|
|
35319
35782
|
const message = detail.message ? ` ${styleText.dim(detail.message)}` : "";
|
|
35320
|
-
const
|
|
35321
|
-
return ` ${styleText.color("error", "blocked ".padEnd(8))} ${
|
|
35783
|
+
const path22 = formatCheckoutDetailPath(detail, syncRules);
|
|
35784
|
+
return ` ${styleText.color("error", "blocked ".padEnd(8))} ${path22}${message}`;
|
|
35322
35785
|
};
|
|
35323
35786
|
var actionableStatusDetails = (result) => result.details.filter(
|
|
35324
35787
|
(detail) => detail.status === "succeeded" || detail.status === "deleted"
|
|
@@ -35451,7 +35914,7 @@ var assertCheckoutSyncEnabled = (checkout) => {
|
|
|
35451
35914
|
return;
|
|
35452
35915
|
}
|
|
35453
35916
|
throw new Error(
|
|
35454
|
-
"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."
|
|
35455
35918
|
);
|
|
35456
35919
|
};
|
|
35457
35920
|
var warnReadonlyCheckoutPush = (checkout, force) => {
|
|
@@ -35459,7 +35922,7 @@ var warnReadonlyCheckoutPush = (checkout, force) => {
|
|
|
35459
35922
|
return;
|
|
35460
35923
|
}
|
|
35461
35924
|
renderWarning(
|
|
35462
|
-
"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."
|
|
35463
35926
|
);
|
|
35464
35927
|
};
|
|
35465
35928
|
var referenceStructuralChangeLabel = (detail) => {
|
|
@@ -35518,20 +35981,26 @@ var confirmCheckoutReferenceStructuralWrites = async ({
|
|
|
35518
35981
|
yes
|
|
35519
35982
|
}) => {
|
|
35520
35983
|
const result = operation === "sync" ? await syncCheckout({
|
|
35984
|
+
ignoreSettings: "sync",
|
|
35521
35985
|
client,
|
|
35522
35986
|
dryRun: true,
|
|
35523
35987
|
force,
|
|
35524
35988
|
ignorePatterns: checkout.ignore,
|
|
35989
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
35990
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35525
35991
|
localPath: checkout.rootDir,
|
|
35526
35992
|
progress,
|
|
35527
35993
|
storeRef: {},
|
|
35528
35994
|
syncRules: checkout.syncRules
|
|
35529
35995
|
}) : await pushCheckout({
|
|
35996
|
+
ignoreSettings: "preview",
|
|
35530
35997
|
client,
|
|
35531
35998
|
dryRun: true,
|
|
35532
35999
|
filePaths,
|
|
35533
36000
|
force,
|
|
35534
36001
|
ignorePatterns: checkout.ignore,
|
|
36002
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36003
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35535
36004
|
localPath: checkout.rootDir,
|
|
35536
36005
|
progress,
|
|
35537
36006
|
storeRef: {},
|
|
@@ -35576,12 +36045,18 @@ var runCheckoutOperation = async ({
|
|
|
35576
36045
|
filePaths,
|
|
35577
36046
|
force,
|
|
35578
36047
|
ignorePatterns: checkout.ignore,
|
|
36048
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36049
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35579
36050
|
localPath: checkout.rootDir,
|
|
35580
36051
|
progress,
|
|
35581
36052
|
storeRef: {},
|
|
35582
36053
|
syncRules: checkout.syncRules
|
|
35583
36054
|
};
|
|
35584
|
-
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
|
+
});
|
|
35585
36060
|
formatCheckoutResult(labels.summaryVerb, result, {
|
|
35586
36061
|
detailsRendered: Boolean(progress),
|
|
35587
36062
|
dryRun,
|
|
@@ -35675,6 +36150,7 @@ var assertCheckoutReadyForReadOnlyPull = async (checkout) => {
|
|
|
35675
36150
|
};
|
|
35676
36151
|
var runCheckoutPullThenPush = async ({
|
|
35677
36152
|
checkout,
|
|
36153
|
+
conflictPolicy,
|
|
35678
36154
|
client,
|
|
35679
36155
|
force,
|
|
35680
36156
|
verbose,
|
|
@@ -35692,6 +36168,8 @@ var runCheckoutPullThenPush = async ({
|
|
|
35692
36168
|
}
|
|
35693
36169
|
progress?.start?.();
|
|
35694
36170
|
const result = await syncCheckout({
|
|
36171
|
+
ignoreSettings: "sync",
|
|
36172
|
+
conflictPolicy,
|
|
35695
36173
|
beforeRuleApply: async ({ result: rulePlan }) => {
|
|
35696
36174
|
await confirmReferenceStructuralWrites(
|
|
35697
36175
|
referenceStructuralWriteDetails(rulePlan),
|
|
@@ -35701,6 +36179,8 @@ var runCheckoutPullThenPush = async ({
|
|
|
35701
36179
|
client,
|
|
35702
36180
|
force,
|
|
35703
36181
|
ignorePatterns: checkout.ignore,
|
|
36182
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36183
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35704
36184
|
localPath: checkout.rootDir,
|
|
35705
36185
|
progress,
|
|
35706
36186
|
storeRef: {},
|
|
@@ -35727,10 +36207,13 @@ var assertGitSyncHasNoPushPlan = async ({
|
|
|
35727
36207
|
force
|
|
35728
36208
|
}) => {
|
|
35729
36209
|
const result = await pushCheckout({
|
|
36210
|
+
ignoreSettings: "preview",
|
|
35730
36211
|
client,
|
|
35731
36212
|
dryRun: true,
|
|
35732
36213
|
force,
|
|
35733
36214
|
ignorePatterns: checkout.ignore,
|
|
36215
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36216
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35734
36217
|
localPath: checkout.rootDir,
|
|
35735
36218
|
storeRef: {},
|
|
35736
36219
|
syncRules: checkout.syncRules
|
|
@@ -35754,16 +36237,6 @@ var assertGitSyncHasNoPushPlan = async ({
|
|
|
35754
36237
|
].join("\n")
|
|
35755
36238
|
);
|
|
35756
36239
|
};
|
|
35757
|
-
var refreshStoreIgnoreCache = async (checkout, client) => {
|
|
35758
|
-
const storeRef = await resolveProjectStoreRef();
|
|
35759
|
-
if (!storeRef) {
|
|
35760
|
-
return null;
|
|
35761
|
-
}
|
|
35762
|
-
const metadata = await client.readStoreByRef(storeRef);
|
|
35763
|
-
const storeIgnore = metadata?.ignore ?? [];
|
|
35764
|
-
await writeStoreIgnoreCache(checkout.rootDir, storeIgnore);
|
|
35765
|
-
return { storeIgnore, storeRef };
|
|
35766
|
-
};
|
|
35767
36240
|
var analyzeLocalIgnore = async (checkout) => {
|
|
35768
36241
|
const [files, presentMarkers, gitignorePatterns] = await Promise.all([
|
|
35769
36242
|
collectLocalCheckoutFiles(checkout.rootDir, []),
|
|
@@ -35777,7 +36250,7 @@ var analyzeLocalIgnore = async (checkout) => {
|
|
|
35777
36250
|
});
|
|
35778
36251
|
};
|
|
35779
36252
|
var promptIgnoreAction = async () => {
|
|
35780
|
-
const readline =
|
|
36253
|
+
const readline = createInterface2({
|
|
35781
36254
|
input: process.stdin,
|
|
35782
36255
|
output: process.stdout
|
|
35783
36256
|
});
|
|
@@ -35794,17 +36267,30 @@ var promptIgnoreAction = async () => {
|
|
|
35794
36267
|
};
|
|
35795
36268
|
var isInteractiveTty = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
35796
36269
|
var runIgnoreSetupGate = async (checkout, client, assumeYes) => {
|
|
35797
|
-
const
|
|
35798
|
-
if (!
|
|
35799
|
-
|
|
35800
|
-
|
|
35801
|
-
|
|
35802
|
-
|
|
35803
|
-
|
|
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;
|
|
35804
36289
|
}
|
|
36290
|
+
if (storeIgnore.length > 0) return;
|
|
35805
36291
|
await maybePromptIgnoreSetup({
|
|
35806
36292
|
assumeYes,
|
|
35807
|
-
|
|
36293
|
+
writePatterns: (patterns) => writeSharedIgnoreFile(sharedFilePath, patterns),
|
|
35808
36294
|
analysis: await analyzeLocalIgnore(checkout),
|
|
35809
36295
|
onboarded: await readIgnoreOnboardedAt(checkout.rootDir) !== null,
|
|
35810
36296
|
currentPatterns: storeIgnore,
|
|
@@ -35812,11 +36298,11 @@ var runIgnoreSetupGate = async (checkout, client, assumeYes) => {
|
|
|
35812
36298
|
chooseAction: promptIgnoreAction,
|
|
35813
36299
|
markOnboarded: () => markIgnoreOnboarded(checkout.rootDir),
|
|
35814
36300
|
renderOutput,
|
|
35815
|
-
renderWarning
|
|
35816
|
-
storeRef
|
|
36301
|
+
renderWarning
|
|
35817
36302
|
});
|
|
35818
36303
|
};
|
|
35819
36304
|
var runCheckoutSyncOnce = async ({
|
|
36305
|
+
conflictPolicy,
|
|
35820
36306
|
client,
|
|
35821
36307
|
force,
|
|
35822
36308
|
verbose,
|
|
@@ -35824,17 +36310,27 @@ var runCheckoutSyncOnce = async ({
|
|
|
35824
36310
|
}) => {
|
|
35825
36311
|
const checkout = await resolveCheckoutConfig();
|
|
35826
36312
|
assertCheckoutSyncEnabled(checkout);
|
|
35827
|
-
await runCheckoutPullThenPush({
|
|
36313
|
+
await runCheckoutPullThenPush({
|
|
36314
|
+
checkout,
|
|
36315
|
+
client,
|
|
36316
|
+
conflictPolicy,
|
|
36317
|
+
force,
|
|
36318
|
+
verbose,
|
|
36319
|
+
yes
|
|
36320
|
+
});
|
|
35828
36321
|
};
|
|
35829
36322
|
var DEFAULT_FULL_SYNC_INTERVAL_MS = 5 * 60 * 1e3;
|
|
35830
36323
|
var runCheckoutSyncCollecting = async ({
|
|
35831
36324
|
checkout,
|
|
36325
|
+
conflictPolicy,
|
|
35832
36326
|
client,
|
|
35833
36327
|
force,
|
|
35834
36328
|
yes = false
|
|
35835
36329
|
}) => {
|
|
35836
36330
|
assertCheckoutSyncEnabled(checkout);
|
|
35837
36331
|
return syncCheckout({
|
|
36332
|
+
ignoreSettings: "sync",
|
|
36333
|
+
conflictPolicy,
|
|
35838
36334
|
beforeRuleApply: async ({ result }) => {
|
|
35839
36335
|
await confirmReferenceStructuralWrites(
|
|
35840
36336
|
referenceStructuralWriteDetails(result),
|
|
@@ -35844,6 +36340,8 @@ var runCheckoutSyncCollecting = async ({
|
|
|
35844
36340
|
client,
|
|
35845
36341
|
force,
|
|
35846
36342
|
ignorePatterns: checkout.ignore,
|
|
36343
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36344
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35847
36345
|
localPath: checkout.rootDir,
|
|
35848
36346
|
storeRef: {},
|
|
35849
36347
|
syncRules: checkout.syncRules
|
|
@@ -35870,14 +36368,15 @@ var runCheckoutStatus = async ({
|
|
|
35870
36368
|
}) => {
|
|
35871
36369
|
const initialCheckout = await resolveCheckoutConfig();
|
|
35872
36370
|
assertCheckoutSyncEnabled(initialCheckout);
|
|
35873
|
-
|
|
35874
|
-
const checkout = await resolveCheckoutConfig();
|
|
35875
|
-
assertCheckoutSyncEnabled(checkout);
|
|
36371
|
+
const checkout = initialCheckout;
|
|
35876
36372
|
const pullResult = await pullCheckout({
|
|
36373
|
+
ignoreSettings: "preview",
|
|
35877
36374
|
client,
|
|
35878
36375
|
dryRun: true,
|
|
35879
36376
|
force,
|
|
35880
36377
|
ignorePatterns: checkout.ignore,
|
|
36378
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36379
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35881
36380
|
localPath: checkout.rootDir,
|
|
35882
36381
|
storeRef: {},
|
|
35883
36382
|
syncRules: checkout.syncRules
|
|
@@ -35920,10 +36419,13 @@ var runCheckoutStatus = async ({
|
|
|
35920
36419
|
return;
|
|
35921
36420
|
}
|
|
35922
36421
|
const pushResult = await pushCheckout({
|
|
36422
|
+
ignoreSettings: "preview",
|
|
35923
36423
|
client,
|
|
35924
36424
|
dryRun: true,
|
|
35925
36425
|
force,
|
|
35926
36426
|
ignorePatterns: checkout.ignore,
|
|
36427
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
36428
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
35927
36429
|
localPath: checkout.rootDir,
|
|
35928
36430
|
storeRef: {},
|
|
35929
36431
|
syncRules: checkout.syncRules
|
|
@@ -35936,18 +36438,18 @@ var runCheckoutStatus = async ({
|
|
|
35936
36438
|
});
|
|
35937
36439
|
};
|
|
35938
36440
|
var isCheckoutStateGitPath = isCheckoutStateDirectoryPath;
|
|
35939
|
-
var checkoutFilesManifestPath2 = (
|
|
36441
|
+
var checkoutFilesManifestPath2 = () => `${resolveCheckoutStateDirectoryName()}/files.json`;
|
|
35940
36442
|
var isInsideOrEqual = (parentPath, childPath2) => {
|
|
35941
|
-
const relativePath =
|
|
35942
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
36443
|
+
const relativePath = path21.relative(parentPath, childPath2);
|
|
36444
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path21.isAbsolute(relativePath);
|
|
35943
36445
|
};
|
|
35944
36446
|
var resolveSyncTargetPaths = (checkout) => checkout.syncRules.map(
|
|
35945
|
-
(rule) =>
|
|
36447
|
+
(rule) => path21.resolve(checkout.rootDir, rule.target || ".")
|
|
35946
36448
|
);
|
|
35947
|
-
var resolveCheckoutManifestGitPath = (checkout, gitRoot) =>
|
|
36449
|
+
var resolveCheckoutManifestGitPath = (checkout, gitRoot) => path21.relative(
|
|
35948
36450
|
gitRoot,
|
|
35949
|
-
|
|
35950
|
-
) || checkoutFilesManifestPath2(
|
|
36451
|
+
path21.join(checkout.rootDir, checkoutFilesManifestPath2())
|
|
36452
|
+
) || checkoutFilesManifestPath2();
|
|
35951
36453
|
var stageCheckoutManifest = async ({
|
|
35952
36454
|
checkout,
|
|
35953
36455
|
gitRoot
|
|
@@ -35972,7 +36474,7 @@ var assertGitChangesStayInSyncTargets = async ({
|
|
|
35972
36474
|
if (isCheckoutStateGitPath(entry.path)) {
|
|
35973
36475
|
return false;
|
|
35974
36476
|
}
|
|
35975
|
-
const absolutePath =
|
|
36477
|
+
const absolutePath = path21.resolve(gitRoot, entry.path);
|
|
35976
36478
|
return !allowedPaths.some(
|
|
35977
36479
|
(allowedPath) => isInsideOrEqual(allowedPath, absolutePath)
|
|
35978
36480
|
);
|
|
@@ -35994,7 +36496,7 @@ var stageGitSyncTargets = async ({
|
|
|
35994
36496
|
}) => {
|
|
35995
36497
|
const targetPaths = [];
|
|
35996
36498
|
for (const targetPath of resolveSyncTargetPaths(checkout)) {
|
|
35997
|
-
const relativePath =
|
|
36499
|
+
const relativePath = path21.relative(gitRoot, targetPath) || ".";
|
|
35998
36500
|
const tracked = await runGit(gitRoot, ["ls-files", "--", relativePath]);
|
|
35999
36501
|
if (await pathExists3(targetPath) || tracked.stdout.trim()) {
|
|
36000
36502
|
targetPaths.push(relativePath);
|
|
@@ -36036,7 +36538,7 @@ var runGitSyncCommand = async ({
|
|
|
36036
36538
|
assertCheckoutSyncEnabled(checkout);
|
|
36037
36539
|
if (!checkout.gitSyncCommitMessage) {
|
|
36038
36540
|
throw new Error(
|
|
36039
|
-
"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."
|
|
36040
36542
|
);
|
|
36041
36543
|
}
|
|
36042
36544
|
const gitRoot = await resolveGitRoot(checkout.rootDir);
|
|
@@ -36069,6 +36571,7 @@ var runCheckoutReadOnlyPullOnce = async ({
|
|
|
36069
36571
|
};
|
|
36070
36572
|
var buildCheckoutWatchEntry = ({
|
|
36071
36573
|
checkout,
|
|
36574
|
+
conflictPolicy,
|
|
36072
36575
|
client,
|
|
36073
36576
|
force,
|
|
36074
36577
|
yes
|
|
@@ -36077,10 +36580,17 @@ var buildCheckoutWatchEntry = ({
|
|
|
36077
36580
|
rootDir: checkout.rootDir,
|
|
36078
36581
|
startMessage: `Watching ${checkout.rootDir}`,
|
|
36079
36582
|
storeRefs: changesFeedStoreRefsForCheckout(checkout),
|
|
36080
|
-
syncOnce: () => runCheckoutSyncCollecting({
|
|
36583
|
+
syncOnce: async () => runCheckoutSyncCollecting({
|
|
36584
|
+
checkout: await resolveCheckoutConfig(checkout.rootDir),
|
|
36585
|
+
client,
|
|
36586
|
+
conflictPolicy,
|
|
36587
|
+
force,
|
|
36588
|
+
yes
|
|
36589
|
+
})
|
|
36081
36590
|
});
|
|
36082
36591
|
var resolveExplicitCheckoutEntry = async ({
|
|
36083
36592
|
checkoutPath,
|
|
36593
|
+
conflictPolicy,
|
|
36084
36594
|
client,
|
|
36085
36595
|
force,
|
|
36086
36596
|
yes
|
|
@@ -36088,13 +36598,20 @@ var resolveExplicitCheckoutEntry = async ({
|
|
|
36088
36598
|
const checkout = await resolveCheckoutConfig(checkoutPath);
|
|
36089
36599
|
if (checkout.rootDir !== checkoutPath) {
|
|
36090
36600
|
throw new Error(
|
|
36091
|
-
`${checkoutPath} is not a Forum checkout (no forum.yaml here).`
|
|
36601
|
+
`${checkoutPath} is not a Forum checkout (no .forum/sync.yaml here).`
|
|
36092
36602
|
);
|
|
36093
36603
|
}
|
|
36094
36604
|
assertCheckoutSyncEnabled(checkout);
|
|
36095
|
-
return buildCheckoutWatchEntry({
|
|
36605
|
+
return buildCheckoutWatchEntry({
|
|
36606
|
+
checkout,
|
|
36607
|
+
client,
|
|
36608
|
+
conflictPolicy,
|
|
36609
|
+
force,
|
|
36610
|
+
yes
|
|
36611
|
+
});
|
|
36096
36612
|
};
|
|
36097
36613
|
var resolveDiscoveredCheckoutEntries = async ({
|
|
36614
|
+
conflictPolicy,
|
|
36098
36615
|
client,
|
|
36099
36616
|
force,
|
|
36100
36617
|
rootPath,
|
|
@@ -36110,7 +36627,9 @@ var resolveDiscoveredCheckoutEntries = async ({
|
|
|
36110
36627
|
if (checkout.syncRules.length === 0) {
|
|
36111
36628
|
continue;
|
|
36112
36629
|
}
|
|
36113
|
-
entries.push(
|
|
36630
|
+
entries.push(
|
|
36631
|
+
buildCheckoutWatchEntry({ checkout, client, conflictPolicy, force, yes })
|
|
36632
|
+
);
|
|
36114
36633
|
}
|
|
36115
36634
|
if (entries.length === 0) {
|
|
36116
36635
|
throw new Error(
|
|
@@ -36120,6 +36639,7 @@ var resolveDiscoveredCheckoutEntries = async ({
|
|
|
36120
36639
|
return entries;
|
|
36121
36640
|
};
|
|
36122
36641
|
var runCheckoutSyncWatch = async ({
|
|
36642
|
+
conflictPolicy,
|
|
36123
36643
|
client,
|
|
36124
36644
|
force,
|
|
36125
36645
|
intervalMs,
|
|
@@ -36192,12 +36712,30 @@ var runCheckoutSyncWatch = async ({
|
|
|
36192
36712
|
{ watchPaths, pathsFile },
|
|
36193
36713
|
{
|
|
36194
36714
|
readPathsFile,
|
|
36195
|
-
resolveDiscoveredEntries: (rootPath) => resolveDiscoveredCheckoutEntries({
|
|
36196
|
-
|
|
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
|
+
}),
|
|
36197
36729
|
resolveSingleCheckoutEntry: async () => {
|
|
36198
36730
|
const checkout = await resolveCheckoutConfig();
|
|
36199
36731
|
assertCheckoutSyncEnabled(checkout);
|
|
36200
|
-
return buildCheckoutWatchEntry({
|
|
36732
|
+
return buildCheckoutWatchEntry({
|
|
36733
|
+
checkout,
|
|
36734
|
+
client,
|
|
36735
|
+
conflictPolicy,
|
|
36736
|
+
force,
|
|
36737
|
+
yes
|
|
36738
|
+
});
|
|
36201
36739
|
}
|
|
36202
36740
|
}
|
|
36203
36741
|
);
|
|
@@ -36254,11 +36792,11 @@ var resolveReadableStore = async (storeInput, client) => {
|
|
|
36254
36792
|
var writeCheckoutConfig = async (directoryPath, metadata, workspaceSlug, options2 = {}) => {
|
|
36255
36793
|
if (!workspaceSlug) {
|
|
36256
36794
|
throw new Error(
|
|
36257
|
-
`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.`
|
|
36258
36796
|
);
|
|
36259
36797
|
}
|
|
36260
36798
|
await writeForumProjectConfig(
|
|
36261
|
-
|
|
36799
|
+
path21.join(directoryPath, defaultProjectConfigFilename),
|
|
36262
36800
|
{
|
|
36263
36801
|
syncRules: [
|
|
36264
36802
|
{
|
|
@@ -36274,6 +36812,18 @@ var writeCheckoutConfig = async (directoryPath, metadata, workspaceSlug, options
|
|
|
36274
36812
|
]
|
|
36275
36813
|
}
|
|
36276
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
|
+
});
|
|
36277
36827
|
};
|
|
36278
36828
|
var normalizeProjectConfigPath = (value, fieldName, allowCurrentDirectory = false) => {
|
|
36279
36829
|
const trimmed = value.trim().replace(/^\/+/, "").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
@@ -36283,7 +36833,7 @@ var normalizeProjectConfigPath = (value, fieldName, allowCurrentDirectory = fals
|
|
|
36283
36833
|
}
|
|
36284
36834
|
throw new Error(`${fieldName} must be a non-empty relative path.`);
|
|
36285
36835
|
}
|
|
36286
|
-
if (
|
|
36836
|
+
if (path21.isAbsolute(value)) {
|
|
36287
36837
|
throw new Error(`${fieldName} must be a relative path.`);
|
|
36288
36838
|
}
|
|
36289
36839
|
const segments2 = trimmed.split("/");
|
|
@@ -36336,7 +36886,7 @@ var runProjectConfigSyncCommand = async (mode, args) => {
|
|
|
36336
36886
|
const projectConfig = await findForumProjectConfig();
|
|
36337
36887
|
if (!projectConfig) {
|
|
36338
36888
|
throw new Error(
|
|
36339
|
-
"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."
|
|
36340
36890
|
);
|
|
36341
36891
|
}
|
|
36342
36892
|
if (mode === "clear") {
|
|
@@ -36439,7 +36989,7 @@ var runProjectConfigSyncCommand = async (mode, args) => {
|
|
|
36439
36989
|
var runProjectConfigValidateCommand = async () => {
|
|
36440
36990
|
const projectConfig = await findForumProjectConfig();
|
|
36441
36991
|
if (!projectConfig) {
|
|
36442
|
-
throw new Error("No forum.yaml found.");
|
|
36992
|
+
throw new Error("No .forum/sync.yaml found.");
|
|
36443
36993
|
}
|
|
36444
36994
|
renderOutput(`Valid Forum config: ${projectConfig.path}`);
|
|
36445
36995
|
renderOutput(
|
|
@@ -36449,7 +36999,7 @@ var runProjectConfigValidateCommand = async () => {
|
|
|
36449
36999
|
var runProjectConfigStandardizeCommand = async () => {
|
|
36450
37000
|
const projectConfig = await findForumProjectConfig();
|
|
36451
37001
|
if (!projectConfig) {
|
|
36452
|
-
throw new Error("No forum.yaml found.");
|
|
37002
|
+
throw new Error("No .forum/sync.yaml found.");
|
|
36453
37003
|
}
|
|
36454
37004
|
await writeForumProjectConfig(projectConfig.path, {
|
|
36455
37005
|
defaultStore: projectConfig.defaultStore,
|
|
@@ -36465,7 +37015,7 @@ var defaultCloneDirectoryName = (storeId) => {
|
|
|
36465
37015
|
var fsErrorCode = (error51) => error51 instanceof Error && "code" in error51 ? String(error51.code ?? "") : "";
|
|
36466
37016
|
var ensureGitMetadataExists = async (directoryPath) => {
|
|
36467
37017
|
try {
|
|
36468
|
-
await lstat2(
|
|
37018
|
+
await lstat2(path21.join(directoryPath, ".git"));
|
|
36469
37019
|
} catch (error51) {
|
|
36470
37020
|
if (fsErrorCode(error51) === "ENOENT") {
|
|
36471
37021
|
throw new Error(
|
|
@@ -36503,8 +37053,8 @@ var confirmGitMetadataDeletion = async (localPath, assumeYes) => {
|
|
|
36503
37053
|
"Refusing to delete .git without interactive confirmation. Rerun with --yes to confirm in a non-interactive shell."
|
|
36504
37054
|
);
|
|
36505
37055
|
}
|
|
36506
|
-
const gitPath =
|
|
36507
|
-
const gitignorePath =
|
|
37056
|
+
const gitPath = path21.join(localPath, ".git");
|
|
37057
|
+
const gitignorePath = path21.join(localPath, ".gitignore");
|
|
36508
37058
|
const confirmationPhrase = "DELETE GIT";
|
|
36509
37059
|
renderWarning("");
|
|
36510
37060
|
renderWarning("DANGER: Forum is about to remove Git from this checkout.");
|
|
@@ -36516,7 +37066,7 @@ var confirmGitMetadataDeletion = async (localPath, assumeYes) => {
|
|
|
36516
37066
|
renderWarning(
|
|
36517
37067
|
"Only continue if the repository history is backed up or you are certain you no longer need it here."
|
|
36518
37068
|
);
|
|
36519
|
-
const readline =
|
|
37069
|
+
const readline = createInterface2({
|
|
36520
37070
|
input: process.stdin,
|
|
36521
37071
|
output: process.stdout
|
|
36522
37072
|
});
|
|
@@ -36546,11 +37096,11 @@ var runGitConvertCommand = async ({
|
|
|
36546
37096
|
const { created, metadata, workspaceSlug, storeRef } = await resolveOrCreateConversionStore(storeInput, client);
|
|
36547
37097
|
if (!workspaceSlug) {
|
|
36548
37098
|
throw new Error(
|
|
36549
|
-
`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.`
|
|
36550
37100
|
);
|
|
36551
37101
|
}
|
|
36552
37102
|
await writeForumProjectConfig(
|
|
36553
|
-
|
|
37103
|
+
path21.join(localPath, defaultProjectConfigFilename),
|
|
36554
37104
|
{
|
|
36555
37105
|
syncRules: [
|
|
36556
37106
|
{
|
|
@@ -36565,14 +37115,24 @@ var runGitConvertCommand = async ({
|
|
|
36565
37115
|
]
|
|
36566
37116
|
}
|
|
36567
37117
|
);
|
|
36568
|
-
|
|
36569
|
-
|
|
36570
|
-
|
|
36571
|
-
|
|
36572
|
-
|
|
36573
|
-
|
|
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
|
+
);
|
|
36574
37133
|
const conversionIgnorePatterns = [...ignorePatterns, ".gitignore"];
|
|
36575
37134
|
await pushCheckout({
|
|
37135
|
+
ignoreSettings: "preview",
|
|
36576
37136
|
client,
|
|
36577
37137
|
dryRun: true,
|
|
36578
37138
|
force,
|
|
@@ -36581,6 +37141,7 @@ var runGitConvertCommand = async ({
|
|
|
36581
37141
|
storeRef
|
|
36582
37142
|
});
|
|
36583
37143
|
const result = await pushCheckout({
|
|
37144
|
+
ignoreSettings: "preview",
|
|
36584
37145
|
client,
|
|
36585
37146
|
force,
|
|
36586
37147
|
ignorePatterns: conversionIgnorePatterns,
|
|
@@ -36601,8 +37162,8 @@ var runGitConvertCommand = async ({
|
|
|
36601
37162
|
"Aborted before deleting Git metadata. The Forum push completed, but .git and .gitignore were left in place."
|
|
36602
37163
|
);
|
|
36603
37164
|
}
|
|
36604
|
-
await
|
|
36605
|
-
await
|
|
37165
|
+
await rm5(path21.join(localPath, ".gitignore"), { force: true });
|
|
37166
|
+
await rm5(path21.join(localPath, ".git"), { recursive: true, force: true });
|
|
36606
37167
|
renderOutput(
|
|
36607
37168
|
`${created ? "Created" : "Using existing"} store ${metadata.slug}`
|
|
36608
37169
|
);
|
|
@@ -36641,7 +37202,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
36641
37202
|
const config3 = await resolveConfig(parsed);
|
|
36642
37203
|
if (subcommand === "login") {
|
|
36643
37204
|
const apiBaseUrl2 = ensureApiBaseUrl(config3.apiBaseUrl);
|
|
36644
|
-
const
|
|
37205
|
+
const token = await withActivity(
|
|
36645
37206
|
"Starting login",
|
|
36646
37207
|
() => interactiveLogin({
|
|
36647
37208
|
apiBaseUrl: apiBaseUrl2,
|
|
@@ -36649,7 +37210,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
36649
37210
|
})
|
|
36650
37211
|
);
|
|
36651
37212
|
await writeConfig(parsed.stateDir, {
|
|
36652
|
-
token
|
|
37213
|
+
token,
|
|
36653
37214
|
pollIntervalMs: config3.pollIntervalMs,
|
|
36654
37215
|
forceWrites: config3.forceWrites
|
|
36655
37216
|
});
|
|
@@ -36720,7 +37281,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
36720
37281
|
}
|
|
36721
37282
|
if (command === "hash" && parsed.local) {
|
|
36722
37283
|
const filePath = rest[0];
|
|
36723
|
-
renderOutput(await hashLocalFile(
|
|
37284
|
+
renderOutput(await hashLocalFile(path21.resolve(filePath)));
|
|
36724
37285
|
return;
|
|
36725
37286
|
}
|
|
36726
37287
|
const config2 = await resolveConfig(parsed);
|
|
@@ -36746,8 +37307,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
36746
37307
|
}
|
|
36747
37308
|
}
|
|
36748
37309
|
const apiBaseUrl = ensureApiBaseUrl(config2.apiBaseUrl);
|
|
36749
|
-
const
|
|
36750
|
-
const client = createClient({ ...config2, apiBaseUrl, token });
|
|
37310
|
+
const client = createClient({ ...config2, apiBaseUrl });
|
|
36751
37311
|
if (command === "encrypt") {
|
|
36752
37312
|
await runEncryptCommand(rest, parsed, client);
|
|
36753
37313
|
return;
|
|
@@ -36995,26 +37555,45 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
36995
37555
|
const subcommand = rest[0];
|
|
36996
37556
|
const checkout = await resolveCheckoutConfig();
|
|
36997
37557
|
assertCheckoutSyncEnabled(checkout);
|
|
36998
|
-
const
|
|
36999
|
-
|
|
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)
|
|
37000
37564
|
throw new Error(
|
|
37001
|
-
"
|
|
37565
|
+
"Select one configured store with fm ignore --store workspace/store."
|
|
37002
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 ?? [];
|
|
37003
37586
|
}
|
|
37004
|
-
const metadata = await client.readStoreByRef(storeRef);
|
|
37005
|
-
const currentPatterns = metadata?.ignore ?? [];
|
|
37006
37587
|
await runIgnoreCommand({
|
|
37007
|
-
|
|
37008
|
-
client,
|
|
37588
|
+
writePatterns: (patterns) => writeSharedIgnoreFile(sharedFilePath, patterns),
|
|
37009
37589
|
commandNames,
|
|
37010
37590
|
confirmYesNo,
|
|
37011
|
-
currentPatterns,
|
|
37591
|
+
currentPatterns: currentPatterns ?? [],
|
|
37012
37592
|
analyzeLocal: () => analyzeLocalIgnore(checkout),
|
|
37013
37593
|
markOnboarded: () => markIgnoreOnboarded(checkout.rootDir),
|
|
37014
37594
|
pattern: rest[1],
|
|
37015
37595
|
patterns: rest.slice(1),
|
|
37016
37596
|
renderOutput,
|
|
37017
|
-
storeRef,
|
|
37018
37597
|
subcommand,
|
|
37019
37598
|
assumeYes: parsed.yes
|
|
37020
37599
|
});
|
|
@@ -37093,7 +37672,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37093
37672
|
}
|
|
37094
37673
|
const checkout = await resolveCheckoutConfig();
|
|
37095
37674
|
assertCheckoutSyncEnabled(checkout);
|
|
37096
|
-
await runIgnoreSetupGate(checkout, client, parsed.yes);
|
|
37675
|
+
if (!parsed.dryRun) await runIgnoreSetupGate(checkout, client, parsed.yes);
|
|
37097
37676
|
await runCheckoutPush({
|
|
37098
37677
|
checkout,
|
|
37099
37678
|
client,
|
|
@@ -37106,12 +37685,41 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37106
37685
|
return;
|
|
37107
37686
|
}
|
|
37108
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
|
+
}
|
|
37109
37693
|
if (rest[0] === "reset") {
|
|
37110
37694
|
const checkout = await resolveCheckoutConfig();
|
|
37111
37695
|
await resetCheckoutSyncState(checkout.rootDir);
|
|
37112
37696
|
renderOutput("Cleared local checkout sync state.");
|
|
37113
37697
|
return;
|
|
37114
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
|
+
}
|
|
37115
37723
|
if (parsed.dryRun) {
|
|
37116
37724
|
await withActivity(
|
|
37117
37725
|
"Checking status",
|
|
@@ -37125,6 +37733,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37125
37733
|
}
|
|
37126
37734
|
if (parsed.watch) {
|
|
37127
37735
|
await runCheckoutSyncWatch({
|
|
37736
|
+
conflictPolicy: parsed.conflictPolicy,
|
|
37128
37737
|
client,
|
|
37129
37738
|
force: parsed.force,
|
|
37130
37739
|
intervalMs: config2.pollIntervalMs,
|
|
@@ -37152,6 +37761,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37152
37761
|
}
|
|
37153
37762
|
await runIgnoreSetupGate(await resolveCheckoutConfig(), client, parsed.yes);
|
|
37154
37763
|
await runCheckoutSyncOnce({
|
|
37764
|
+
conflictPolicy: parsed.conflictPolicy,
|
|
37155
37765
|
client,
|
|
37156
37766
|
force: parsed.force,
|
|
37157
37767
|
verbose: parsed.verbose,
|
|
@@ -37193,8 +37803,8 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37193
37803
|
`Usage: ${commandNames} clone <storeId> [localPath] [--readonly]`
|
|
37194
37804
|
);
|
|
37195
37805
|
}
|
|
37196
|
-
const localPath =
|
|
37197
|
-
rest[1] ??
|
|
37806
|
+
const localPath = path21.resolve(
|
|
37807
|
+
rest[1] ?? path21.join(process.cwd(), defaultCloneDirectoryName(remoteInput))
|
|
37198
37808
|
);
|
|
37199
37809
|
const { metadata, workspaceSlug, storeRef } = await resolveReadableStore(
|
|
37200
37810
|
remoteInput,
|
|
@@ -37212,14 +37822,17 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
37212
37822
|
verbose: parsed.verbose
|
|
37213
37823
|
});
|
|
37214
37824
|
const result = await pullCheckout({
|
|
37825
|
+
ignoreSettings: "preview",
|
|
37215
37826
|
client,
|
|
37216
37827
|
ignorePatterns: checkout.ignore,
|
|
37828
|
+
ignorePatternsByStore: checkout.ignorePatternsByStore,
|
|
37829
|
+
ignoreMatchersByRule: checkout.ignoreMatchersByRule,
|
|
37217
37830
|
localPath: checkout.rootDir,
|
|
37218
37831
|
progress,
|
|
37219
37832
|
storeRef,
|
|
37220
37833
|
syncRules: checkout.syncRules
|
|
37221
37834
|
});
|
|
37222
|
-
renderOutput(`Cloned store ${metadata.slug} to ${
|
|
37835
|
+
renderOutput(`Cloned store ${metadata.slug} to ${path21.resolve(localPath)}`);
|
|
37223
37836
|
formatCheckoutResult("Pulled", result, {
|
|
37224
37837
|
detailsRendered: Boolean(progress),
|
|
37225
37838
|
verbose: parsed.verbose
|