mason-context 0.3.2 → 0.3.4
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/bin/mason-mcp.js +25 -11
- package/dist/bin/mason-mcp.js.map +1 -1
- package/dist/bin/mason.js +55 -18
- package/dist/bin/mason.js.map +1 -1
- package/dist/src/cli.js +55 -18
- package/dist/src/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -405,13 +405,12 @@ function spawnWithStdin(command, args, input) {
|
|
|
405
405
|
});
|
|
406
406
|
}
|
|
407
407
|
async function callClaudeCLI(system, userMessage) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
${userMessage}`;
|
|
411
|
-
return spawnWithStdin("claude", ["-p"], prompt);
|
|
408
|
+
return spawnWithStdin("claude", ["-p", "--system-prompt", system], userMessage);
|
|
412
409
|
}
|
|
413
410
|
async function callGeminiCLI(system, userMessage) {
|
|
414
|
-
const prompt =
|
|
411
|
+
const prompt = `<system>
|
|
412
|
+
${system}
|
|
413
|
+
</system>
|
|
415
414
|
|
|
416
415
|
${userMessage}`;
|
|
417
416
|
return spawnWithStdin("gemini", ["-p", ""], prompt);
|
|
@@ -519,10 +518,22 @@ async function loadProjectConfig(rootDir) {
|
|
|
519
518
|
return {};
|
|
520
519
|
}
|
|
521
520
|
}
|
|
521
|
+
async function getTrackedFiles(rootDir) {
|
|
522
|
+
try {
|
|
523
|
+
const { stdout } = await exec5("git", ["ls-files", "--cached", "--others", "--exclude-standard"], {
|
|
524
|
+
cwd: rootDir,
|
|
525
|
+
maxBuffer: 1e7
|
|
526
|
+
});
|
|
527
|
+
return new Set(stdout.trim().split("\n").filter(Boolean));
|
|
528
|
+
} catch {
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
522
532
|
async function sampleFiles(rootDir, maxFiles = 25) {
|
|
523
533
|
const selected = /* @__PURE__ */ new Map();
|
|
524
534
|
const projectConfig = await loadProjectConfig(rootDir);
|
|
525
535
|
const ignorePatterns = [...IGNORE_PATTERNS, ...projectConfig.ignore ?? []];
|
|
536
|
+
const trackedFiles = await getTrackedFiles(rootDir);
|
|
526
537
|
for (const filePath of projectConfig.alwaysInclude ?? []) {
|
|
527
538
|
if (selected.size >= maxFiles) break;
|
|
528
539
|
const resolvedPath = path2.resolve(rootDir, filePath);
|
|
@@ -701,6 +712,7 @@ async function sampleFiles(rootDir, maxFiles = 25) {
|
|
|
701
712
|
const fullPath = path2.resolve(rootDir, filePath);
|
|
702
713
|
if (!fullPath.startsWith(path2.resolve(rootDir))) continue;
|
|
703
714
|
if (isSensitiveFile(filePath)) continue;
|
|
715
|
+
if (trackedFiles && !trackedFiles.has(filePath)) continue;
|
|
704
716
|
const stat = await fs3.stat(fullPath);
|
|
705
717
|
if (stat.size > 1e5) continue;
|
|
706
718
|
const content = await fs3.readFile(fullPath, "utf-8");
|
|
@@ -1094,6 +1106,7 @@ import fs4 from "fs/promises";
|
|
|
1094
1106
|
import path4 from "path";
|
|
1095
1107
|
import { execFile as execFile6 } from "child_process";
|
|
1096
1108
|
import { promisify as promisify6 } from "util";
|
|
1109
|
+
import fg4 from "fast-glob";
|
|
1097
1110
|
function snapshotDir(rootDir) {
|
|
1098
1111
|
return path4.join(rootDir, ".mason");
|
|
1099
1112
|
}
|
|
@@ -1157,7 +1170,31 @@ function parseSnapshotResponse(raw) {
|
|
|
1157
1170
|
}
|
|
1158
1171
|
async function createSnapshot(rootDir, config) {
|
|
1159
1172
|
const resolvedRoot = path4.resolve(rootDir);
|
|
1160
|
-
const
|
|
1173
|
+
const allFiles = await fg4(
|
|
1174
|
+
"**/*.{ts,tsx,js,jsx,kt,kts,java,py,go,rs,swift,rb,cs,cpp,c,dart}",
|
|
1175
|
+
{
|
|
1176
|
+
cwd: resolvedRoot,
|
|
1177
|
+
ignore: [
|
|
1178
|
+
"**/node_modules/**",
|
|
1179
|
+
"**/dist/**",
|
|
1180
|
+
"**/build/**",
|
|
1181
|
+
"**/.gradle/**",
|
|
1182
|
+
"**/target/**",
|
|
1183
|
+
"**/.git/**",
|
|
1184
|
+
"**/vendor/**",
|
|
1185
|
+
"**/__pycache__/**",
|
|
1186
|
+
"**/venv/**",
|
|
1187
|
+
"**/.venv/**",
|
|
1188
|
+
"**/*.min.*",
|
|
1189
|
+
"**/*.map",
|
|
1190
|
+
"**/generated/**",
|
|
1191
|
+
"**/R.java",
|
|
1192
|
+
"**/BuildConfig.java"
|
|
1193
|
+
]
|
|
1194
|
+
}
|
|
1195
|
+
);
|
|
1196
|
+
const sampleCount = Math.min(80, Math.max(20, Math.round(allFiles.length * 0.15)));
|
|
1197
|
+
const sampled = await sampleFiles(resolvedRoot, sampleCount);
|
|
1161
1198
|
const filesWithContent = [];
|
|
1162
1199
|
for (const sample of sampled) {
|
|
1163
1200
|
const full = await readFullFile(resolvedRoot, sample.path);
|
|
@@ -1324,7 +1361,7 @@ import fs5 from "fs/promises";
|
|
|
1324
1361
|
import path5 from "path";
|
|
1325
1362
|
import { execFile as execFile7 } from "child_process";
|
|
1326
1363
|
import { promisify as promisify7 } from "util";
|
|
1327
|
-
import
|
|
1364
|
+
import fg5 from "fast-glob";
|
|
1328
1365
|
async function analyzeImpact(rootDir, targetFiles) {
|
|
1329
1366
|
const resolvedRoot = path5.resolve(rootDir);
|
|
1330
1367
|
const resolvedTargets = await resolveTargetFiles(resolvedRoot, targetFiles);
|
|
@@ -1347,7 +1384,7 @@ async function resolveTargetFiles(rootDir, targets) {
|
|
|
1347
1384
|
resolved.push(target);
|
|
1348
1385
|
continue;
|
|
1349
1386
|
}
|
|
1350
|
-
const matches = await
|
|
1387
|
+
const matches = await fg5(`**/${target}`, {
|
|
1351
1388
|
cwd: rootDir,
|
|
1352
1389
|
ignore: IGNORE2
|
|
1353
1390
|
});
|
|
@@ -1355,7 +1392,7 @@ async function resolveTargetFiles(rootDir, targets) {
|
|
|
1355
1392
|
resolved.push(matches[0]);
|
|
1356
1393
|
} else {
|
|
1357
1394
|
const noExt = target.replace(/\.[^.]+$/, "");
|
|
1358
|
-
const extMatches = await
|
|
1395
|
+
const extMatches = await fg5(`**/${noExt}.*`, {
|
|
1359
1396
|
cwd: rootDir,
|
|
1360
1397
|
ignore: IGNORE2
|
|
1361
1398
|
});
|
|
@@ -1412,7 +1449,7 @@ async function getReferences(rootDir, targetFiles) {
|
|
|
1412
1449
|
const basename = path5.basename(target).replace(/\.[^.]+$/, "");
|
|
1413
1450
|
searchNames.add(basename);
|
|
1414
1451
|
}
|
|
1415
|
-
const allSourceFiles = await
|
|
1452
|
+
const allSourceFiles = await fg5(`**/${SOURCE_EXTENSIONS2}`, {
|
|
1416
1453
|
cwd: rootDir,
|
|
1417
1454
|
ignore: IGNORE2
|
|
1418
1455
|
});
|
|
@@ -1461,7 +1498,7 @@ async function getRelatedTests(rootDir, targetFiles) {
|
|
|
1461
1498
|
"**/*Test.swift",
|
|
1462
1499
|
"**/*_test.rs"
|
|
1463
1500
|
];
|
|
1464
|
-
const testFiles = await
|
|
1501
|
+
const testFiles = await fg5(testPatterns, { cwd: rootDir, ignore: IGNORE2 });
|
|
1465
1502
|
const results = [];
|
|
1466
1503
|
for (const target of targetFiles) {
|
|
1467
1504
|
const targetBaseName = path5.basename(target).replace(/\.[^.]+$/, "");
|
|
@@ -1508,7 +1545,7 @@ import fs6 from "fs/promises";
|
|
|
1508
1545
|
import path6 from "path";
|
|
1509
1546
|
import { execFile as execFile8 } from "child_process";
|
|
1510
1547
|
import { promisify as promisify8 } from "util";
|
|
1511
|
-
import
|
|
1548
|
+
import fg6 from "fast-glob";
|
|
1512
1549
|
async function buildContext(dir) {
|
|
1513
1550
|
return {
|
|
1514
1551
|
rootDir: dir,
|
|
@@ -1588,7 +1625,7 @@ async function detectProjectSnapshot(rootDir) {
|
|
|
1588
1625
|
];
|
|
1589
1626
|
const testInfo = {};
|
|
1590
1627
|
for (const pattern of testDirs) {
|
|
1591
|
-
const files = await
|
|
1628
|
+
const files = await fg6(`${pattern}/**/*`, {
|
|
1592
1629
|
cwd: rootDir,
|
|
1593
1630
|
ignore: IGNORE3,
|
|
1594
1631
|
onlyFiles: true
|
|
@@ -1608,12 +1645,12 @@ async function detectProjectSnapshot(rootDir) {
|
|
|
1608
1645
|
{ pattern: "**/*_test.rs", label: "*_test.rs" }
|
|
1609
1646
|
];
|
|
1610
1647
|
for (const { pattern, label } of testFilePatterns) {
|
|
1611
|
-
const files = await
|
|
1648
|
+
const files = await fg6(pattern, { cwd: rootDir, ignore: IGNORE3 });
|
|
1612
1649
|
if (files.length > 0) {
|
|
1613
1650
|
testInfo[label] = files.length;
|
|
1614
1651
|
}
|
|
1615
1652
|
}
|
|
1616
|
-
const sourceFiles = await
|
|
1653
|
+
const sourceFiles = await fg6("**/*.{ts,tsx,js,jsx,kt,kts,java,py,go,rs,swift,rb,cs,cpp,c,dart}", {
|
|
1617
1654
|
cwd: rootDir,
|
|
1618
1655
|
ignore: IGNORE3
|
|
1619
1656
|
});
|
|
@@ -1646,7 +1683,7 @@ async function getCodeSamples(dir, count = 15) {
|
|
|
1646
1683
|
}
|
|
1647
1684
|
async function getProjectStructure(dir) {
|
|
1648
1685
|
const rootDir = path6.resolve(dir);
|
|
1649
|
-
const allFiles = await
|
|
1686
|
+
const allFiles = await fg6("**/*", {
|
|
1650
1687
|
cwd: rootDir,
|
|
1651
1688
|
ignore: IGNORE3,
|
|
1652
1689
|
onlyFiles: true
|
|
@@ -1829,7 +1866,7 @@ function createMcpServer() {
|
|
|
1829
1866
|
const server = new McpServer(
|
|
1830
1867
|
{
|
|
1831
1868
|
name: "mason",
|
|
1832
|
-
version: "0.3.
|
|
1869
|
+
version: "0.3.4"
|
|
1833
1870
|
},
|
|
1834
1871
|
{
|
|
1835
1872
|
instructions: "Mason is a context engineering tool. Always call get_snapshot before using Explore agents, Glob, or Grep to understand the codebase. The snapshot is a concept map that maps features and flows to their implementing files \u2014 it eliminates the need to search. This applies to ANY question about architecture, features, flows, how things work, cross-feature interactions, or bug investigation. Workflow: 1) Call get_snapshot first. 2) If no snapshot, call full_analysis and then save_snapshot to create one. 3) If the snapshot is stale, tell the user and offer to update it. 4) Use your native file reading tool to read files the snapshot points to. 5) Before modifying a file, call get_impact to check what else might be affected. 6) After making significant changes (new features, refactors, architecture changes), call save_snapshot to update the concept map."
|
|
@@ -2014,7 +2051,7 @@ function createCLI() {
|
|
|
2014
2051
|
const program = new Command();
|
|
2015
2052
|
program.name("mason").description(
|
|
2016
2053
|
"Context engineering CLI & MCP server \u2014 generates intelligent CLAUDE.md files"
|
|
2017
|
-
).version("0.3.
|
|
2054
|
+
).version("0.3.4");
|
|
2018
2055
|
program.command("setup").description("Register Mason as an MCP server with Claude Code").option("--scope <scope>", "Config scope: user or project", "user").action(async (opts) => {
|
|
2019
2056
|
const { execFile: execFile9 } = await import("child_process");
|
|
2020
2057
|
const { promisify: promisify9 } = await import("util");
|