mason-context 0.3.3 → 0.3.5

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.js CHANGED
@@ -518,10 +518,22 @@ async function loadProjectConfig(rootDir) {
518
518
  return {};
519
519
  }
520
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
+ }
521
532
  async function sampleFiles(rootDir, maxFiles = 25) {
522
533
  const selected = /* @__PURE__ */ new Map();
523
534
  const projectConfig = await loadProjectConfig(rootDir);
524
535
  const ignorePatterns = [...IGNORE_PATTERNS, ...projectConfig.ignore ?? []];
536
+ const trackedFiles = await getTrackedFiles(rootDir);
525
537
  for (const filePath of projectConfig.alwaysInclude ?? []) {
526
538
  if (selected.size >= maxFiles) break;
527
539
  const resolvedPath = path2.resolve(rootDir, filePath);
@@ -700,6 +712,7 @@ async function sampleFiles(rootDir, maxFiles = 25) {
700
712
  const fullPath = path2.resolve(rootDir, filePath);
701
713
  if (!fullPath.startsWith(path2.resolve(rootDir))) continue;
702
714
  if (isSensitiveFile(filePath)) continue;
715
+ if (trackedFiles && !trackedFiles.has(filePath)) continue;
703
716
  const stat = await fs3.stat(fullPath);
704
717
  if (stat.size > 1e5) continue;
705
718
  const content = await fs3.readFile(fullPath, "utf-8");
@@ -1776,10 +1789,23 @@ async function fullAnalysis(dir) {
1776
1789
  }
1777
1790
  return JSON.stringify(output, null, 2);
1778
1791
  }
1792
+ function sanitizePaths(rootDir, files) {
1793
+ return files.filter((f) => {
1794
+ const resolved = path6.resolve(rootDir, f);
1795
+ return resolved.startsWith(rootDir) && !f.startsWith("/") && !f.includes("..");
1796
+ });
1797
+ }
1779
1798
  async function saveSnapshotData(dir, features, flows) {
1780
1799
  const rootDir = path6.resolve(dir);
1781
1800
  const gitHash = await getCurrentGitHash(rootDir);
1782
1801
  const now = (/* @__PURE__ */ new Date()).toISOString();
1802
+ for (const feat of Object.values(features)) {
1803
+ feat.files = sanitizePaths(rootDir, feat.files);
1804
+ if (feat.tests) feat.tests = sanitizePaths(rootDir, feat.tests);
1805
+ }
1806
+ for (const flow of Object.values(flows)) {
1807
+ flow.chain = sanitizePaths(rootDir, flow.chain);
1808
+ }
1783
1809
  const existing = await loadSnapshot(rootDir);
1784
1810
  if (existing) {
1785
1811
  existing.features = { ...existing.features, ...features };
@@ -1853,7 +1879,7 @@ function createMcpServer() {
1853
1879
  const server = new McpServer(
1854
1880
  {
1855
1881
  name: "mason",
1856
- version: "0.3.3"
1882
+ version: "0.3.5"
1857
1883
  },
1858
1884
  {
1859
1885
  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."
@@ -2038,7 +2064,7 @@ function createCLI() {
2038
2064
  const program2 = new Command();
2039
2065
  program2.name("mason").description(
2040
2066
  "Context engineering CLI & MCP server \u2014 generates intelligent CLAUDE.md files"
2041
- ).version("0.3.3");
2067
+ ).version("0.3.5");
2042
2068
  program2.command("setup").description("Register Mason as an MCP server with Claude Code").option("--scope <scope>", "Config scope: user or project", "user").action(async (opts) => {
2043
2069
  const { execFile: execFile9 } = await import("child_process");
2044
2070
  const { promisify: promisify9 } = await import("util");