@winci/local-rag 0.2.3 → 0.2.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.
@@ -0,0 +1,3 @@
1
+ {
2
+ "hooks": {}
3
+ }
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: local-rag
3
+ description: >
4
+ TRIGGER when: starting a new session, exploring unfamiliar code, searching for
5
+ functions/types/files, planning refactors, or needing context about past decisions.
6
+ Use local-rag MCP tools (search, read_relevant, project_map, etc.) instead of
7
+ manually grepping or reading files when semantic understanding is needed.
8
+ user-invocable: false
9
+ ---
10
+
11
+ ## Using local-rag tools
12
+
13
+ This project has a local RAG index (local-rag). Use these MCP tools:
14
+
15
+ - **`search`**: Discover which files are relevant to a topic. Returns file paths
16
+ with snippet previews — use this when you need to know *where* something is.
17
+ - **`read_relevant`**: Get the actual content of relevant semantic chunks —
18
+ individual functions, classes, or markdown sections — ranked by relevance.
19
+ Results include exact line ranges (`src/db.ts:42-67`) so you can navigate
20
+ directly to the edit location. Use this instead of `search` + `Read` when
21
+ you need the content itself. Two chunks from the same file can both appear
22
+ (no file deduplication).
23
+ - **`project_map`**: When you need to understand how files relate to each other,
24
+ generate a dependency graph. Use `focus` to zoom into a specific file's
25
+ neighborhood. This is faster than reading import statements across many files.
26
+ - **`search_conversation`**: Search past conversation history to recall previous
27
+ decisions, discussions, and tool outputs. Use this before re-investigating
28
+ something that may have been discussed in an earlier session.
29
+ - **`create_checkpoint`**: Mark important moments — decisions, milestones,
30
+ blockers, direction changes. Do this liberally: after completing any feature
31
+ or task, after adding/modifying tools, after key technical decisions, before
32
+ and after large refactors, or when changing direction. If in doubt, create one.
33
+ - **`list_checkpoints`** / **`search_checkpoints`**: Review or search past
34
+ checkpoints to understand project history and prior decisions.
35
+ - **`index_files`**: If you've created or modified files and want them searchable,
36
+ re-index the project directory.
37
+ - **`search_analytics`**: Check what queries return no results or low-relevance
38
+ results — this reveals documentation gaps.
39
+ - **`search_symbols`**: When you know a symbol name (function, class, type, etc.),
40
+ find it directly by name instead of using semantic search.
41
+ - **`find_usages`**: Before changing a function or type, find all its call sites.
42
+ Use this to understand the blast radius of a rename or API change. Faster and
43
+ more reliable than semantic search for finding usages.
44
+ - **`git_context`**: At the start of a session (or any time you need orientation),
45
+ call this to see what files have already been modified, recent commits, and
46
+ which changed files are in the index. Avoids redundant searches and conflicting
47
+ edits on already-modified files.
48
+ - **`annotate`**: Attach a persistent note to a file or symbol — "known race
49
+ condition", "don't refactor until auth rewrite lands", etc. Notes appear as
50
+ `[NOTE]` blocks inline in `read_relevant` results automatically.
51
+ - **`get_annotations`**: Retrieve all notes for a file, or search semantically
52
+ across all annotations to find relevant caveats before editing.
53
+ - **`write_relevant`**: Before adding new code or docs, find the best insertion
54
+ point — returns the most semantically appropriate file and anchor.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@winci/local-rag",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Semantic search for your codebase — local-first RAG MCP server with hybrid search, AST-aware chunking, and usage analytics",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/cli/setup.ts CHANGED
@@ -2,7 +2,7 @@ import { existsSync } from "fs";
2
2
  import { readFile, writeFile, mkdir } from "fs/promises";
3
3
  import { join, resolve } from "path";
4
4
  import { createInterface } from "readline";
5
- import { writeDefaultConfig } from "../config";
5
+ import { loadConfig } from "../config";
6
6
 
7
7
  const MARKER = "<!-- local-rag -->";
8
8
 
@@ -69,7 +69,8 @@ export interface SetupResult {
69
69
  export async function ensureConfig(projectDir: string): Promise<string | null> {
70
70
  const configPath = join(projectDir, ".rag", "config.json");
71
71
  if (existsSync(configPath)) return null;
72
- await writeDefaultConfig(projectDir);
72
+ // loadConfig auto-creates the file with defaults if missing
73
+ await loadConfig(projectDir);
73
74
  return "Created .rag/config.json";
74
75
  }
75
76
 
@@ -23,28 +23,40 @@ export type RagConfig = z.infer<typeof RagConfigSchema>;
23
23
 
24
24
  const DEFAULT_CONFIG: RagConfig = {
25
25
  include: [
26
+ // Source code — AST-aware chunking
27
+ "**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx",
28
+ "**/*.py",
29
+ "**/*.go",
30
+ "**/*.rs",
31
+ "**/*.java",
32
+ // Source code — heuristic chunking
33
+ "**/*.c", "**/*.cpp", "**/*.h", "**/*.hpp",
34
+ "**/*.rb",
35
+ "**/*.swift",
26
36
  // Markdown & plain text
27
- "**/*.md", "**/*.txt",
37
+ "**/*.md", "**/*.mdx", "**/*.markdown", "**/*.txt",
28
38
  // Build / task runners (no extension or prefix-named)
29
39
  "**/Makefile", "**/makefile", "**/GNUmakefile",
30
40
  "**/Dockerfile", "**/Dockerfile.*",
31
41
  "**/Jenkinsfile", "**/Jenkinsfile.*",
32
42
  "**/Vagrantfile", "**/Gemfile", "**/Rakefile",
33
43
  "**/Brewfile", "**/Procfile",
44
+ // Shell & scripting
45
+ "**/*.sh", "**/*.bash", "**/*.zsh", "**/*.fish",
34
46
  // Structured data & config
35
47
  "**/*.yaml", "**/*.yml",
36
48
  "**/*.json",
37
49
  "**/*.toml",
38
50
  "**/*.xml",
39
- // Shell & scripting
40
- "**/*.sh", "**/*.bash", "**/*.zsh",
41
51
  // Infrastructure / schema languages
42
52
  "**/*.tf",
43
53
  "**/*.proto",
44
54
  "**/*.graphql", "**/*.gql",
45
55
  "**/*.sql",
46
56
  "**/*.mod",
57
+ // API collections
47
58
  "**/*.bru",
59
+ // Stylesheets
48
60
  "**/*.css", "**/*.scss", "**/*.less",
49
61
  ],
50
62
  exclude: ["node_modules/**", ".git/**", "dist/**", ".rag/**"],
@@ -60,28 +72,30 @@ const DEFAULT_CONFIG: RagConfig = {
60
72
  };
61
73
 
62
74
  /**
63
- * Load config from .rag/config.json, merged with defaults.
64
- * Note: array fields (include, exclude) from user config *replace* the defaults
65
- * entirely they are not merged. This lets users fully control which files are indexed.
75
+ * Load config from .rag/config.json.
76
+ * If the file doesn't exist, writes the defaults there first so users can
77
+ * edit the file directly no hidden merge logic, what's on disk is what runs.
66
78
  */
67
79
  export async function loadConfig(projectDir: string): Promise<RagConfig> {
68
- const configPath = join(projectDir, ".rag", "config.json");
80
+ const ragDir = join(projectDir, ".rag");
81
+ const configPath = join(ragDir, "config.json");
69
82
 
70
83
  if (!existsSync(configPath)) {
84
+ await mkdir(ragDir, { recursive: true });
85
+ await writeFile(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n");
71
86
  return { ...DEFAULT_CONFIG };
72
87
  }
73
88
 
74
89
  const raw = await readFile(configPath, "utf-8");
75
- let userConfig: unknown;
90
+ let parsed: unknown;
76
91
  try {
77
- userConfig = JSON.parse(raw);
92
+ parsed = JSON.parse(raw);
78
93
  } catch {
79
94
  log.warn(`Invalid JSON in ${configPath}, using defaults`, "config");
80
95
  return { ...DEFAULT_CONFIG };
81
96
  }
82
97
 
83
- const merged = { ...DEFAULT_CONFIG, ...(userConfig as Record<string, unknown>) };
84
- const result = RagConfigSchema.safeParse(merged);
98
+ const result = RagConfigSchema.safeParse(parsed);
85
99
 
86
100
  if (!result.success) {
87
101
  const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
@@ -91,11 +105,3 @@ export async function loadConfig(projectDir: string): Promise<RagConfig> {
91
105
 
92
106
  return result.data;
93
107
  }
94
-
95
- export async function writeDefaultConfig(projectDir: string): Promise<string> {
96
- const ragDir = join(projectDir, ".rag");
97
- await mkdir(ragDir, { recursive: true });
98
- const configPath = join(ragDir, "config.json");
99
- await writeFile(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n");
100
- return configPath;
101
- }
@@ -8,6 +8,7 @@ import { indexDirectory } from "../indexing/indexer";
8
8
  import { startWatcher, type Watcher } from "../indexing/watcher";
9
9
  import { discoverSessions } from "../conversation/parser";
10
10
  import { indexConversation, startConversationTail } from "../conversation/indexer";
11
+ import { ensureGitignore } from "../cli/setup";
11
12
  import { registerAllTools } from "../tools";
12
13
  import { log } from "../utils/log";
13
14
 
@@ -54,6 +55,11 @@ export async function startServer() {
54
55
  let convWatcher: Watcher | null = null;
55
56
 
56
57
  if (!isHomeDirTrap) {
58
+ // Ensure .rag/ is gitignored
59
+ ensureGitignore(startupDir).catch((err) => {
60
+ log.warn(`Failed to update .gitignore: ${err instanceof Error ? err.message : err}`, "server");
61
+ });
62
+
57
63
  // Index in background — don't block server startup
58
64
  indexDirectory(startupDir, startupDb, startupConfig, (msg) => {
59
65
  process.stderr.write(`[local-rag] ${msg}\n`);
package/.mcp.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "local-rag": {
4
- "command": "bunx",
5
- "args": [
6
- "@winci/local-rag",
7
- "serve"
8
- ]
9
- }
10
- }
11
- }