@hsingjui/contextweaver 0.0.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.
@@ -0,0 +1,158 @@
1
+ // src/config.ts
2
+ import dotenv from "dotenv";
3
+ import path from "path";
4
+ import os from "os";
5
+ import fs from "fs";
6
+ var isDev = process.env.NODE_ENV !== "dev";
7
+ function loadEnv() {
8
+ const candidates = isDev ? [
9
+ path.join(process.cwd(), ".env"),
10
+ // 1. 当前目录(开发用)
11
+ path.join(os.homedir(), ".contextweaver", ".env")
12
+ // 2. 用户配置目录(回退)
13
+ ] : [
14
+ path.join(os.homedir(), ".contextweaver", ".env")
15
+ // 生产环境只用用户配置
16
+ ];
17
+ const envPath = candidates.find((p) => fs.existsSync(p));
18
+ if (envPath) {
19
+ const result = dotenv.config({ path: envPath, quiet: true });
20
+ if (result.error) {
21
+ console.error(`[config] \u52A0\u8F7D\u73AF\u5883\u53D8\u91CF\u5931\u8D25: ${result.error.message}`);
22
+ process.exit(1);
23
+ }
24
+ }
25
+ }
26
+ loadEnv();
27
+ function checkEmbeddingEnv() {
28
+ const missingVars = [];
29
+ if (!process.env.EMBEDDINGS_API_KEY) {
30
+ missingVars.push("EMBEDDINGS_API_KEY");
31
+ }
32
+ if (!process.env.EMBEDDINGS_BASE_URL) {
33
+ missingVars.push("EMBEDDINGS_BASE_URL");
34
+ }
35
+ if (!process.env.EMBEDDINGS_MODEL) {
36
+ missingVars.push("EMBEDDINGS_MODEL");
37
+ }
38
+ return {
39
+ isValid: missingVars.length === 0,
40
+ missingVars
41
+ };
42
+ }
43
+ function checkRerankerEnv() {
44
+ const missingVars = [];
45
+ if (!process.env.RERANK_API_KEY) {
46
+ missingVars.push("RERANK_API_KEY");
47
+ }
48
+ if (!process.env.RERANK_BASE_URL) {
49
+ missingVars.push("RERANK_BASE_URL");
50
+ }
51
+ if (!process.env.RERANK_MODEL) {
52
+ missingVars.push("RERANK_MODEL");
53
+ }
54
+ return {
55
+ isValid: missingVars.length === 0,
56
+ missingVars
57
+ };
58
+ }
59
+ function getEmbeddingConfig() {
60
+ const apiKey = process.env.EMBEDDINGS_API_KEY;
61
+ const baseUrl = process.env.EMBEDDINGS_BASE_URL;
62
+ const model = process.env.EMBEDDINGS_MODEL;
63
+ const maxConcurrency = parseInt(process.env.EMBEDDINGS_MAX_CONCURRENCY || "10", 10);
64
+ if (!apiKey) {
65
+ throw new Error("EMBEDDINGS_API_KEY \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E");
66
+ }
67
+ if (!baseUrl) {
68
+ throw new Error("EMBEDDINGS_BASE_URL \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E");
69
+ }
70
+ if (!model) {
71
+ throw new Error("EMBEDDINGS_MODEL \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E");
72
+ }
73
+ const dimensions = parseInt(process.env.EMBEDDINGS_DIMENSIONS || "1024", 10);
74
+ return {
75
+ apiKey,
76
+ baseUrl,
77
+ model,
78
+ maxConcurrency: isNaN(maxConcurrency) ? 4 : maxConcurrency,
79
+ dimensions: isNaN(dimensions) ? 1024 : dimensions
80
+ };
81
+ }
82
+ function getRerankerConfig() {
83
+ const apiKey = process.env.RERANK_API_KEY;
84
+ const baseUrl = process.env.RERANK_BASE_URL;
85
+ const model = process.env.RERANK_MODEL;
86
+ const topN = parseInt(process.env.RERANK_TOP_N || "10", 10);
87
+ if (!apiKey) {
88
+ throw new Error("RERANK_API_KEY \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E");
89
+ }
90
+ if (!baseUrl) {
91
+ throw new Error("RERANK_BASE_URL \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E");
92
+ }
93
+ if (!model) {
94
+ throw new Error("RERANK_MODEL \u73AF\u5883\u53D8\u91CF\u672A\u8BBE\u7F6E");
95
+ }
96
+ return {
97
+ apiKey,
98
+ baseUrl,
99
+ model,
100
+ topN: isNaN(topN) ? 10 : topN
101
+ };
102
+ }
103
+ var DEFAULT_EXCLUDE_PATTERNS = [
104
+ // 虚拟环境
105
+ ".venv",
106
+ "venv",
107
+ ".env",
108
+ "env",
109
+ "node_modules",
110
+ // 版本控制
111
+ ".git",
112
+ ".svn",
113
+ ".hg",
114
+ // Python 缓存
115
+ "__pycache__",
116
+ ".pytest_cache",
117
+ ".mypy_cache",
118
+ ".tox",
119
+ ".eggs",
120
+ "*.egg-info",
121
+ // 构建产物
122
+ "dist",
123
+ "build",
124
+ "target",
125
+ "out",
126
+ // IDE 配置
127
+ ".idea",
128
+ ".vscode",
129
+ ".vs",
130
+ // 系统文件
131
+ ".DS_Store",
132
+ "Thumbs.db",
133
+ // 编译文件
134
+ "*.pyc",
135
+ "*.pyo",
136
+ "*.pyd",
137
+ "*.so",
138
+ "*.dll"
139
+ ];
140
+ function getExcludePatterns() {
141
+ const envPatterns = process.env.IGNORE_PATTERNS;
142
+ const patterns = [...DEFAULT_EXCLUDE_PATTERNS];
143
+ if (envPatterns) {
144
+ const additional = envPatterns.split(",").map((p) => p.trim()).filter(Boolean);
145
+ patterns.push(...additional);
146
+ }
147
+ return patterns;
148
+ }
149
+
150
+ export {
151
+ isDev,
152
+ checkEmbeddingEnv,
153
+ checkRerankerEnv,
154
+ getEmbeddingConfig,
155
+ getRerankerConfig,
156
+ DEFAULT_EXCLUDE_PATTERNS,
157
+ getExcludePatterns
158
+ };
@@ -0,0 +1,10 @@
1
+ import {
2
+ codebaseRetrievalSchema,
3
+ handleCodebaseRetrieval
4
+ } from "./chunk-5TV4JNTE.js";
5
+ import "./chunk-5SRSUMKW.js";
6
+ import "./chunk-PN7DP6XL.js";
7
+ export {
8
+ codebaseRetrievalSchema,
9
+ handleCodebaseRetrieval
10
+ };
@@ -0,0 +1,18 @@
1
+ import {
2
+ DEFAULT_EXCLUDE_PATTERNS,
3
+ checkEmbeddingEnv,
4
+ checkRerankerEnv,
5
+ getEmbeddingConfig,
6
+ getExcludePatterns,
7
+ getRerankerConfig,
8
+ isDev
9
+ } from "./chunk-PN7DP6XL.js";
10
+ export {
11
+ DEFAULT_EXCLUDE_PATTERNS,
12
+ checkEmbeddingEnv,
13
+ checkRerankerEnv,
14
+ getEmbeddingConfig,
15
+ getExcludePatterns,
16
+ getRerankerConfig,
17
+ isDev
18
+ };
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ scan
4
+ } from "./chunk-34YZ2U3O.js";
5
+ import "./chunk-6C2D5Y4R.js";
6
+ import {
7
+ generateProjectId,
8
+ logger
9
+ } from "./chunk-5SRSUMKW.js";
10
+ import "./chunk-PN7DP6XL.js";
11
+
12
+ // src/index.ts
13
+ import cac from "cac";
14
+ import { promises as fs } from "fs";
15
+ import path from "path";
16
+ import os from "os";
17
+ var cli = cac("contextweaver");
18
+ cli.command("init", "\u521D\u59CB\u5316 ContextWeaver \u914D\u7F6E").action(async () => {
19
+ const configDir = path.join(os.homedir(), ".contextweaver");
20
+ const envFile = path.join(configDir, ".env");
21
+ logger.info("\u5F00\u59CB\u521D\u59CB\u5316 ContextWeaver...");
22
+ try {
23
+ await fs.mkdir(configDir, { recursive: true });
24
+ logger.info(`\u521B\u5EFA\u914D\u7F6E\u76EE\u5F55: ${configDir}`);
25
+ } catch (err) {
26
+ if (err.code !== "EEXIST") {
27
+ logger.error({ err, stack: err.stack }, `\u521B\u5EFA\u914D\u7F6E\u76EE\u5F55\u5931\u8D25: ${err.message}`);
28
+ process.exit(1);
29
+ }
30
+ logger.info(`\u914D\u7F6E\u76EE\u5F55\u5DF2\u5B58\u5728: ${configDir}`);
31
+ }
32
+ try {
33
+ await fs.access(envFile);
34
+ logger.warn(`.env \u6587\u4EF6\u5DF2\u5B58\u5728: ${envFile}`);
35
+ logger.info("\u521D\u59CB\u5316\u5B8C\u6210\uFF01");
36
+ return;
37
+ } catch {
38
+ }
39
+ const defaultEnvContent = `# ContextWeaver \u793A\u4F8B\u73AF\u5883\u53D8\u91CF\u914D\u7F6E\u6587\u4EF6
40
+
41
+ # Embedding API \u914D\u7F6E\uFF08\u5FC5\u9700\uFF09
42
+ EMBEDDINGS_API_KEY=your-api-key-here
43
+ EMBEDDINGS_BASE_URL=https://api.siliconflow.cn/v1/embeddings
44
+ EMBEDDINGS_MODEL=BAAI/bge-m3
45
+ EMBEDDINGS_MAX_CONCURRENCY=10
46
+ EMBEDDINGS_DIMENSIONS=1024
47
+
48
+ # Reranker \u914D\u7F6E\uFF08\u5FC5\u9700\uFF09
49
+ RERANK_API_KEY=your-api-key-here
50
+ RERANK_BASE_URL=https://api.siliconflow.cn/v1/rerank
51
+ RERANK_MODEL=BAAI/bge-reranker-v2-m3
52
+ RERANK_TOP_N=20
53
+
54
+ # \u7D22\u5F15\u5FFD\u7565\u6A21\u5F0F\uFF08\u53EF\u9009\uFF0C\u9017\u53F7\u5206\u9694\uFF0C\u9ED8\u8BA4\u5DF2\u5305\u542B\u5E38\u89C1\u5FFD\u7565\u9879\uFF09
55
+ # IGNORE_PATTERNS=.venv,node_modules
56
+ `;
57
+ try {
58
+ await fs.writeFile(envFile, defaultEnvContent);
59
+ logger.info(`\u521B\u5EFA .env \u6587\u4EF6: ${envFile}`);
60
+ } catch (err) {
61
+ logger.error({ err, stack: err.stack }, `\u521B\u5EFA .env \u6587\u4EF6\u5931\u8D25: ${err.message}`);
62
+ process.exit(1);
63
+ }
64
+ logger.info("\u4E0B\u4E00\u6B65\u64CD\u4F5C:");
65
+ logger.info(` 1. \u7F16\u8F91\u914D\u7F6E\u6587\u4EF6: ${envFile}`);
66
+ logger.info(" 2. \u586B\u5199\u4F60\u7684 API Key \u548C\u5176\u4ED6\u914D\u7F6E");
67
+ logger.info("\u521D\u59CB\u5316\u5B8C\u6210\uFF01");
68
+ });
69
+ cli.command("index [path]", "\u626B\u63CF\u4EE3\u7801\u5E93\u5E76\u5EFA\u7ACB\u7D22\u5F15").option("-f, --force", "\u5F3A\u5236\u91CD\u65B0\u7D22\u5F15").action(async (targetPath, options) => {
70
+ const rootPath = targetPath ? path.resolve(targetPath) : process.cwd();
71
+ const projectId = generateProjectId(rootPath);
72
+ logger.info(`\u5F00\u59CB\u626B\u63CF: ${rootPath}`);
73
+ logger.info(`\u9879\u76EE ID: ${projectId}`);
74
+ if (options.force) {
75
+ logger.info("\u5F3A\u5236\u91CD\u65B0\u7D22\u5F15: \u662F");
76
+ }
77
+ const startTime = Date.now();
78
+ try {
79
+ const stats = await scan(rootPath, {
80
+ force: options.force,
81
+ onProgress: (current, total) => {
82
+ const percent = (current / total * 100).toFixed(1);
83
+ process.stdout.write(`\r\u8FDB\u5EA6: ${current}/${total} (${percent}%)`);
84
+ }
85
+ });
86
+ process.stdout.write("\n");
87
+ const duration = ((Date.now() - startTime) / 1e3).toFixed(2);
88
+ logger.info("\u626B\u63CF\u5B8C\u6210\uFF01");
89
+ logger.info(`\u8017\u65F6: ${duration}s`);
90
+ logger.info(`\u6587\u4EF6\u603B\u6570: ${stats.totalFiles}`);
91
+ logger.info(`\u65B0\u589E: ${stats.added}`);
92
+ logger.info(`\u4FEE\u6539: ${stats.modified}`);
93
+ logger.info(`\u672A\u53D8: ${stats.unchanged}`);
94
+ logger.info(`\u5220\u9664: ${stats.deleted}`);
95
+ logger.info(`\u8DF3\u8FC7: ${stats.skipped}`);
96
+ logger.info(`\u9519\u8BEF: ${stats.errors}`);
97
+ } catch (err) {
98
+ logger.error({ err, stack: err.stack }, `\u626B\u63CF\u5931\u8D25: ${err.message}`);
99
+ process.exit(1);
100
+ }
101
+ });
102
+ cli.command("mcp", "\u542F\u52A8 MCP \u670D\u52A1\u5668").action(async () => {
103
+ const { startMcpServer } = await import("./server-2SAFEAEY.js");
104
+ try {
105
+ await startMcpServer();
106
+ } catch (error) {
107
+ logger.error({ error: error.message, stack: error.stack }, `MCP \u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25: ${error.message}`);
108
+ process.exit(1);
109
+ }
110
+ });
111
+ cli.command("search", "\u672C\u5730\u68C0\u7D22\uFF08\u53C2\u6570\u5BF9\u9F50 MCP\uFF09").option("--repo-path <path>", "\u4EE3\u7801\u5E93\u6839\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09").option("--information-request <text>", "\u81EA\u7136\u8BED\u8A00\u95EE\u9898\u63CF\u8FF0\uFF08\u5FC5\u586B\uFF09").option("--technical-terms <terms>", "\u7CBE\u786E\u672F\u8BED\uFF08\u9017\u53F7\u5206\u9694\uFF09").option("--zen", "\u4F7F\u7528 MCP Zen \u914D\u7F6E\uFF08\u9ED8\u8BA4\u5F00\u542F\uFF09").action(async (options) => {
112
+ const repoPath = options.repoPath ? path.resolve(options.repoPath) : process.cwd();
113
+ const informationRequest = options.informationRequest;
114
+ if (!informationRequest) {
115
+ logger.error("\u7F3A\u5C11 --information-request");
116
+ process.exit(1);
117
+ }
118
+ const technicalTerms = (options.technicalTerms || "").split(",").map((t) => t.trim()).filter(Boolean);
119
+ const useZen = options.zen !== false;
120
+ const { handleCodebaseRetrieval } = await import("./codebaseRetrieval-RDCNIUDM.js");
121
+ const response = await handleCodebaseRetrieval({
122
+ repo_path: repoPath,
123
+ information_request: informationRequest,
124
+ technical_terms: technicalTerms.length > 0 ? technicalTerms : void 0
125
+ }, useZen ? void 0 : {});
126
+ const text = response.content.map((item) => item.text).join("\n");
127
+ process.stdout.write(text + "\n");
128
+ });
129
+ cli.help();
130
+ cli.parse();
@@ -0,0 +1,9 @@
1
+ import {
2
+ scan
3
+ } from "./chunk-34YZ2U3O.js";
4
+ import "./chunk-6C2D5Y4R.js";
5
+ import "./chunk-5SRSUMKW.js";
6
+ import "./chunk-PN7DP6XL.js";
7
+ export {
8
+ scan
9
+ };
@@ -0,0 +1,131 @@
1
+ import {
2
+ codebaseRetrievalSchema,
3
+ handleCodebaseRetrieval
4
+ } from "./chunk-5TV4JNTE.js";
5
+ import {
6
+ logger
7
+ } from "./chunk-5SRSUMKW.js";
8
+ import "./chunk-PN7DP6XL.js";
9
+
10
+ // src/mcp/server.ts
11
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
12
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
+ import {
14
+ CallToolRequestSchema,
15
+ ListToolsRequestSchema
16
+ } from "@modelcontextprotocol/sdk/types.js";
17
+ var SERVER_NAME = "contextweaver";
18
+ var SERVER_VERSION = "0.1.0";
19
+ var TOOLS = [
20
+ {
21
+ name: "codebase-retrieval",
22
+ description: `
23
+ IMPORTANT: This is the PRIMARY tool for searching the codebase.
24
+ It uses a hybrid engine (Semantic + Exact Match) to find relevant code.
25
+ Think of it as the "Google Search" for this repository.
26
+
27
+ Capabilities:
28
+ 1. Semantic Search: Understands "what code does" (e.g., "auth logic") via high-dimensional embeddings.
29
+ 2. Exact Match: Filters by precise symbols (e.g., class names) via FTS (Full Text Search).
30
+ 3. Zen Context: Returns code with localized context (breadcrumbs) to avoid token overflow.
31
+
32
+ <RULES>
33
+ # 1. Tool Selection (When to use)
34
+ - ALWAYS use this tool FIRST for any code exploration or understanding task.
35
+ - DO NOT try to guess file paths. If you don't have the exact path, use this tool.
36
+ - DO NOT use 'grep' or 'find' for semantic understanding. Only use them for exhaustive text matching (e.g. "Find ALL occurrences of string 'foo'").
37
+
38
+ # 2. Before Editing (Critical)
39
+ - Before creating a plan or editing any file, YOU MUST call this tool to gather context.
40
+ - Ask for ALL symbols involved in the edit (classes, functions, types, constants).
41
+ - Do not assume you remember the code structure. Verify it with this tool.
42
+
43
+ # 3. Query Strategy (How to use)
44
+ - Split your intent:
45
+ - Put the "Goal/Context" in 'information_request'.
46
+ - Put "Known Class/Func Names" in 'technical_terms'.
47
+ - If the first search is too broad, add more specific 'technical_terms'.
48
+ </RULES>
49
+
50
+ Examples of GOOD queries:
51
+ * [Goal: Understand Auth]
52
+ information_request: "How is user authentication flow handled?"
53
+ * [Goal: Fix DB Pool bug]
54
+ information_request: "Logic for database connection pooling and error handling"
55
+ technical_terms: ["PoolConfig", "Connection", "release"]
56
+
57
+ Examples of BAD queries:
58
+ * "Show me src/main.ts" (Use 'read_file' instead)
59
+ * "Find definition of constructor of class Foo" (Use this tool, but put "Foo" in technical_terms)
60
+ * "Find all references to function bar across the whole project" (Use 'grep' tool for exhaustive reference counting)
61
+ `,
62
+ inputSchema: {
63
+ type: "object",
64
+ properties: {
65
+ repo_path: {
66
+ type: "string",
67
+ description: "The absolute file system path to the repository root."
68
+ },
69
+ information_request: {
70
+ type: "string",
71
+ description: "The SEMANTIC GOAL. Describe the functionality, logic, or behavior you are looking for in full natural language sentences. Focus on 'how it works' rather than exact names. (e.g., 'Trace the execution flow of the login process')"
72
+ },
73
+ technical_terms: {
74
+ type: "array",
75
+ items: { type: "string" },
76
+ description: "HARD FILTERS. An optional list of EXACT, KNOWN identifiers (class/function names, constants) that MUST appear in the code. Only use terms you are 100% sure exist. Leave empty if exploring."
77
+ }
78
+ },
79
+ required: ["repo_path", "information_request"]
80
+ }
81
+ }
82
+ ];
83
+ async function startMcpServer() {
84
+ logger.info({ name: SERVER_NAME, version: SERVER_VERSION }, "\u542F\u52A8 MCP \u670D\u52A1\u5668");
85
+ const server = new Server(
86
+ {
87
+ name: SERVER_NAME,
88
+ version: SERVER_VERSION
89
+ },
90
+ {
91
+ capabilities: {
92
+ tools: {}
93
+ }
94
+ }
95
+ );
96
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
97
+ logger.debug("\u6536\u5230 list_tools \u8BF7\u6C42");
98
+ return { tools: TOOLS };
99
+ });
100
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
101
+ const { name, arguments: args } = request.params;
102
+ logger.info({ tool: name }, "\u6536\u5230 call_tool \u8BF7\u6C42");
103
+ try {
104
+ switch (name) {
105
+ case "codebase-retrieval": {
106
+ const parsed = codebaseRetrievalSchema.parse(args);
107
+ return await handleCodebaseRetrieval(parsed);
108
+ }
109
+ default:
110
+ throw new Error(`Unknown tool: ${name}`);
111
+ }
112
+ } catch (error) {
113
+ logger.error({ error: error.message, stack: error.stack, tool: name }, "\u5DE5\u5177\u8C03\u7528\u5931\u8D25");
114
+ return {
115
+ content: [
116
+ {
117
+ type: "text",
118
+ text: `Error: ${error.message}`
119
+ }
120
+ ],
121
+ isError: true
122
+ };
123
+ }
124
+ });
125
+ const transport = new StdioServerTransport();
126
+ await server.connect(transport);
127
+ logger.info("MCP \u670D\u52A1\u5668\u5DF2\u542F\u52A8\uFF0C\u7B49\u5F85\u8FDE\u63A5...");
128
+ }
129
+ export {
130
+ startMcpServer
131
+ };
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@hsingjui/contextweaver",
3
+ "version": "0.0.1",
4
+ "description": "A context weaving tool for LLMs",
5
+ "license": "MIT",
6
+ "author": "hsingjui",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/hsingjui/contextweaver.git"
10
+ },
11
+ "homepage": "https://github.com/hsingjui/contextweaver#readme",
12
+ "private": false,
13
+ "type": "module",
14
+ "bin": {
15
+ "contextweaver": "dist/index.js",
16
+ "cw": "dist/index.js"
17
+ },
18
+ "files": [
19
+ "dist/**/*.js",
20
+ "dist/**/*.d.ts"
21
+ ],
22
+ "engines": {
23
+ "node": ">=20"
24
+ },
25
+ "dependencies": {
26
+ "@lancedb/lancedb": "^0.19.1",
27
+ "@modelcontextprotocol/sdk": "^1.25.1",
28
+ "better-sqlite3": "^11.10.0",
29
+ "cac": "^6.7.14",
30
+ "chardet": "^2.1.1",
31
+ "dotenv": "^17.2.3",
32
+ "fdir": "^6.5.0",
33
+ "iconv-lite": "^0.7.1",
34
+ "ignore": "^7.0.5",
35
+ "p-limit": "^7.2.0",
36
+ "pino": "^10.1.0",
37
+ "tree-sitter": "0.20.6",
38
+ "tree-sitter-go": "0.20.0",
39
+ "tree-sitter-java": "0.20.2",
40
+ "tree-sitter-javascript": "0.20.4",
41
+ "tree-sitter-python": "0.20.4",
42
+ "tree-sitter-rust": "0.20.4",
43
+ "tree-sitter-typescript": "0.20.5",
44
+ "zod": "^4.2.1"
45
+ },
46
+ "devDependencies": {
47
+ "@types/better-sqlite3": "^7.6.13",
48
+ "@types/node": "^25.0.3",
49
+ "pino-pretty": "^13.1.3",
50
+ "tsup": "^8.5.1",
51
+ "typescript": "^5.9.3"
52
+ },
53
+ "scripts": {
54
+ "build": "tsup src/index.ts src/mcp/main.ts --format esm --dts --out-dir dist --sourcemap --clean",
55
+ "build:release": "tsup src/index.ts src/mcp/main.ts --format esm --dts --out-dir dist --clean",
56
+ "dev": "tsup src/index.ts src/mcp/main.ts --format esm --dts --out-dir dist --sourcemap --watch",
57
+ "start": "node dist/index.js"
58
+ }
59
+ }