@massu/core 0.8.1 → 0.9.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/dist/cli.js +467 -166
- package/package.json +1 -1
- package/src/claude-md-templates.ts +342 -0
- package/src/commands/doctor.ts +28 -0
- package/src/commands/init.ts +33 -0
- package/src/knowledge-indexer.ts +1 -1
package/dist/cli.js
CHANGED
|
@@ -1488,9 +1488,9 @@ import { join } from "path";
|
|
|
1488
1488
|
function ingestMemoryFile(db, sessionId, filePath) {
|
|
1489
1489
|
if (!existsSync3(filePath)) return "skipped";
|
|
1490
1490
|
const content = readFileSync2(filePath, "utf-8");
|
|
1491
|
-
const
|
|
1491
|
+
const basename9 = (filePath.split("/").pop() ?? "").replace(".md", "");
|
|
1492
1492
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1493
|
-
let name =
|
|
1493
|
+
let name = basename9;
|
|
1494
1494
|
let description = "";
|
|
1495
1495
|
let type = "discovery";
|
|
1496
1496
|
let confidence;
|
|
@@ -1503,7 +1503,7 @@ function ingestMemoryFile(db, sessionId, filePath) {
|
|
|
1503
1503
|
fm[line.slice(0, sep).trim()] = line.slice(sep + 1).trim();
|
|
1504
1504
|
}
|
|
1505
1505
|
}
|
|
1506
|
-
name = fm.name ??
|
|
1506
|
+
name = fm.name ?? basename9;
|
|
1507
1507
|
description = fm.description ?? "";
|
|
1508
1508
|
type = fm.type ?? "discovery";
|
|
1509
1509
|
confidence = fm.confidence != null ? Number(fm.confidence) : void 0;
|
|
@@ -1563,6 +1563,265 @@ var init_memory_file_ingest = __esm({
|
|
|
1563
1563
|
}
|
|
1564
1564
|
});
|
|
1565
1565
|
|
|
1566
|
+
// src/claude-md-templates.ts
|
|
1567
|
+
import { readdirSync as readdirSync2, statSync } from "fs";
|
|
1568
|
+
import { resolve as resolve3, basename as basename2 } from "path";
|
|
1569
|
+
function scanDirectoryStructure(projectRoot, maxDepth = 2) {
|
|
1570
|
+
const lines = [];
|
|
1571
|
+
const rootName = basename2(projectRoot);
|
|
1572
|
+
lines.push(`${rootName}/`);
|
|
1573
|
+
scanLevel(projectRoot, "", maxDepth, 0, lines);
|
|
1574
|
+
return lines.join("\n");
|
|
1575
|
+
}
|
|
1576
|
+
function scanLevel(dir, prefix2, maxDepth, currentDepth, lines) {
|
|
1577
|
+
if (currentDepth >= maxDepth) return;
|
|
1578
|
+
let entries;
|
|
1579
|
+
try {
|
|
1580
|
+
entries = readdirSync2(dir).sort();
|
|
1581
|
+
} catch {
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
const dirs = [];
|
|
1585
|
+
const files = [];
|
|
1586
|
+
for (const entry of entries) {
|
|
1587
|
+
if (entry.startsWith(".") && EXCLUDED_DIRS.has(entry)) continue;
|
|
1588
|
+
if (EXCLUDED_DIRS.has(entry)) continue;
|
|
1589
|
+
try {
|
|
1590
|
+
const stat = statSync(resolve3(dir, entry));
|
|
1591
|
+
if (stat.isDirectory()) dirs.push(entry);
|
|
1592
|
+
else files.push(entry);
|
|
1593
|
+
} catch {
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
const allEntries = [...dirs, ...files];
|
|
1597
|
+
for (let i = 0; i < allEntries.length; i++) {
|
|
1598
|
+
const entry = allEntries[i];
|
|
1599
|
+
const isLast = i === allEntries.length - 1;
|
|
1600
|
+
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
1601
|
+
const childPrefix = isLast ? " " : "\u2502 ";
|
|
1602
|
+
const isDir = dirs.includes(entry);
|
|
1603
|
+
lines.push(`${prefix2}${connector}${entry}${isDir ? "/" : ""}`);
|
|
1604
|
+
if (isDir) {
|
|
1605
|
+
scanLevel(resolve3(dir, entry), prefix2 + childPrefix, maxDepth, currentDepth + 1, lines);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
function buildClaudeMdContent(projectName, projectRoot, framework, python) {
|
|
1610
|
+
const sections = [];
|
|
1611
|
+
sections.push(buildProjectOverview(projectName, framework, python));
|
|
1612
|
+
sections.push(buildTechStack(framework, python));
|
|
1613
|
+
sections.push(buildDirectorySection(projectRoot));
|
|
1614
|
+
sections.push(buildCodingConventions(framework, python));
|
|
1615
|
+
sections.push(buildTestingSection(framework, python));
|
|
1616
|
+
sections.push(buildMassuWorkflow());
|
|
1617
|
+
sections.push(buildMemorySystem());
|
|
1618
|
+
sections.push(buildCriticalRules());
|
|
1619
|
+
return sections.join("\n\n---\n\n") + "\n";
|
|
1620
|
+
}
|
|
1621
|
+
function buildProjectOverview(projectName, framework, python) {
|
|
1622
|
+
const stack = [];
|
|
1623
|
+
if (framework.type !== "javascript") stack.push(capitalize(framework.type));
|
|
1624
|
+
if (framework.ui !== "none") stack.push(formatUiName(framework.ui));
|
|
1625
|
+
if (framework.router !== "none") stack.push(framework.router.toUpperCase());
|
|
1626
|
+
if (framework.orm !== "none") stack.push(capitalize(framework.orm));
|
|
1627
|
+
if (python.detected) {
|
|
1628
|
+
stack.push("Python");
|
|
1629
|
+
if (python.hasFastapi) stack.push("FastAPI");
|
|
1630
|
+
}
|
|
1631
|
+
const stackStr = stack.length > 0 ? stack.join(", ") : "JavaScript";
|
|
1632
|
+
return `# ${projectName}
|
|
1633
|
+
|
|
1634
|
+
## Project Overview
|
|
1635
|
+
|
|
1636
|
+
${projectName} is a ${stackStr} project.
|
|
1637
|
+
|
|
1638
|
+
<!-- Add a brief description of what this project does -->`;
|
|
1639
|
+
}
|
|
1640
|
+
function buildTechStack(framework, python) {
|
|
1641
|
+
const rows = [];
|
|
1642
|
+
rows.push("| Technology | Details |");
|
|
1643
|
+
rows.push("|-----------|---------|");
|
|
1644
|
+
rows.push(`| Language | ${capitalize(framework.type)} |`);
|
|
1645
|
+
if (framework.ui !== "none") rows.push(`| UI Framework | ${formatUiName(framework.ui)} |`);
|
|
1646
|
+
if (framework.router !== "none") rows.push(`| Router/API | ${framework.router.toUpperCase()} |`);
|
|
1647
|
+
if (framework.orm !== "none") rows.push(`| ORM | ${capitalize(framework.orm)} |`);
|
|
1648
|
+
if (python.detected) {
|
|
1649
|
+
rows.push("| Python | Yes |");
|
|
1650
|
+
if (python.hasFastapi) rows.push("| Python Framework | FastAPI |");
|
|
1651
|
+
if (python.hasSqlalchemy) rows.push("| Python ORM | SQLAlchemy |");
|
|
1652
|
+
if (python.hasAlembic) rows.push("| Migrations | Alembic |");
|
|
1653
|
+
}
|
|
1654
|
+
return `## Tech Stack
|
|
1655
|
+
|
|
1656
|
+
${rows.join("\n")}`;
|
|
1657
|
+
}
|
|
1658
|
+
function buildDirectorySection(projectRoot) {
|
|
1659
|
+
const tree = scanDirectoryStructure(projectRoot);
|
|
1660
|
+
return `## Directory Structure
|
|
1661
|
+
|
|
1662
|
+
\`\`\`
|
|
1663
|
+
${tree}
|
|
1664
|
+
\`\`\``;
|
|
1665
|
+
}
|
|
1666
|
+
function buildCodingConventions(framework, python) {
|
|
1667
|
+
const rules = [];
|
|
1668
|
+
if (framework.type === "typescript") {
|
|
1669
|
+
rules.push("- Use ESM imports (`import`), not CommonJS (`require`)");
|
|
1670
|
+
rules.push("- Enable strict TypeScript (`strict: true` in tsconfig.json)");
|
|
1671
|
+
rules.push("- Prefer explicit types over `any`");
|
|
1672
|
+
}
|
|
1673
|
+
switch (framework.ui) {
|
|
1674
|
+
case "nextjs":
|
|
1675
|
+
rules.push("- Use App Router conventions (`app/` directory)");
|
|
1676
|
+
rules.push('- Default to Server Components; add `"use client"` only when needed');
|
|
1677
|
+
rules.push("- Use `next/image` for images, `next/link` for navigation");
|
|
1678
|
+
rules.push("- API routes go in `app/api/` using Route Handlers");
|
|
1679
|
+
break;
|
|
1680
|
+
case "sveltekit":
|
|
1681
|
+
rules.push("- Use load functions for data fetching (`+page.server.ts`)");
|
|
1682
|
+
rules.push("- Use form actions for mutations");
|
|
1683
|
+
rules.push("- Server-only code in `+server.ts` files");
|
|
1684
|
+
break;
|
|
1685
|
+
case "react":
|
|
1686
|
+
rules.push("- Prefer functional components with hooks");
|
|
1687
|
+
rules.push("- Colocate component, styles, and tests");
|
|
1688
|
+
break;
|
|
1689
|
+
}
|
|
1690
|
+
if (framework.router === "trpc") {
|
|
1691
|
+
rules.push("- Define tRPC routers with Zod input validation");
|
|
1692
|
+
rules.push("- Keep router files focused (one domain per router)");
|
|
1693
|
+
}
|
|
1694
|
+
if (framework.orm === "prisma") {
|
|
1695
|
+
rules.push("- Define models in `prisma/schema.prisma`");
|
|
1696
|
+
rules.push("- Run `npx prisma generate` after schema changes");
|
|
1697
|
+
} else if (framework.orm === "drizzle") {
|
|
1698
|
+
rules.push("- Define schemas with Drizzle table builders");
|
|
1699
|
+
rules.push("- Run migrations with `drizzle-kit`");
|
|
1700
|
+
}
|
|
1701
|
+
if (python.detected) {
|
|
1702
|
+
rules.push("- Use type hints for function signatures");
|
|
1703
|
+
rules.push("- Use `async def` for async endpoints");
|
|
1704
|
+
if (python.hasFastapi) {
|
|
1705
|
+
rules.push("- Use Pydantic models for request/response schemas");
|
|
1706
|
+
rules.push("- Organize routes with `APIRouter`");
|
|
1707
|
+
}
|
|
1708
|
+
if (python.hasSqlalchemy) {
|
|
1709
|
+
rules.push("- Use SQLAlchemy 2.0 style (select/insert builders)");
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
if (rules.length === 0) {
|
|
1713
|
+
rules.push("- Follow consistent naming conventions");
|
|
1714
|
+
rules.push("- Keep functions small and focused");
|
|
1715
|
+
}
|
|
1716
|
+
return `## Coding Conventions
|
|
1717
|
+
|
|
1718
|
+
${rules.join("\n")}`;
|
|
1719
|
+
}
|
|
1720
|
+
function buildTestingSection(framework, python) {
|
|
1721
|
+
const lines = [];
|
|
1722
|
+
if (framework.type === "typescript") {
|
|
1723
|
+
lines.push("- Test framework: vitest (or jest)");
|
|
1724
|
+
lines.push("- Test files: `__tests__/*.test.ts` or `*.test.ts` colocated");
|
|
1725
|
+
lines.push("- Run tests: `npm test`");
|
|
1726
|
+
}
|
|
1727
|
+
if (python.detected) {
|
|
1728
|
+
lines.push("- Python tests: pytest");
|
|
1729
|
+
lines.push("- Test files: `tests/` directory or `test_*.py` files");
|
|
1730
|
+
lines.push("- Run: `pytest`");
|
|
1731
|
+
}
|
|
1732
|
+
if (lines.length === 0) {
|
|
1733
|
+
lines.push("- Configure a test framework for this project");
|
|
1734
|
+
lines.push("- Run tests before committing changes");
|
|
1735
|
+
}
|
|
1736
|
+
return `## Testing
|
|
1737
|
+
|
|
1738
|
+
${lines.join("\n")}`;
|
|
1739
|
+
}
|
|
1740
|
+
function buildMassuWorkflow() {
|
|
1741
|
+
return `## Massu Workflow
|
|
1742
|
+
|
|
1743
|
+
This project uses [Massu AI](https://massu.ai) for development governance.
|
|
1744
|
+
|
|
1745
|
+
### Common Commands
|
|
1746
|
+
|
|
1747
|
+
| Command | Purpose |
|
|
1748
|
+
|---------|---------|
|
|
1749
|
+
| \`/massu-create-plan\` | Create an implementation plan |
|
|
1750
|
+
| \`/massu-plan\` | Audit and improve a plan |
|
|
1751
|
+
| \`/massu-golden-path\` | Full implementation flow (plan to push) |
|
|
1752
|
+
| \`/massu-test\` | Run tests with failure analysis |
|
|
1753
|
+
| \`/massu-commit\` | Pre-commit verification gate |
|
|
1754
|
+
| \`/massu-push\` | Pre-push verification gate |
|
|
1755
|
+
| \`/massu-status\` | Project health dashboard |
|
|
1756
|
+
| \`/massu-debug\` | Systematic debugging |
|
|
1757
|
+
|
|
1758
|
+
### Workflow Flow
|
|
1759
|
+
|
|
1760
|
+
\`\`\`
|
|
1761
|
+
/massu-create-plan -> /massu-plan (audit) -> /massu-golden-path (implement + push)
|
|
1762
|
+
\`\`\``;
|
|
1763
|
+
}
|
|
1764
|
+
function buildMemorySystem() {
|
|
1765
|
+
return `## Memory System
|
|
1766
|
+
|
|
1767
|
+
Massu maintains persistent memory across sessions in \`~/.claude/projects/.../memory/\`.
|
|
1768
|
+
|
|
1769
|
+
- **User memories**: Your role, preferences, and expertise
|
|
1770
|
+
- **Feedback memories**: Corrections and validated approaches
|
|
1771
|
+
- **Project memories**: Ongoing work, decisions, deadlines
|
|
1772
|
+
- **Reference memories**: External resources and tools
|
|
1773
|
+
|
|
1774
|
+
Memory is automatically loaded at session start and updated as you work.`;
|
|
1775
|
+
}
|
|
1776
|
+
function buildCriticalRules() {
|
|
1777
|
+
return `## Critical Rules
|
|
1778
|
+
|
|
1779
|
+
1. **Never commit secrets** \u2014 no API keys, tokens, or credentials in code
|
|
1780
|
+
2. **Run tests before committing** \u2014 all tests must pass
|
|
1781
|
+
3. **Verify before claiming done** \u2014 use VR-* verification checks
|
|
1782
|
+
4. **Fix all issues encountered** \u2014 pre-existing issues get fixed too
|
|
1783
|
+
5. **Read before editing** \u2014 understand existing code before modifying
|
|
1784
|
+
|
|
1785
|
+
<!-- Add project-specific rules as you discover them -->`;
|
|
1786
|
+
}
|
|
1787
|
+
function capitalize(str) {
|
|
1788
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1789
|
+
}
|
|
1790
|
+
function formatUiName(name) {
|
|
1791
|
+
const names = {
|
|
1792
|
+
nextjs: "Next.js",
|
|
1793
|
+
sveltekit: "SvelteKit",
|
|
1794
|
+
nuxt: "Nuxt",
|
|
1795
|
+
angular: "Angular",
|
|
1796
|
+
vue: "Vue",
|
|
1797
|
+
react: "React"
|
|
1798
|
+
};
|
|
1799
|
+
return names[name] ?? capitalize(name);
|
|
1800
|
+
}
|
|
1801
|
+
var EXCLUDED_DIRS;
|
|
1802
|
+
var init_claude_md_templates = __esm({
|
|
1803
|
+
"src/claude-md-templates.ts"() {
|
|
1804
|
+
"use strict";
|
|
1805
|
+
EXCLUDED_DIRS = /* @__PURE__ */ new Set([
|
|
1806
|
+
"node_modules",
|
|
1807
|
+
".git",
|
|
1808
|
+
".venv",
|
|
1809
|
+
"venv",
|
|
1810
|
+
"__pycache__",
|
|
1811
|
+
"dist",
|
|
1812
|
+
"build",
|
|
1813
|
+
".next",
|
|
1814
|
+
".nuxt",
|
|
1815
|
+
".svelte-kit",
|
|
1816
|
+
"coverage",
|
|
1817
|
+
".massu",
|
|
1818
|
+
".turbo",
|
|
1819
|
+
".cache",
|
|
1820
|
+
".output"
|
|
1821
|
+
]);
|
|
1822
|
+
}
|
|
1823
|
+
});
|
|
1824
|
+
|
|
1566
1825
|
// src/commands/install-commands.ts
|
|
1567
1826
|
var install_commands_exports = {};
|
|
1568
1827
|
__export(install_commands_exports, {
|
|
@@ -1572,20 +1831,20 @@ __export(install_commands_exports, {
|
|
|
1572
1831
|
resolveCommandsDir: () => resolveCommandsDir,
|
|
1573
1832
|
runInstallCommands: () => runInstallCommands
|
|
1574
1833
|
});
|
|
1575
|
-
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync as mkdirSync2, readdirSync as
|
|
1576
|
-
import { resolve as
|
|
1834
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync as mkdirSync2, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
|
|
1835
|
+
import { resolve as resolve4, dirname as dirname3 } from "path";
|
|
1577
1836
|
import { fileURLToPath } from "url";
|
|
1578
1837
|
function resolveAssetDir(assetName) {
|
|
1579
1838
|
const cwd = process.cwd();
|
|
1580
|
-
const nodeModulesPath =
|
|
1839
|
+
const nodeModulesPath = resolve4(cwd, "node_modules/@massu/core", assetName);
|
|
1581
1840
|
if (existsSync4(nodeModulesPath)) {
|
|
1582
1841
|
return nodeModulesPath;
|
|
1583
1842
|
}
|
|
1584
|
-
const distRelPath =
|
|
1843
|
+
const distRelPath = resolve4(__dirname, "..", assetName);
|
|
1585
1844
|
if (existsSync4(distRelPath)) {
|
|
1586
1845
|
return distRelPath;
|
|
1587
1846
|
}
|
|
1588
|
-
const srcRelPath =
|
|
1847
|
+
const srcRelPath = resolve4(__dirname, "../..", assetName);
|
|
1589
1848
|
if (existsSync4(srcRelPath)) {
|
|
1590
1849
|
return srcRelPath;
|
|
1591
1850
|
}
|
|
@@ -1599,11 +1858,11 @@ function syncDirectory(sourceDir, targetDir) {
|
|
|
1599
1858
|
if (!existsSync4(targetDir)) {
|
|
1600
1859
|
mkdirSync2(targetDir, { recursive: true });
|
|
1601
1860
|
}
|
|
1602
|
-
const entries =
|
|
1861
|
+
const entries = readdirSync3(sourceDir);
|
|
1603
1862
|
for (const entry of entries) {
|
|
1604
|
-
const sourcePath =
|
|
1605
|
-
const targetPath =
|
|
1606
|
-
const entryStat =
|
|
1863
|
+
const sourcePath = resolve4(sourceDir, entry);
|
|
1864
|
+
const targetPath = resolve4(targetDir, entry);
|
|
1865
|
+
const entryStat = statSync2(sourcePath);
|
|
1607
1866
|
if (entryStat.isDirectory()) {
|
|
1608
1867
|
const subStats = syncDirectory(sourcePath, targetPath);
|
|
1609
1868
|
stats.installed += subStats.installed;
|
|
@@ -1629,7 +1888,7 @@ function syncDirectory(sourceDir, targetDir) {
|
|
|
1629
1888
|
}
|
|
1630
1889
|
function installCommands(projectRoot) {
|
|
1631
1890
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
1632
|
-
const targetDir =
|
|
1891
|
+
const targetDir = resolve4(projectRoot, claudeDirName, "commands");
|
|
1633
1892
|
if (!existsSync4(targetDir)) {
|
|
1634
1893
|
mkdirSync2(targetDir, { recursive: true });
|
|
1635
1894
|
}
|
|
@@ -1644,7 +1903,7 @@ function installCommands(projectRoot) {
|
|
|
1644
1903
|
}
|
|
1645
1904
|
function installAll(projectRoot) {
|
|
1646
1905
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
1647
|
-
const claudeDir =
|
|
1906
|
+
const claudeDir = resolve4(projectRoot, claudeDirName);
|
|
1648
1907
|
const assets = {};
|
|
1649
1908
|
let totalInstalled = 0;
|
|
1650
1909
|
let totalUpdated = 0;
|
|
@@ -1654,7 +1913,7 @@ function installAll(projectRoot) {
|
|
|
1654
1913
|
if (!sourceDir) {
|
|
1655
1914
|
continue;
|
|
1656
1915
|
}
|
|
1657
|
-
const targetDir =
|
|
1916
|
+
const targetDir = resolve4(claudeDir, assetType.targetSubdir);
|
|
1658
1917
|
const stats = syncDirectory(sourceDir, targetDir);
|
|
1659
1918
|
assets[assetType.name] = stats;
|
|
1660
1919
|
totalInstalled += stats.installed;
|
|
@@ -1714,6 +1973,7 @@ __export(init_exports, {
|
|
|
1714
1973
|
buildHooksConfig: () => buildHooksConfig,
|
|
1715
1974
|
detectFramework: () => detectFramework,
|
|
1716
1975
|
detectPython: () => detectPython,
|
|
1976
|
+
generateClaudeMd: () => generateClaudeMd,
|
|
1717
1977
|
generateConfig: () => generateConfig,
|
|
1718
1978
|
initMemoryDir: () => initMemoryDir,
|
|
1719
1979
|
installHooks: () => installHooks,
|
|
@@ -1721,8 +1981,8 @@ __export(init_exports, {
|
|
|
1721
1981
|
resolveHooksDir: () => resolveHooksDir,
|
|
1722
1982
|
runInit: () => runInit
|
|
1723
1983
|
});
|
|
1724
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, readdirSync as
|
|
1725
|
-
import { resolve as
|
|
1984
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, readdirSync as readdirSync4 } from "fs";
|
|
1985
|
+
import { resolve as resolve5, basename as basename3, dirname as dirname4 } from "path";
|
|
1726
1986
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1727
1987
|
import { homedir as homedir2 } from "os";
|
|
1728
1988
|
import { stringify as yamlStringify } from "yaml";
|
|
@@ -1733,7 +1993,7 @@ function detectFramework(projectRoot) {
|
|
|
1733
1993
|
orm: "none",
|
|
1734
1994
|
ui: "none"
|
|
1735
1995
|
};
|
|
1736
|
-
const pkgPath =
|
|
1996
|
+
const pkgPath = resolve5(projectRoot, "package.json");
|
|
1737
1997
|
if (!existsSync5(pkgPath)) return result;
|
|
1738
1998
|
try {
|
|
1739
1999
|
const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
@@ -1770,7 +2030,7 @@ function detectPython(projectRoot) {
|
|
|
1770
2030
|
alembicDir: null
|
|
1771
2031
|
};
|
|
1772
2032
|
const markers = ["pyproject.toml", "setup.py", "requirements.txt", "Pipfile"];
|
|
1773
|
-
const hasMarker = markers.some((m) => existsSync5(
|
|
2033
|
+
const hasMarker = markers.some((m) => existsSync5(resolve5(projectRoot, m)));
|
|
1774
2034
|
if (!hasMarker) return result;
|
|
1775
2035
|
result.detected = true;
|
|
1776
2036
|
const depFiles = [
|
|
@@ -1780,7 +2040,7 @@ function detectPython(projectRoot) {
|
|
|
1780
2040
|
{ file: "Pipfile", parser: parsePipfileDeps }
|
|
1781
2041
|
];
|
|
1782
2042
|
for (const { file, parser } of depFiles) {
|
|
1783
|
-
const filePath =
|
|
2043
|
+
const filePath = resolve5(projectRoot, file);
|
|
1784
2044
|
if (existsSync5(filePath)) {
|
|
1785
2045
|
try {
|
|
1786
2046
|
const content = readFileSync4(filePath, "utf-8");
|
|
@@ -1791,25 +2051,25 @@ function detectPython(projectRoot) {
|
|
|
1791
2051
|
}
|
|
1792
2052
|
}
|
|
1793
2053
|
}
|
|
1794
|
-
if (existsSync5(
|
|
2054
|
+
if (existsSync5(resolve5(projectRoot, "alembic.ini"))) {
|
|
1795
2055
|
result.hasAlembic = true;
|
|
1796
|
-
if (existsSync5(
|
|
2056
|
+
if (existsSync5(resolve5(projectRoot, "alembic"))) {
|
|
1797
2057
|
result.alembicDir = "alembic";
|
|
1798
2058
|
}
|
|
1799
|
-
} else if (existsSync5(
|
|
2059
|
+
} else if (existsSync5(resolve5(projectRoot, "alembic"))) {
|
|
1800
2060
|
result.hasAlembic = true;
|
|
1801
2061
|
result.alembicDir = "alembic";
|
|
1802
2062
|
}
|
|
1803
2063
|
const candidateRoots = ["app", "src", "backend", "api"];
|
|
1804
2064
|
for (const candidate of candidateRoots) {
|
|
1805
|
-
const candidatePath =
|
|
1806
|
-
if (existsSync5(candidatePath) && existsSync5(
|
|
2065
|
+
const candidatePath = resolve5(projectRoot, candidate);
|
|
2066
|
+
if (existsSync5(candidatePath) && existsSync5(resolve5(candidatePath, "__init__.py"))) {
|
|
1807
2067
|
result.root = candidate;
|
|
1808
2068
|
break;
|
|
1809
2069
|
}
|
|
1810
2070
|
if (existsSync5(candidatePath)) {
|
|
1811
2071
|
try {
|
|
1812
|
-
const files =
|
|
2072
|
+
const files = readdirSync4(candidatePath);
|
|
1813
2073
|
if (files.some((f) => f.endsWith(".py"))) {
|
|
1814
2074
|
result.root = candidate;
|
|
1815
2075
|
break;
|
|
@@ -1855,11 +2115,11 @@ function parsePipfileDeps(content) {
|
|
|
1855
2115
|
return deps;
|
|
1856
2116
|
}
|
|
1857
2117
|
function generateConfig(projectRoot, framework) {
|
|
1858
|
-
const configPath =
|
|
2118
|
+
const configPath = resolve5(projectRoot, "massu.config.yaml");
|
|
1859
2119
|
if (existsSync5(configPath)) {
|
|
1860
2120
|
return false;
|
|
1861
2121
|
}
|
|
1862
|
-
const projectName =
|
|
2122
|
+
const projectName = basename3(projectRoot);
|
|
1863
2123
|
const config = {
|
|
1864
2124
|
project: {
|
|
1865
2125
|
name: projectName,
|
|
@@ -1905,8 +2165,18 @@ ${yamlStringify(config)}`;
|
|
|
1905
2165
|
writeFileSync2(configPath, yamlContent, "utf-8");
|
|
1906
2166
|
return true;
|
|
1907
2167
|
}
|
|
2168
|
+
function generateClaudeMd(projectRoot, framework, python) {
|
|
2169
|
+
const claudeMdPath = resolve5(projectRoot, "CLAUDE.md");
|
|
2170
|
+
if (existsSync5(claudeMdPath)) {
|
|
2171
|
+
return { created: false, skipped: true };
|
|
2172
|
+
}
|
|
2173
|
+
const projectName = basename3(projectRoot);
|
|
2174
|
+
const content = buildClaudeMdContent(projectName, projectRoot, framework, python);
|
|
2175
|
+
writeFileSync2(claudeMdPath, content, "utf-8");
|
|
2176
|
+
return { created: true, skipped: false };
|
|
2177
|
+
}
|
|
1908
2178
|
function registerMcpServer(projectRoot) {
|
|
1909
|
-
const mcpPath =
|
|
2179
|
+
const mcpPath = resolve5(projectRoot, ".mcp.json");
|
|
1910
2180
|
let existing = {};
|
|
1911
2181
|
if (existsSync5(mcpPath)) {
|
|
1912
2182
|
try {
|
|
@@ -2009,8 +2279,8 @@ function buildHooksConfig(hooksDir) {
|
|
|
2009
2279
|
}
|
|
2010
2280
|
function installHooks(projectRoot) {
|
|
2011
2281
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
2012
|
-
const claudeDir =
|
|
2013
|
-
const settingsPath =
|
|
2282
|
+
const claudeDir = resolve5(projectRoot, claudeDirName);
|
|
2283
|
+
const settingsPath = resolve5(claudeDir, "settings.local.json");
|
|
2014
2284
|
if (!existsSync5(claudeDir)) {
|
|
2015
2285
|
mkdirSync3(claudeDir, { recursive: true });
|
|
2016
2286
|
}
|
|
@@ -2036,16 +2306,16 @@ function installHooks(projectRoot) {
|
|
|
2036
2306
|
}
|
|
2037
2307
|
function initMemoryDir(projectRoot) {
|
|
2038
2308
|
const encodedRoot = "-" + projectRoot.replace(/\//g, "-");
|
|
2039
|
-
const memoryDir =
|
|
2309
|
+
const memoryDir = resolve5(homedir2(), `.claude/projects/${encodedRoot}/memory`);
|
|
2040
2310
|
let created = false;
|
|
2041
2311
|
if (!existsSync5(memoryDir)) {
|
|
2042
2312
|
mkdirSync3(memoryDir, { recursive: true });
|
|
2043
2313
|
created = true;
|
|
2044
2314
|
}
|
|
2045
|
-
const memoryMdPath =
|
|
2315
|
+
const memoryMdPath = resolve5(memoryDir, "MEMORY.md");
|
|
2046
2316
|
let memoryMdCreated = false;
|
|
2047
2317
|
if (!existsSync5(memoryMdPath)) {
|
|
2048
|
-
const projectName =
|
|
2318
|
+
const projectName = basename3(projectRoot);
|
|
2049
2319
|
const memoryContent = `# ${projectName} - Massu Memory
|
|
2050
2320
|
|
|
2051
2321
|
## Key Learnings
|
|
@@ -2073,9 +2343,9 @@ async function runInit() {
|
|
|
2073
2343
|
console.log("");
|
|
2074
2344
|
const framework = detectFramework(projectRoot);
|
|
2075
2345
|
const frameworkParts = [];
|
|
2076
|
-
if (framework.type !== "javascript") frameworkParts.push(
|
|
2346
|
+
if (framework.type !== "javascript") frameworkParts.push(capitalize2(framework.type));
|
|
2077
2347
|
if (framework.ui !== "none") frameworkParts.push(formatName(framework.ui));
|
|
2078
|
-
if (framework.orm !== "none") frameworkParts.push(
|
|
2348
|
+
if (framework.orm !== "none") frameworkParts.push(capitalize2(framework.orm));
|
|
2079
2349
|
if (framework.router !== "none") frameworkParts.push(framework.router.toUpperCase());
|
|
2080
2350
|
const detected = frameworkParts.length > 0 ? frameworkParts.join(", ") : "JavaScript";
|
|
2081
2351
|
console.log(` Detected: ${detected}`);
|
|
@@ -2087,6 +2357,12 @@ async function runInit() {
|
|
|
2087
2357
|
if (python.hasAlembic) pyParts.push("Alembic");
|
|
2088
2358
|
console.log(` Detected: ${pyParts.join(", ")} (root: ${python.root})`);
|
|
2089
2359
|
}
|
|
2360
|
+
const claudeMdResult = generateClaudeMd(projectRoot, framework, python);
|
|
2361
|
+
if (claudeMdResult.created) {
|
|
2362
|
+
console.log(" Created CLAUDE.md (project instructions for Claude Code)");
|
|
2363
|
+
} else {
|
|
2364
|
+
console.log(" CLAUDE.md already exists (preserved)");
|
|
2365
|
+
}
|
|
2090
2366
|
const configCreated = generateConfig(projectRoot, framework);
|
|
2091
2367
|
if (configCreated) {
|
|
2092
2368
|
console.log(" Created massu.config.yaml");
|
|
@@ -2120,8 +2396,8 @@ async function runInit() {
|
|
|
2120
2396
|
try {
|
|
2121
2397
|
const claudeDirName = ".claude";
|
|
2122
2398
|
const encodedRoot = projectRoot.replace(/\//g, "-");
|
|
2123
|
-
const computedMemoryDir =
|
|
2124
|
-
const memFiles = existsSync5(computedMemoryDir) ?
|
|
2399
|
+
const computedMemoryDir = resolve5(homedir2(), claudeDirName, "projects", encodedRoot, "memory");
|
|
2400
|
+
const memFiles = existsSync5(computedMemoryDir) ? readdirSync4(computedMemoryDir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md") : [];
|
|
2125
2401
|
if (memFiles.length > 0) {
|
|
2126
2402
|
const { getMemoryDb: getMemoryDb2 } = await Promise.resolve().then(() => (init_memory_db(), memory_db_exports));
|
|
2127
2403
|
const db = getMemoryDb2();
|
|
@@ -2147,7 +2423,7 @@ async function runInit() {
|
|
|
2147
2423
|
console.log("Documentation: https://massu.ai/docs");
|
|
2148
2424
|
console.log("");
|
|
2149
2425
|
}
|
|
2150
|
-
function
|
|
2426
|
+
function capitalize2(str) {
|
|
2151
2427
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
2152
2428
|
}
|
|
2153
2429
|
function formatName(name) {
|
|
@@ -2159,13 +2435,14 @@ function formatName(name) {
|
|
|
2159
2435
|
vue: "Vue",
|
|
2160
2436
|
react: "React"
|
|
2161
2437
|
};
|
|
2162
|
-
return names[name] ??
|
|
2438
|
+
return names[name] ?? capitalize2(name);
|
|
2163
2439
|
}
|
|
2164
2440
|
var __filename2, __dirname2;
|
|
2165
2441
|
var init_init = __esm({
|
|
2166
2442
|
"src/commands/init.ts"() {
|
|
2167
2443
|
"use strict";
|
|
2168
2444
|
init_memory_file_ingest();
|
|
2445
|
+
init_claude_md_templates();
|
|
2169
2446
|
init_config();
|
|
2170
2447
|
init_install_commands();
|
|
2171
2448
|
__filename2 = fileURLToPath2(import.meta.url);
|
|
@@ -2469,12 +2746,12 @@ __export(doctor_exports, {
|
|
|
2469
2746
|
runDoctor: () => runDoctor,
|
|
2470
2747
|
runValidateConfig: () => runValidateConfig
|
|
2471
2748
|
});
|
|
2472
|
-
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as
|
|
2473
|
-
import { resolve as
|
|
2749
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync5 } from "fs";
|
|
2750
|
+
import { resolve as resolve6, dirname as dirname5 } from "path";
|
|
2474
2751
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2475
2752
|
import { parse as parseYaml2 } from "yaml";
|
|
2476
2753
|
function checkConfig(projectRoot) {
|
|
2477
|
-
const configPath =
|
|
2754
|
+
const configPath = resolve6(projectRoot, "massu.config.yaml");
|
|
2478
2755
|
if (!existsSync6(configPath)) {
|
|
2479
2756
|
return { name: "Configuration", status: "fail", detail: "massu.config.yaml not found. Run: npx massu init" };
|
|
2480
2757
|
}
|
|
@@ -2535,10 +2812,10 @@ function checkHooksConfig(projectRoot) {
|
|
|
2535
2812
|
}
|
|
2536
2813
|
}
|
|
2537
2814
|
function checkHookFiles(projectRoot) {
|
|
2538
|
-
const nodeModulesHooksDir =
|
|
2815
|
+
const nodeModulesHooksDir = resolve6(projectRoot, "node_modules/@massu/core/dist/hooks");
|
|
2539
2816
|
let hooksDir = nodeModulesHooksDir;
|
|
2540
2817
|
if (!existsSync6(nodeModulesHooksDir)) {
|
|
2541
|
-
const devHooksDir =
|
|
2818
|
+
const devHooksDir = resolve6(__dirname3, "../../dist/hooks");
|
|
2542
2819
|
if (existsSync6(devHooksDir)) {
|
|
2543
2820
|
hooksDir = devHooksDir;
|
|
2544
2821
|
} else {
|
|
@@ -2547,7 +2824,7 @@ function checkHookFiles(projectRoot) {
|
|
|
2547
2824
|
}
|
|
2548
2825
|
const missing = [];
|
|
2549
2826
|
for (const hookFile of EXPECTED_HOOKS) {
|
|
2550
|
-
if (!existsSync6(
|
|
2827
|
+
if (!existsSync6(resolve6(hooksDir, hookFile))) {
|
|
2551
2828
|
missing.push(hookFile);
|
|
2552
2829
|
}
|
|
2553
2830
|
}
|
|
@@ -2573,7 +2850,7 @@ function checkNodeVersion() {
|
|
|
2573
2850
|
return { name: "Node.js", status: "fail", detail: `v${version} \u2014 Node.js 18+ is required` };
|
|
2574
2851
|
}
|
|
2575
2852
|
async function checkGitRepo(projectRoot) {
|
|
2576
|
-
const gitDir =
|
|
2853
|
+
const gitDir = resolve6(projectRoot, ".git");
|
|
2577
2854
|
if (!existsSync6(gitDir)) {
|
|
2578
2855
|
return { name: "Git Repository", status: "warn", detail: "Not a git repository (optional but recommended)" };
|
|
2579
2856
|
}
|
|
@@ -2673,7 +2950,7 @@ async function checkLicenseStatus() {
|
|
|
2673
2950
|
function checkPythonHealth(projectRoot) {
|
|
2674
2951
|
const config = getConfig();
|
|
2675
2952
|
if (!config.python?.root) return null;
|
|
2676
|
-
const pythonRoot =
|
|
2953
|
+
const pythonRoot = resolve6(projectRoot, config.python.root);
|
|
2677
2954
|
if (!existsSync6(pythonRoot)) {
|
|
2678
2955
|
return {
|
|
2679
2956
|
name: "Python",
|
|
@@ -2688,15 +2965,15 @@ function checkPythonHealth(projectRoot) {
|
|
|
2688
2965
|
function scanDir(dir, depth) {
|
|
2689
2966
|
if (depth > 5) return;
|
|
2690
2967
|
try {
|
|
2691
|
-
const entries =
|
|
2968
|
+
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
2692
2969
|
for (const entry of entries) {
|
|
2693
2970
|
if (entry.isDirectory()) {
|
|
2694
2971
|
const excludeDirs = config.python?.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
2695
2972
|
if (!excludeDirs.includes(entry.name)) {
|
|
2696
|
-
const subdir =
|
|
2697
|
-
if (depth <= 2 && !existsSync6(
|
|
2973
|
+
const subdir = resolve6(dir, entry.name);
|
|
2974
|
+
if (depth <= 2 && !existsSync6(resolve6(subdir, "__init__.py"))) {
|
|
2698
2975
|
try {
|
|
2699
|
-
const subEntries =
|
|
2976
|
+
const subEntries = readdirSync5(subdir);
|
|
2700
2977
|
if (subEntries.some((f) => f.endsWith(".py") && f !== "__init__.py")) {
|
|
2701
2978
|
initPyMissing.push(entry.name);
|
|
2702
2979
|
}
|
|
@@ -2743,6 +3020,29 @@ function checkPythonHealth(projectRoot) {
|
|
|
2743
3020
|
detail: parts.join(", ")
|
|
2744
3021
|
};
|
|
2745
3022
|
}
|
|
3023
|
+
function checkClaudeMd(projectRoot) {
|
|
3024
|
+
const claudeMdPath = resolve6(projectRoot, "CLAUDE.md");
|
|
3025
|
+
if (!existsSync6(claudeMdPath)) {
|
|
3026
|
+
return {
|
|
3027
|
+
name: "CLAUDE.md",
|
|
3028
|
+
status: "warn",
|
|
3029
|
+
detail: "CLAUDE.md not found. Run: npx massu init (or create manually)"
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
const content = readFileSync5(claudeMdPath, "utf-8");
|
|
3033
|
+
if (content.trim().length < 50) {
|
|
3034
|
+
return {
|
|
3035
|
+
name: "CLAUDE.md",
|
|
3036
|
+
status: "warn",
|
|
3037
|
+
detail: "CLAUDE.md exists but appears empty or minimal"
|
|
3038
|
+
};
|
|
3039
|
+
}
|
|
3040
|
+
return {
|
|
3041
|
+
name: "CLAUDE.md",
|
|
3042
|
+
status: "pass",
|
|
3043
|
+
detail: "CLAUDE.md found and has content"
|
|
3044
|
+
};
|
|
3045
|
+
}
|
|
2746
3046
|
async function runDoctor() {
|
|
2747
3047
|
const projectRoot = process.cwd();
|
|
2748
3048
|
console.log("");
|
|
@@ -2760,7 +3060,8 @@ async function runDoctor() {
|
|
|
2760
3060
|
await checkNativeModules(),
|
|
2761
3061
|
checkNodeVersion(),
|
|
2762
3062
|
await checkGitRepo(projectRoot),
|
|
2763
|
-
await checkLicenseStatus()
|
|
3063
|
+
await checkLicenseStatus(),
|
|
3064
|
+
checkClaudeMd(projectRoot)
|
|
2764
3065
|
];
|
|
2765
3066
|
const pythonCheck = checkPythonHealth(projectRoot);
|
|
2766
3067
|
if (pythonCheck) checks.push(pythonCheck);
|
|
@@ -2789,7 +3090,7 @@ async function runDoctor() {
|
|
|
2789
3090
|
}
|
|
2790
3091
|
async function runValidateConfig() {
|
|
2791
3092
|
const projectRoot = process.cwd();
|
|
2792
|
-
const configPath =
|
|
3093
|
+
const configPath = resolve6(projectRoot, "massu.config.yaml");
|
|
2793
3094
|
if (!existsSync6(configPath)) {
|
|
2794
3095
|
console.error("Error: massu.config.yaml not found in current directory");
|
|
2795
3096
|
console.error("Run: npx massu init");
|
|
@@ -2880,7 +3181,7 @@ var init_install_hooks = __esm({
|
|
|
2880
3181
|
// src/db.ts
|
|
2881
3182
|
import Database2 from "better-sqlite3";
|
|
2882
3183
|
import { dirname as dirname6, join as join3 } from "path";
|
|
2883
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync as
|
|
3184
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
|
|
2884
3185
|
function getCodeGraphDb() {
|
|
2885
3186
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
2886
3187
|
if (!existsSync7(dbPath)) {
|
|
@@ -3164,14 +3465,14 @@ function isPythonDataStale(dataDb2, pythonRoot) {
|
|
|
3164
3465
|
const lastBuildTime = new Date(lastBuild.value).getTime();
|
|
3165
3466
|
function checkDir(dir) {
|
|
3166
3467
|
try {
|
|
3167
|
-
const entries =
|
|
3468
|
+
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
3168
3469
|
for (const entry of entries) {
|
|
3169
3470
|
const fullPath = join3(dir, entry.name);
|
|
3170
3471
|
if (entry.isDirectory()) {
|
|
3171
3472
|
if (["__pycache__", ".venv", "venv", "node_modules", ".mypy_cache", ".pytest_cache"].includes(entry.name)) continue;
|
|
3172
3473
|
if (checkDir(fullPath)) return true;
|
|
3173
3474
|
} else if (entry.name.endsWith(".py")) {
|
|
3174
|
-
if (
|
|
3475
|
+
if (statSync3(fullPath).mtimeMs > lastBuildTime) return true;
|
|
3175
3476
|
}
|
|
3176
3477
|
}
|
|
3177
3478
|
} catch {
|
|
@@ -3191,10 +3492,10 @@ var init_db = __esm({
|
|
|
3191
3492
|
});
|
|
3192
3493
|
|
|
3193
3494
|
// src/security-utils.ts
|
|
3194
|
-
import { resolve as
|
|
3495
|
+
import { resolve as resolve7, normalize } from "path";
|
|
3195
3496
|
function ensureWithinRoot(filePath, projectRoot) {
|
|
3196
|
-
const resolvedRoot =
|
|
3197
|
-
const resolvedPath =
|
|
3497
|
+
const resolvedRoot = resolve7(projectRoot);
|
|
3498
|
+
const resolvedPath = resolve7(resolvedRoot, filePath);
|
|
3198
3499
|
const normalizedPath = normalize(resolvedPath);
|
|
3199
3500
|
const normalizedRoot = normalize(resolvedRoot);
|
|
3200
3501
|
if (!normalizedPath.startsWith(normalizedRoot + "/") && normalizedPath !== normalizedRoot) {
|
|
@@ -3267,8 +3568,8 @@ var init_rules = __esm({
|
|
|
3267
3568
|
});
|
|
3268
3569
|
|
|
3269
3570
|
// src/import-resolver.ts
|
|
3270
|
-
import { readFileSync as readFileSync6, existsSync as existsSync8, statSync as
|
|
3271
|
-
import { resolve as
|
|
3571
|
+
import { readFileSync as readFileSync6, existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
3572
|
+
import { resolve as resolve8, dirname as dirname7, join as join4 } from "path";
|
|
3272
3573
|
function parseImports(source) {
|
|
3273
3574
|
const imports = [];
|
|
3274
3575
|
const lines = source.split("\n");
|
|
@@ -3324,9 +3625,9 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
3324
3625
|
let basePath;
|
|
3325
3626
|
if (specifier.startsWith("@/")) {
|
|
3326
3627
|
const paths = getResolvedPaths();
|
|
3327
|
-
basePath =
|
|
3628
|
+
basePath = resolve8(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
3328
3629
|
} else {
|
|
3329
|
-
basePath =
|
|
3630
|
+
basePath = resolve8(dirname7(fromFile), specifier);
|
|
3330
3631
|
}
|
|
3331
3632
|
if (existsSync8(basePath) && !isDirectory(basePath)) {
|
|
3332
3633
|
return toRelative(basePath);
|
|
@@ -3348,7 +3649,7 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
3348
3649
|
}
|
|
3349
3650
|
function isDirectory(path) {
|
|
3350
3651
|
try {
|
|
3351
|
-
return
|
|
3652
|
+
return statSync4(path).isDirectory();
|
|
3352
3653
|
} catch {
|
|
3353
3654
|
return false;
|
|
3354
3655
|
}
|
|
@@ -3376,7 +3677,7 @@ function buildImportIndex(dataDb2, codegraphDb2) {
|
|
|
3376
3677
|
const batchSize = 500;
|
|
3377
3678
|
let batch = [];
|
|
3378
3679
|
for (const file of files) {
|
|
3379
|
-
const absPath = ensureWithinRoot(
|
|
3680
|
+
const absPath = ensureWithinRoot(resolve8(projectRoot, file.path), projectRoot);
|
|
3380
3681
|
if (!existsSync8(absPath)) continue;
|
|
3381
3682
|
let source;
|
|
3382
3683
|
try {
|
|
@@ -3416,8 +3717,8 @@ var init_import_resolver = __esm({
|
|
|
3416
3717
|
});
|
|
3417
3718
|
|
|
3418
3719
|
// src/trpc-index.ts
|
|
3419
|
-
import { readFileSync as readFileSync7, existsSync as existsSync9, readdirSync as
|
|
3420
|
-
import { resolve as
|
|
3720
|
+
import { readFileSync as readFileSync7, existsSync as existsSync9, readdirSync as readdirSync7 } from "fs";
|
|
3721
|
+
import { resolve as resolve9, join as join5 } from "path";
|
|
3421
3722
|
function parseRootRouter() {
|
|
3422
3723
|
const paths = getResolvedPaths();
|
|
3423
3724
|
const rootPath = paths.rootRouterPath;
|
|
@@ -3432,7 +3733,7 @@ function parseRootRouter() {
|
|
|
3432
3733
|
while ((match = importRegex.exec(source)) !== null) {
|
|
3433
3734
|
const variable = match[1];
|
|
3434
3735
|
let filePath = match[2];
|
|
3435
|
-
const fullPath =
|
|
3736
|
+
const fullPath = resolve9(paths.routersDir, filePath);
|
|
3436
3737
|
for (const ext of [".ts", ".tsx", ""]) {
|
|
3437
3738
|
const candidate = fullPath + ext;
|
|
3438
3739
|
const routersRelPath = getConfig().paths.routers ?? "src/server/api/routers";
|
|
@@ -3460,7 +3761,7 @@ function parseRootRouter() {
|
|
|
3460
3761
|
return mappings;
|
|
3461
3762
|
}
|
|
3462
3763
|
function extractProcedures(routerFilePath) {
|
|
3463
|
-
const absPath =
|
|
3764
|
+
const absPath = resolve9(getProjectRoot(), routerFilePath);
|
|
3464
3765
|
if (!existsSync9(absPath)) return [];
|
|
3465
3766
|
const source = readFileSync7(absPath, "utf-8");
|
|
3466
3767
|
const procedures = [];
|
|
@@ -3485,9 +3786,9 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
3485
3786
|
const root = getProjectRoot();
|
|
3486
3787
|
const src = config.paths.source;
|
|
3487
3788
|
const searchDirs = [
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3789
|
+
resolve9(root, config.paths.pages ?? src + "/app"),
|
|
3790
|
+
resolve9(root, config.paths.components ?? src + "/components"),
|
|
3791
|
+
resolve9(root, config.paths.hooks ?? src + "/hooks")
|
|
3491
3792
|
];
|
|
3492
3793
|
const searchPattern = `api.${routerKey}.${procedureName}`;
|
|
3493
3794
|
for (const dir of searchDirs) {
|
|
@@ -3497,7 +3798,7 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
3497
3798
|
return callSites;
|
|
3498
3799
|
}
|
|
3499
3800
|
function searchDirectory(dir, pattern, results) {
|
|
3500
|
-
const entries =
|
|
3801
|
+
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
3501
3802
|
for (const entry of entries) {
|
|
3502
3803
|
const fullPath = join5(dir, entry.name);
|
|
3503
3804
|
if (entry.isDirectory()) {
|
|
@@ -3569,7 +3870,7 @@ var init_trpc_index = __esm({
|
|
|
3569
3870
|
|
|
3570
3871
|
// src/page-deps.ts
|
|
3571
3872
|
import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
|
|
3572
|
-
import { resolve as
|
|
3873
|
+
import { resolve as resolve10 } from "path";
|
|
3573
3874
|
function deriveRoute(pageFile) {
|
|
3574
3875
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
3575
3876
|
return route || "/";
|
|
@@ -3607,7 +3908,7 @@ function findRouterCalls(files) {
|
|
|
3607
3908
|
const routers = /* @__PURE__ */ new Set();
|
|
3608
3909
|
const projectRoot = getProjectRoot();
|
|
3609
3910
|
for (const file of files) {
|
|
3610
|
-
const absPath = ensureWithinRoot(
|
|
3911
|
+
const absPath = ensureWithinRoot(resolve10(projectRoot, file), projectRoot);
|
|
3611
3912
|
if (!existsSync10(absPath)) continue;
|
|
3612
3913
|
try {
|
|
3613
3914
|
const source = readFileSync8(absPath, "utf-8");
|
|
@@ -3628,7 +3929,7 @@ function findTablesFromRouters(routerNames, dataDb2) {
|
|
|
3628
3929
|
"SELECT DISTINCT router_file FROM massu_trpc_procedures WHERE router_name = ?"
|
|
3629
3930
|
).all(routerName);
|
|
3630
3931
|
for (const proc of procs) {
|
|
3631
|
-
const absPath = ensureWithinRoot(
|
|
3932
|
+
const absPath = ensureWithinRoot(resolve10(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
3632
3933
|
if (!existsSync10(absPath)) continue;
|
|
3633
3934
|
try {
|
|
3634
3935
|
const source = readFileSync8(absPath, "utf-8");
|
|
@@ -3900,7 +4201,7 @@ var init_domains = __esm({
|
|
|
3900
4201
|
});
|
|
3901
4202
|
|
|
3902
4203
|
// src/schema-mapper.ts
|
|
3903
|
-
import { readFileSync as readFileSync9, existsSync as existsSync11, readdirSync as
|
|
4204
|
+
import { readFileSync as readFileSync9, existsSync as existsSync11, readdirSync as readdirSync8 } from "fs";
|
|
3904
4205
|
import { join as join6 } from "path";
|
|
3905
4206
|
function parsePrismaSchema() {
|
|
3906
4207
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
@@ -3970,7 +4271,7 @@ function findColumnUsageInRouters(tableName) {
|
|
|
3970
4271
|
return usage;
|
|
3971
4272
|
}
|
|
3972
4273
|
function scanDirectory(dir, tableName, usage) {
|
|
3973
|
-
const entries =
|
|
4274
|
+
const entries = readdirSync8(dir, { withFileTypes: true });
|
|
3974
4275
|
for (const entry of entries) {
|
|
3975
4276
|
const fullPath = join6(dir, entry.name);
|
|
3976
4277
|
if (entry.isDirectory()) {
|
|
@@ -4028,7 +4329,7 @@ function detectMismatches(models) {
|
|
|
4028
4329
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
4029
4330
|
const result = [];
|
|
4030
4331
|
if (!existsSync11(dir)) return result;
|
|
4031
|
-
const entries =
|
|
4332
|
+
const entries = readdirSync8(dir, { withFileTypes: true });
|
|
4032
4333
|
for (const entry of entries) {
|
|
4033
4334
|
const fullPath = join6(dir, entry.name);
|
|
4034
4335
|
if (entry.isDirectory()) {
|
|
@@ -4180,12 +4481,12 @@ var init_import_parser = __esm({
|
|
|
4180
4481
|
});
|
|
4181
4482
|
|
|
4182
4483
|
// src/python/import-resolver.ts
|
|
4183
|
-
import { readFileSync as readFileSync10, existsSync as existsSync12, readdirSync as
|
|
4184
|
-
import { resolve as
|
|
4484
|
+
import { readFileSync as readFileSync10, existsSync as existsSync12, readdirSync as readdirSync9 } from "fs";
|
|
4485
|
+
import { resolve as resolve12, join as join7, relative as relative3, dirname as dirname8 } from "path";
|
|
4185
4486
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
4186
4487
|
const projectRoot = getProjectRoot();
|
|
4187
4488
|
if (level > 0) {
|
|
4188
|
-
let baseDir = dirname8(
|
|
4489
|
+
let baseDir = dirname8(resolve12(projectRoot, fromFile));
|
|
4189
4490
|
for (let i = 1; i < level; i++) {
|
|
4190
4491
|
baseDir = dirname8(baseDir);
|
|
4191
4492
|
}
|
|
@@ -4197,25 +4498,25 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
4197
4498
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
4198
4499
|
}
|
|
4199
4500
|
const parts = module.split(".");
|
|
4200
|
-
const candidate = join7(
|
|
4501
|
+
const candidate = join7(resolve12(projectRoot, pythonRoot), ...parts);
|
|
4201
4502
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
4202
4503
|
}
|
|
4203
4504
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
4204
4505
|
if (existsSync12(basePath + ".py")) {
|
|
4205
|
-
return
|
|
4506
|
+
return relative3(projectRoot, basePath + ".py");
|
|
4206
4507
|
}
|
|
4207
4508
|
if (existsSync12(join7(basePath, "__init__.py"))) {
|
|
4208
|
-
return
|
|
4509
|
+
return relative3(projectRoot, join7(basePath, "__init__.py"));
|
|
4209
4510
|
}
|
|
4210
4511
|
if (basePath.endsWith(".py") && existsSync12(basePath)) {
|
|
4211
|
-
return
|
|
4512
|
+
return relative3(projectRoot, basePath);
|
|
4212
4513
|
}
|
|
4213
4514
|
return null;
|
|
4214
4515
|
}
|
|
4215
4516
|
function walkPythonFiles(dir, excludeDirs) {
|
|
4216
4517
|
const files = [];
|
|
4217
4518
|
try {
|
|
4218
|
-
const entries =
|
|
4519
|
+
const entries = readdirSync9(dir, { withFileTypes: true });
|
|
4219
4520
|
for (const entry of entries) {
|
|
4220
4521
|
if (entry.isDirectory()) {
|
|
4221
4522
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -4230,7 +4531,7 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
4230
4531
|
}
|
|
4231
4532
|
function buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
4232
4533
|
const projectRoot = getProjectRoot();
|
|
4233
|
-
const absRoot =
|
|
4534
|
+
const absRoot = resolve12(projectRoot, pythonRoot);
|
|
4234
4535
|
dataDb2.exec("DELETE FROM massu_py_imports");
|
|
4235
4536
|
const insertStmt = dataDb2.prepare(
|
|
4236
4537
|
"INSERT INTO massu_py_imports (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)"
|
|
@@ -4244,7 +4545,7 @@ function buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__
|
|
|
4244
4545
|
});
|
|
4245
4546
|
const batch = [];
|
|
4246
4547
|
for (const absFile of files) {
|
|
4247
|
-
const relFile =
|
|
4548
|
+
const relFile = relative3(projectRoot, absFile);
|
|
4248
4549
|
let source;
|
|
4249
4550
|
try {
|
|
4250
4551
|
source = readFileSync10(absFile, "utf-8");
|
|
@@ -4513,12 +4814,12 @@ var init_route_parser = __esm({
|
|
|
4513
4814
|
});
|
|
4514
4815
|
|
|
4515
4816
|
// src/python/route-indexer.ts
|
|
4516
|
-
import { readFileSync as readFileSync11, readdirSync as
|
|
4517
|
-
import { join as join8, relative as
|
|
4817
|
+
import { readFileSync as readFileSync11, readdirSync as readdirSync10 } from "fs";
|
|
4818
|
+
import { join as join8, relative as relative4 } from "path";
|
|
4518
4819
|
function walkPyFiles(dir, excludeDirs) {
|
|
4519
4820
|
const files = [];
|
|
4520
4821
|
try {
|
|
4521
|
-
const entries =
|
|
4822
|
+
const entries = readdirSync10(dir, { withFileTypes: true });
|
|
4522
4823
|
for (const entry of entries) {
|
|
4523
4824
|
if (entry.isDirectory()) {
|
|
4524
4825
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -4543,7 +4844,7 @@ function buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
4543
4844
|
let count = 0;
|
|
4544
4845
|
dataDb2.transaction(() => {
|
|
4545
4846
|
for (const absFile of files) {
|
|
4546
|
-
const relFile =
|
|
4847
|
+
const relFile = relative4(projectRoot, absFile);
|
|
4547
4848
|
let source;
|
|
4548
4849
|
try {
|
|
4549
4850
|
source = readFileSync11(absFile, "utf-8");
|
|
@@ -4757,12 +5058,12 @@ var init_model_parser = __esm({
|
|
|
4757
5058
|
});
|
|
4758
5059
|
|
|
4759
5060
|
// src/python/model-indexer.ts
|
|
4760
|
-
import { readFileSync as readFileSync12, readdirSync as
|
|
4761
|
-
import { join as join9, relative as
|
|
5061
|
+
import { readFileSync as readFileSync12, readdirSync as readdirSync11 } from "fs";
|
|
5062
|
+
import { join as join9, relative as relative5 } from "path";
|
|
4762
5063
|
function walkPyFiles2(dir, excludeDirs) {
|
|
4763
5064
|
const files = [];
|
|
4764
5065
|
try {
|
|
4765
|
-
const entries =
|
|
5066
|
+
const entries = readdirSync11(dir, { withFileTypes: true });
|
|
4766
5067
|
for (const entry of entries) {
|
|
4767
5068
|
if (entry.isDirectory()) {
|
|
4768
5069
|
if (excludeDirs.includes(entry.name)) continue;
|
|
@@ -4790,7 +5091,7 @@ function buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
4790
5091
|
let count = 0;
|
|
4791
5092
|
dataDb2.transaction(() => {
|
|
4792
5093
|
for (const absFile of files) {
|
|
4793
|
-
const relFile =
|
|
5094
|
+
const relFile = relative5(projectRoot, absFile);
|
|
4794
5095
|
let source;
|
|
4795
5096
|
try {
|
|
4796
5097
|
source = readFileSync12(absFile, "utf-8");
|
|
@@ -5053,8 +5354,8 @@ var init_migration_parser = __esm({
|
|
|
5053
5354
|
});
|
|
5054
5355
|
|
|
5055
5356
|
// src/python/migration-indexer.ts
|
|
5056
|
-
import { readFileSync as readFileSync13, readdirSync as
|
|
5057
|
-
import { join as join10, relative as
|
|
5357
|
+
import { readFileSync as readFileSync13, readdirSync as readdirSync12 } from "fs";
|
|
5358
|
+
import { join as join10, relative as relative6 } from "path";
|
|
5058
5359
|
function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
5059
5360
|
const projectRoot = getProjectRoot();
|
|
5060
5361
|
const absDir = join10(projectRoot, alembicDir);
|
|
@@ -5062,10 +5363,10 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
|
5062
5363
|
const versionsDir = join10(absDir, "versions");
|
|
5063
5364
|
let files = [];
|
|
5064
5365
|
try {
|
|
5065
|
-
files =
|
|
5366
|
+
files = readdirSync12(versionsDir).filter((f) => f.endsWith(".py")).map((f) => join10(versionsDir, f));
|
|
5066
5367
|
} catch {
|
|
5067
5368
|
try {
|
|
5068
|
-
files =
|
|
5369
|
+
files = readdirSync12(absDir).filter((f) => f.endsWith(".py") && f !== "env.py").map((f) => join10(absDir, f));
|
|
5069
5370
|
} catch {
|
|
5070
5371
|
}
|
|
5071
5372
|
}
|
|
@@ -5090,7 +5391,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
|
5090
5391
|
rows.push({
|
|
5091
5392
|
revision: parsed.revision,
|
|
5092
5393
|
downRevision: parsed.downRevision,
|
|
5093
|
-
file:
|
|
5394
|
+
file: relative6(projectRoot, absFile),
|
|
5094
5395
|
description: parsed.description,
|
|
5095
5396
|
operations: JSON.stringify(parsed.operations)
|
|
5096
5397
|
});
|
|
@@ -5113,8 +5414,8 @@ var init_migration_indexer = __esm({
|
|
|
5113
5414
|
});
|
|
5114
5415
|
|
|
5115
5416
|
// src/python/coupling-detector.ts
|
|
5116
|
-
import { readFileSync as readFileSync14, readdirSync as
|
|
5117
|
-
import { join as join11, relative as
|
|
5417
|
+
import { readFileSync as readFileSync14, readdirSync as readdirSync13 } from "fs";
|
|
5418
|
+
import { join as join11, relative as relative7 } from "path";
|
|
5118
5419
|
function buildPythonCouplingIndex(dataDb2) {
|
|
5119
5420
|
const projectRoot = getProjectRoot();
|
|
5120
5421
|
const config = getConfig();
|
|
@@ -5147,7 +5448,7 @@ function buildPythonCouplingIndex(dataDb2) {
|
|
|
5147
5448
|
];
|
|
5148
5449
|
dataDb2.transaction(() => {
|
|
5149
5450
|
for (const absFile of frontendFiles) {
|
|
5150
|
-
const relFile =
|
|
5451
|
+
const relFile = relative7(projectRoot, absFile);
|
|
5151
5452
|
let source;
|
|
5152
5453
|
try {
|
|
5153
5454
|
source = readFileSync14(absFile, "utf-8");
|
|
@@ -5178,7 +5479,7 @@ function walkFrontendFiles(dir) {
|
|
|
5178
5479
|
const files = [];
|
|
5179
5480
|
const exclude = ["node_modules", ".next", "dist", ".git", "__pycache__", ".venv", "venv"];
|
|
5180
5481
|
try {
|
|
5181
|
-
const entries =
|
|
5482
|
+
const entries = readdirSync13(dir, { withFileTypes: true });
|
|
5182
5483
|
for (const entry of entries) {
|
|
5183
5484
|
if (entry.isDirectory()) {
|
|
5184
5485
|
if (exclude.includes(entry.name)) continue;
|
|
@@ -5556,7 +5857,7 @@ var init_memory_tools = __esm({
|
|
|
5556
5857
|
|
|
5557
5858
|
// src/docs-tools.ts
|
|
5558
5859
|
import { readFileSync as readFileSync15, existsSync as existsSync13 } from "fs";
|
|
5559
|
-
import { resolve as
|
|
5860
|
+
import { resolve as resolve13, basename as basename4 } from "path";
|
|
5560
5861
|
function p2(baseName) {
|
|
5561
5862
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
5562
5863
|
}
|
|
@@ -5623,7 +5924,7 @@ function matchesPattern(filePath, pattern) {
|
|
|
5623
5924
|
function findAffectedMappings(docsMap, changedFiles) {
|
|
5624
5925
|
const affected = /* @__PURE__ */ new Map();
|
|
5625
5926
|
for (const file of changedFiles) {
|
|
5626
|
-
const fileName =
|
|
5927
|
+
const fileName = basename4(file);
|
|
5627
5928
|
for (const mapping of docsMap.mappings) {
|
|
5628
5929
|
let matched = false;
|
|
5629
5930
|
for (const routePattern of mapping.appRoutes) {
|
|
@@ -5684,9 +5985,9 @@ function extractFrontmatter(content) {
|
|
|
5684
5985
|
}
|
|
5685
5986
|
function extractProcedureNames(routerPath) {
|
|
5686
5987
|
const root = getProjectRoot();
|
|
5687
|
-
const absPath = ensureWithinRoot(
|
|
5988
|
+
const absPath = ensureWithinRoot(resolve13(getResolvedPaths().srcDir, "..", routerPath), root);
|
|
5688
5989
|
if (!existsSync13(absPath)) {
|
|
5689
|
-
const altPath = ensureWithinRoot(
|
|
5990
|
+
const altPath = ensureWithinRoot(resolve13(getResolvedPaths().srcDir, "../server/api/routers", basename4(routerPath)), root);
|
|
5690
5991
|
if (!existsSync13(altPath)) return [];
|
|
5691
5992
|
return extractProcedureNamesFromContent(readFileSync15(altPath, "utf-8"));
|
|
5692
5993
|
}
|
|
@@ -5730,7 +6031,7 @@ function handleDocsAudit(args2) {
|
|
|
5730
6031
|
for (const [mappingId, triggeringFiles] of affectedMappings) {
|
|
5731
6032
|
const mapping = docsMap.mappings.find((m) => m.id === mappingId);
|
|
5732
6033
|
if (!mapping) continue;
|
|
5733
|
-
const helpPagePath = ensureWithinRoot(
|
|
6034
|
+
const helpPagePath = ensureWithinRoot(resolve13(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
5734
6035
|
if (!existsSync13(helpPagePath)) {
|
|
5735
6036
|
results.push({
|
|
5736
6037
|
helpPage: mapping.helpPage,
|
|
@@ -5748,7 +6049,7 @@ function handleDocsAudit(args2) {
|
|
|
5748
6049
|
const frontmatter = extractFrontmatter(content);
|
|
5749
6050
|
const staleReasons = [];
|
|
5750
6051
|
for (const file of triggeringFiles) {
|
|
5751
|
-
const fileName =
|
|
6052
|
+
const fileName = basename4(file);
|
|
5752
6053
|
if (mapping.routers.includes(fileName)) {
|
|
5753
6054
|
const procedures = extractProcedureNames(file);
|
|
5754
6055
|
const undocumented = procedures.filter((p19) => !contentMentions(content, p19));
|
|
@@ -5779,11 +6080,11 @@ function handleDocsAudit(args2) {
|
|
|
5779
6080
|
reason: staleReasons.length > 0 ? staleReasons.join("; ") : "Content appears current",
|
|
5780
6081
|
sections,
|
|
5781
6082
|
changedFiles: triggeringFiles,
|
|
5782
|
-
suggestedAction: status === "STALE" ? `Review and update ${mapping.helpPage} to reflect changes in: ${triggeringFiles.map((f) =>
|
|
6083
|
+
suggestedAction: status === "STALE" ? `Review and update ${mapping.helpPage} to reflect changes in: ${triggeringFiles.map((f) => basename4(f)).join(", ")}` : "No action needed"
|
|
5783
6084
|
});
|
|
5784
6085
|
for (const [guideName, parentId] of Object.entries(docsMap.userGuideInheritance.examples)) {
|
|
5785
6086
|
if (parentId === mappingId) {
|
|
5786
|
-
const guidePath = ensureWithinRoot(
|
|
6087
|
+
const guidePath = ensureWithinRoot(resolve13(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
5787
6088
|
if (existsSync13(guidePath)) {
|
|
5788
6089
|
const guideContent = readFileSync15(guidePath, "utf-8");
|
|
5789
6090
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
@@ -5818,7 +6119,7 @@ function handleDocsCoverage(args2) {
|
|
|
5818
6119
|
const gaps = [];
|
|
5819
6120
|
const mappings = filterDomain ? docsMap.mappings.filter((m) => m.id === filterDomain) : docsMap.mappings;
|
|
5820
6121
|
for (const mapping of mappings) {
|
|
5821
|
-
const helpPagePath = ensureWithinRoot(
|
|
6122
|
+
const helpPagePath = ensureWithinRoot(resolve13(getResolvedPaths().helpSitePath, mapping.helpPage), getProjectRoot());
|
|
5822
6123
|
const exists = existsSync13(helpPagePath);
|
|
5823
6124
|
let hasContent = false;
|
|
5824
6125
|
let lineCount = 0;
|
|
@@ -6167,7 +6468,7 @@ var init_observability_tools = __esm({
|
|
|
6167
6468
|
|
|
6168
6469
|
// src/sentinel-db.ts
|
|
6169
6470
|
import { existsSync as existsSync14 } from "fs";
|
|
6170
|
-
import { resolve as
|
|
6471
|
+
import { resolve as resolve14 } from "path";
|
|
6171
6472
|
function parsePortalScope(raw) {
|
|
6172
6473
|
if (!raw) return [];
|
|
6173
6474
|
try {
|
|
@@ -6403,22 +6704,22 @@ function validateFeatures(db, domainFilter) {
|
|
|
6403
6704
|
const missingProcedures = [];
|
|
6404
6705
|
const missingPages = [];
|
|
6405
6706
|
for (const comp of components) {
|
|
6406
|
-
const absPath =
|
|
6707
|
+
const absPath = resolve14(PROJECT_ROOT, comp.component_file);
|
|
6407
6708
|
if (!existsSync14(absPath)) {
|
|
6408
6709
|
missingComponents.push(comp.component_file);
|
|
6409
6710
|
}
|
|
6410
6711
|
}
|
|
6411
6712
|
for (const proc of procedures) {
|
|
6412
|
-
const routerPath =
|
|
6713
|
+
const routerPath = resolve14(PROJECT_ROOT, `src/server/api/routers/${proc.router_name}.ts`);
|
|
6413
6714
|
if (!existsSync14(routerPath)) {
|
|
6414
6715
|
missingProcedures.push({ router: proc.router_name, procedure: proc.procedure_name });
|
|
6415
6716
|
}
|
|
6416
6717
|
}
|
|
6417
6718
|
for (const page of pages) {
|
|
6418
6719
|
const routeToPath = page.page_route.replace(/^\/(portal-[^/]+\/)?/, "src/app/").replace(/\/$/, "") + "/page.tsx";
|
|
6419
|
-
const absPath =
|
|
6720
|
+
const absPath = resolve14(PROJECT_ROOT, routeToPath);
|
|
6420
6721
|
if (page.page_route.startsWith("/") && !existsSync14(absPath)) {
|
|
6421
|
-
const altPath =
|
|
6722
|
+
const altPath = resolve14(PROJECT_ROOT, `src/app${page.page_route}/page.tsx`);
|
|
6422
6723
|
if (!existsSync14(altPath)) {
|
|
6423
6724
|
missingPages.push(page.page_route);
|
|
6424
6725
|
}
|
|
@@ -6943,8 +7244,8 @@ var init_sentinel_tools = __esm({
|
|
|
6943
7244
|
});
|
|
6944
7245
|
|
|
6945
7246
|
// src/sentinel-scanner.ts
|
|
6946
|
-
import { readFileSync as readFileSync16, existsSync as existsSync15, readdirSync as
|
|
6947
|
-
import { resolve as
|
|
7247
|
+
import { readFileSync as readFileSync16, existsSync as existsSync15, readdirSync as readdirSync14, statSync as statSync5 } from "fs";
|
|
7248
|
+
import { resolve as resolve15, join as join12, basename as basename5, dirname as dirname9, relative as relative8 } from "path";
|
|
6948
7249
|
function inferDomain(filePath) {
|
|
6949
7250
|
const domains = getConfig().domains;
|
|
6950
7251
|
const path = filePath.toLowerCase();
|
|
@@ -7073,10 +7374,10 @@ function scanComponentExports(dataDb2) {
|
|
|
7073
7374
|
const projectRoot = getProjectRoot();
|
|
7074
7375
|
const componentsBase = config.paths.components ?? config.paths.source + "/components";
|
|
7075
7376
|
const componentDirs = [];
|
|
7076
|
-
const basePath =
|
|
7377
|
+
const basePath = resolve15(projectRoot, componentsBase);
|
|
7077
7378
|
if (existsSync15(basePath)) {
|
|
7078
7379
|
try {
|
|
7079
|
-
const entries =
|
|
7380
|
+
const entries = readdirSync14(basePath, { withFileTypes: true });
|
|
7080
7381
|
for (const entry of entries) {
|
|
7081
7382
|
if (entry.isDirectory()) {
|
|
7082
7383
|
componentDirs.push(componentsBase + "/" + entry.name);
|
|
@@ -7086,11 +7387,11 @@ function scanComponentExports(dataDb2) {
|
|
|
7086
7387
|
}
|
|
7087
7388
|
}
|
|
7088
7389
|
for (const dir of componentDirs) {
|
|
7089
|
-
const absDir =
|
|
7390
|
+
const absDir = resolve15(projectRoot, dir);
|
|
7090
7391
|
if (!existsSync15(absDir)) continue;
|
|
7091
7392
|
const files = walkDir(absDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
|
|
7092
7393
|
for (const file of files) {
|
|
7093
|
-
const relPath =
|
|
7394
|
+
const relPath = relative8(projectRoot, file);
|
|
7094
7395
|
const source = readFileSync16(file, "utf-8");
|
|
7095
7396
|
const annotations = parseFeatureAnnotations(source);
|
|
7096
7397
|
if (annotations.length > 0) {
|
|
@@ -7117,7 +7418,7 @@ function scanComponentExports(dataDb2) {
|
|
|
7117
7418
|
if (hasHandlers && exportMatch) {
|
|
7118
7419
|
const componentName = exportMatch[1];
|
|
7119
7420
|
const domain = inferDomain(relPath);
|
|
7120
|
-
const subdomain =
|
|
7421
|
+
const subdomain = basename5(dirname9(relPath));
|
|
7121
7422
|
const featureKey = `component.${subdomain}.${componentName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "")}`;
|
|
7122
7423
|
if (!annotations.some((a) => a.featureKey === featureKey)) {
|
|
7123
7424
|
features.push({
|
|
@@ -7140,11 +7441,11 @@ function scanComponentExports(dataDb2) {
|
|
|
7140
7441
|
function walkDir(dir) {
|
|
7141
7442
|
const results = [];
|
|
7142
7443
|
try {
|
|
7143
|
-
const entries =
|
|
7444
|
+
const entries = readdirSync14(dir);
|
|
7144
7445
|
for (const entry of entries) {
|
|
7145
7446
|
const fullPath = join12(dir, entry);
|
|
7146
7447
|
try {
|
|
7147
|
-
const stat =
|
|
7448
|
+
const stat = statSync5(fullPath);
|
|
7148
7449
|
if (stat.isDirectory()) {
|
|
7149
7450
|
results.push(...walkDir(fullPath));
|
|
7150
7451
|
} else {
|
|
@@ -8934,7 +9235,7 @@ var init_security_scorer = __esm({
|
|
|
8934
9235
|
|
|
8935
9236
|
// src/dependency-scorer.ts
|
|
8936
9237
|
import { existsSync as existsSync18, readFileSync as readFileSync19 } from "fs";
|
|
8937
|
-
import { resolve as
|
|
9238
|
+
import { resolve as resolve16 } from "path";
|
|
8938
9239
|
function p12(baseName) {
|
|
8939
9240
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
8940
9241
|
}
|
|
@@ -8966,7 +9267,7 @@ function calculateDepRisk(factors) {
|
|
|
8966
9267
|
return Math.min(100, risk);
|
|
8967
9268
|
}
|
|
8968
9269
|
function getInstalledPackages(projectRoot) {
|
|
8969
|
-
const pkgPath =
|
|
9270
|
+
const pkgPath = resolve16(projectRoot, "package.json");
|
|
8970
9271
|
if (!existsSync18(pkgPath)) return /* @__PURE__ */ new Map();
|
|
8971
9272
|
try {
|
|
8972
9273
|
const pkg = JSON.parse(readFileSync19(pkgPath, "utf-8"));
|
|
@@ -9572,8 +9873,8 @@ var init_regression_detector = __esm({
|
|
|
9572
9873
|
|
|
9573
9874
|
// src/knowledge-indexer.ts
|
|
9574
9875
|
import { createHash as createHash2 } from "crypto";
|
|
9575
|
-
import { readFileSync as readFileSync20, readdirSync as
|
|
9576
|
-
import { resolve as
|
|
9876
|
+
import { readFileSync as readFileSync20, readdirSync as readdirSync15, statSync as statSync6, existsSync as existsSync19 } from "fs";
|
|
9877
|
+
import { resolve as resolve17, relative as relative9, basename as basename6, extname } from "path";
|
|
9577
9878
|
function getKnowledgePaths() {
|
|
9578
9879
|
const resolved = getResolvedPaths();
|
|
9579
9880
|
const config = getConfig();
|
|
@@ -9599,9 +9900,9 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
9599
9900
|
const files = [];
|
|
9600
9901
|
function walk(dir) {
|
|
9601
9902
|
try {
|
|
9602
|
-
const entries =
|
|
9903
|
+
const entries = readdirSync15(dir, { withFileTypes: true });
|
|
9603
9904
|
for (const entry of entries) {
|
|
9604
|
-
const fullPath =
|
|
9905
|
+
const fullPath = resolve17(dir, entry.name);
|
|
9605
9906
|
if (entry.isDirectory()) {
|
|
9606
9907
|
if (entry.name === "archive" && dir.includes("session-state")) continue;
|
|
9607
9908
|
if (entry.name === "archive" && dir.includes("status")) continue;
|
|
@@ -9621,7 +9922,7 @@ function categorizeFile(filePath) {
|
|
|
9621
9922
|
const paths = getKnowledgePaths();
|
|
9622
9923
|
if (filePath.startsWith(paths.plansDir)) return "plan";
|
|
9623
9924
|
if (filePath.startsWith(paths.docsDir)) {
|
|
9624
|
-
const relFromDocs =
|
|
9925
|
+
const relFromDocs = relative9(paths.docsDir, filePath).replace(/\\/g, "/").toLowerCase();
|
|
9625
9926
|
if (relFromDocs.startsWith("plans/")) return "plan";
|
|
9626
9927
|
if (relFromDocs.includes("architecture")) return "architecture";
|
|
9627
9928
|
if (relFromDocs.includes("security")) return "security";
|
|
@@ -9637,7 +9938,7 @@ function categorizeFile(filePath) {
|
|
|
9637
9938
|
}
|
|
9638
9939
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
9639
9940
|
if (filePath.includes(`${claudeDirName}/projects/`) && filePath.includes("/memory/")) return "memory";
|
|
9640
|
-
const rel =
|
|
9941
|
+
const rel = relative9(paths.claudeDir, filePath).replace(/\\/g, "/");
|
|
9641
9942
|
const firstDir = rel.split("/")[0];
|
|
9642
9943
|
const knownCategories = getConfig().conventions?.knowledgeCategories ?? [
|
|
9643
9944
|
"patterns",
|
|
@@ -9778,7 +10079,7 @@ function parseCorrections(content) {
|
|
|
9778
10079
|
function extractTitle(content, filePath) {
|
|
9779
10080
|
const h1Match = content.match(/^#\s+(.+)/m);
|
|
9780
10081
|
if (h1Match) return h1Match[1].trim();
|
|
9781
|
-
return
|
|
10082
|
+
return basename6(filePath, ".md");
|
|
9782
10083
|
}
|
|
9783
10084
|
function extractDescription2(content) {
|
|
9784
10085
|
const fmMatch = content.match(/^---\s*\n[\s\S]*?description:\s*"?([^"\n]+)"?\s*\n[\s\S]*?---/);
|
|
@@ -9807,7 +10108,7 @@ function buildCrossReferences(db) {
|
|
|
9807
10108
|
}
|
|
9808
10109
|
}
|
|
9809
10110
|
if (rule.reference_path) {
|
|
9810
|
-
const patternName =
|
|
10111
|
+
const patternName = basename6(rule.reference_path, ".md");
|
|
9811
10112
|
insertEdge.run("cr", rule.rule_id, "pattern", patternName, "references");
|
|
9812
10113
|
edgeCount++;
|
|
9813
10114
|
}
|
|
@@ -9929,7 +10230,7 @@ function indexAllKnowledge(db) {
|
|
|
9929
10230
|
if (!existsSync19(filePath)) continue;
|
|
9930
10231
|
const content = readFileSync20(filePath, "utf-8");
|
|
9931
10232
|
const hash = hashContent(content);
|
|
9932
|
-
const relPath = filePath.startsWith(paths.claudeDir) ?
|
|
10233
|
+
const relPath = filePath.startsWith(paths.claudeDir) ? relative9(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative9(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative9(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative9(paths.memoryDir, filePath)}` : basename6(filePath);
|
|
9933
10234
|
const category = categorizeFile(filePath);
|
|
9934
10235
|
const title = extractTitle(content, filePath);
|
|
9935
10236
|
const description = extractDescription2(content);
|
|
@@ -9943,10 +10244,10 @@ function indexAllKnowledge(db) {
|
|
|
9943
10244
|
stats.chunksCreated++;
|
|
9944
10245
|
}
|
|
9945
10246
|
}
|
|
9946
|
-
const fileName =
|
|
10247
|
+
const fileName = basename6(filePath);
|
|
9947
10248
|
const fileNameLower = fileName.toLowerCase();
|
|
9948
10249
|
const relPathLower = relPath.toLowerCase();
|
|
9949
|
-
const claudeMdName =
|
|
10250
|
+
const claudeMdName = basename6(getResolvedPaths().claudeMdPath).toLowerCase();
|
|
9950
10251
|
if (fileNameLower === claudeMdName || relPathLower.includes(claudeMdName)) {
|
|
9951
10252
|
const crRules = parseCRTable(content);
|
|
9952
10253
|
for (const rule of crRules) {
|
|
@@ -9980,12 +10281,12 @@ function indexAllKnowledge(db) {
|
|
|
9980
10281
|
}
|
|
9981
10282
|
}
|
|
9982
10283
|
if (category === "commands" && fileName !== "_shared-preamble.md") {
|
|
9983
|
-
const cmdName =
|
|
10284
|
+
const cmdName = basename6(filePath, ".md");
|
|
9984
10285
|
insertChunk.run(docId, "command", cmdName, content.substring(0, 1e3), 1, null, JSON.stringify({ command_name: cmdName }));
|
|
9985
10286
|
stats.chunksCreated++;
|
|
9986
10287
|
}
|
|
9987
10288
|
if (category === "plan") {
|
|
9988
|
-
const planItemRegex = /^###\s+(P
|
|
10289
|
+
const planItemRegex = /^###\s+(P[-A-Z]*\d*-?\w+):\s+(.+)$/gm;
|
|
9989
10290
|
let planMatch;
|
|
9990
10291
|
while ((planMatch = planItemRegex.exec(content)) !== null) {
|
|
9991
10292
|
insertChunk.run(docId, "pattern", planMatch[1], `${planMatch[1]}: ${planMatch[2]}`, null, null, JSON.stringify({ plan_item_id: planMatch[1] }));
|
|
@@ -10057,7 +10358,7 @@ function isKnowledgeStale(db) {
|
|
|
10057
10358
|
}
|
|
10058
10359
|
for (const filePath of files) {
|
|
10059
10360
|
try {
|
|
10060
|
-
const stat =
|
|
10361
|
+
const stat = statSync6(filePath);
|
|
10061
10362
|
if (stat.mtimeMs > lastIndexTime) return true;
|
|
10062
10363
|
} catch {
|
|
10063
10364
|
continue;
|
|
@@ -10079,8 +10380,8 @@ var init_knowledge_indexer = __esm({
|
|
|
10079
10380
|
});
|
|
10080
10381
|
|
|
10081
10382
|
// src/knowledge-tools.ts
|
|
10082
|
-
import { readFileSync as readFileSync21, writeFileSync as writeFileSync3, appendFileSync, readdirSync as
|
|
10083
|
-
import { resolve as
|
|
10383
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync3, appendFileSync, readdirSync as readdirSync16 } from "fs";
|
|
10384
|
+
import { resolve as resolve18, basename as basename7 } from "path";
|
|
10084
10385
|
function p15(baseName) {
|
|
10085
10386
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
10086
10387
|
}
|
|
@@ -10817,7 +11118,7 @@ function handleCorrect(db, args2) {
|
|
|
10817
11118
|
if (!wrong || !correction || !rule) {
|
|
10818
11119
|
return text15("Error: wrong, correction, and rule are all required.");
|
|
10819
11120
|
}
|
|
10820
|
-
const correctionsPath =
|
|
11121
|
+
const correctionsPath = resolve18(getResolvedPaths().memoryDir, "corrections.md");
|
|
10821
11122
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
10822
11123
|
const title = rule.slice(0, 60);
|
|
10823
11124
|
const entry = `
|
|
@@ -10879,7 +11180,7 @@ function handlePlan(db, args2) {
|
|
|
10879
11180
|
AND kc.content LIKE ?
|
|
10880
11181
|
ORDER BY kd.file_path DESC
|
|
10881
11182
|
LIMIT 20
|
|
10882
|
-
`).all(`%${
|
|
11183
|
+
`).all(`%${basename7(file)}%`);
|
|
10883
11184
|
lines.push(`## Plans referencing \`${file}\` (${results.length} found)`);
|
|
10884
11185
|
lines.push("");
|
|
10885
11186
|
for (const r of results) {
|
|
@@ -11012,7 +11313,7 @@ function handleGaps(db, args2) {
|
|
|
11012
11313
|
} else if (checkType === "routers") {
|
|
11013
11314
|
try {
|
|
11014
11315
|
const routersDir = getResolvedPaths().routersDir;
|
|
11015
|
-
const routerFiles =
|
|
11316
|
+
const routerFiles = readdirSync16(routersDir).filter((f) => f.endsWith(".ts") && !f.startsWith("_"));
|
|
11016
11317
|
lines.push(`| Router | Knowledge Hits | Status |`);
|
|
11017
11318
|
lines.push(`|--------|----------------|--------|`);
|
|
11018
11319
|
for (const file of routerFiles) {
|
|
@@ -11909,7 +12210,7 @@ var init_python_tools = __esm({
|
|
|
11909
12210
|
// src/mcp-bridge-tools.ts
|
|
11910
12211
|
import { spawn } from "child_process";
|
|
11911
12212
|
import { readFileSync as readFileSync22, existsSync as existsSync22 } from "fs";
|
|
11912
|
-
import { resolve as
|
|
12213
|
+
import { resolve as resolve19 } from "path";
|
|
11913
12214
|
function p17(baseName) {
|
|
11914
12215
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
11915
12216
|
}
|
|
@@ -11930,7 +12231,7 @@ function buildSubprocessEnv() {
|
|
|
11930
12231
|
}
|
|
11931
12232
|
function loadMcpConfig() {
|
|
11932
12233
|
const root = getProjectRoot();
|
|
11933
|
-
const mcpPath =
|
|
12234
|
+
const mcpPath = resolve19(root, ".mcp.json");
|
|
11934
12235
|
if (!existsSync22(mcpPath)) return {};
|
|
11935
12236
|
try {
|
|
11936
12237
|
const raw = JSON.parse(readFileSync22(mcpPath, "utf-8"));
|
|
@@ -11958,7 +12259,7 @@ async function mcpRequest(conn, method, params = {}) {
|
|
|
11958
12259
|
method,
|
|
11959
12260
|
params
|
|
11960
12261
|
};
|
|
11961
|
-
return new Promise((
|
|
12262
|
+
return new Promise((resolve23, reject) => {
|
|
11962
12263
|
const timeout = setTimeout(() => {
|
|
11963
12264
|
conn.process?.stdout?.removeListener("data", onData);
|
|
11964
12265
|
reject(new Error(`MCP request timed out: ${method}`));
|
|
@@ -11978,7 +12279,7 @@ async function mcpRequest(conn, method, params = {}) {
|
|
|
11978
12279
|
if (response.error) {
|
|
11979
12280
|
reject(new Error(`MCP error ${response.error.code}: ${response.error.message}`));
|
|
11980
12281
|
} else {
|
|
11981
|
-
|
|
12282
|
+
resolve23(response.result || {});
|
|
11982
12283
|
}
|
|
11983
12284
|
return;
|
|
11984
12285
|
}
|
|
@@ -12000,7 +12301,7 @@ async function connectToServer(name, config) {
|
|
|
12000
12301
|
return existing;
|
|
12001
12302
|
}
|
|
12002
12303
|
const root = getProjectRoot();
|
|
12003
|
-
const cwd = config.cwd ?
|
|
12304
|
+
const cwd = config.cwd ? resolve19(root, config.cwd) : root;
|
|
12004
12305
|
const args2 = config.args || [];
|
|
12005
12306
|
const proc = spawn(config.command, args2, {
|
|
12006
12307
|
cwd,
|
|
@@ -12262,7 +12563,7 @@ var init_mcp_bridge_tools = __esm({
|
|
|
12262
12563
|
|
|
12263
12564
|
// src/tools.ts
|
|
12264
12565
|
import { readFileSync as readFileSync23, existsSync as existsSync23 } from "fs";
|
|
12265
|
-
import { resolve as
|
|
12566
|
+
import { resolve as resolve20, basename as basename8 } from "path";
|
|
12266
12567
|
function prefix() {
|
|
12267
12568
|
return getConfig().toolPrefix;
|
|
12268
12569
|
}
|
|
@@ -12297,7 +12598,7 @@ function ensureIndexes(dataDb2, codegraphDb2, force = false) {
|
|
|
12297
12598
|
if (config.python?.root) {
|
|
12298
12599
|
const pythonRoot = config.python.root;
|
|
12299
12600
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
12300
|
-
if (force || isPythonDataStale(dataDb2,
|
|
12601
|
+
if (force || isPythonDataStale(dataDb2, resolve20(getProjectRoot(), pythonRoot))) {
|
|
12301
12602
|
const pyImports = buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs);
|
|
12302
12603
|
results.push(`Python imports: ${pyImports}`);
|
|
12303
12604
|
const pyRoutes = buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs);
|
|
@@ -12701,7 +13002,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
12701
13002
|
try {
|
|
12702
13003
|
const resolvedPaths = getResolvedPaths();
|
|
12703
13004
|
const root = getProjectRoot();
|
|
12704
|
-
const absFilePath = ensureWithinRoot(
|
|
13005
|
+
const absFilePath = ensureWithinRoot(resolve20(resolvedPaths.srcDir, "..", file), root);
|
|
12705
13006
|
if (existsSync23(absFilePath)) {
|
|
12706
13007
|
const fileContent = readFileSync23(absFilePath, "utf-8").slice(0, 3e3);
|
|
12707
13008
|
const keywords = [];
|
|
@@ -12797,7 +13098,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
12797
13098
|
WHERE o.files_involved LIKE ?
|
|
12798
13099
|
ORDER BY o.importance DESC, o.created_at_epoch DESC
|
|
12799
13100
|
LIMIT 5
|
|
12800
|
-
`).all(`%${
|
|
13101
|
+
`).all(`%${basename8(file)}%`);
|
|
12801
13102
|
if (fileObservations.length > 0) {
|
|
12802
13103
|
lines.push("## Past Observations (This File)");
|
|
12803
13104
|
for (const obs of fileObservations) {
|
|
@@ -12813,7 +13114,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
12813
13114
|
WHERE type = 'failed_attempt' AND files_involved LIKE ?
|
|
12814
13115
|
ORDER BY recurrence_count DESC
|
|
12815
13116
|
LIMIT 3
|
|
12816
|
-
`).all(`%${
|
|
13117
|
+
`).all(`%${basename8(file)}%`);
|
|
12817
13118
|
if (failures.length > 0) {
|
|
12818
13119
|
lines.push("## Failed Attempts (DO NOT RETRY)");
|
|
12819
13120
|
for (const f of failures) {
|
|
@@ -13127,7 +13428,7 @@ function handleSchema(args2) {
|
|
|
13127
13428
|
lines.push("Checking all column references against Prisma schema...");
|
|
13128
13429
|
lines.push("");
|
|
13129
13430
|
const projectRoot = getProjectRoot();
|
|
13130
|
-
const absPath = ensureWithinRoot(
|
|
13431
|
+
const absPath = ensureWithinRoot(resolve20(projectRoot, file), projectRoot);
|
|
13131
13432
|
if (!existsSync23(absPath)) {
|
|
13132
13433
|
return text18(`File not found: ${file}`);
|
|
13133
13434
|
}
|
|
@@ -13211,7 +13512,7 @@ var init_tools = __esm({
|
|
|
13211
13512
|
// src/server.ts
|
|
13212
13513
|
var server_exports = {};
|
|
13213
13514
|
import { readFileSync as readFileSync24 } from "fs";
|
|
13214
|
-
import { resolve as
|
|
13515
|
+
import { resolve as resolve21, dirname as dirname11 } from "path";
|
|
13215
13516
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13216
13517
|
function getDb() {
|
|
13217
13518
|
if (!codegraphDb) codegraphDb = getCodeGraphDb();
|
|
@@ -13306,7 +13607,7 @@ var init_server = __esm({
|
|
|
13306
13607
|
__dirname4 = dirname11(fileURLToPath4(import.meta.url));
|
|
13307
13608
|
PKG_VERSION = (() => {
|
|
13308
13609
|
try {
|
|
13309
|
-
const pkg = JSON.parse(readFileSync24(
|
|
13610
|
+
const pkg = JSON.parse(readFileSync24(resolve21(__dirname4, "..", "package.json"), "utf-8"));
|
|
13310
13611
|
return pkg.version ?? "0.0.0";
|
|
13311
13612
|
} catch {
|
|
13312
13613
|
return "0.0.0";
|
|
@@ -13371,7 +13672,7 @@ var init_server = __esm({
|
|
|
13371
13672
|
|
|
13372
13673
|
// src/cli.ts
|
|
13373
13674
|
import { readFileSync as readFileSync25 } from "fs";
|
|
13374
|
-
import { resolve as
|
|
13675
|
+
import { resolve as resolve22, dirname as dirname12 } from "path";
|
|
13375
13676
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
13376
13677
|
var __filename4 = fileURLToPath5(import.meta.url);
|
|
13377
13678
|
var __dirname5 = dirname12(__filename4);
|
|
@@ -13445,7 +13746,7 @@ Documentation: https://massu.ai/docs
|
|
|
13445
13746
|
}
|
|
13446
13747
|
function printVersion() {
|
|
13447
13748
|
try {
|
|
13448
|
-
const pkg = JSON.parse(readFileSync25(
|
|
13749
|
+
const pkg = JSON.parse(readFileSync25(resolve22(__dirname5, "../package.json"), "utf-8"));
|
|
13449
13750
|
console.log(`massu v${pkg.version}`);
|
|
13450
13751
|
} catch {
|
|
13451
13752
|
console.log("massu v0.1.0");
|