@massu/core 0.5.0 → 0.6.1
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/agents/massu-architecture-reviewer.md +104 -0
- package/agents/massu-blast-radius-analyzer.md +84 -0
- package/agents/massu-competitive-scorer.md +126 -0
- package/agents/massu-help-sync.md +73 -0
- package/agents/massu-migration-writer.md +94 -0
- package/agents/massu-output-scorer.md +87 -0
- package/agents/massu-pattern-reviewer.md +84 -0
- package/agents/massu-plan-auditor.md +170 -0
- package/agents/massu-schema-sync-verifier.md +70 -0
- package/agents/massu-security-reviewer.md +98 -0
- package/agents/massu-ux-reviewer.md +106 -0
- package/commands/_shared-preamble.md +53 -23
- package/commands/_shared-references/auto-learning-protocol.md +71 -0
- package/commands/_shared-references/blast-radius-protocol.md +76 -0
- package/commands/_shared-references/security-pre-screen.md +64 -0
- package/commands/_shared-references/test-first-protocol.md +87 -0
- package/commands/_shared-references/verification-table.md +55 -0
- package/commands/massu-article-review.md +343 -0
- package/commands/massu-autoresearch/references/eval-runner.md +84 -0
- package/commands/massu-autoresearch/references/safety-rails.md +125 -0
- package/commands/massu-autoresearch/references/scoring-protocol.md +151 -0
- package/commands/massu-autoresearch.md +258 -0
- package/commands/massu-batch.md +44 -12
- package/commands/massu-bearings.md +42 -8
- package/commands/massu-checkpoint.md +588 -0
- package/commands/massu-ci-fix.md +2 -2
- package/commands/massu-command-health.md +132 -0
- package/commands/massu-command-improve.md +232 -0
- package/commands/massu-commit.md +205 -44
- package/commands/massu-create-plan.md +239 -57
- package/commands/massu-data/references/common-queries.md +79 -0
- package/commands/massu-data/references/table-guide.md +50 -0
- package/commands/massu-data.md +66 -0
- package/commands/massu-dead-code.md +29 -34
- package/commands/massu-debug/references/auto-learning.md +61 -0
- package/commands/massu-debug/references/codegraph-tracing.md +80 -0
- package/commands/massu-debug/references/common-shortcuts.md +98 -0
- package/commands/massu-debug/references/investigation-phases.md +294 -0
- package/commands/massu-debug/references/report-format.md +107 -0
- package/commands/massu-debug.md +105 -386
- package/commands/massu-docs.md +1 -1
- package/commands/massu-full-audit.md +61 -0
- package/commands/massu-gap-enhancement-analyzer.md +276 -16
- package/commands/massu-golden-path/references/approval-points.md +216 -0
- package/commands/massu-golden-path/references/competitive-mode.md +273 -0
- package/commands/massu-golden-path/references/error-handling.md +121 -0
- package/commands/massu-golden-path/references/phase-0-requirements.md +53 -0
- package/commands/massu-golden-path/references/phase-1-plan-creation.md +168 -0
- package/commands/massu-golden-path/references/phase-2-implementation.md +403 -0
- package/commands/massu-golden-path/references/phase-2.5-gap-analyzer.md +170 -0
- package/commands/massu-golden-path/references/phase-3-simplify.md +40 -0
- package/commands/massu-golden-path/references/phase-3.5-security-audit.md +108 -0
- package/commands/massu-golden-path/references/phase-4-commit.md +94 -0
- package/commands/massu-golden-path/references/phase-5-push.md +116 -0
- package/commands/massu-golden-path/references/phase-5.5-production-verify.md +170 -0
- package/commands/massu-golden-path/references/phase-6-completion.md +113 -0
- package/commands/massu-golden-path/references/qa-evaluator-spec.md +137 -0
- package/commands/massu-golden-path/references/sprint-contract-protocol.md +117 -0
- package/commands/massu-golden-path/references/vr-visual-calibration.md +73 -0
- package/commands/massu-golden-path.md +121 -844
- package/commands/massu-guide.md +72 -69
- package/commands/massu-hooks.md +27 -12
- package/commands/massu-hotfix.md +221 -144
- package/commands/massu-incident.md +49 -20
- package/commands/massu-infra-audit.md +187 -0
- package/commands/massu-learning-audit.md +211 -0
- package/commands/massu-loop/references/auto-learning.md +49 -0
- package/commands/massu-loop/references/checkpoint-audit.md +40 -0
- package/commands/massu-loop/references/guardrails.md +17 -0
- package/commands/massu-loop/references/iteration-structure.md +115 -0
- package/commands/massu-loop/references/loop-controller.md +188 -0
- package/commands/massu-loop/references/plan-extraction.md +78 -0
- package/commands/massu-loop/references/vr-plan-spec.md +140 -0
- package/commands/massu-loop-playwright.md +9 -9
- package/commands/massu-loop.md +115 -670
- package/commands/massu-new-pattern.md +423 -0
- package/commands/massu-perf.md +422 -0
- package/commands/massu-plan-audit.md +1 -1
- package/commands/massu-plan.md +389 -122
- package/commands/massu-production-verify.md +433 -0
- package/commands/massu-push.md +62 -378
- package/commands/massu-recap.md +29 -3
- package/commands/massu-rollback.md +613 -0
- package/commands/massu-scaffold-hook.md +2 -4
- package/commands/massu-scaffold-page.md +2 -3
- package/commands/massu-scaffold-router.md +1 -2
- package/commands/massu-security.md +619 -0
- package/commands/massu-simplify.md +115 -85
- package/commands/massu-squirrels.md +2 -2
- package/commands/massu-tdd.md +38 -22
- package/commands/massu-test.md +3 -3
- package/commands/massu-type-mismatch-audit.md +469 -0
- package/commands/massu-ui-audit.md +587 -0
- package/commands/massu-verify-playwright.md +287 -32
- package/commands/massu-verify.md +150 -46
- package/dist/cli.js +146 -95
- package/package.json +6 -2
- package/patterns/build-patterns.md +302 -0
- package/patterns/component-patterns.md +246 -0
- package/patterns/display-patterns.md +185 -0
- package/patterns/form-patterns.md +890 -0
- package/patterns/integration-testing-checklist.md +445 -0
- package/patterns/security-patterns.md +219 -0
- package/patterns/testing-patterns.md +569 -0
- package/patterns/tool-routing.md +81 -0
- package/patterns/ui-patterns.md +371 -0
- package/protocols/plan-implementation.md +267 -0
- package/protocols/recovery.md +225 -0
- package/protocols/verification.md +404 -0
- package/reference/command-taxonomy.md +178 -0
- package/reference/cr-rules-reference.md +76 -0
- package/reference/hook-execution-order.md +148 -0
- package/reference/lessons-learned.md +175 -0
- package/reference/patterns-quickref.md +208 -0
- package/reference/standards.md +135 -0
- package/reference/subagents-reference.md +17 -0
- package/reference/vr-verification-reference.md +867 -0
- package/src/commands/install-commands.ts +149 -53
package/dist/cli.js
CHANGED
|
@@ -1397,94 +1397,145 @@ var init_memory_file_ingest = __esm({
|
|
|
1397
1397
|
// src/commands/install-commands.ts
|
|
1398
1398
|
var install_commands_exports = {};
|
|
1399
1399
|
__export(install_commands_exports, {
|
|
1400
|
+
installAll: () => installAll,
|
|
1400
1401
|
installCommands: () => installCommands,
|
|
1402
|
+
resolveAssetDir: () => resolveAssetDir,
|
|
1401
1403
|
resolveCommandsDir: () => resolveCommandsDir,
|
|
1402
1404
|
runInstallCommands: () => runInstallCommands
|
|
1403
1405
|
});
|
|
1404
|
-
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } from "fs";
|
|
1406
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync, mkdirSync as mkdirSync2, readdirSync as readdirSync2, statSync } from "fs";
|
|
1405
1407
|
import { resolve as resolve3, dirname as dirname3 } from "path";
|
|
1406
1408
|
import { fileURLToPath } from "url";
|
|
1407
|
-
function
|
|
1409
|
+
function resolveAssetDir(assetName) {
|
|
1408
1410
|
const cwd = process.cwd();
|
|
1409
|
-
const nodeModulesPath = resolve3(cwd, "node_modules/@massu/core
|
|
1411
|
+
const nodeModulesPath = resolve3(cwd, "node_modules/@massu/core", assetName);
|
|
1410
1412
|
if (existsSync4(nodeModulesPath)) {
|
|
1411
1413
|
return nodeModulesPath;
|
|
1412
1414
|
}
|
|
1413
|
-
const distRelPath = resolve3(__dirname, "
|
|
1415
|
+
const distRelPath = resolve3(__dirname, "..", assetName);
|
|
1414
1416
|
if (existsSync4(distRelPath)) {
|
|
1415
1417
|
return distRelPath;
|
|
1416
1418
|
}
|
|
1417
|
-
const srcRelPath = resolve3(__dirname, "
|
|
1419
|
+
const srcRelPath = resolve3(__dirname, "../..", assetName);
|
|
1418
1420
|
if (existsSync4(srcRelPath)) {
|
|
1419
1421
|
return srcRelPath;
|
|
1420
1422
|
}
|
|
1421
1423
|
return null;
|
|
1422
1424
|
}
|
|
1425
|
+
function resolveCommandsDir() {
|
|
1426
|
+
return resolveAssetDir("commands");
|
|
1427
|
+
}
|
|
1428
|
+
function syncDirectory(sourceDir, targetDir) {
|
|
1429
|
+
const stats = { installed: 0, updated: 0, skipped: 0 };
|
|
1430
|
+
if (!existsSync4(targetDir)) {
|
|
1431
|
+
mkdirSync2(targetDir, { recursive: true });
|
|
1432
|
+
}
|
|
1433
|
+
const entries = readdirSync2(sourceDir);
|
|
1434
|
+
for (const entry of entries) {
|
|
1435
|
+
const sourcePath = resolve3(sourceDir, entry);
|
|
1436
|
+
const targetPath = resolve3(targetDir, entry);
|
|
1437
|
+
const entryStat = statSync(sourcePath);
|
|
1438
|
+
if (entryStat.isDirectory()) {
|
|
1439
|
+
const subStats = syncDirectory(sourcePath, targetPath);
|
|
1440
|
+
stats.installed += subStats.installed;
|
|
1441
|
+
stats.updated += subStats.updated;
|
|
1442
|
+
stats.skipped += subStats.skipped;
|
|
1443
|
+
} else if (entry.endsWith(".md")) {
|
|
1444
|
+
const sourceContent = readFileSync3(sourcePath, "utf-8");
|
|
1445
|
+
if (existsSync4(targetPath)) {
|
|
1446
|
+
const existingContent = readFileSync3(targetPath, "utf-8");
|
|
1447
|
+
if (existingContent === sourceContent) {
|
|
1448
|
+
stats.skipped++;
|
|
1449
|
+
continue;
|
|
1450
|
+
}
|
|
1451
|
+
writeFileSync(targetPath, sourceContent, "utf-8");
|
|
1452
|
+
stats.updated++;
|
|
1453
|
+
} else {
|
|
1454
|
+
writeFileSync(targetPath, sourceContent, "utf-8");
|
|
1455
|
+
stats.installed++;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return stats;
|
|
1460
|
+
}
|
|
1423
1461
|
function installCommands(projectRoot) {
|
|
1424
1462
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
1425
1463
|
const targetDir = resolve3(projectRoot, claudeDirName, "commands");
|
|
1426
1464
|
if (!existsSync4(targetDir)) {
|
|
1427
1465
|
mkdirSync2(targetDir, { recursive: true });
|
|
1428
1466
|
}
|
|
1429
|
-
const sourceDir =
|
|
1467
|
+
const sourceDir = resolveAssetDir("commands");
|
|
1430
1468
|
if (!sourceDir) {
|
|
1431
1469
|
console.error(" ERROR: Could not find massu commands directory.");
|
|
1432
1470
|
console.error(" Try reinstalling: npm install @massu/core");
|
|
1433
1471
|
return { installed: 0, updated: 0, skipped: 0, commandsDir: targetDir };
|
|
1434
1472
|
}
|
|
1435
|
-
const
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
writeFileSync(targetPath, sourceContent, "utf-8");
|
|
1450
|
-
updated++;
|
|
1451
|
-
} else {
|
|
1452
|
-
writeFileSync(targetPath, sourceContent, "utf-8");
|
|
1453
|
-
installed++;
|
|
1473
|
+
const stats = syncDirectory(sourceDir, targetDir);
|
|
1474
|
+
return { ...stats, commandsDir: targetDir };
|
|
1475
|
+
}
|
|
1476
|
+
function installAll(projectRoot) {
|
|
1477
|
+
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
1478
|
+
const claudeDir = resolve3(projectRoot, claudeDirName);
|
|
1479
|
+
const assets = {};
|
|
1480
|
+
let totalInstalled = 0;
|
|
1481
|
+
let totalUpdated = 0;
|
|
1482
|
+
let totalSkipped = 0;
|
|
1483
|
+
for (const assetType of ASSET_TYPES) {
|
|
1484
|
+
const sourceDir = resolveAssetDir(assetType.name);
|
|
1485
|
+
if (!sourceDir) {
|
|
1486
|
+
continue;
|
|
1454
1487
|
}
|
|
1488
|
+
const targetDir = resolve3(claudeDir, assetType.targetSubdir);
|
|
1489
|
+
const stats = syncDirectory(sourceDir, targetDir);
|
|
1490
|
+
assets[assetType.name] = stats;
|
|
1491
|
+
totalInstalled += stats.installed;
|
|
1492
|
+
totalUpdated += stats.updated;
|
|
1493
|
+
totalSkipped += stats.skipped;
|
|
1455
1494
|
}
|
|
1456
|
-
return {
|
|
1495
|
+
return { assets, totalInstalled, totalUpdated, totalSkipped, claudeDir };
|
|
1457
1496
|
}
|
|
1458
1497
|
async function runInstallCommands() {
|
|
1459
1498
|
const projectRoot = process.cwd();
|
|
1460
1499
|
console.log("");
|
|
1461
|
-
console.log("Massu AI - Install
|
|
1500
|
+
console.log("Massu AI - Install Project Assets");
|
|
1462
1501
|
console.log("==================================");
|
|
1463
1502
|
console.log("");
|
|
1464
|
-
const result =
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1503
|
+
const result = installAll(projectRoot);
|
|
1504
|
+
for (const assetType of ASSET_TYPES) {
|
|
1505
|
+
const stats = result.assets[assetType.name];
|
|
1506
|
+
if (!stats) {
|
|
1507
|
+
continue;
|
|
1508
|
+
}
|
|
1509
|
+
const total = stats.installed + stats.updated + stats.skipped;
|
|
1510
|
+
if (total === 0) continue;
|
|
1511
|
+
const parts = [];
|
|
1512
|
+
if (stats.installed > 0) parts.push(`${stats.installed} new`);
|
|
1513
|
+
if (stats.updated > 0) parts.push(`${stats.updated} updated`);
|
|
1514
|
+
if (stats.skipped > 0) parts.push(`${stats.skipped} current`);
|
|
1515
|
+
const description = assetType.description;
|
|
1516
|
+
console.log(` ${description}: ${parts.join(", ")} (${total} total)`);
|
|
1473
1517
|
}
|
|
1474
|
-
const
|
|
1518
|
+
const grandTotal = result.totalInstalled + result.totalUpdated + result.totalSkipped;
|
|
1475
1519
|
console.log("");
|
|
1476
|
-
console.log(` ${
|
|
1520
|
+
console.log(` ${grandTotal} total files synced to ${result.claudeDir}`);
|
|
1477
1521
|
console.log("");
|
|
1478
1522
|
console.log(" Restart your Claude Code session to use them.");
|
|
1479
1523
|
console.log("");
|
|
1480
1524
|
}
|
|
1481
|
-
var __filename, __dirname;
|
|
1525
|
+
var __filename, __dirname, ASSET_TYPES;
|
|
1482
1526
|
var init_install_commands = __esm({
|
|
1483
1527
|
"src/commands/install-commands.ts"() {
|
|
1484
1528
|
"use strict";
|
|
1485
1529
|
init_config();
|
|
1486
1530
|
__filename = fileURLToPath(import.meta.url);
|
|
1487
1531
|
__dirname = dirname3(__filename);
|
|
1532
|
+
ASSET_TYPES = [
|
|
1533
|
+
{ name: "commands", targetSubdir: "commands", description: "slash commands" },
|
|
1534
|
+
{ name: "agents", targetSubdir: "agents", description: "agent definitions" },
|
|
1535
|
+
{ name: "patterns", targetSubdir: "patterns", description: "pattern files" },
|
|
1536
|
+
{ name: "protocols", targetSubdir: "protocols", description: "protocol files" },
|
|
1537
|
+
{ name: "reference", targetSubdir: "reference", description: "reference files" }
|
|
1538
|
+
];
|
|
1488
1539
|
}
|
|
1489
1540
|
});
|
|
1490
1541
|
|
|
@@ -2656,8 +2707,8 @@ var init_install_hooks = __esm({
|
|
|
2656
2707
|
|
|
2657
2708
|
// src/db.ts
|
|
2658
2709
|
import Database2 from "better-sqlite3";
|
|
2659
|
-
import { dirname as dirname6, join as
|
|
2660
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync as readdirSync5, statSync } from "fs";
|
|
2710
|
+
import { dirname as dirname6, join as join3 } from "path";
|
|
2711
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
2661
2712
|
function getCodeGraphDb() {
|
|
2662
2713
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
2663
2714
|
if (!existsSync7(dbPath)) {
|
|
@@ -2943,12 +2994,12 @@ function isPythonDataStale(dataDb2, pythonRoot) {
|
|
|
2943
2994
|
try {
|
|
2944
2995
|
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
2945
2996
|
for (const entry of entries) {
|
|
2946
|
-
const fullPath =
|
|
2997
|
+
const fullPath = join3(dir, entry.name);
|
|
2947
2998
|
if (entry.isDirectory()) {
|
|
2948
2999
|
if (["__pycache__", ".venv", "venv", "node_modules", ".mypy_cache", ".pytest_cache"].includes(entry.name)) continue;
|
|
2949
3000
|
if (checkDir(fullPath)) return true;
|
|
2950
3001
|
} else if (entry.name.endsWith(".py")) {
|
|
2951
|
-
if (
|
|
3002
|
+
if (statSync2(fullPath).mtimeMs > lastBuildTime) return true;
|
|
2952
3003
|
}
|
|
2953
3004
|
}
|
|
2954
3005
|
} catch {
|
|
@@ -3044,8 +3095,8 @@ var init_rules = __esm({
|
|
|
3044
3095
|
});
|
|
3045
3096
|
|
|
3046
3097
|
// src/import-resolver.ts
|
|
3047
|
-
import { readFileSync as readFileSync6, existsSync as existsSync8, statSync as
|
|
3048
|
-
import { resolve as resolve7, dirname as dirname7, join as
|
|
3098
|
+
import { readFileSync as readFileSync6, existsSync as existsSync8, statSync as statSync3 } from "fs";
|
|
3099
|
+
import { resolve as resolve7, dirname as dirname7, join as join4 } from "path";
|
|
3049
3100
|
function parseImports(source) {
|
|
3050
3101
|
const imports = [];
|
|
3051
3102
|
const lines = source.split("\n");
|
|
@@ -3116,7 +3167,7 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
3116
3167
|
}
|
|
3117
3168
|
}
|
|
3118
3169
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
3119
|
-
const indexPath =
|
|
3170
|
+
const indexPath = join4(basePath, indexFile);
|
|
3120
3171
|
if (existsSync8(indexPath)) {
|
|
3121
3172
|
return toRelative(indexPath);
|
|
3122
3173
|
}
|
|
@@ -3125,7 +3176,7 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
3125
3176
|
}
|
|
3126
3177
|
function isDirectory(path) {
|
|
3127
3178
|
try {
|
|
3128
|
-
return
|
|
3179
|
+
return statSync3(path).isDirectory();
|
|
3129
3180
|
} catch {
|
|
3130
3181
|
return false;
|
|
3131
3182
|
}
|
|
@@ -3194,7 +3245,7 @@ var init_import_resolver = __esm({
|
|
|
3194
3245
|
|
|
3195
3246
|
// src/trpc-index.ts
|
|
3196
3247
|
import { readFileSync as readFileSync7, existsSync as existsSync9, readdirSync as readdirSync6 } from "fs";
|
|
3197
|
-
import { resolve as resolve8, join as
|
|
3248
|
+
import { resolve as resolve8, join as join5 } from "path";
|
|
3198
3249
|
function parseRootRouter() {
|
|
3199
3250
|
const paths = getResolvedPaths();
|
|
3200
3251
|
const rootPath = paths.rootRouterPath;
|
|
@@ -3217,7 +3268,7 @@ function parseRootRouter() {
|
|
|
3217
3268
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
3218
3269
|
break;
|
|
3219
3270
|
}
|
|
3220
|
-
const indexCandidate =
|
|
3271
|
+
const indexCandidate = join5(fullPath, "index.ts");
|
|
3221
3272
|
if (existsSync9(indexCandidate)) {
|
|
3222
3273
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
3223
3274
|
break;
|
|
@@ -3276,7 +3327,7 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
3276
3327
|
function searchDirectory(dir, pattern, results) {
|
|
3277
3328
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
3278
3329
|
for (const entry of entries) {
|
|
3279
|
-
const fullPath =
|
|
3330
|
+
const fullPath = join5(dir, entry.name);
|
|
3280
3331
|
if (entry.isDirectory()) {
|
|
3281
3332
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
3282
3333
|
searchDirectory(fullPath, pattern, results);
|
|
@@ -3678,7 +3729,7 @@ var init_domains = __esm({
|
|
|
3678
3729
|
|
|
3679
3730
|
// src/schema-mapper.ts
|
|
3680
3731
|
import { readFileSync as readFileSync9, existsSync as existsSync11, readdirSync as readdirSync7 } from "fs";
|
|
3681
|
-
import { join as
|
|
3732
|
+
import { join as join6 } from "path";
|
|
3682
3733
|
function parsePrismaSchema() {
|
|
3683
3734
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
3684
3735
|
if (!existsSync11(schemaPath)) {
|
|
@@ -3749,7 +3800,7 @@ function findColumnUsageInRouters(tableName) {
|
|
|
3749
3800
|
function scanDirectory(dir, tableName, usage) {
|
|
3750
3801
|
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
3751
3802
|
for (const entry of entries) {
|
|
3752
|
-
const fullPath =
|
|
3803
|
+
const fullPath = join6(dir, entry.name);
|
|
3753
3804
|
if (entry.isDirectory()) {
|
|
3754
3805
|
scanDirectory(fullPath, tableName, usage);
|
|
3755
3806
|
} else if (entry.name.endsWith(".ts")) {
|
|
@@ -3807,7 +3858,7 @@ function findFilesUsingColumn(dir, column, tableName) {
|
|
|
3807
3858
|
if (!existsSync11(dir)) return result;
|
|
3808
3859
|
const entries = readdirSync7(dir, { withFileTypes: true });
|
|
3809
3860
|
for (const entry of entries) {
|
|
3810
|
-
const fullPath =
|
|
3861
|
+
const fullPath = join6(dir, entry.name);
|
|
3811
3862
|
if (entry.isDirectory()) {
|
|
3812
3863
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
3813
3864
|
} else if (entry.name.endsWith(".ts")) {
|
|
@@ -3958,7 +4009,7 @@ var init_import_parser = __esm({
|
|
|
3958
4009
|
|
|
3959
4010
|
// src/python/import-resolver.ts
|
|
3960
4011
|
import { readFileSync as readFileSync10, existsSync as existsSync12, readdirSync as readdirSync8 } from "fs";
|
|
3961
|
-
import { resolve as resolve11, join as
|
|
4012
|
+
import { resolve as resolve11, join as join7, relative as relative2, dirname as dirname8 } from "path";
|
|
3962
4013
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
3963
4014
|
const projectRoot = getProjectRoot();
|
|
3964
4015
|
if (level > 0) {
|
|
@@ -3969,23 +4020,23 @@ function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
|
3969
4020
|
const modulePart = module.replace(/^\.+/, "");
|
|
3970
4021
|
if (modulePart) {
|
|
3971
4022
|
const parts2 = modulePart.split(".");
|
|
3972
|
-
return tryResolvePythonPath(
|
|
4023
|
+
return tryResolvePythonPath(join7(baseDir, ...parts2), projectRoot);
|
|
3973
4024
|
}
|
|
3974
4025
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
3975
4026
|
}
|
|
3976
4027
|
const parts = module.split(".");
|
|
3977
|
-
const candidate =
|
|
4028
|
+
const candidate = join7(resolve11(projectRoot, pythonRoot), ...parts);
|
|
3978
4029
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
3979
4030
|
}
|
|
3980
4031
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
3981
4032
|
if (existsSync12(basePath + ".py")) {
|
|
3982
|
-
return
|
|
4033
|
+
return relative2(projectRoot, basePath + ".py");
|
|
3983
4034
|
}
|
|
3984
|
-
if (existsSync12(
|
|
3985
|
-
return
|
|
4035
|
+
if (existsSync12(join7(basePath, "__init__.py"))) {
|
|
4036
|
+
return relative2(projectRoot, join7(basePath, "__init__.py"));
|
|
3986
4037
|
}
|
|
3987
4038
|
if (basePath.endsWith(".py") && existsSync12(basePath)) {
|
|
3988
|
-
return
|
|
4039
|
+
return relative2(projectRoot, basePath);
|
|
3989
4040
|
}
|
|
3990
4041
|
return null;
|
|
3991
4042
|
}
|
|
@@ -3996,9 +4047,9 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
3996
4047
|
for (const entry of entries) {
|
|
3997
4048
|
if (entry.isDirectory()) {
|
|
3998
4049
|
if (excludeDirs.includes(entry.name)) continue;
|
|
3999
|
-
files.push(...walkPythonFiles(
|
|
4050
|
+
files.push(...walkPythonFiles(join7(dir, entry.name), excludeDirs));
|
|
4000
4051
|
} else if (entry.name.endsWith(".py")) {
|
|
4001
|
-
files.push(
|
|
4052
|
+
files.push(join7(dir, entry.name));
|
|
4002
4053
|
}
|
|
4003
4054
|
}
|
|
4004
4055
|
} catch {
|
|
@@ -4021,7 +4072,7 @@ function buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__
|
|
|
4021
4072
|
});
|
|
4022
4073
|
const batch = [];
|
|
4023
4074
|
for (const absFile of files) {
|
|
4024
|
-
const relFile =
|
|
4075
|
+
const relFile = relative2(projectRoot, absFile);
|
|
4025
4076
|
let source;
|
|
4026
4077
|
try {
|
|
4027
4078
|
source = readFileSync10(absFile, "utf-8");
|
|
@@ -4291,7 +4342,7 @@ var init_route_parser = __esm({
|
|
|
4291
4342
|
|
|
4292
4343
|
// src/python/route-indexer.ts
|
|
4293
4344
|
import { readFileSync as readFileSync11, readdirSync as readdirSync9 } from "fs";
|
|
4294
|
-
import { join as
|
|
4345
|
+
import { join as join8, relative as relative3 } from "path";
|
|
4295
4346
|
function walkPyFiles(dir, excludeDirs) {
|
|
4296
4347
|
const files = [];
|
|
4297
4348
|
try {
|
|
@@ -4299,9 +4350,9 @@ function walkPyFiles(dir, excludeDirs) {
|
|
|
4299
4350
|
for (const entry of entries) {
|
|
4300
4351
|
if (entry.isDirectory()) {
|
|
4301
4352
|
if (excludeDirs.includes(entry.name)) continue;
|
|
4302
|
-
files.push(...walkPyFiles(
|
|
4353
|
+
files.push(...walkPyFiles(join8(dir, entry.name), excludeDirs));
|
|
4303
4354
|
} else if (entry.name.endsWith(".py")) {
|
|
4304
|
-
files.push(
|
|
4355
|
+
files.push(join8(dir, entry.name));
|
|
4305
4356
|
}
|
|
4306
4357
|
}
|
|
4307
4358
|
} catch {
|
|
@@ -4310,7 +4361,7 @@ function walkPyFiles(dir, excludeDirs) {
|
|
|
4310
4361
|
}
|
|
4311
4362
|
function buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
4312
4363
|
const projectRoot = getProjectRoot();
|
|
4313
|
-
const absRoot =
|
|
4364
|
+
const absRoot = join8(projectRoot, pythonRoot);
|
|
4314
4365
|
dataDb2.exec("DELETE FROM massu_py_routes");
|
|
4315
4366
|
dataDb2.exec("DELETE FROM massu_py_route_callers");
|
|
4316
4367
|
const insertStmt = dataDb2.prepare(
|
|
@@ -4320,7 +4371,7 @@ function buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
4320
4371
|
let count = 0;
|
|
4321
4372
|
dataDb2.transaction(() => {
|
|
4322
4373
|
for (const absFile of files) {
|
|
4323
|
-
const relFile =
|
|
4374
|
+
const relFile = relative3(projectRoot, absFile);
|
|
4324
4375
|
let source;
|
|
4325
4376
|
try {
|
|
4326
4377
|
source = readFileSync11(absFile, "utf-8");
|
|
@@ -4535,7 +4586,7 @@ var init_model_parser = __esm({
|
|
|
4535
4586
|
|
|
4536
4587
|
// src/python/model-indexer.ts
|
|
4537
4588
|
import { readFileSync as readFileSync12, readdirSync as readdirSync10 } from "fs";
|
|
4538
|
-
import { join as
|
|
4589
|
+
import { join as join9, relative as relative4 } from "path";
|
|
4539
4590
|
function walkPyFiles2(dir, excludeDirs) {
|
|
4540
4591
|
const files = [];
|
|
4541
4592
|
try {
|
|
@@ -4543,9 +4594,9 @@ function walkPyFiles2(dir, excludeDirs) {
|
|
|
4543
4594
|
for (const entry of entries) {
|
|
4544
4595
|
if (entry.isDirectory()) {
|
|
4545
4596
|
if (excludeDirs.includes(entry.name)) continue;
|
|
4546
|
-
files.push(...walkPyFiles2(
|
|
4597
|
+
files.push(...walkPyFiles2(join9(dir, entry.name), excludeDirs));
|
|
4547
4598
|
} else if (entry.name.endsWith(".py")) {
|
|
4548
|
-
files.push(
|
|
4599
|
+
files.push(join9(dir, entry.name));
|
|
4549
4600
|
}
|
|
4550
4601
|
}
|
|
4551
4602
|
} catch {
|
|
@@ -4554,7 +4605,7 @@ function walkPyFiles2(dir, excludeDirs) {
|
|
|
4554
4605
|
}
|
|
4555
4606
|
function buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
4556
4607
|
const projectRoot = getProjectRoot();
|
|
4557
|
-
const absRoot =
|
|
4608
|
+
const absRoot = join9(projectRoot, pythonRoot);
|
|
4558
4609
|
dataDb2.exec("DELETE FROM massu_py_models");
|
|
4559
4610
|
dataDb2.exec("DELETE FROM massu_py_fk_edges");
|
|
4560
4611
|
const insertModel = dataDb2.prepare(
|
|
@@ -4567,7 +4618,7 @@ function buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
|
|
|
4567
4618
|
let count = 0;
|
|
4568
4619
|
dataDb2.transaction(() => {
|
|
4569
4620
|
for (const absFile of files) {
|
|
4570
|
-
const relFile =
|
|
4621
|
+
const relFile = relative4(projectRoot, absFile);
|
|
4571
4622
|
let source;
|
|
4572
4623
|
try {
|
|
4573
4624
|
source = readFileSync12(absFile, "utf-8");
|
|
@@ -4831,18 +4882,18 @@ var init_migration_parser = __esm({
|
|
|
4831
4882
|
|
|
4832
4883
|
// src/python/migration-indexer.ts
|
|
4833
4884
|
import { readFileSync as readFileSync13, readdirSync as readdirSync11 } from "fs";
|
|
4834
|
-
import { join as
|
|
4885
|
+
import { join as join10, relative as relative5 } from "path";
|
|
4835
4886
|
function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
4836
4887
|
const projectRoot = getProjectRoot();
|
|
4837
|
-
const absDir =
|
|
4888
|
+
const absDir = join10(projectRoot, alembicDir);
|
|
4838
4889
|
dataDb2.exec("DELETE FROM massu_py_migrations");
|
|
4839
|
-
const versionsDir =
|
|
4890
|
+
const versionsDir = join10(absDir, "versions");
|
|
4840
4891
|
let files = [];
|
|
4841
4892
|
try {
|
|
4842
|
-
files = readdirSync11(versionsDir).filter((f) => f.endsWith(".py")).map((f) =>
|
|
4893
|
+
files = readdirSync11(versionsDir).filter((f) => f.endsWith(".py")).map((f) => join10(versionsDir, f));
|
|
4843
4894
|
} catch {
|
|
4844
4895
|
try {
|
|
4845
|
-
files = readdirSync11(absDir).filter((f) => f.endsWith(".py") && f !== "env.py").map((f) =>
|
|
4896
|
+
files = readdirSync11(absDir).filter((f) => f.endsWith(".py") && f !== "env.py").map((f) => join10(absDir, f));
|
|
4846
4897
|
} catch {
|
|
4847
4898
|
}
|
|
4848
4899
|
}
|
|
@@ -4867,7 +4918,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
|
4867
4918
|
rows.push({
|
|
4868
4919
|
revision: parsed.revision,
|
|
4869
4920
|
downRevision: parsed.downRevision,
|
|
4870
|
-
file:
|
|
4921
|
+
file: relative5(projectRoot, absFile),
|
|
4871
4922
|
description: parsed.description,
|
|
4872
4923
|
operations: JSON.stringify(parsed.operations)
|
|
4873
4924
|
});
|
|
@@ -4891,11 +4942,11 @@ var init_migration_indexer = __esm({
|
|
|
4891
4942
|
|
|
4892
4943
|
// src/python/coupling-detector.ts
|
|
4893
4944
|
import { readFileSync as readFileSync14, readdirSync as readdirSync12 } from "fs";
|
|
4894
|
-
import { join as
|
|
4945
|
+
import { join as join11, relative as relative6 } from "path";
|
|
4895
4946
|
function buildPythonCouplingIndex(dataDb2) {
|
|
4896
4947
|
const projectRoot = getProjectRoot();
|
|
4897
4948
|
const config = getConfig();
|
|
4898
|
-
const srcDir =
|
|
4949
|
+
const srcDir = join11(projectRoot, config.paths.source);
|
|
4899
4950
|
const routes = dataDb2.prepare("SELECT id, method, path FROM massu_py_routes").all();
|
|
4900
4951
|
if (routes.length === 0) return 0;
|
|
4901
4952
|
dataDb2.exec("DELETE FROM massu_py_route_callers");
|
|
@@ -4924,7 +4975,7 @@ function buildPythonCouplingIndex(dataDb2) {
|
|
|
4924
4975
|
];
|
|
4925
4976
|
dataDb2.transaction(() => {
|
|
4926
4977
|
for (const absFile of frontendFiles) {
|
|
4927
|
-
const relFile =
|
|
4978
|
+
const relFile = relative6(projectRoot, absFile);
|
|
4928
4979
|
let source;
|
|
4929
4980
|
try {
|
|
4930
4981
|
source = readFileSync14(absFile, "utf-8");
|
|
@@ -4959,9 +5010,9 @@ function walkFrontendFiles(dir) {
|
|
|
4959
5010
|
for (const entry of entries) {
|
|
4960
5011
|
if (entry.isDirectory()) {
|
|
4961
5012
|
if (exclude.includes(entry.name)) continue;
|
|
4962
|
-
files.push(...walkFrontendFiles(
|
|
5013
|
+
files.push(...walkFrontendFiles(join11(dir, entry.name)));
|
|
4963
5014
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
4964
|
-
files.push(
|
|
5015
|
+
files.push(join11(dir, entry.name));
|
|
4965
5016
|
}
|
|
4966
5017
|
}
|
|
4967
5018
|
} catch {
|
|
@@ -6720,8 +6771,8 @@ var init_sentinel_tools = __esm({
|
|
|
6720
6771
|
});
|
|
6721
6772
|
|
|
6722
6773
|
// src/sentinel-scanner.ts
|
|
6723
|
-
import { readFileSync as readFileSync16, existsSync as existsSync15, readdirSync as readdirSync13, statSync as
|
|
6724
|
-
import { resolve as resolve14, join as
|
|
6774
|
+
import { readFileSync as readFileSync16, existsSync as existsSync15, readdirSync as readdirSync13, statSync as statSync4 } from "fs";
|
|
6775
|
+
import { resolve as resolve14, join as join12, basename as basename4, dirname as dirname9, relative as relative7 } from "path";
|
|
6725
6776
|
function inferDomain(filePath) {
|
|
6726
6777
|
const domains = getConfig().domains;
|
|
6727
6778
|
const path = filePath.toLowerCase();
|
|
@@ -6867,7 +6918,7 @@ function scanComponentExports(dataDb2) {
|
|
|
6867
6918
|
if (!existsSync15(absDir)) continue;
|
|
6868
6919
|
const files = walkDir(absDir).filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"));
|
|
6869
6920
|
for (const file of files) {
|
|
6870
|
-
const relPath =
|
|
6921
|
+
const relPath = relative7(projectRoot, file);
|
|
6871
6922
|
const source = readFileSync16(file, "utf-8");
|
|
6872
6923
|
const annotations = parseFeatureAnnotations(source);
|
|
6873
6924
|
if (annotations.length > 0) {
|
|
@@ -6919,9 +6970,9 @@ function walkDir(dir) {
|
|
|
6919
6970
|
try {
|
|
6920
6971
|
const entries = readdirSync13(dir);
|
|
6921
6972
|
for (const entry of entries) {
|
|
6922
|
-
const fullPath =
|
|
6973
|
+
const fullPath = join12(dir, entry);
|
|
6923
6974
|
try {
|
|
6924
|
-
const stat =
|
|
6975
|
+
const stat = statSync4(fullPath);
|
|
6925
6976
|
if (stat.isDirectory()) {
|
|
6926
6977
|
results.push(...walkDir(fullPath));
|
|
6927
6978
|
} else {
|
|
@@ -9349,8 +9400,8 @@ var init_regression_detector = __esm({
|
|
|
9349
9400
|
|
|
9350
9401
|
// src/knowledge-indexer.ts
|
|
9351
9402
|
import { createHash as createHash2 } from "crypto";
|
|
9352
|
-
import { readFileSync as readFileSync20, readdirSync as readdirSync14, statSync as
|
|
9353
|
-
import { resolve as resolve16, relative as
|
|
9403
|
+
import { readFileSync as readFileSync20, readdirSync as readdirSync14, statSync as statSync5, existsSync as existsSync19 } from "fs";
|
|
9404
|
+
import { resolve as resolve16, relative as relative8, basename as basename5, extname } from "path";
|
|
9354
9405
|
function getKnowledgePaths() {
|
|
9355
9406
|
const resolved = getResolvedPaths();
|
|
9356
9407
|
const config = getConfig();
|
|
@@ -9398,7 +9449,7 @@ function categorizeFile(filePath) {
|
|
|
9398
9449
|
const paths = getKnowledgePaths();
|
|
9399
9450
|
if (filePath.startsWith(paths.plansDir)) return "plan";
|
|
9400
9451
|
if (filePath.startsWith(paths.docsDir)) {
|
|
9401
|
-
const relFromDocs =
|
|
9452
|
+
const relFromDocs = relative8(paths.docsDir, filePath).replace(/\\/g, "/").toLowerCase();
|
|
9402
9453
|
if (relFromDocs.startsWith("plans/")) return "plan";
|
|
9403
9454
|
if (relFromDocs.includes("architecture")) return "architecture";
|
|
9404
9455
|
if (relFromDocs.includes("security")) return "security";
|
|
@@ -9414,7 +9465,7 @@ function categorizeFile(filePath) {
|
|
|
9414
9465
|
}
|
|
9415
9466
|
const claudeDirName = getConfig().conventions?.claudeDirName ?? ".claude";
|
|
9416
9467
|
if (filePath.includes(`${claudeDirName}/projects/`) && filePath.includes("/memory/")) return "memory";
|
|
9417
|
-
const rel =
|
|
9468
|
+
const rel = relative8(paths.claudeDir, filePath).replace(/\\/g, "/");
|
|
9418
9469
|
const firstDir = rel.split("/")[0];
|
|
9419
9470
|
const knownCategories = getConfig().conventions?.knowledgeCategories ?? [
|
|
9420
9471
|
"patterns",
|
|
@@ -9706,7 +9757,7 @@ function indexAllKnowledge(db) {
|
|
|
9706
9757
|
if (!existsSync19(filePath)) continue;
|
|
9707
9758
|
const content = readFileSync20(filePath, "utf-8");
|
|
9708
9759
|
const hash = hashContent(content);
|
|
9709
|
-
const relPath = filePath.startsWith(paths.claudeDir) ?
|
|
9760
|
+
const relPath = filePath.startsWith(paths.claudeDir) ? relative8(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative8(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative8(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative8(paths.memoryDir, filePath)}` : basename5(filePath);
|
|
9710
9761
|
const category = categorizeFile(filePath);
|
|
9711
9762
|
const title = extractTitle(content, filePath);
|
|
9712
9763
|
const description = extractDescription2(content);
|
|
@@ -9834,7 +9885,7 @@ function isKnowledgeStale(db) {
|
|
|
9834
9885
|
}
|
|
9835
9886
|
for (const filePath of files) {
|
|
9836
9887
|
try {
|
|
9837
|
-
const stat =
|
|
9888
|
+
const stat = statSync5(filePath);
|
|
9838
9889
|
if (stat.mtimeMs > lastIndexTime) return true;
|
|
9839
9890
|
} catch {
|
|
9840
9891
|
continue;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massu/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "AI Engineering Governance MCP Server - Session memory, knowledge system, feature registry, code intelligence, rule enforcement, tiered tooling (12 free / 72 total),
|
|
5
|
+
"description": "AI Engineering Governance MCP Server - Session memory, knowledge system, feature registry, code intelligence, rule enforcement, tiered tooling (12 free / 72 total), 55+ workflow commands, 11 agents, 20+ patterns",
|
|
6
6
|
"main": "src/server.ts",
|
|
7
7
|
"bin": {
|
|
8
8
|
"massu": "./dist/cli.js"
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"!src/__tests__/**",
|
|
33
33
|
"dist/**/*",
|
|
34
34
|
"commands/**/*",
|
|
35
|
+
"agents/**/*",
|
|
36
|
+
"patterns/**/*",
|
|
37
|
+
"protocols/**/*",
|
|
38
|
+
"reference/**/*",
|
|
35
39
|
"LICENSE"
|
|
36
40
|
],
|
|
37
41
|
"keywords": [
|