syntax-map-mcp 0.1.4 → 0.1.6

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/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.6 - 2026-05-06
6
+
7
+ - 하위 디렉터리의 `.gitignore` 패턴도 인덱싱 대상 파일 제외에 반영하도록 했습니다.
8
+
9
+ ## 0.1.5 - 2026-05-06
10
+
11
+ - `express-rate-limit` transitive 의존성을 override해 npm audit 취약점 경고를 제거했습니다.
12
+ - `index_workspace`가 `workspaceRoot`의 `.gitignore` 패턴에 매칭되는 소스 파일을 인덱싱 대상에서 제외하도록 했습니다.
13
+
5
14
  ## 0.1.4 - 2026-05-04
6
15
 
7
16
  - `build_context` 인덱스 검색 metadata에 `summarizedFiles`와 `omittedFiles`를 추가했습니다.
package/README.md CHANGED
@@ -45,7 +45,7 @@ npx -y syntax-map-mcp --workspace-root /path/to/workspace
45
45
 
46
46
  ## SQLite 인덱스
47
47
 
48
- `index_workspace`는 `workspaceRoot` 아래의 `.syntax-map-mcp/index.sqlite`에 인덱스를 저장합니다. 인덱싱 대상은 `.js`, `.jsx`, `.ts`, `.tsx`, `.py` 파일이며, `.git`, `.syntax-map-mcp`, `dist`, `node_modules` 디렉터리는 제외합니다.
48
+ `index_workspace`는 `workspaceRoot` 아래의 `.syntax-map-mcp/index.sqlite`에 인덱스를 저장합니다. 인덱싱 대상은 `.js`, `.jsx`, `.ts`, `.tsx`, `.py` 파일이며, `.git`, `.syntax-map-mcp`, `dist`, `node_modules` 디렉터리와 `workspaceRoot` 아래의 `.gitignore` 패턴에 매칭되는 파일은 제외합니다. 하위 디렉터리의 `.gitignore`는 해당 디렉터리 기준으로 적용합니다.
49
49
 
50
50
  파일 변경 여부는 `mtimeMs`와 `size`로 판단합니다. 다시 `index_workspace`를 호출하면 변경된 파일만 재파싱하고, 삭제된 파일은 인덱스에서 제거합니다. `search_symbols`, `find_indexed_definition`, `find_indexed_references`는 `isStale`, `staleFiles`, `refreshed`를 반환해 검색 결과가 최신 인덱스 기반인지 알려줍니다. 세 도구에 `refreshIfStale: true`를 전달하면 stale 파일이 있을 때 먼저 인덱스를 갱신한 뒤 검색합니다. 인덱스 검색 도구는 인덱스에 저장된 위치를 조회한 뒤 현재 파일에서 해당 줄 snippet을 읽어 반환합니다. `contextBefore`, `contextAfter`를 0-10 사이 정수로 전달하면 snippet 주변 라인도 함께 반환합니다. `includePreview: true`를 전달하면 `path:line` 헤더와 코드블록으로 구성된 `previewMarkdown`도 함께 반환합니다. 자동 watch 모드는 아직 포함하지 않았습니다.
51
51
 
package/dist/workspace.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { readdir, readFile, realpath, stat } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
+ import ignore from 'ignore';
3
4
  const SUPPORTED_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx', '.py']);
4
5
  const EXCLUDED_DIRECTORIES = new Set(['.git', '.syntax-map-mcp', 'dist', 'node_modules']);
5
6
  function isInsideRoot(root, candidate) {
@@ -9,6 +10,36 @@ function isInsideRoot(root, candidate) {
9
10
  function failure(code, message) {
10
11
  return { ok: false, error: { code, message } };
11
12
  }
13
+ async function loadGitignore(directory) {
14
+ const matcher = ignore();
15
+ try {
16
+ matcher.add(await readFile(path.join(directory, '.gitignore'), 'utf8'));
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ return { baseDirectory: directory, matcher };
22
+ }
23
+ function toGitignorePath(relativePath) {
24
+ return relativePath.split(path.sep).join('/');
25
+ }
26
+ function isGitignored(absolutePath, matchers) {
27
+ let ignored = false;
28
+ for (const { baseDirectory, matcher } of matchers) {
29
+ const relativePath = path.relative(baseDirectory, absolutePath);
30
+ if (relativePath === '' || relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
31
+ continue;
32
+ }
33
+ const result = matcher.test(toGitignorePath(relativePath));
34
+ if (result.ignored) {
35
+ ignored = true;
36
+ }
37
+ if (result.unignored) {
38
+ ignored = false;
39
+ }
40
+ }
41
+ return ignored;
42
+ }
12
43
  export async function createWorkspace(workspaceRoot) {
13
44
  const root = await realpath(path.resolve(workspaceRoot));
14
45
  async function readSourceFile(inputPath) {
@@ -47,18 +78,22 @@ export async function createWorkspace(workspaceRoot) {
47
78
  mtimeMs: fileStat.mtimeMs
48
79
  };
49
80
  }
50
- async function listSourceFilesInDirectory(directory) {
81
+ async function listSourceFilesInDirectory(directory, parentMatchers) {
82
+ const gitignore = await loadGitignore(directory);
83
+ const matchers = gitignore ? [...parentMatchers, gitignore] : parentMatchers;
51
84
  const entries = await readdir(directory, { withFileTypes: true });
52
85
  const files = [];
53
86
  for (const entry of entries) {
54
87
  const absolutePath = path.join(directory, entry.name);
55
88
  if (entry.isDirectory()) {
56
89
  if (!EXCLUDED_DIRECTORIES.has(entry.name)) {
57
- files.push(...(await listSourceFilesInDirectory(absolutePath)));
90
+ files.push(...(await listSourceFilesInDirectory(absolutePath, matchers)));
58
91
  }
59
92
  continue;
60
93
  }
61
- if (!entry.isFile() || !SUPPORTED_EXTENSIONS.has(path.extname(entry.name))) {
94
+ if (!entry.isFile() ||
95
+ !SUPPORTED_EXTENSIONS.has(path.extname(entry.name)) ||
96
+ isGitignored(absolutePath, matchers)) {
62
97
  continue;
63
98
  }
64
99
  let actualPath;
@@ -91,7 +126,7 @@ export async function createWorkspace(workspaceRoot) {
91
126
  return Promise.all(inputPaths.map(readSourceFile));
92
127
  },
93
128
  listSourceFiles() {
94
- return listSourceFilesInDirectory(root);
129
+ return listSourceFilesInDirectory(root, []);
95
130
  }
96
131
  };
97
132
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "syntax-map-mcp",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Tree-sitter based code analysis MCP server",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,6 +36,7 @@
36
36
  "dependencies": {
37
37
  "@modelcontextprotocol/sdk": "^1.29.0",
38
38
  "@types/sql.js": "^1.4.11",
39
+ "ignore": "^7.0.5",
39
40
  "sql.js": "^1.14.1",
40
41
  "tree-sitter": "^0.21.1",
41
42
  "tree-sitter-javascript": "^0.21.4",
@@ -48,5 +49,8 @@
48
49
  "tsx": "^4.0.0",
49
50
  "typescript": "^5.8.0",
50
51
  "vitest": "^3.0.0"
52
+ },
53
+ "overrides": {
54
+ "express-rate-limit": "7.5.1"
51
55
  }
52
56
  }