@massu/core 1.2.0 → 1.3.0
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/README.md +40 -0
- package/commands/README.md +122 -0
- package/commands/massu-deploy.python.md +200 -0
- package/commands/massu-scaffold-page.md +172 -59
- package/commands/massu-scaffold-page.swift.md +121 -0
- package/commands/massu-scaffold-router.python.md +143 -0
- package/dist/cli.js +562 -231
- package/dist/hooks/auto-learning-pipeline.js +8 -4
- package/dist/hooks/classify-failure.js +8 -4
- package/dist/hooks/cost-tracker.js +8 -4
- package/dist/hooks/fix-detector.js +8 -4
- package/dist/hooks/incident-pipeline.js +8 -4
- package/dist/hooks/post-edit-context.js +8 -4
- package/dist/hooks/post-tool-use.js +8 -4
- package/dist/hooks/pre-compact.js +8 -4
- package/dist/hooks/pre-delete-check.js +8 -4
- package/dist/hooks/quality-event.js +8 -4
- package/dist/hooks/rule-enforcement-pipeline.js +8 -4
- package/dist/hooks/session-end.js +8 -4
- package/dist/hooks/session-start.js +20 -7
- package/dist/hooks/user-prompt.js +8 -4
- package/package.json +1 -1
- package/src/cli.ts +6 -0
- package/src/commands/init.ts +89 -4
- package/src/commands/install-commands.ts +366 -42
- package/src/commands/show-template.ts +65 -0
- package/src/config.ts +11 -3
- package/src/detect/index.ts +10 -1
- package/src/detect/migrate.ts +52 -1
- package/src/detect/source-dir-detector.ts +28 -2
package/dist/cli.js
CHANGED
|
@@ -118,13 +118,16 @@ Hint: run \`massu config refresh\` to regenerate a valid config or fix the liste
|
|
|
118
118
|
name: parsed.project.name,
|
|
119
119
|
root: projectRoot
|
|
120
120
|
},
|
|
121
|
+
// Spread `fw` first so zod-`.passthrough()` extras (e.g., `framework.swift`,
|
|
122
|
+
// `framework.python`) survive into the consumer-visible Config. Then override
|
|
123
|
+
// the v2-backcompat-mirrored router/orm/ui values. Without the spread, the
|
|
124
|
+
// variant-resolution `pickVariant` (install-commands.ts) cannot see the
|
|
125
|
+
// top-level passthrough language blocks.
|
|
121
126
|
framework: {
|
|
122
|
-
|
|
127
|
+
...fw,
|
|
123
128
|
router,
|
|
124
129
|
orm,
|
|
125
|
-
ui
|
|
126
|
-
primary: fw.primary,
|
|
127
|
-
languages: fw.languages
|
|
130
|
+
ui
|
|
128
131
|
},
|
|
129
132
|
paths: parsed.paths,
|
|
130
133
|
toolPrefix: parsed.toolPrefix,
|
|
@@ -414,6 +417,7 @@ var init_config = __esm({
|
|
|
414
417
|
PathsConfigSchema = z.object({
|
|
415
418
|
source: z.string().default("src"),
|
|
416
419
|
aliases: z.record(z.string(), z.string()).default({ "@": "src" }),
|
|
420
|
+
monorepo_roots: z.array(z.string()).optional(),
|
|
417
421
|
routers: z.string().optional(),
|
|
418
422
|
routerRoot: z.string().optional(),
|
|
419
423
|
pages: z.string().optional(),
|
|
@@ -1680,15 +1684,30 @@ var init_memory_file_ingest = __esm({
|
|
|
1680
1684
|
// src/commands/install-commands.ts
|
|
1681
1685
|
var install_commands_exports = {};
|
|
1682
1686
|
__export(install_commands_exports, {
|
|
1687
|
+
hashContent: () => hashContent,
|
|
1683
1688
|
installAll: () => installAll,
|
|
1684
1689
|
installCommands: () => installCommands,
|
|
1690
|
+
loadManifest: () => loadManifest,
|
|
1691
|
+
pickVariant: () => pickVariant,
|
|
1685
1692
|
resolveAssetDir: () => resolveAssetDir,
|
|
1686
1693
|
resolveCommandsDir: () => resolveCommandsDir,
|
|
1687
|
-
runInstallCommands: () => runInstallCommands
|
|
1694
|
+
runInstallCommands: () => runInstallCommands,
|
|
1695
|
+
runWithManifest: () => runWithManifest,
|
|
1696
|
+
saveManifest: () => saveManifest,
|
|
1697
|
+
syncDirectory: () => syncDirectory
|
|
1688
1698
|
});
|
|
1689
|
-
import {
|
|
1690
|
-
|
|
1699
|
+
import {
|
|
1700
|
+
existsSync as existsSync4,
|
|
1701
|
+
readFileSync as readFileSync3,
|
|
1702
|
+
writeFileSync,
|
|
1703
|
+
mkdirSync as mkdirSync2,
|
|
1704
|
+
readdirSync as readdirSync2,
|
|
1705
|
+
statSync,
|
|
1706
|
+
renameSync
|
|
1707
|
+
} from "fs";
|
|
1708
|
+
import { resolve as resolve3, dirname as dirname3, join as join2 } from "path";
|
|
1691
1709
|
import { fileURLToPath } from "url";
|
|
1710
|
+
import { createHash } from "crypto";
|
|
1692
1711
|
function resolveAssetDir(assetName) {
|
|
1693
1712
|
const cwd = process.cwd();
|
|
1694
1713
|
const nodeModulesPath = resolve3(cwd, "node_modules/@massu/core", assetName);
|
|
@@ -1708,42 +1727,189 @@ function resolveAssetDir(assetName) {
|
|
|
1708
1727
|
function resolveCommandsDir() {
|
|
1709
1728
|
return resolveAssetDir("commands");
|
|
1710
1729
|
}
|
|
1711
|
-
function
|
|
1712
|
-
|
|
1730
|
+
function hashContent(content) {
|
|
1731
|
+
return createHash("sha256").update(content, "utf-8").digest("hex");
|
|
1732
|
+
}
|
|
1733
|
+
function loadManifest(claudeDir) {
|
|
1734
|
+
const path = resolve3(claudeDir, MANIFEST_RELPATH);
|
|
1735
|
+
if (!existsSync4(path)) {
|
|
1736
|
+
return emptyManifest();
|
|
1737
|
+
}
|
|
1738
|
+
try {
|
|
1739
|
+
const raw = readFileSync3(path, "utf-8");
|
|
1740
|
+
const parsed = JSON.parse(raw);
|
|
1741
|
+
if (!parsed || typeof parsed !== "object" || !parsed.entries) {
|
|
1742
|
+
return emptyManifest();
|
|
1743
|
+
}
|
|
1744
|
+
return parsed;
|
|
1745
|
+
} catch {
|
|
1746
|
+
return emptyManifest();
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
function saveManifest(claudeDir, manifest) {
|
|
1750
|
+
const dir = resolve3(claudeDir, ".massu");
|
|
1751
|
+
if (!existsSync4(dir)) {
|
|
1752
|
+
mkdirSync2(dir, { recursive: true });
|
|
1753
|
+
}
|
|
1754
|
+
const finalPath = resolve3(dir, "install-manifest.json");
|
|
1755
|
+
const tempPath = finalPath + ".tmp";
|
|
1756
|
+
manifest.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1757
|
+
writeFileSync(tempPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
1758
|
+
renameSync(tempPath, finalPath);
|
|
1759
|
+
}
|
|
1760
|
+
function emptyManifest() {
|
|
1761
|
+
return {
|
|
1762
|
+
version: MANIFEST_VERSION,
|
|
1763
|
+
generatedBy: "@massu/core",
|
|
1764
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1765
|
+
entries: {}
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
function runWithManifest(claudeDir, fn) {
|
|
1769
|
+
const manifest = loadManifest(claudeDir);
|
|
1770
|
+
const result = fn(manifest);
|
|
1771
|
+
saveManifest(claudeDir, manifest);
|
|
1772
|
+
return result;
|
|
1773
|
+
}
|
|
1774
|
+
function pickVariant(baseName, sourceDir, framework) {
|
|
1775
|
+
const candidates = [];
|
|
1776
|
+
const primary = framework.primary ?? framework.type;
|
|
1777
|
+
if (primary && primary !== "multi") {
|
|
1778
|
+
candidates.push(primary);
|
|
1779
|
+
}
|
|
1780
|
+
if (framework.languages) {
|
|
1781
|
+
for (const lang of Object.keys(framework.languages)) {
|
|
1782
|
+
const entry = framework.languages[lang];
|
|
1783
|
+
if (entry && typeof entry.framework === "string" && entry.framework.length > 0) {
|
|
1784
|
+
if (!candidates.includes(lang)) {
|
|
1785
|
+
candidates.push(lang);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
const passthrough = framework;
|
|
1791
|
+
for (const lang of PASSTHROUGH_LANG_KEYS) {
|
|
1792
|
+
if (candidates.includes(lang)) continue;
|
|
1793
|
+
const block = passthrough[lang];
|
|
1794
|
+
if (block && typeof block === "object") {
|
|
1795
|
+
const fw = block.framework;
|
|
1796
|
+
if (typeof fw === "string" && fw.length > 0) {
|
|
1797
|
+
candidates.push(lang);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
for (const cand of candidates) {
|
|
1802
|
+
const path = resolve3(sourceDir, `${baseName}.${cand}.md`);
|
|
1803
|
+
if (existsSync4(path)) {
|
|
1804
|
+
return { kind: "hit", suffix: `.${cand}` };
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
const defaultPath = resolve3(sourceDir, `${baseName}.md`);
|
|
1808
|
+
if (existsSync4(defaultPath)) {
|
|
1809
|
+
return { kind: "hit", suffix: "" };
|
|
1810
|
+
}
|
|
1811
|
+
if (framework.type === "multi" && !framework.primary) {
|
|
1812
|
+
process.stderr.write(
|
|
1813
|
+
"massu: warning - framework.type=multi but framework.primary is undefined; falling back to default templates\n"
|
|
1814
|
+
);
|
|
1815
|
+
return { kind: "fallback", reason: "multi-without-primary" };
|
|
1816
|
+
}
|
|
1817
|
+
return { kind: "miss" };
|
|
1818
|
+
}
|
|
1819
|
+
function isVariantFilename(entry) {
|
|
1820
|
+
return /^[^.]+\.[^.]+\.md$/.test(entry);
|
|
1821
|
+
}
|
|
1822
|
+
function syncDirectory(sourceDir, targetDir, framework, manifest, manifestKeyPrefix, topLevel = true) {
|
|
1823
|
+
const stats = { installed: 0, updated: 0, skipped: 0, kept: 0 };
|
|
1713
1824
|
if (!existsSync4(targetDir)) {
|
|
1714
1825
|
mkdirSync2(targetDir, { recursive: true });
|
|
1715
1826
|
}
|
|
1716
1827
|
const entries = readdirSync2(sourceDir);
|
|
1717
1828
|
for (const entry of entries) {
|
|
1718
1829
|
const sourcePath = resolve3(sourceDir, entry);
|
|
1719
|
-
const targetPath = resolve3(targetDir, entry);
|
|
1720
1830
|
const entryStat = statSync(sourcePath);
|
|
1721
1831
|
if (entryStat.isDirectory()) {
|
|
1722
|
-
const
|
|
1832
|
+
const subTargetDir = resolve3(targetDir, entry);
|
|
1833
|
+
const subPrefix = manifestKeyPrefix === "" ? entry : `${manifestKeyPrefix}/${entry}`;
|
|
1834
|
+
const subStats = syncDirectory(
|
|
1835
|
+
sourcePath,
|
|
1836
|
+
subTargetDir,
|
|
1837
|
+
framework,
|
|
1838
|
+
manifest,
|
|
1839
|
+
subPrefix,
|
|
1840
|
+
false
|
|
1841
|
+
);
|
|
1723
1842
|
stats.installed += subStats.installed;
|
|
1724
1843
|
stats.updated += subStats.updated;
|
|
1725
1844
|
stats.skipped += subStats.skipped;
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
writeFileSync(targetPath, sourceContent, "utf-8");
|
|
1738
|
-
stats.installed++;
|
|
1845
|
+
stats.kept += subStats.kept;
|
|
1846
|
+
continue;
|
|
1847
|
+
}
|
|
1848
|
+
if (!entry.endsWith(".md")) continue;
|
|
1849
|
+
let sourceFilename = entry;
|
|
1850
|
+
let baseName = entry.slice(0, -".md".length);
|
|
1851
|
+
if (topLevel) {
|
|
1852
|
+
if (isVariantFilename(entry)) continue;
|
|
1853
|
+
const choice = pickVariant(baseName, sourceDir, framework);
|
|
1854
|
+
if (choice.kind === "miss") {
|
|
1855
|
+
continue;
|
|
1739
1856
|
}
|
|
1857
|
+
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
1858
|
+
sourceFilename = suffix === "" ? `${baseName}.md` : `${baseName}${suffix}.md`;
|
|
1859
|
+
}
|
|
1860
|
+
const resolvedSourcePath = resolve3(sourceDir, sourceFilename);
|
|
1861
|
+
if (!existsSync4(resolvedSourcePath)) {
|
|
1862
|
+
continue;
|
|
1863
|
+
}
|
|
1864
|
+
const targetFilename = topLevel ? `${baseName}.md` : entry;
|
|
1865
|
+
const targetPath = resolve3(targetDir, targetFilename);
|
|
1866
|
+
const sourceContent = readFileSync3(resolvedSourcePath, "utf-8");
|
|
1867
|
+
const sourceHash = hashContent(sourceContent);
|
|
1868
|
+
const manifestKey = manifestKeyPrefix === "" ? targetFilename : `${manifestKeyPrefix}/${targetFilename}`;
|
|
1869
|
+
const lastInstalledHash = manifest.entries[manifestKey];
|
|
1870
|
+
if (existsSync4(targetPath)) {
|
|
1871
|
+
const existingContent = readFileSync3(targetPath, "utf-8");
|
|
1872
|
+
const existingHash = hashContent(existingContent);
|
|
1873
|
+
if (existingHash === sourceHash) {
|
|
1874
|
+
manifest.entries[manifestKey] = sourceHash;
|
|
1875
|
+
stats.skipped++;
|
|
1876
|
+
continue;
|
|
1877
|
+
}
|
|
1878
|
+
if (lastInstalledHash === void 0) {
|
|
1879
|
+
manifest.entries[manifestKey] = existingHash;
|
|
1880
|
+
process.stderr.write(
|
|
1881
|
+
`First-install heuristic: keeping existing ${targetPath} (differs from upstream).
|
|
1882
|
+
To accept upstream: rm ${targetPath} && npx massu install-commands
|
|
1883
|
+
`
|
|
1884
|
+
);
|
|
1885
|
+
stats.kept++;
|
|
1886
|
+
continue;
|
|
1887
|
+
}
|
|
1888
|
+
if (existingHash !== lastInstalledHash) {
|
|
1889
|
+
process.stderr.write(
|
|
1890
|
+
`${targetFilename} has local edits - kept your version.
|
|
1891
|
+
To accept upstream: rm ${targetPath} && npx massu install-commands
|
|
1892
|
+
To diff: diff ${targetPath} <(npx massu show-template ${baseName})
|
|
1893
|
+
`
|
|
1894
|
+
);
|
|
1895
|
+
stats.kept++;
|
|
1896
|
+
continue;
|
|
1897
|
+
}
|
|
1898
|
+
writeFileSync(targetPath, sourceContent, "utf-8");
|
|
1899
|
+
manifest.entries[manifestKey] = sourceHash;
|
|
1900
|
+
stats.updated++;
|
|
1901
|
+
} else {
|
|
1902
|
+
writeFileSync(targetPath, sourceContent, "utf-8");
|
|
1903
|
+
manifest.entries[manifestKey] = sourceHash;
|
|
1904
|
+
stats.installed++;
|
|
1740
1905
|
}
|
|
1741
1906
|
}
|
|
1742
1907
|
return stats;
|
|
1743
1908
|
}
|
|
1744
1909
|
function installCommands(projectRoot) {
|
|
1745
1910
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
1746
|
-
const
|
|
1911
|
+
const claudeDir = resolve3(projectRoot, claudeDirName);
|
|
1912
|
+
const targetDir = resolve3(claudeDir, "commands");
|
|
1747
1913
|
if (!existsSync4(targetDir)) {
|
|
1748
1914
|
mkdirSync2(targetDir, { recursive: true });
|
|
1749
1915
|
}
|
|
@@ -1751,9 +1917,13 @@ function installCommands(projectRoot) {
|
|
|
1751
1917
|
if (!sourceDir) {
|
|
1752
1918
|
console.error(" ERROR: Could not find massu commands directory.");
|
|
1753
1919
|
console.error(" Try reinstalling: npm install @massu/core");
|
|
1754
|
-
return { installed: 0, updated: 0, skipped: 0, commandsDir: targetDir };
|
|
1920
|
+
return { installed: 0, updated: 0, skipped: 0, kept: 0, commandsDir: targetDir };
|
|
1755
1921
|
}
|
|
1756
|
-
const
|
|
1922
|
+
const framework = getConfig().framework;
|
|
1923
|
+
const stats = runWithManifest(
|
|
1924
|
+
claudeDir,
|
|
1925
|
+
(manifest) => syncDirectory(sourceDir, targetDir, framework, manifest, "commands", true)
|
|
1926
|
+
);
|
|
1757
1927
|
return { ...stats, commandsDir: targetDir };
|
|
1758
1928
|
}
|
|
1759
1929
|
function installAll(projectRoot) {
|
|
@@ -1763,19 +1933,36 @@ function installAll(projectRoot) {
|
|
|
1763
1933
|
let totalInstalled = 0;
|
|
1764
1934
|
let totalUpdated = 0;
|
|
1765
1935
|
let totalSkipped = 0;
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1936
|
+
let totalKept = 0;
|
|
1937
|
+
const framework = getConfig().framework;
|
|
1938
|
+
runWithManifest(claudeDir, (manifest) => {
|
|
1939
|
+
for (const assetType of ASSET_TYPES) {
|
|
1940
|
+
const sourceDir = resolveAssetDir(assetType.name);
|
|
1941
|
+
if (!sourceDir) continue;
|
|
1942
|
+
const targetDir = resolve3(claudeDir, assetType.targetSubdir);
|
|
1943
|
+
const stats = syncDirectory(
|
|
1944
|
+
sourceDir,
|
|
1945
|
+
targetDir,
|
|
1946
|
+
framework,
|
|
1947
|
+
manifest,
|
|
1948
|
+
assetType.targetSubdir,
|
|
1949
|
+
true
|
|
1950
|
+
);
|
|
1951
|
+
assets[assetType.name] = stats;
|
|
1952
|
+
totalInstalled += stats.installed;
|
|
1953
|
+
totalUpdated += stats.updated;
|
|
1954
|
+
totalSkipped += stats.skipped;
|
|
1955
|
+
totalKept += stats.kept;
|
|
1770
1956
|
}
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
assets
|
|
1774
|
-
totalInstalled
|
|
1775
|
-
totalUpdated
|
|
1776
|
-
totalSkipped
|
|
1777
|
-
|
|
1778
|
-
|
|
1957
|
+
});
|
|
1958
|
+
return {
|
|
1959
|
+
assets,
|
|
1960
|
+
totalInstalled,
|
|
1961
|
+
totalUpdated,
|
|
1962
|
+
totalSkipped,
|
|
1963
|
+
totalKept,
|
|
1964
|
+
claudeDir
|
|
1965
|
+
};
|
|
1779
1966
|
}
|
|
1780
1967
|
async function runInstallCommands() {
|
|
1781
1968
|
const projectRoot = process.cwd();
|
|
@@ -1789,23 +1976,29 @@ async function runInstallCommands() {
|
|
|
1789
1976
|
if (!stats) {
|
|
1790
1977
|
continue;
|
|
1791
1978
|
}
|
|
1792
|
-
const total = stats.installed + stats.updated + stats.skipped;
|
|
1979
|
+
const total = stats.installed + stats.updated + stats.skipped + stats.kept;
|
|
1793
1980
|
if (total === 0) continue;
|
|
1794
1981
|
const parts = [];
|
|
1795
1982
|
if (stats.installed > 0) parts.push(`${stats.installed} new`);
|
|
1796
1983
|
if (stats.updated > 0) parts.push(`${stats.updated} updated`);
|
|
1797
1984
|
if (stats.skipped > 0) parts.push(`${stats.skipped} current`);
|
|
1985
|
+
if (stats.kept > 0) parts.push(`${stats.kept} kept (local edits)`);
|
|
1798
1986
|
const description = assetType.description;
|
|
1799
1987
|
console.log(` ${description}: ${parts.join(", ")} (${total} total)`);
|
|
1800
1988
|
}
|
|
1801
|
-
const grandTotal = result.totalInstalled + result.totalUpdated + result.totalSkipped;
|
|
1989
|
+
const grandTotal = result.totalInstalled + result.totalUpdated + result.totalSkipped + result.totalKept;
|
|
1802
1990
|
console.log("");
|
|
1803
1991
|
console.log(` ${grandTotal} total files synced to ${result.claudeDir}`);
|
|
1992
|
+
if (result.totalKept > 0) {
|
|
1993
|
+
console.log(
|
|
1994
|
+
` ${result.totalKept} file(s) had local edits and were preserved (see stderr above).`
|
|
1995
|
+
);
|
|
1996
|
+
}
|
|
1804
1997
|
console.log("");
|
|
1805
1998
|
console.log(" Restart your Claude Code session to use them.");
|
|
1806
1999
|
console.log("");
|
|
1807
2000
|
}
|
|
1808
|
-
var __filename, __dirname, ASSET_TYPES;
|
|
2001
|
+
var __filename, __dirname, ASSET_TYPES, MANIFEST_VERSION, MANIFEST_RELPATH, PASSTHROUGH_LANG_KEYS;
|
|
1809
2002
|
var init_install_commands = __esm({
|
|
1810
2003
|
"src/commands/install-commands.ts"() {
|
|
1811
2004
|
"use strict";
|
|
@@ -1819,6 +2012,16 @@ var init_install_commands = __esm({
|
|
|
1819
2012
|
{ name: "protocols", targetSubdir: "protocols", description: "protocol files" },
|
|
1820
2013
|
{ name: "reference", targetSubdir: "reference", description: "reference files" }
|
|
1821
2014
|
];
|
|
2015
|
+
MANIFEST_VERSION = 1;
|
|
2016
|
+
MANIFEST_RELPATH = join2(".massu", "install-manifest.json");
|
|
2017
|
+
PASSTHROUGH_LANG_KEYS = [
|
|
2018
|
+
"typescript",
|
|
2019
|
+
"javascript",
|
|
2020
|
+
"python",
|
|
2021
|
+
"swift",
|
|
2022
|
+
"rust",
|
|
2023
|
+
"go"
|
|
2024
|
+
];
|
|
1822
2025
|
}
|
|
1823
2026
|
});
|
|
1824
2027
|
|
|
@@ -7797,41 +8000,41 @@ var require_queue = __commonJS({
|
|
|
7797
8000
|
queue.drained = drained;
|
|
7798
8001
|
return queue;
|
|
7799
8002
|
function push(value) {
|
|
7800
|
-
var p19 = new Promise(function(
|
|
8003
|
+
var p19 = new Promise(function(resolve26, reject) {
|
|
7801
8004
|
pushCb(value, function(err, result) {
|
|
7802
8005
|
if (err) {
|
|
7803
8006
|
reject(err);
|
|
7804
8007
|
return;
|
|
7805
8008
|
}
|
|
7806
|
-
|
|
8009
|
+
resolve26(result);
|
|
7807
8010
|
});
|
|
7808
8011
|
});
|
|
7809
8012
|
p19.catch(noop);
|
|
7810
8013
|
return p19;
|
|
7811
8014
|
}
|
|
7812
8015
|
function unshift(value) {
|
|
7813
|
-
var p19 = new Promise(function(
|
|
8016
|
+
var p19 = new Promise(function(resolve26, reject) {
|
|
7814
8017
|
unshiftCb(value, function(err, result) {
|
|
7815
8018
|
if (err) {
|
|
7816
8019
|
reject(err);
|
|
7817
8020
|
return;
|
|
7818
8021
|
}
|
|
7819
|
-
|
|
8022
|
+
resolve26(result);
|
|
7820
8023
|
});
|
|
7821
8024
|
});
|
|
7822
8025
|
p19.catch(noop);
|
|
7823
8026
|
return p19;
|
|
7824
8027
|
}
|
|
7825
8028
|
function drained() {
|
|
7826
|
-
var p19 = new Promise(function(
|
|
8029
|
+
var p19 = new Promise(function(resolve26) {
|
|
7827
8030
|
process.nextTick(function() {
|
|
7828
8031
|
if (queue.idle()) {
|
|
7829
|
-
|
|
8032
|
+
resolve26();
|
|
7830
8033
|
} else {
|
|
7831
8034
|
var previousDrain = queue.drain;
|
|
7832
8035
|
queue.drain = function() {
|
|
7833
8036
|
if (typeof previousDrain === "function") previousDrain();
|
|
7834
|
-
|
|
8037
|
+
resolve26();
|
|
7835
8038
|
queue.drain = previousDrain;
|
|
7836
8039
|
};
|
|
7837
8040
|
}
|
|
@@ -8317,9 +8520,9 @@ var require_stream3 = __commonJS({
|
|
|
8317
8520
|
});
|
|
8318
8521
|
}
|
|
8319
8522
|
_getStat(filepath) {
|
|
8320
|
-
return new Promise((
|
|
8523
|
+
return new Promise((resolve26, reject) => {
|
|
8321
8524
|
this._stat(filepath, this._fsStatSettings, (error, stats) => {
|
|
8322
|
-
return error === null ?
|
|
8525
|
+
return error === null ? resolve26(stats) : reject(error);
|
|
8323
8526
|
});
|
|
8324
8527
|
});
|
|
8325
8528
|
}
|
|
@@ -8343,10 +8546,10 @@ var require_async5 = __commonJS({
|
|
|
8343
8546
|
this._readerStream = new stream_1.default(this._settings);
|
|
8344
8547
|
}
|
|
8345
8548
|
dynamic(root, options) {
|
|
8346
|
-
return new Promise((
|
|
8549
|
+
return new Promise((resolve26, reject) => {
|
|
8347
8550
|
this._walkAsync(root, options, (error, entries) => {
|
|
8348
8551
|
if (error === null) {
|
|
8349
|
-
|
|
8552
|
+
resolve26(entries);
|
|
8350
8553
|
} else {
|
|
8351
8554
|
reject(error);
|
|
8352
8555
|
}
|
|
@@ -8356,10 +8559,10 @@ var require_async5 = __commonJS({
|
|
|
8356
8559
|
async static(patterns, options) {
|
|
8357
8560
|
const entries = [];
|
|
8358
8561
|
const stream = this._readerStream.static(patterns, options);
|
|
8359
|
-
return new Promise((
|
|
8562
|
+
return new Promise((resolve26, reject) => {
|
|
8360
8563
|
stream.once("error", reject);
|
|
8361
8564
|
stream.on("data", (entry) => entries.push(entry));
|
|
8362
|
-
stream.once("end", () =>
|
|
8565
|
+
stream.once("end", () => resolve26(entries));
|
|
8363
8566
|
});
|
|
8364
8567
|
}
|
|
8365
8568
|
};
|
|
@@ -9022,6 +9225,13 @@ import { resolve as resolve4 } from "path";
|
|
|
9022
9225
|
function extsFor(language) {
|
|
9023
9226
|
return EXTENSIONS[language] ?? [];
|
|
9024
9227
|
}
|
|
9228
|
+
function extsWithFallback(language, fallbackTsForJs) {
|
|
9229
|
+
const base = extsFor(language);
|
|
9230
|
+
if (language === "javascript" && fallbackTsForJs) {
|
|
9231
|
+
return [...base, "ts", "tsx"];
|
|
9232
|
+
}
|
|
9233
|
+
return base;
|
|
9234
|
+
}
|
|
9025
9235
|
function isTestPath(language, path) {
|
|
9026
9236
|
const segments = path.split("/");
|
|
9027
9237
|
for (const seg of segments) {
|
|
@@ -9043,10 +9253,11 @@ function isInsideRoot(root, candidate) {
|
|
|
9043
9253
|
return false;
|
|
9044
9254
|
}
|
|
9045
9255
|
}
|
|
9046
|
-
function detectSourceDirs(projectRoot, languages) {
|
|
9256
|
+
function detectSourceDirs(projectRoot, languages, opts) {
|
|
9257
|
+
const fallbackTsForJs = opts?.fallbackTsForJs ?? false;
|
|
9047
9258
|
const out = {};
|
|
9048
9259
|
for (const lang of languages) {
|
|
9049
|
-
const exts =
|
|
9260
|
+
const exts = extsWithFallback(lang, fallbackTsForJs);
|
|
9050
9261
|
if (exts.length === 0) continue;
|
|
9051
9262
|
const patterns = exts.map((e2) => `**/*.${e2}`);
|
|
9052
9263
|
let files;
|
|
@@ -9644,8 +9855,9 @@ async function runDetection(projectRoot, overrides) {
|
|
|
9644
9855
|
const languages = Array.from(
|
|
9645
9856
|
new Set(pkg.manifests.map((m3) => m3.language))
|
|
9646
9857
|
);
|
|
9858
|
+
const fallbackTsForJs = languages.includes("javascript") && !languages.includes("typescript");
|
|
9647
9859
|
const [sourceDirs, monorepo] = await Promise.all([
|
|
9648
|
-
Promise.resolve(detectSourceDirs(projectRoot, languages)),
|
|
9860
|
+
Promise.resolve(detectSourceDirs(projectRoot, languages, { fallbackTsForJs })),
|
|
9649
9861
|
Promise.resolve(detectMonorepo(projectRoot))
|
|
9650
9862
|
]);
|
|
9651
9863
|
const domains = inferDomains(projectRoot, monorepo, sourceDirs);
|
|
@@ -9687,7 +9899,7 @@ var init_detect = __esm({
|
|
|
9687
9899
|
});
|
|
9688
9900
|
|
|
9689
9901
|
// src/detect/drift.ts
|
|
9690
|
-
import { createHash } from "crypto";
|
|
9902
|
+
import { createHash as createHash2 } from "crypto";
|
|
9691
9903
|
function summarizeDetection(det) {
|
|
9692
9904
|
const languages = Array.from(new Set(det.manifests.map((m3) => m3.language))).sort();
|
|
9693
9905
|
const frameworks = {};
|
|
@@ -9718,7 +9930,7 @@ function summarizeDetection(det) {
|
|
|
9718
9930
|
function computeFingerprint(det) {
|
|
9719
9931
|
const data = summarizeDetection(det);
|
|
9720
9932
|
const stable = JSON.stringify(data, Object.keys(data).sort());
|
|
9721
|
-
return
|
|
9933
|
+
return createHash2("sha256").update(stable).digest("hex");
|
|
9722
9934
|
}
|
|
9723
9935
|
function stringOf(v3) {
|
|
9724
9936
|
if (typeof v3 === "string") return v3;
|
|
@@ -10876,7 +11088,7 @@ __export(init_exports, {
|
|
|
10876
11088
|
validateWrittenConfig: () => validateWrittenConfig,
|
|
10877
11089
|
writeConfigAtomic: () => writeConfigAtomic
|
|
10878
11090
|
});
|
|
10879
|
-
import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, readdirSync as readdirSync6, renameSync, rmSync, statSync as statSync4, chmodSync } from "fs";
|
|
11091
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, readdirSync as readdirSync6, renameSync as renameSync2, rmSync, statSync as statSync4, chmodSync } from "fs";
|
|
10880
11092
|
import { resolve as resolve5, basename as basename2, dirname as dirname4 } from "path";
|
|
10881
11093
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10882
11094
|
import { homedir as homedir2 } from "os";
|
|
@@ -10978,6 +11190,9 @@ function detectPython(projectRoot) {
|
|
|
10978
11190
|
return result;
|
|
10979
11191
|
}
|
|
10980
11192
|
function generateConfig(projectRoot, framework) {
|
|
11193
|
+
console.warn(
|
|
11194
|
+
"[@massu/core] generateConfig() is deprecated since 1.2.1 \u2014 use buildConfigFromDetection instead. It cannot produce valid configs for monorepos."
|
|
11195
|
+
);
|
|
10981
11196
|
const configPath = resolve5(projectRoot, "massu.config.yaml");
|
|
10982
11197
|
if (existsSync8(configPath)) {
|
|
10983
11198
|
return false;
|
|
@@ -11028,6 +11243,20 @@ ${yamlStringify(config)}`;
|
|
|
11028
11243
|
writeFileSync2(configPath, yamlContent, "utf-8");
|
|
11029
11244
|
return true;
|
|
11030
11245
|
}
|
|
11246
|
+
function monorepoCommonRoot(packages) {
|
|
11247
|
+
const roots = monorepoDistinctRoots(packages);
|
|
11248
|
+
return roots.length === 1 ? roots[0] : ".";
|
|
11249
|
+
}
|
|
11250
|
+
function monorepoDistinctRoots(packages) {
|
|
11251
|
+
const set = /* @__PURE__ */ new Set();
|
|
11252
|
+
for (const p19 of packages) {
|
|
11253
|
+
const parts = p19.path.split("/");
|
|
11254
|
+
if (parts.length > 1 && parts[0] !== "" && parts[0] !== ".") {
|
|
11255
|
+
set.add(parts[0]);
|
|
11256
|
+
}
|
|
11257
|
+
}
|
|
11258
|
+
return [...set].sort();
|
|
11259
|
+
}
|
|
11031
11260
|
function buildConfigFromDetection(opts) {
|
|
11032
11261
|
const { projectRoot, detection } = opts;
|
|
11033
11262
|
if (!detection) {
|
|
@@ -11072,6 +11301,16 @@ function buildConfigFromDetection(opts) {
|
|
|
11072
11301
|
const primaryDirs = detection.sourceDirs[primary]?.source_dirs ?? [];
|
|
11073
11302
|
if (primaryDirs.length > 0) {
|
|
11074
11303
|
pathsSource = primaryDirs[0];
|
|
11304
|
+
} else if (detection.monorepo.type !== "single" && detection.monorepo.packages.length > 0) {
|
|
11305
|
+
pathsSource = monorepoCommonRoot(detection.monorepo.packages);
|
|
11306
|
+
}
|
|
11307
|
+
}
|
|
11308
|
+
let monorepoRoots;
|
|
11309
|
+
if (detection.monorepo.type !== "single") {
|
|
11310
|
+
if (detection.monorepo.packages.length > 0) {
|
|
11311
|
+
monorepoRoots = monorepoDistinctRoots(detection.monorepo.packages);
|
|
11312
|
+
} else if (pathsSource !== "src" && pathsSource !== ".") {
|
|
11313
|
+
monorepoRoots = [pathsSource];
|
|
11075
11314
|
}
|
|
11076
11315
|
}
|
|
11077
11316
|
const verification = {};
|
|
@@ -11108,6 +11347,13 @@ function buildConfigFromDetection(opts) {
|
|
|
11108
11347
|
if (Object.keys(languageEntries).length > 0) {
|
|
11109
11348
|
frameworkBlock.languages = languageEntries;
|
|
11110
11349
|
}
|
|
11350
|
+
const pathsBlock = {
|
|
11351
|
+
source: pathsSource,
|
|
11352
|
+
aliases: { "@": pathsSource }
|
|
11353
|
+
};
|
|
11354
|
+
if (monorepoRoots && monorepoRoots.length > 0) {
|
|
11355
|
+
pathsBlock.monorepo_roots = monorepoRoots;
|
|
11356
|
+
}
|
|
11111
11357
|
const config = {
|
|
11112
11358
|
schema_version: 2,
|
|
11113
11359
|
project: {
|
|
@@ -11115,10 +11361,7 @@ function buildConfigFromDetection(opts) {
|
|
|
11115
11361
|
root: "auto"
|
|
11116
11362
|
},
|
|
11117
11363
|
framework: frameworkBlock,
|
|
11118
|
-
paths:
|
|
11119
|
-
source: pathsSource,
|
|
11120
|
-
aliases: { "@": pathsSource }
|
|
11121
|
-
},
|
|
11364
|
+
paths: pathsBlock,
|
|
11122
11365
|
toolPrefix: "massu",
|
|
11123
11366
|
domains,
|
|
11124
11367
|
rules: []
|
|
@@ -11167,7 +11410,7 @@ function writeConfigAtomic(configPath, content) {
|
|
|
11167
11410
|
if (parsed === null || typeof parsed !== "object") {
|
|
11168
11411
|
throw new Error("Generated config is not a valid YAML object");
|
|
11169
11412
|
}
|
|
11170
|
-
|
|
11413
|
+
renameSync2(tmpPath, configPath);
|
|
11171
11414
|
if (existingMode !== void 0) {
|
|
11172
11415
|
try {
|
|
11173
11416
|
chmodSync(configPath, existingMode);
|
|
@@ -11225,6 +11468,15 @@ function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
|
|
|
11225
11468
|
}
|
|
11226
11469
|
}
|
|
11227
11470
|
}
|
|
11471
|
+
const mRoots = cfg.paths.monorepo_roots;
|
|
11472
|
+
if (Array.isArray(mRoots)) {
|
|
11473
|
+
for (const r2 of mRoots) {
|
|
11474
|
+
if (typeof r2 !== "string" || r2 === ".") continue;
|
|
11475
|
+
if (!existsSync8(resolve5(projectRoot, r2))) {
|
|
11476
|
+
return `paths.monorepo_roots '${r2}' does not exist on disk`;
|
|
11477
|
+
}
|
|
11478
|
+
}
|
|
11479
|
+
}
|
|
11228
11480
|
}
|
|
11229
11481
|
} catch (err) {
|
|
11230
11482
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -11736,7 +11988,7 @@ var init_init = __esm({
|
|
|
11736
11988
|
});
|
|
11737
11989
|
|
|
11738
11990
|
// src/license.ts
|
|
11739
|
-
import { createHash as
|
|
11991
|
+
import { createHash as createHash3 } from "crypto";
|
|
11740
11992
|
function tierLevel(tier) {
|
|
11741
11993
|
return TIER_LEVELS[tier] ?? 0;
|
|
11742
11994
|
}
|
|
@@ -11761,7 +12013,7 @@ function annotateToolDefinitions(defs) {
|
|
|
11761
12013
|
});
|
|
11762
12014
|
}
|
|
11763
12015
|
async function validateLicense(apiKey) {
|
|
11764
|
-
const keyHash =
|
|
12016
|
+
const keyHash = createHash3("sha256").update(apiKey).digest("hex");
|
|
11765
12017
|
const memDb = getMemoryDb();
|
|
11766
12018
|
try {
|
|
11767
12019
|
const cached = memDb.prepare(
|
|
@@ -11822,7 +12074,7 @@ async function validateLicense(apiKey) {
|
|
|
11822
12074
|
}
|
|
11823
12075
|
}
|
|
11824
12076
|
function updateLicenseCache(apiKey, tier, validUntil, features = []) {
|
|
11825
|
-
const keyHash =
|
|
12077
|
+
const keyHash = createHash3("sha256").update(apiKey).digest("hex");
|
|
11826
12078
|
const memDb = getMemoryDb();
|
|
11827
12079
|
try {
|
|
11828
12080
|
memDb.prepare(`
|
|
@@ -12438,13 +12690,64 @@ var init_install_hooks = __esm({
|
|
|
12438
12690
|
}
|
|
12439
12691
|
});
|
|
12440
12692
|
|
|
12693
|
+
// src/commands/show-template.ts
|
|
12694
|
+
var show_template_exports = {};
|
|
12695
|
+
__export(show_template_exports, {
|
|
12696
|
+
runShowTemplate: () => runShowTemplate
|
|
12697
|
+
});
|
|
12698
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
12699
|
+
import { resolve as resolve7 } from "path";
|
|
12700
|
+
function normalizeBaseName(input) {
|
|
12701
|
+
return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
|
|
12702
|
+
}
|
|
12703
|
+
async function runShowTemplate(args2) {
|
|
12704
|
+
const rawName = args2[0];
|
|
12705
|
+
if (!rawName) {
|
|
12706
|
+
process.stderr.write("massu: show-template requires a template name\n");
|
|
12707
|
+
process.stderr.write(" usage: massu show-template <name>\n");
|
|
12708
|
+
process.exit(1);
|
|
12709
|
+
return;
|
|
12710
|
+
}
|
|
12711
|
+
const baseName = normalizeBaseName(rawName);
|
|
12712
|
+
const sourceDir = resolveAssetDir("commands");
|
|
12713
|
+
if (!sourceDir) {
|
|
12714
|
+
process.stderr.write("massu: could not locate the bundled commands directory\n");
|
|
12715
|
+
process.exit(1);
|
|
12716
|
+
return;
|
|
12717
|
+
}
|
|
12718
|
+
const framework = getConfig().framework;
|
|
12719
|
+
const choice = pickVariant(baseName, sourceDir, framework);
|
|
12720
|
+
if (choice.kind === "miss") {
|
|
12721
|
+
process.stderr.write(`massu: no template named "${baseName}" found
|
|
12722
|
+
`);
|
|
12723
|
+
process.exit(1);
|
|
12724
|
+
return;
|
|
12725
|
+
}
|
|
12726
|
+
const suffix = choice.kind === "hit" ? choice.suffix : "";
|
|
12727
|
+
const file = suffix === "" ? resolve7(sourceDir, `${baseName}.md`) : resolve7(sourceDir, `${baseName}${suffix}.md`);
|
|
12728
|
+
if (!existsSync10(file)) {
|
|
12729
|
+
process.stderr.write(`massu: resolved template "${file}" no longer exists
|
|
12730
|
+
`);
|
|
12731
|
+
process.exit(1);
|
|
12732
|
+
return;
|
|
12733
|
+
}
|
|
12734
|
+
process.stdout.write(readFileSync8(file, "utf-8"));
|
|
12735
|
+
}
|
|
12736
|
+
var init_show_template = __esm({
|
|
12737
|
+
"src/commands/show-template.ts"() {
|
|
12738
|
+
"use strict";
|
|
12739
|
+
init_config();
|
|
12740
|
+
init_install_commands();
|
|
12741
|
+
}
|
|
12742
|
+
});
|
|
12743
|
+
|
|
12441
12744
|
// src/db.ts
|
|
12442
12745
|
import Database2 from "better-sqlite3";
|
|
12443
12746
|
import { dirname as dirname6, join as join6 } from "path";
|
|
12444
|
-
import { existsSync as
|
|
12747
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readdirSync as readdirSync8, statSync as statSync5 } from "fs";
|
|
12445
12748
|
function getCodeGraphDb() {
|
|
12446
12749
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
12447
|
-
if (!
|
|
12750
|
+
if (!existsSync11(dbPath)) {
|
|
12448
12751
|
throw new Error(`CodeGraph database not found at ${dbPath}. Run 'npx @colbymchenry/codegraph sync' first.`);
|
|
12449
12752
|
}
|
|
12450
12753
|
const db = new Database2(dbPath, { readonly: true });
|
|
@@ -12454,7 +12757,7 @@ function getCodeGraphDb() {
|
|
|
12454
12757
|
function getDataDb() {
|
|
12455
12758
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
12456
12759
|
const dir = dirname6(dbPath);
|
|
12457
|
-
if (!
|
|
12760
|
+
if (!existsSync11(dir)) {
|
|
12458
12761
|
mkdirSync4(dir, { recursive: true });
|
|
12459
12762
|
}
|
|
12460
12763
|
const db = new Database2(dbPath);
|
|
@@ -12752,10 +13055,10 @@ var init_db = __esm({
|
|
|
12752
13055
|
});
|
|
12753
13056
|
|
|
12754
13057
|
// src/security-utils.ts
|
|
12755
|
-
import { resolve as
|
|
13058
|
+
import { resolve as resolve8, normalize } from "path";
|
|
12756
13059
|
function ensureWithinRoot(filePath, projectRoot) {
|
|
12757
|
-
const resolvedRoot =
|
|
12758
|
-
const resolvedPath =
|
|
13060
|
+
const resolvedRoot = resolve8(projectRoot);
|
|
13061
|
+
const resolvedPath = resolve8(resolvedRoot, filePath);
|
|
12759
13062
|
const normalizedPath = normalize(resolvedPath);
|
|
12760
13063
|
const normalizedRoot = normalize(resolvedRoot);
|
|
12761
13064
|
if (!normalizedPath.startsWith(normalizedRoot + "/") && normalizedPath !== normalizedRoot) {
|
|
@@ -12828,8 +13131,8 @@ var init_rules = __esm({
|
|
|
12828
13131
|
});
|
|
12829
13132
|
|
|
12830
13133
|
// src/import-resolver.ts
|
|
12831
|
-
import { readFileSync as
|
|
12832
|
-
import { resolve as
|
|
13134
|
+
import { readFileSync as readFileSync9, existsSync as existsSync12, statSync as statSync6 } from "fs";
|
|
13135
|
+
import { resolve as resolve9, dirname as dirname7, join as join7 } from "path";
|
|
12833
13136
|
function parseImports(source) {
|
|
12834
13137
|
const imports = [];
|
|
12835
13138
|
const lines = source.split("\n");
|
|
@@ -12885,23 +13188,23 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
12885
13188
|
let basePath;
|
|
12886
13189
|
if (specifier.startsWith("@/")) {
|
|
12887
13190
|
const paths = getResolvedPaths();
|
|
12888
|
-
basePath =
|
|
13191
|
+
basePath = resolve9(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
12889
13192
|
} else {
|
|
12890
|
-
basePath =
|
|
13193
|
+
basePath = resolve9(dirname7(fromFile), specifier);
|
|
12891
13194
|
}
|
|
12892
|
-
if (
|
|
13195
|
+
if (existsSync12(basePath) && !isDirectory(basePath)) {
|
|
12893
13196
|
return toRelative(basePath);
|
|
12894
13197
|
}
|
|
12895
13198
|
const resolvedPaths = getResolvedPaths();
|
|
12896
13199
|
for (const ext of resolvedPaths.extensions) {
|
|
12897
13200
|
const withExt = basePath + ext;
|
|
12898
|
-
if (
|
|
13201
|
+
if (existsSync12(withExt)) {
|
|
12899
13202
|
return toRelative(withExt);
|
|
12900
13203
|
}
|
|
12901
13204
|
}
|
|
12902
13205
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
12903
13206
|
const indexPath = join7(basePath, indexFile);
|
|
12904
|
-
if (
|
|
13207
|
+
if (existsSync12(indexPath)) {
|
|
12905
13208
|
return toRelative(indexPath);
|
|
12906
13209
|
}
|
|
12907
13210
|
}
|
|
@@ -12937,11 +13240,11 @@ function buildImportIndex(dataDb2, codegraphDb2) {
|
|
|
12937
13240
|
const batchSize = 500;
|
|
12938
13241
|
let batch = [];
|
|
12939
13242
|
for (const file of files) {
|
|
12940
|
-
const absPath = ensureWithinRoot(
|
|
12941
|
-
if (!
|
|
13243
|
+
const absPath = ensureWithinRoot(resolve9(projectRoot, file.path), projectRoot);
|
|
13244
|
+
if (!existsSync12(absPath)) continue;
|
|
12942
13245
|
let source;
|
|
12943
13246
|
try {
|
|
12944
|
-
source =
|
|
13247
|
+
source = readFileSync9(absPath, "utf-8");
|
|
12945
13248
|
} catch {
|
|
12946
13249
|
continue;
|
|
12947
13250
|
}
|
|
@@ -12977,15 +13280,15 @@ var init_import_resolver = __esm({
|
|
|
12977
13280
|
});
|
|
12978
13281
|
|
|
12979
13282
|
// src/trpc-index.ts
|
|
12980
|
-
import { readFileSync as
|
|
12981
|
-
import { resolve as
|
|
13283
|
+
import { readFileSync as readFileSync10, existsSync as existsSync13, readdirSync as readdirSync9 } from "fs";
|
|
13284
|
+
import { resolve as resolve10, join as join8 } from "path";
|
|
12982
13285
|
function parseRootRouter() {
|
|
12983
13286
|
const paths = getResolvedPaths();
|
|
12984
13287
|
const rootPath = paths.rootRouterPath;
|
|
12985
|
-
if (!
|
|
13288
|
+
if (!existsSync13(rootPath)) {
|
|
12986
13289
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
12987
13290
|
}
|
|
12988
|
-
const source =
|
|
13291
|
+
const source = readFileSync10(rootPath, "utf-8");
|
|
12989
13292
|
const mappings = [];
|
|
12990
13293
|
const importMap = /* @__PURE__ */ new Map();
|
|
12991
13294
|
const importRegex = /import\s+\{[^}]*?(\w+Router)[^}]*\}\s+from\s+['"]\.\/routers\/([^'"]+)['"]/g;
|
|
@@ -12993,16 +13296,16 @@ function parseRootRouter() {
|
|
|
12993
13296
|
while ((match = importRegex.exec(source)) !== null) {
|
|
12994
13297
|
const variable = match[1];
|
|
12995
13298
|
let filePath = match[2];
|
|
12996
|
-
const fullPath =
|
|
13299
|
+
const fullPath = resolve10(paths.routersDir, filePath);
|
|
12997
13300
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
12998
13301
|
const candidate = fullPath + ext;
|
|
12999
13302
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
13000
|
-
if (
|
|
13303
|
+
if (existsSync13(candidate)) {
|
|
13001
13304
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
13002
13305
|
break;
|
|
13003
13306
|
}
|
|
13004
13307
|
const indexCandidate = join8(fullPath, "index.ts");
|
|
13005
|
-
if (
|
|
13308
|
+
if (existsSync13(indexCandidate)) {
|
|
13006
13309
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
13007
13310
|
break;
|
|
13008
13311
|
}
|
|
@@ -13021,9 +13324,9 @@ function parseRootRouter() {
|
|
|
13021
13324
|
return mappings;
|
|
13022
13325
|
}
|
|
13023
13326
|
function extractProcedures(routerFilePath) {
|
|
13024
|
-
const absPath =
|
|
13025
|
-
if (!
|
|
13026
|
-
const source =
|
|
13327
|
+
const absPath = resolve10(getProjectRoot(), routerFilePath);
|
|
13328
|
+
if (!existsSync13(absPath)) return [];
|
|
13329
|
+
const source = readFileSync10(absPath, "utf-8");
|
|
13027
13330
|
const procedures = [];
|
|
13028
13331
|
const seen = /* @__PURE__ */ new Set();
|
|
13029
13332
|
const procRegex = /(\w+)\s*:\s*(protected|public)Procedure/g;
|
|
@@ -13046,13 +13349,13 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
13046
13349
|
const root = getProjectRoot();
|
|
13047
13350
|
const src = config.paths.source;
|
|
13048
13351
|
const searchDirs = [
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13352
|
+
resolve10(root, config.paths.pages ?? src + "/app"),
|
|
13353
|
+
resolve10(root, config.paths.components ?? src + "/components"),
|
|
13354
|
+
resolve10(root, config.paths.hooks ?? src + "/hooks")
|
|
13052
13355
|
];
|
|
13053
13356
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
13054
13357
|
for (const dir of searchDirs) {
|
|
13055
|
-
if (!
|
|
13358
|
+
if (!existsSync13(dir)) continue;
|
|
13056
13359
|
searchDirectory(dir, searchPattern, callSites);
|
|
13057
13360
|
}
|
|
13058
13361
|
return callSites;
|
|
@@ -13066,7 +13369,7 @@ function searchDirectory(dir, pattern, results) {
|
|
|
13066
13369
|
searchDirectory(fullPath, pattern, results);
|
|
13067
13370
|
} else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
13068
13371
|
try {
|
|
13069
|
-
const source =
|
|
13372
|
+
const source = readFileSync10(fullPath, "utf-8");
|
|
13070
13373
|
const lines = source.split("\n");
|
|
13071
13374
|
for (let i = 0; i < lines.length; i++) {
|
|
13072
13375
|
if (lines[i].includes(pattern)) {
|
|
@@ -13129,8 +13432,8 @@ var init_trpc_index = __esm({
|
|
|
13129
13432
|
});
|
|
13130
13433
|
|
|
13131
13434
|
// src/page-deps.ts
|
|
13132
|
-
import { readFileSync as
|
|
13133
|
-
import { resolve as
|
|
13435
|
+
import { readFileSync as readFileSync11, existsSync as existsSync14 } from "fs";
|
|
13436
|
+
import { resolve as resolve11 } from "path";
|
|
13134
13437
|
function deriveRoute(pageFile) {
|
|
13135
13438
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
13136
13439
|
return route || "/";
|
|
@@ -13168,10 +13471,10 @@ function findRouterCalls(files) {
|
|
|
13168
13471
|
const routers = /* @__PURE__ */ new Set();
|
|
13169
13472
|
const projectRoot = getProjectRoot();
|
|
13170
13473
|
for (const file of files) {
|
|
13171
|
-
const absPath = ensureWithinRoot(
|
|
13172
|
-
if (!
|
|
13474
|
+
const absPath = ensureWithinRoot(resolve11(projectRoot, file), projectRoot);
|
|
13475
|
+
if (!existsSync14(absPath)) continue;
|
|
13173
13476
|
try {
|
|
13174
|
-
const source =
|
|
13477
|
+
const source = readFileSync11(absPath, "utf-8");
|
|
13175
13478
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
13176
13479
|
let match;
|
|
13177
13480
|
while ((match = apiCallRegex.exec(source)) !== null) {
|
|
@@ -13189,10 +13492,10 @@ function findTablesFromRouters(routerNames, dataDb2) {
|
|
|
13189
13492
|
"SELECT DISTINCT router_file FROM massu_trpc_procedures WHERE router_name = ?"
|
|
13190
13493
|
).all(routerName);
|
|
13191
13494
|
for (const proc of procs) {
|
|
13192
|
-
const absPath = ensureWithinRoot(
|
|
13193
|
-
if (!
|
|
13495
|
+
const absPath = ensureWithinRoot(resolve11(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
13496
|
+
if (!existsSync14(absPath)) continue;
|
|
13194
13497
|
try {
|
|
13195
|
-
const source =
|
|
13498
|
+
const source = readFileSync11(absPath, "utf-8");
|
|
13196
13499
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
13197
13500
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
13198
13501
|
const tableRegex = new RegExp(regexStr + "\\.", "g");
|
|
@@ -13461,14 +13764,14 @@ var init_domains = __esm({
|
|
|
13461
13764
|
});
|
|
13462
13765
|
|
|
13463
13766
|
// src/schema-mapper.ts
|
|
13464
|
-
import { readFileSync as
|
|
13767
|
+
import { readFileSync as readFileSync12, existsSync as existsSync15, readdirSync as readdirSync10 } from "fs";
|
|
13465
13768
|
import { join as join9 } from "path";
|
|
13466
13769
|
function parsePrismaSchema() {
|
|
13467
13770
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
13468
|
-
if (!
|
|
13771
|
+
if (!existsSync15(schemaPath)) {
|
|
13469
13772
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
13470
13773
|
}
|
|
13471
|
-
const source =
|
|
13774
|
+
const source = readFileSync12(schemaPath, "utf-8");
|
|
13472
13775
|
const models = [];
|
|
13473
13776
|
const sourceLines = source.split("\n");
|
|
13474
13777
|
let i = 0;
|
|
@@ -13526,7 +13829,7 @@ function toSnakeCase(str) {
|
|
|
13526
13829
|
function findColumnUsageInRouters(tableName) {
|
|
13527
13830
|
const usage = /* @__PURE__ */ new Map();
|
|
13528
13831
|
const routersDir = getResolvedPaths().routersDir;
|
|
13529
|
-
if (!
|
|
13832
|
+
if (!existsSync15(routersDir)) return usage;
|
|
13530
13833
|
scanDirectory(routersDir, tableName, usage);
|
|
13531
13834
|
return usage;
|
|
13532
13835
|
}
|
|
@@ -13543,7 +13846,7 @@ function scanDirectory(dir, tableName, usage) {
|
|
|
13543
13846
|
}
|
|
13544
13847
|
function scanFile(absPath, tableName, usage) {
|
|
13545
13848
|
try {
|
|
13546
|
-
const source =
|
|
13849
|
+
const source = readFileSync12(absPath, "utf-8");
|
|
13547
13850
|
if (!source.includes(tableName)) return;
|
|
13548
13851
|
const relPath = absPath.slice(getProjectRoot().length + 1);
|
|
13549
13852
|
const lines = source.split("\n");
|
|
@@ -13588,7 +13891,7 @@ function detectMismatches(models) {
|
|
|
13588
13891
|
}
|
|
13589
13892
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
13590
13893
|
const result = [];
|
|
13591
|
-
if (!
|
|
13894
|
+
if (!existsSync15(dir)) return result;
|
|
13592
13895
|
const entries = readdirSync10(dir, { withFileTypes: true });
|
|
13593
13896
|
for (const entry of entries) {
|
|
13594
13897
|
const fullPath = join9(dir, entry.name);
|
|
@@ -13596,7 +13899,7 @@ function findFilesUsingColumn(dir, column, tableName) {
|
|
|
13596
13899
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
13597
13900
|
} else if (entry.name.endsWith(".ts")) {
|
|
13598
13901
|
try {
|
|
13599
|
-
const source =
|
|
13902
|
+
const source = readFileSync12(fullPath, "utf-8");
|
|
13600
13903
|
if (source.includes(tableName) && source.includes(column)) {
|
|
13601
13904
|
result.push(fullPath.slice(getProjectRoot().length + 1));
|
|
13602
13905
|
}
|
|
@@ -13741,12 +14044,12 @@ var init_import_parser = __esm({
|
|
|
13741
14044
|
});
|
|
13742
14045
|
|
|
13743
14046
|
// src/python/import-resolver.ts
|
|
13744
|
-
import { readFileSync as
|
|
13745
|
-
import { resolve as
|
|
14047
|
+
import { readFileSync as readFileSync13, existsSync as existsSync16, readdirSync as readdirSync11 } from "fs";
|
|
14048
|
+
import { resolve as resolve13, join as join10, relative as relative4, dirname as dirname8 } from "path";
|
|
13746
14049
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
13747
14050
|
const projectRoot = getProjectRoot();
|
|
13748
14051
|
if (level > 0) {
|
|
13749
|
-
let baseDir = dirname8(
|
|
14052
|
+
let baseDir = dirname8(resolve13(projectRoot, fromFile));
|
|
13750
14053
|
for (let i = 1; i < level; i++) {
|
|
13751
14054
|
baseDir = dirname8(baseDir);
|
|
13752
14055
|
}
|
|
@@ -13758,17 +14061,17 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
13758
14061
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
13759
14062
|
}
|
|
13760
14063
|
const parts = module.split(".");
|
|
13761
|
-
const candidate = join10(
|
|
14064
|
+
const candidate = join10(resolve13(projectRoot, pythonRoot), ...parts);
|
|
13762
14065
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
13763
14066
|
}
|
|
13764
14067
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
13765
|
-
if (
|
|
14068
|
+
if (existsSync16(basePath + ".py")) {
|
|
13766
14069
|
return relative4(projectRoot, basePath + ".py");
|
|
13767
14070
|
}
|
|
13768
|
-
if (
|
|
14071
|
+
if (existsSync16(join10(basePath, "__init__.py"))) {
|
|
13769
14072
|
return relative4(projectRoot, join10(basePath, "__init__.py"));
|
|
13770
14073
|
}
|
|
13771
|
-
if (basePath.endsWith(".py") &&
|
|
14074
|
+
if (basePath.endsWith(".py") && existsSync16(basePath)) {
|
|
13772
14075
|
return relative4(projectRoot, basePath);
|
|
13773
14076
|
}
|
|
13774
14077
|
return null;
|
|
@@ -13791,7 +14094,7 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
13791
14094
|
}
|
|
13792
14095
|
function buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
13793
14096
|
const projectRoot = getProjectRoot();
|
|
13794
|
-
const absRoot =
|
|
14097
|
+
const absRoot = resolve13(projectRoot, pythonRoot);
|
|
13795
14098
|
dataDb2.exec("DELETE FROM massu_py_imports");
|
|
13796
14099
|
const insertStmt = dataDb2.prepare(
|
|
13797
14100
|
"INSERT INTO massu_py_imports (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)"
|
|
@@ -13808,7 +14111,7 @@ function buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__
|
|
|
13808
14111
|
const relFile = relative4(projectRoot, absFile);
|
|
13809
14112
|
let source;
|
|
13810
14113
|
try {
|
|
13811
|
-
source =
|
|
14114
|
+
source = readFileSync13(absFile, "utf-8");
|
|
13812
14115
|
} catch {
|
|
13813
14116
|
continue;
|
|
13814
14117
|
}
|
|
@@ -14074,7 +14377,7 @@ var init_route_parser = __esm({
|
|
|
14074
14377
|
});
|
|
14075
14378
|
|
|
14076
14379
|
// src/python/route-indexer.ts
|
|
14077
|
-
import { readFileSync as
|
|
14380
|
+
import { readFileSync as readFileSync14, readdirSync as readdirSync12 } from "fs";
|
|
14078
14381
|
import { join as join11, relative as relative5 } from "path";
|
|
14079
14382
|
function walkPyFiles(dir, excludeDirs) {
|
|
14080
14383
|
const files = [];
|
|
@@ -14107,7 +14410,7 @@ function buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
14107
14410
|
const relFile = relative5(projectRoot, absFile);
|
|
14108
14411
|
let source;
|
|
14109
14412
|
try {
|
|
14110
|
-
source =
|
|
14413
|
+
source = readFileSync14(absFile, "utf-8");
|
|
14111
14414
|
} catch {
|
|
14112
14415
|
continue;
|
|
14113
14416
|
}
|
|
@@ -14318,7 +14621,7 @@ var init_model_parser = __esm({
|
|
|
14318
14621
|
});
|
|
14319
14622
|
|
|
14320
14623
|
// src/python/model-indexer.ts
|
|
14321
|
-
import { readFileSync as
|
|
14624
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync13 } from "fs";
|
|
14322
14625
|
import { join as join12, relative as relative6 } from "path";
|
|
14323
14626
|
function walkPyFiles2(dir, excludeDirs) {
|
|
14324
14627
|
const files = [];
|
|
@@ -14354,7 +14657,7 @@ function buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
14354
14657
|
const relFile = relative6(projectRoot, absFile);
|
|
14355
14658
|
let source;
|
|
14356
14659
|
try {
|
|
14357
|
-
source =
|
|
14660
|
+
source = readFileSync15(absFile, "utf-8");
|
|
14358
14661
|
} catch {
|
|
14359
14662
|
continue;
|
|
14360
14663
|
}
|
|
@@ -14614,7 +14917,7 @@ var init_migration_parser = __esm({
|
|
|
14614
14917
|
});
|
|
14615
14918
|
|
|
14616
14919
|
// src/python/migration-indexer.ts
|
|
14617
|
-
import { readFileSync as
|
|
14920
|
+
import { readFileSync as readFileSync16, readdirSync as readdirSync14 } from "fs";
|
|
14618
14921
|
import { join as join13, relative as relative7 } from "path";
|
|
14619
14922
|
function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
14620
14923
|
const projectRoot = getProjectRoot();
|
|
@@ -14640,7 +14943,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
|
14640
14943
|
for (const absFile of files) {
|
|
14641
14944
|
let source;
|
|
14642
14945
|
try {
|
|
14643
|
-
source =
|
|
14946
|
+
source = readFileSync16(absFile, "utf-8");
|
|
14644
14947
|
} catch {
|
|
14645
14948
|
continue;
|
|
14646
14949
|
}
|
|
@@ -14674,7 +14977,7 @@ var init_migration_indexer = __esm({
|
|
|
14674
14977
|
});
|
|
14675
14978
|
|
|
14676
14979
|
// src/python/coupling-detector.ts
|
|
14677
|
-
import { readFileSync as
|
|
14980
|
+
import { readFileSync as readFileSync17, readdirSync as readdirSync15 } from "fs";
|
|
14678
14981
|
import { join as join14, relative as relative8 } from "path";
|
|
14679
14982
|
function buildPythonCouplingIndex(dataDb2) {
|
|
14680
14983
|
const projectRoot = getProjectRoot();
|
|
@@ -14711,7 +15014,7 @@ function buildPythonCouplingIndex(dataDb2) {
|
|
|
14711
15014
|
const relFile = relative8(projectRoot, absFile);
|
|
14712
15015
|
let source;
|
|
14713
15016
|
try {
|
|
14714
|
-
source =
|
|
15017
|
+
source = readFileSync17(absFile, "utf-8");
|
|
14715
15018
|
} catch {
|
|
14716
15019
|
continue;
|
|
14717
15020
|
}
|
|
@@ -15116,8 +15419,8 @@ var init_memory_tools = __esm({
|
|
|
15116
15419
|
});
|
|
15117
15420
|
|
|
15118
15421
|
// src/docs-tools.ts
|
|
15119
|
-
import { readFileSync as
|
|
15120
|
-
import { resolve as
|
|
15422
|
+
import { readFileSync as readFileSync18, existsSync as existsSync17 } from "fs";
|
|
15423
|
+
import { resolve as resolve14, basename as basename3 } from "path";
|
|
15121
15424
|
function p3(baseName) {
|
|
15122
15425
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
15123
15426
|
}
|
|
@@ -15172,10 +15475,10 @@ function handleDocsToolCall(name, args2) {
|
|
|
15172
15475
|
}
|
|
15173
15476
|
function loadDocsMap() {
|
|
15174
15477
|
const mapPath = getResolvedPaths().docsMapPath;
|
|
15175
|
-
if (!
|
|
15478
|
+
if (!existsSync17(mapPath)) {
|
|
15176
15479
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
15177
15480
|
}
|
|
15178
|
-
return JSON.parse(
|
|
15481
|
+
return JSON.parse(readFileSync18(mapPath, "utf-8"));
|
|
15179
15482
|
}
|
|
15180
15483
|
function matchesPattern(filePath, pattern) {
|
|
15181
15484
|
const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
@@ -15245,13 +15548,13 @@ function extractFrontmatter(content) {
|
|
|
15245
15548
|
}
|
|
15246
15549
|
function extractProcedureNames(routerPath) {
|
|
15247
15550
|
const root = getProjectRoot();
|
|
15248
|
-
const absPath = ensureWithinRoot(
|
|
15249
|
-
if (!
|
|
15250
|
-
const altPath = ensureWithinRoot(
|
|
15251
|
-
if (!
|
|
15252
|
-
return extractProcedureNamesFromContent(
|
|
15551
|
+
const absPath = ensureWithinRoot(resolve14(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
15552
|
+
if (!existsSync17(absPath)) {
|
|
15553
|
+
const altPath = ensureWithinRoot(resolve14(getResolvedPaths().srcDir, "../server/api/routers", basename3(routerPath)), root);
|
|
15554
|
+
if (!existsSync17(altPath)) return [];
|
|
15555
|
+
return extractProcedureNamesFromContent(readFileSync18(altPath, "utf-8"));
|
|
15253
15556
|
}
|
|
15254
|
-
return extractProcedureNamesFromContent(
|
|
15557
|
+
return extractProcedureNamesFromContent(readFileSync18(absPath, "utf-8"));
|
|
15255
15558
|
}
|
|
15256
15559
|
function extractProcedureNamesFromContent(content) {
|
|
15257
15560
|
const procRegex = /\.(?:query|mutation)\s*\(/g;
|
|
@@ -15291,8 +15594,8 @@ function handleDocsAudit(args2) {
|
|
|
15291
15594
|
for (const [mappingId, triggeringFiles] of affectedMappings) {
|
|
15292
15595
|
const mapping = docsMap.mappings.find((m3) => m3.id === mappingId);
|
|
15293
15596
|
if (!mapping) continue;
|
|
15294
|
-
const helpPagePath = ensureWithinRoot(
|
|
15295
|
-
if (!
|
|
15597
|
+
const helpPagePath = ensureWithinRoot(resolve14(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
15598
|
+
if (!existsSync17(helpPagePath)) {
|
|
15296
15599
|
results.push({
|
|
15297
15600
|
helpPage: mapping.helpPage,
|
|
15298
15601
|
mappingId,
|
|
@@ -15304,7 +15607,7 @@ function handleDocsAudit(args2) {
|
|
|
15304
15607
|
});
|
|
15305
15608
|
continue;
|
|
15306
15609
|
}
|
|
15307
|
-
const content =
|
|
15610
|
+
const content = readFileSync18(helpPagePath, "utf-8");
|
|
15308
15611
|
const sections = extractSections(content);
|
|
15309
15612
|
const frontmatter = extractFrontmatter(content);
|
|
15310
15613
|
const staleReasons = [];
|
|
@@ -15344,9 +15647,9 @@ function handleDocsAudit(args2) {
|
|
|
15344
15647
|
});
|
|
15345
15648
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
15346
15649
|
if (parentId === mappingId) {
|
|
15347
|
-
const guidePath = ensureWithinRoot(
|
|
15348
|
-
if (
|
|
15349
|
-
const guideContent =
|
|
15650
|
+
const guidePath = ensureWithinRoot(resolve14(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
15651
|
+
if (existsSync17(guidePath)) {
|
|
15652
|
+
const guideContent = readFileSync18(guidePath, "utf-8");
|
|
15350
15653
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
15351
15654
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
15352
15655
|
results.push({
|
|
@@ -15379,14 +15682,14 @@ function handleDocsCoverage(args2) {
|
|
|
15379
15682
|
const gaps = [];
|
|
15380
15683
|
const mappings = filterDomain ? docsMap.mappings.filter((m3) => m3.id === filterDomain) : docsMap.mappings;
|
|
15381
15684
|
for (const mapping of mappings) {
|
|
15382
|
-
const helpPagePath = ensureWithinRoot(
|
|
15383
|
-
const exists =
|
|
15685
|
+
const helpPagePath = ensureWithinRoot(resolve14(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
15686
|
+
const exists = existsSync17(helpPagePath);
|
|
15384
15687
|
let hasContent = false;
|
|
15385
15688
|
let lineCount = 0;
|
|
15386
15689
|
let lastVerified = null;
|
|
15387
15690
|
let status = null;
|
|
15388
15691
|
if (exists) {
|
|
15389
|
-
const content =
|
|
15692
|
+
const content = readFileSync18(helpPagePath, "utf-8");
|
|
15390
15693
|
lineCount = content.split("\n").length;
|
|
15391
15694
|
hasContent = lineCount > 10;
|
|
15392
15695
|
const frontmatter = extractFrontmatter(content);
|
|
@@ -15727,8 +16030,8 @@ var init_observability_tools = __esm({
|
|
|
15727
16030
|
});
|
|
15728
16031
|
|
|
15729
16032
|
// src/sentinel-db.ts
|
|
15730
|
-
import { existsSync as
|
|
15731
|
-
import { resolve as
|
|
16033
|
+
import { existsSync as existsSync18 } from "fs";
|
|
16034
|
+
import { resolve as resolve15 } from "path";
|
|
15732
16035
|
function parsePortalScope(raw) {
|
|
15733
16036
|
if (!raw) return [];
|
|
15734
16037
|
try {
|
|
@@ -15964,23 +16267,23 @@ function validateFeatures(db, domainFilter) {
|
|
|
15964
16267
|
const missingProcedures = [];
|
|
15965
16268
|
const missingPages = [];
|
|
15966
16269
|
for (const comp of components) {
|
|
15967
|
-
const absPath =
|
|
15968
|
-
if (!
|
|
16270
|
+
const absPath = resolve15(PROJECT_ROOT, comp.component_file);
|
|
16271
|
+
if (!existsSync18(absPath)) {
|
|
15969
16272
|
missingComponents.push(comp.component_file);
|
|
15970
16273
|
}
|
|
15971
16274
|
}
|
|
15972
16275
|
for (const proc of procedures) {
|
|
15973
|
-
const routerPath =
|
|
15974
|
-
if (!
|
|
16276
|
+
const routerPath = resolve15(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
16277
|
+
if (!existsSync18(routerPath)) {
|
|
15975
16278
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
15976
16279
|
}
|
|
15977
16280
|
}
|
|
15978
16281
|
for (const page of pages) {
|
|
15979
16282
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
15980
|
-
const absPath =
|
|
15981
|
-
if (page.page_route.startsWith("/") && !
|
|
15982
|
-
const altPath =
|
|
15983
|
-
if (!
|
|
16283
|
+
const absPath = resolve15(PROJECT_ROOT, routeToPath);
|
|
16284
|
+
if (page.page_route.startsWith("/") && !existsSync18(absPath)) {
|
|
16285
|
+
const altPath = resolve15(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
16286
|
+
if (!existsSync18(altPath)) {
|
|
15984
16287
|
missingPages.push(page.page_route);
|
|
15985
16288
|
}
|
|
15986
16289
|
}
|
|
@@ -16504,8 +16807,8 @@ var init_sentinel_tools = __esm({
|
|
|
16504
16807
|
});
|
|
16505
16808
|
|
|
16506
16809
|
// src/sentinel-scanner.ts
|
|
16507
|
-
import { readFileSync as
|
|
16508
|
-
import { resolve as
|
|
16810
|
+
import { readFileSync as readFileSync19, existsSync as existsSync19, readdirSync as readdirSync16, statSync as statSync7 } from "fs";
|
|
16811
|
+
import { resolve as resolve16, join as join15, basename as basename4, dirname as dirname9, relative as relative9 } from "path";
|
|
16509
16812
|
function inferDomain(filePath) {
|
|
16510
16813
|
const domains = getConfig().domains;
|
|
16511
16814
|
const path = filePath.toLowerCase();
|
|
@@ -16634,8 +16937,8 @@ function scanComponentExports(dataDb2) {
|
|
|
16634
16937
|
const projectRoot = getProjectRoot();
|
|
16635
16938
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
16636
16939
|
const componentDirs = [];
|
|
16637
|
-
const basePath =
|
|
16638
|
-
if (
|
|
16940
|
+
const basePath = resolve16(projectRoot, componentsBase);
|
|
16941
|
+
if (existsSync19(basePath)) {
|
|
16639
16942
|
try {
|
|
16640
16943
|
const entries = readdirSync16(basePath, { withFileTypes: true });
|
|
16641
16944
|
for (const entry of entries) {
|
|
@@ -16647,12 +16950,12 @@ function scanComponentExports(dataDb2) {
|
|
|
16647
16950
|
}
|
|
16648
16951
|
}
|
|
16649
16952
|
for (const dir of componentDirs) {
|
|
16650
|
-
const absDir =
|
|
16651
|
-
if (!
|
|
16953
|
+
const absDir = resolve16(projectRoot, dir);
|
|
16954
|
+
if (!existsSync19(absDir)) continue;
|
|
16652
16955
|
const files = walkDir(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
16653
16956
|
for (const file of files) {
|
|
16654
16957
|
const relPath = relative9(projectRoot, file);
|
|
16655
|
-
const source =
|
|
16958
|
+
const source = readFileSync19(file, "utf-8");
|
|
16656
16959
|
const annotations = parseFeatureAnnotations(source);
|
|
16657
16960
|
if (annotations.length > 0) {
|
|
16658
16961
|
for (const ann of annotations) {
|
|
@@ -17691,7 +17994,7 @@ var init_audit_trail = __esm({
|
|
|
17691
17994
|
});
|
|
17692
17995
|
|
|
17693
17996
|
// src/validation-engine.ts
|
|
17694
|
-
import { existsSync as
|
|
17997
|
+
import { existsSync as existsSync20, readFileSync as readFileSync20 } from "fs";
|
|
17695
17998
|
function p10(baseName) {
|
|
17696
17999
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
17697
18000
|
}
|
|
@@ -17722,7 +18025,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
17722
18025
|
});
|
|
17723
18026
|
return checks;
|
|
17724
18027
|
}
|
|
17725
|
-
if (!
|
|
18028
|
+
if (!existsSync20(absPath)) {
|
|
17726
18029
|
checks.push({
|
|
17727
18030
|
name: "file_exists",
|
|
17728
18031
|
severity: "error",
|
|
@@ -17731,7 +18034,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
17731
18034
|
});
|
|
17732
18035
|
return checks;
|
|
17733
18036
|
}
|
|
17734
|
-
const source =
|
|
18037
|
+
const source = readFileSync20(absPath, "utf-8");
|
|
17735
18038
|
const lines = source.split("\n");
|
|
17736
18039
|
if (activeChecks.rule_compliance !== false) {
|
|
17737
18040
|
for (const ruleSet of config.rules) {
|
|
@@ -18176,7 +18479,7 @@ var init_adr_generator = __esm({
|
|
|
18176
18479
|
});
|
|
18177
18480
|
|
|
18178
18481
|
// src/security-scorer.ts
|
|
18179
|
-
import { existsSync as
|
|
18482
|
+
import { existsSync as existsSync21, readFileSync as readFileSync21 } from "fs";
|
|
18180
18483
|
function p12(baseName) {
|
|
18181
18484
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
18182
18485
|
}
|
|
@@ -18200,12 +18503,12 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
18200
18503
|
}]
|
|
18201
18504
|
};
|
|
18202
18505
|
}
|
|
18203
|
-
if (!
|
|
18506
|
+
if (!existsSync21(absPath)) {
|
|
18204
18507
|
return { riskScore: 0, findings: [] };
|
|
18205
18508
|
}
|
|
18206
18509
|
let source;
|
|
18207
18510
|
try {
|
|
18208
|
-
source =
|
|
18511
|
+
source = readFileSync21(absPath, "utf-8");
|
|
18209
18512
|
} catch {
|
|
18210
18513
|
return { riskScore: 0, findings: [] };
|
|
18211
18514
|
}
|
|
@@ -18494,8 +18797,8 @@ var init_security_scorer = __esm({
|
|
|
18494
18797
|
});
|
|
18495
18798
|
|
|
18496
18799
|
// src/dependency-scorer.ts
|
|
18497
|
-
import { existsSync as
|
|
18498
|
-
import { resolve as
|
|
18800
|
+
import { existsSync as existsSync22, readFileSync as readFileSync22 } from "fs";
|
|
18801
|
+
import { resolve as resolve17 } from "path";
|
|
18499
18802
|
function p13(baseName) {
|
|
18500
18803
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
18501
18804
|
}
|
|
@@ -18527,10 +18830,10 @@ function calculateDepRisk(factors) {
|
|
|
18527
18830
|
return Math.min(100, risk);
|
|
18528
18831
|
}
|
|
18529
18832
|
function getInstalledPackages(projectRoot) {
|
|
18530
|
-
const pkgPath =
|
|
18531
|
-
if (!
|
|
18833
|
+
const pkgPath = resolve17(projectRoot, "package.json");
|
|
18834
|
+
if (!existsSync22(pkgPath)) return /* @__PURE__ */ new Map();
|
|
18532
18835
|
try {
|
|
18533
|
-
const pkg = JSON.parse(
|
|
18836
|
+
const pkg = JSON.parse(readFileSync22(pkgPath, "utf-8"));
|
|
18534
18837
|
const packages = /* @__PURE__ */ new Map();
|
|
18535
18838
|
for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
|
|
18536
18839
|
packages.set(name, version);
|
|
@@ -19132,9 +19435,9 @@ var init_regression_detector = __esm({
|
|
|
19132
19435
|
});
|
|
19133
19436
|
|
|
19134
19437
|
// src/knowledge-indexer.ts
|
|
19135
|
-
import { createHash as
|
|
19136
|
-
import { readFileSync as
|
|
19137
|
-
import { resolve as
|
|
19438
|
+
import { createHash as createHash4 } from "crypto";
|
|
19439
|
+
import { readFileSync as readFileSync23, readdirSync as readdirSync17, statSync as statSync8, existsSync as existsSync23 } from "fs";
|
|
19440
|
+
import { resolve as resolve18, relative as relative10, basename as basename5, extname } from "path";
|
|
19138
19441
|
function getKnowledgePaths() {
|
|
19139
19442
|
const resolved = getResolvedPaths();
|
|
19140
19443
|
const config = getConfig();
|
|
@@ -19162,7 +19465,7 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
19162
19465
|
try {
|
|
19163
19466
|
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
19164
19467
|
for (const entry of entries) {
|
|
19165
|
-
const fullPath =
|
|
19468
|
+
const fullPath = resolve18(dir, entry.name);
|
|
19166
19469
|
if (entry.isDirectory()) {
|
|
19167
19470
|
if (entry.name === "archive" && dir.includes("session-state")) continue;
|
|
19168
19471
|
if (entry.name === "archive" && dir.includes("status")) continue;
|
|
@@ -19219,8 +19522,8 @@ function categorizeFile(filePath) {
|
|
|
19219
19522
|
if (knownCategories.includes(firstDir)) return firstDir;
|
|
19220
19523
|
return "root";
|
|
19221
19524
|
}
|
|
19222
|
-
function
|
|
19223
|
-
return
|
|
19525
|
+
function hashContent2(content) {
|
|
19526
|
+
return createHash4("sha256").update(content).digest("hex");
|
|
19224
19527
|
}
|
|
19225
19528
|
function parseCRTable(content) {
|
|
19226
19529
|
const rules = [];
|
|
@@ -19440,11 +19743,11 @@ function indexAllKnowledge(db) {
|
|
|
19440
19743
|
files.push(...memFiles);
|
|
19441
19744
|
} catch {
|
|
19442
19745
|
}
|
|
19443
|
-
if (
|
|
19746
|
+
if (existsSync23(paths.plansDir)) {
|
|
19444
19747
|
const planFiles = discoverMarkdownFiles(paths.plansDir);
|
|
19445
19748
|
files.push(...planFiles);
|
|
19446
19749
|
}
|
|
19447
|
-
if (
|
|
19750
|
+
if (existsSync23(paths.docsDir)) {
|
|
19448
19751
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
19449
19752
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
19450
19753
|
files.push(...docsFiles);
|
|
@@ -19487,9 +19790,9 @@ function indexAllKnowledge(db) {
|
|
|
19487
19790
|
} catch {
|
|
19488
19791
|
}
|
|
19489
19792
|
for (const filePath of files) {
|
|
19490
|
-
if (!
|
|
19491
|
-
const content =
|
|
19492
|
-
const hash =
|
|
19793
|
+
if (!existsSync23(filePath)) continue;
|
|
19794
|
+
const content = readFileSync23(filePath, "utf-8");
|
|
19795
|
+
const hash = hashContent2(content);
|
|
19493
19796
|
const relPath = filePath.startsWith(paths.claudeDir) ? relative10(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative10(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative10(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative10(paths.memoryDir, filePath)}` : basename5(filePath);
|
|
19494
19797
|
const category = categorizeFile(filePath);
|
|
19495
19798
|
const title = extractTitle(content, filePath);
|
|
@@ -19608,10 +19911,10 @@ function isKnowledgeStale(db) {
|
|
|
19608
19911
|
files.push(...discoverMarkdownFiles(paths.memoryDir));
|
|
19609
19912
|
} catch {
|
|
19610
19913
|
}
|
|
19611
|
-
if (
|
|
19914
|
+
if (existsSync23(paths.plansDir)) {
|
|
19612
19915
|
files.push(...discoverMarkdownFiles(paths.plansDir));
|
|
19613
19916
|
}
|
|
19614
|
-
if (
|
|
19917
|
+
if (existsSync23(paths.docsDir)) {
|
|
19615
19918
|
const excludePatterns = getConfig().conventions?.excludePatterns ?? ["/ARCHIVE/", "/SESSION-HISTORY/"];
|
|
19616
19919
|
const docsFiles = discoverMarkdownFiles(paths.docsDir).filter((f2) => !f2.includes("/plans/") && !excludePatterns.some((p19) => f2.includes(p19)));
|
|
19617
19920
|
files.push(...docsFiles);
|
|
@@ -19640,8 +19943,8 @@ var init_knowledge_indexer = __esm({
|
|
|
19640
19943
|
});
|
|
19641
19944
|
|
|
19642
19945
|
// src/knowledge-tools.ts
|
|
19643
|
-
import { readFileSync as
|
|
19644
|
-
import { resolve as
|
|
19946
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync3, appendFileSync, readdirSync as readdirSync18 } from "fs";
|
|
19947
|
+
import { resolve as resolve19, basename as basename6 } from "path";
|
|
19645
19948
|
function p16(baseName) {
|
|
19646
19949
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
19647
19950
|
}
|
|
@@ -20378,7 +20681,7 @@ function handleCorrect(db, args2) {
|
|
|
20378
20681
|
if (!wrong || !correction || !rule) {
|
|
20379
20682
|
return text15("Error: wrong, correction, and rule are all required.");
|
|
20380
20683
|
}
|
|
20381
|
-
const correctionsPath =
|
|
20684
|
+
const correctionsPath = resolve19(getResolvedPaths().memoryDir, "corrections.md");
|
|
20382
20685
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
20383
20686
|
const title = rule.slice(0, 60);
|
|
20384
20687
|
const entry = `
|
|
@@ -20391,7 +20694,7 @@ ${crRule ? `- **CR**: ${crRule}
|
|
|
20391
20694
|
`;
|
|
20392
20695
|
let existing = "";
|
|
20393
20696
|
try {
|
|
20394
|
-
existing =
|
|
20697
|
+
existing = readFileSync24(correctionsPath, "utf-8");
|
|
20395
20698
|
} catch {
|
|
20396
20699
|
}
|
|
20397
20700
|
const archiveIdx = existing.indexOf("## Archived");
|
|
@@ -20730,11 +21033,11 @@ var init_knowledge_tools = __esm({
|
|
|
20730
21033
|
// src/knowledge-db.ts
|
|
20731
21034
|
import Database3 from "better-sqlite3";
|
|
20732
21035
|
import { dirname as dirname10 } from "path";
|
|
20733
|
-
import { existsSync as
|
|
21036
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync5 } from "fs";
|
|
20734
21037
|
function getKnowledgeDb() {
|
|
20735
21038
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
20736
21039
|
const dir = dirname10(dbPath);
|
|
20737
|
-
if (!
|
|
21040
|
+
if (!existsSync25(dir)) {
|
|
20738
21041
|
mkdirSync5(dir, { recursive: true });
|
|
20739
21042
|
}
|
|
20740
21043
|
const db = new Database3(dbPath);
|
|
@@ -21468,8 +21771,8 @@ var init_python_tools = __esm({
|
|
|
21468
21771
|
});
|
|
21469
21772
|
|
|
21470
21773
|
// src/tools.ts
|
|
21471
|
-
import { readFileSync as
|
|
21472
|
-
import { resolve as
|
|
21774
|
+
import { readFileSync as readFileSync25, existsSync as existsSync26 } from "fs";
|
|
21775
|
+
import { resolve as resolve20, basename as basename7 } from "path";
|
|
21473
21776
|
function prefix2() {
|
|
21474
21777
|
return getConfig().toolPrefix;
|
|
21475
21778
|
}
|
|
@@ -21504,7 +21807,7 @@ function ensureIndexes(dataDb2, codegraphDb2, force = false) {
|
|
|
21504
21807
|
if (config.python?.root) {
|
|
21505
21808
|
const pythonRoot = config.python.root;
|
|
21506
21809
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
21507
|
-
if (force || isPythonDataStale(dataDb2,
|
|
21810
|
+
if (force || isPythonDataStale(dataDb2, resolve20(getProjectRoot(), pythonRoot))) {
|
|
21508
21811
|
const pyImports = buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs);
|
|
21509
21812
|
results.push(`Python imports: ${pyImports}`);
|
|
21510
21813
|
const pyRoutes = buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs);
|
|
@@ -21903,9 +22206,9 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
21903
22206
|
try {
|
|
21904
22207
|
const resolvedPaths = getResolvedPaths();
|
|
21905
22208
|
const root = getProjectRoot();
|
|
21906
|
-
const absFilePath = ensureWithinRoot(
|
|
21907
|
-
if (
|
|
21908
|
-
const fileContent =
|
|
22209
|
+
const absFilePath = ensureWithinRoot(resolve20(resolvedPaths.srcDir, "..", file), root);
|
|
22210
|
+
if (existsSync26(absFilePath)) {
|
|
22211
|
+
const fileContent = readFileSync25(absFilePath, "utf-8").slice(0, 3e3);
|
|
21909
22212
|
const keywords = [];
|
|
21910
22213
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
21911
22214
|
if (fileContent.includes("BigInt") || fileContent.includes("Decimal")) keywords.push("BigInt", "serialization");
|
|
@@ -22329,11 +22632,11 @@ function handleSchema(args2) {
|
|
|
22329
22632
|
lines.push("Checking all column references against Prisma schema...");
|
|
22330
22633
|
lines.push("");
|
|
22331
22634
|
const projectRoot = getProjectRoot();
|
|
22332
|
-
const absPath = ensureWithinRoot(
|
|
22333
|
-
if (!
|
|
22635
|
+
const absPath = ensureWithinRoot(resolve20(projectRoot, file), projectRoot);
|
|
22636
|
+
if (!existsSync26(absPath)) {
|
|
22334
22637
|
return text17(`File not found: ${file}`);
|
|
22335
22638
|
}
|
|
22336
|
-
const source =
|
|
22639
|
+
const source = readFileSync25(absPath, "utf-8");
|
|
22337
22640
|
const config = getConfig();
|
|
22338
22641
|
const dbPattern = config.dbAccessPattern ?? "ctx.db.{table}";
|
|
22339
22642
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
@@ -22411,8 +22714,8 @@ var init_tools = __esm({
|
|
|
22411
22714
|
|
|
22412
22715
|
// src/server.ts
|
|
22413
22716
|
var server_exports = {};
|
|
22414
|
-
import { readFileSync as
|
|
22415
|
-
import { resolve as
|
|
22717
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
22718
|
+
import { resolve as resolve21, dirname as dirname11 } from "path";
|
|
22416
22719
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
22417
22720
|
function getDb() {
|
|
22418
22721
|
if (!codegraphDb) codegraphDb = getCodeGraphDb();
|
|
@@ -22507,7 +22810,7 @@ var init_server = __esm({
|
|
|
22507
22810
|
__dirname4 = dirname11(fileURLToPath4(import.meta.url));
|
|
22508
22811
|
PKG_VERSION = (() => {
|
|
22509
22812
|
try {
|
|
22510
|
-
const pkg = JSON.parse(
|
|
22813
|
+
const pkg = JSON.parse(readFileSync26(resolve21(__dirname4, "..", "package.json"), "utf-8"));
|
|
22511
22814
|
return pkg.version ?? "0.0.0";
|
|
22512
22815
|
} catch {
|
|
22513
22816
|
return "0.0.0";
|
|
@@ -22619,8 +22922,8 @@ __export(config_refresh_exports, {
|
|
|
22619
22922
|
mergeRefresh: () => mergeRefresh,
|
|
22620
22923
|
runConfigRefresh: () => runConfigRefresh
|
|
22621
22924
|
});
|
|
22622
|
-
import { existsSync as
|
|
22623
|
-
import { resolve as
|
|
22925
|
+
import { existsSync as existsSync27, readFileSync as readFileSync27 } from "fs";
|
|
22926
|
+
import { resolve as resolve22 } from "path";
|
|
22624
22927
|
import { parse as parseYaml5 } from "yaml";
|
|
22625
22928
|
function flatten(obj, prefix3 = "") {
|
|
22626
22929
|
const out = {};
|
|
@@ -22748,17 +23051,17 @@ function renderDiff(diff) {
|
|
|
22748
23051
|
}
|
|
22749
23052
|
async function runConfigRefresh(opts = {}) {
|
|
22750
23053
|
const cwd = opts.cwd ?? process.cwd();
|
|
22751
|
-
const configPath =
|
|
23054
|
+
const configPath = resolve22(cwd, "massu.config.yaml");
|
|
22752
23055
|
const log = opts.silent ? () => {
|
|
22753
23056
|
} : (s) => process.stdout.write(s);
|
|
22754
|
-
if (!
|
|
23057
|
+
if (!existsSync27(configPath)) {
|
|
22755
23058
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
22756
23059
|
if (!opts.silent) process.stderr.write(message + "\n");
|
|
22757
23060
|
return { exitCode: 1, applied: false, dryRun: !!opts.dryRun, diff: [], message };
|
|
22758
23061
|
}
|
|
22759
23062
|
let existing;
|
|
22760
23063
|
try {
|
|
22761
|
-
const content =
|
|
23064
|
+
const content = readFileSync27(configPath, "utf-8");
|
|
22762
23065
|
const parsed = parseYaml5(content);
|
|
22763
23066
|
if (!parsed || typeof parsed !== "object") {
|
|
22764
23067
|
throw new Error("config is not a YAML object");
|
|
@@ -22958,13 +23261,21 @@ function migrateV1ToV2(v1Config, detection) {
|
|
|
22958
23261
|
let pathsSource = typeof v1Paths.source === "string" ? v1Paths.source : "src";
|
|
22959
23262
|
if (pathsSource === "src" && primary) {
|
|
22960
23263
|
const primaryDirs = detection.sourceDirs[primary]?.source_dirs ?? [];
|
|
22961
|
-
if (primaryDirs.length > 0)
|
|
23264
|
+
if (primaryDirs.length > 0) {
|
|
23265
|
+
pathsSource = primaryDirs[0];
|
|
23266
|
+
} else if (detection.monorepo?.type !== void 0 && detection.monorepo.type !== "single" && detection.monorepo.packages.length > 0) {
|
|
23267
|
+
pathsSource = monorepoCommonRootMigrate(detection.monorepo.packages);
|
|
23268
|
+
}
|
|
22962
23269
|
}
|
|
22963
23270
|
const aliases = v1Paths.aliases && typeof v1Paths.aliases === "object" ? v1Paths.aliases : { "@": pathsSource };
|
|
22964
23271
|
const paths = {
|
|
22965
23272
|
source: pathsSource,
|
|
22966
23273
|
aliases
|
|
22967
23274
|
};
|
|
23275
|
+
if (detection.monorepo?.type !== void 0 && detection.monorepo.type !== "single" && detection.monorepo.packages.length > 0 && !("monorepo_roots" in v1Paths)) {
|
|
23276
|
+
const roots = monorepoDistinctRootsMigrate(detection.monorepo.packages);
|
|
23277
|
+
if (roots.length > 0) paths.monorepo_roots = roots;
|
|
23278
|
+
}
|
|
22968
23279
|
for (const k3 of ["routers", "routerRoot", "pages", "middleware", "schema", "components", "hooks"]) {
|
|
22969
23280
|
if (typeof v1Paths[k3] === "string") paths[k3] = v1Paths[k3];
|
|
22970
23281
|
}
|
|
@@ -23035,6 +23346,20 @@ function migrateV1ToV2(v1Config, detection) {
|
|
|
23035
23346
|
}
|
|
23036
23347
|
return v22;
|
|
23037
23348
|
}
|
|
23349
|
+
function monorepoCommonRootMigrate(packages) {
|
|
23350
|
+
const roots = monorepoDistinctRootsMigrate(packages);
|
|
23351
|
+
return roots.length === 1 ? roots[0] : ".";
|
|
23352
|
+
}
|
|
23353
|
+
function monorepoDistinctRootsMigrate(packages) {
|
|
23354
|
+
const set = /* @__PURE__ */ new Set();
|
|
23355
|
+
for (const p19 of packages) {
|
|
23356
|
+
const parts = p19.path.split("/");
|
|
23357
|
+
if (parts.length > 1 && parts[0] !== "" && parts[0] !== ".") {
|
|
23358
|
+
set.add(parts[0]);
|
|
23359
|
+
}
|
|
23360
|
+
}
|
|
23361
|
+
return [...set].sort();
|
|
23362
|
+
}
|
|
23038
23363
|
var PRESERVED_FIELDS2;
|
|
23039
23364
|
var init_migrate = __esm({
|
|
23040
23365
|
"src/detect/migrate.ts"() {
|
|
@@ -23066,19 +23391,19 @@ var config_upgrade_exports = {};
|
|
|
23066
23391
|
__export(config_upgrade_exports, {
|
|
23067
23392
|
runConfigUpgrade: () => runConfigUpgrade
|
|
23068
23393
|
});
|
|
23069
|
-
import { existsSync as
|
|
23070
|
-
import { resolve as
|
|
23394
|
+
import { existsSync as existsSync28, readFileSync as readFileSync28, writeFileSync as writeFileSync4, copyFileSync, unlinkSync } from "fs";
|
|
23395
|
+
import { resolve as resolve23 } from "path";
|
|
23071
23396
|
import { parse as parseYaml6 } from "yaml";
|
|
23072
23397
|
async function runConfigUpgrade(opts = {}) {
|
|
23073
23398
|
const cwd = opts.cwd ?? process.cwd();
|
|
23074
|
-
const configPath =
|
|
23399
|
+
const configPath = resolve23(cwd, "massu.config.yaml");
|
|
23075
23400
|
const bakPath = `${configPath}.bak`;
|
|
23076
23401
|
const log = opts.silent ? () => {
|
|
23077
23402
|
} : (s) => process.stdout.write(s);
|
|
23078
23403
|
const err = opts.silent ? () => {
|
|
23079
23404
|
} : (s) => process.stderr.write(s);
|
|
23080
23405
|
if (opts.rollback) {
|
|
23081
|
-
if (!
|
|
23406
|
+
if (!existsSync28(bakPath)) {
|
|
23082
23407
|
const message = `No backup found at ${bakPath}`;
|
|
23083
23408
|
err(message + "\n");
|
|
23084
23409
|
return { exitCode: 1, action: "none", message };
|
|
@@ -23094,14 +23419,14 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
23094
23419
|
return { exitCode: 2, action: "none", message };
|
|
23095
23420
|
}
|
|
23096
23421
|
}
|
|
23097
|
-
if (!
|
|
23422
|
+
if (!existsSync28(configPath)) {
|
|
23098
23423
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
23099
23424
|
err(message + "\n");
|
|
23100
23425
|
return { exitCode: 1, action: "none", message };
|
|
23101
23426
|
}
|
|
23102
23427
|
let existing;
|
|
23103
23428
|
try {
|
|
23104
|
-
const content =
|
|
23429
|
+
const content = readFileSync28(configPath, "utf-8");
|
|
23105
23430
|
const parsed = parseYaml6(content);
|
|
23106
23431
|
if (!parsed || typeof parsed !== "object") {
|
|
23107
23432
|
throw new Error("config is not a YAML object");
|
|
@@ -23124,7 +23449,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
23124
23449
|
fingerprint: computeFingerprint(detection)
|
|
23125
23450
|
};
|
|
23126
23451
|
try {
|
|
23127
|
-
const original =
|
|
23452
|
+
const original = readFileSync28(configPath, "utf-8");
|
|
23128
23453
|
writeFileSync4(bakPath, original, "utf-8");
|
|
23129
23454
|
} catch (e2) {
|
|
23130
23455
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
@@ -23158,8 +23483,8 @@ var config_check_drift_exports = {};
|
|
|
23158
23483
|
__export(config_check_drift_exports, {
|
|
23159
23484
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
23160
23485
|
});
|
|
23161
|
-
import { existsSync as
|
|
23162
|
-
import { resolve as
|
|
23486
|
+
import { existsSync as existsSync29, readFileSync as readFileSync29 } from "fs";
|
|
23487
|
+
import { resolve as resolve24 } from "path";
|
|
23163
23488
|
import { parse as parseYaml7 } from "yaml";
|
|
23164
23489
|
function renderChanges(changes) {
|
|
23165
23490
|
if (changes.length === 0) return "(none)\n";
|
|
@@ -23167,12 +23492,12 @@ function renderChanges(changes) {
|
|
|
23167
23492
|
}
|
|
23168
23493
|
async function runConfigCheckDrift(opts = {}) {
|
|
23169
23494
|
const cwd = opts.cwd ?? process.cwd();
|
|
23170
|
-
const configPath =
|
|
23495
|
+
const configPath = resolve24(cwd, "massu.config.yaml");
|
|
23171
23496
|
const log = opts.silent ? () => {
|
|
23172
23497
|
} : (s) => process.stdout.write(s);
|
|
23173
23498
|
const err = opts.silent ? () => {
|
|
23174
23499
|
} : (s) => process.stderr.write(s);
|
|
23175
|
-
if (!
|
|
23500
|
+
if (!existsSync29(configPath)) {
|
|
23176
23501
|
const message = "massu.config.yaml not found. Run: npx massu init";
|
|
23177
23502
|
err(message + "\n");
|
|
23178
23503
|
return {
|
|
@@ -23186,7 +23511,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
23186
23511
|
}
|
|
23187
23512
|
let config;
|
|
23188
23513
|
try {
|
|
23189
|
-
const content =
|
|
23514
|
+
const content = readFileSync29(configPath, "utf-8");
|
|
23190
23515
|
const parsed = parseYaml7(content);
|
|
23191
23516
|
if (!parsed || typeof parsed !== "object") {
|
|
23192
23517
|
throw new Error("config is not a YAML object");
|
|
@@ -23253,8 +23578,8 @@ var init_config_check_drift = __esm({
|
|
|
23253
23578
|
});
|
|
23254
23579
|
|
|
23255
23580
|
// src/cli.ts
|
|
23256
|
-
import { readFileSync as
|
|
23257
|
-
import { resolve as
|
|
23581
|
+
import { readFileSync as readFileSync30 } from "fs";
|
|
23582
|
+
import { resolve as resolve25, dirname as dirname12 } from "path";
|
|
23258
23583
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
23259
23584
|
var __filename4 = fileURLToPath5(import.meta.url);
|
|
23260
23585
|
var __dirname5 = dirname12(__filename4);
|
|
@@ -23282,6 +23607,11 @@ async function main() {
|
|
|
23282
23607
|
await runInstallCommands2();
|
|
23283
23608
|
break;
|
|
23284
23609
|
}
|
|
23610
|
+
case "show-template": {
|
|
23611
|
+
const { runShowTemplate: runShowTemplate2 } = await Promise.resolve().then(() => (init_show_template(), show_template_exports));
|
|
23612
|
+
await runShowTemplate2(args.slice(1));
|
|
23613
|
+
break;
|
|
23614
|
+
}
|
|
23285
23615
|
case "validate-config": {
|
|
23286
23616
|
const { runValidateConfig: runValidateConfig2 } = await Promise.resolve().then(() => (init_doctor(), doctor_exports));
|
|
23287
23617
|
await runValidateConfig2();
|
|
@@ -23368,6 +23698,7 @@ Commands:
|
|
|
23368
23698
|
doctor Check installation health
|
|
23369
23699
|
install-hooks Install/update Claude Code hooks
|
|
23370
23700
|
install-commands Install/update slash commands
|
|
23701
|
+
show-template Print the resolved variant of a bundled template (e.g. for diffs)
|
|
23371
23702
|
validate-config Validate massu.config.yaml (alias: config validate)
|
|
23372
23703
|
config <sub> Config lifecycle: refresh | validate | upgrade | doctor | check-drift
|
|
23373
23704
|
|
|
@@ -23406,7 +23737,7 @@ Examples:
|
|
|
23406
23737
|
}
|
|
23407
23738
|
function printVersion() {
|
|
23408
23739
|
try {
|
|
23409
|
-
const pkg = JSON.parse(
|
|
23740
|
+
const pkg = JSON.parse(readFileSync30(resolve25(__dirname5, "../package.json"), "utf-8"));
|
|
23410
23741
|
console.log(`massu v${pkg.version}`);
|
|
23411
23742
|
} catch {
|
|
23412
23743
|
console.log("massu v0.1.0");
|