@hypothesi/tauri-mcp-server 0.2.2 → 0.3.0
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/README.md +13 -28
- package/dist/driver/plugin-commands.js +0 -15
- package/dist/driver/session-manager.js +28 -3
- package/dist/driver/webview-executor.js +35 -10
- package/dist/driver/webview-interactions.js +27 -3
- package/dist/index.js +27 -1
- package/dist/manager/mobile.js +0 -44
- package/dist/monitor/logs.js +15 -3
- package/dist/prompts-registry.js +109 -1
- package/dist/tools-registry.js +31 -170
- package/package.json +1 -1
- package/dist/manager/cli.js +0 -128
- package/dist/manager/config.js +0 -142
- package/dist/manager/docs.js +0 -213
package/dist/manager/docs.js
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { execa } from 'execa';
|
|
5
|
-
export const GetDocsSchema = z.object({
|
|
6
|
-
projectPath: z.string().describe('Path to the Tauri project'),
|
|
7
|
-
});
|
|
8
|
-
export async function getDocs(projectPath) {
|
|
9
|
-
try {
|
|
10
|
-
const version = await getTauriVersion(projectPath), isV2 = version.startsWith('2'), docs = await fetchDocs(version, isV2);
|
|
11
|
-
return docs;
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
return `Error getting docs: ${error}`;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
async function getTauriVersion(projectPath) {
|
|
18
|
-
try {
|
|
19
|
-
// 1. Try 'cargo tree' to get the exact resolved version of the tauri crate
|
|
20
|
-
try {
|
|
21
|
-
const { stdout } = await execa('cargo', ['tree', '-p', 'tauri', '--depth', '0'], { cwd: path.join(projectPath, 'src-tauri') }), match = stdout.match(/tauri v([\d.]+)/);
|
|
22
|
-
if (match && match[1]) {
|
|
23
|
-
return match[1];
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
catch (e) {
|
|
27
|
-
// Ignore
|
|
28
|
-
}
|
|
29
|
-
// 2. Try 'npm list' for the CLI version
|
|
30
|
-
try {
|
|
31
|
-
const { stdout } = await execa('npm', ['list', '@tauri-apps/cli', '--depth=0', '--json'], { cwd: projectPath }), pkg = JSON.parse(stdout);
|
|
32
|
-
if (pkg.dependencies?.['@tauri-apps/cli']?.version) {
|
|
33
|
-
return pkg.dependencies['@tauri-apps/cli'].version;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
catch (e) {
|
|
37
|
-
// Ignore
|
|
38
|
-
}
|
|
39
|
-
// 3. Fallback: Read Cargo.toml manually
|
|
40
|
-
const cargoPath = path.join(projectPath, 'src-tauri', 'Cargo.toml'), cargoContent = await fs.readFile(cargoPath, 'utf-8'), match = cargoContent.match(/tauri\s*=\s*{?[^}]*version\s*=\s*"([^"]+)"/);
|
|
41
|
-
if (match && match[1]) {
|
|
42
|
-
return match[1];
|
|
43
|
-
}
|
|
44
|
-
// 4. Fallback: Read package.json
|
|
45
|
-
const pkgPath = path.join(projectPath, 'package.json'), pkgContent = await fs.readFile(pkgPath, 'utf-8'), pkgJson = JSON.parse(pkgContent), cliVersion = pkgJson.devDependencies?.['@tauri-apps/cli'] || pkgJson.dependencies?.['@tauri-apps/cli'];
|
|
46
|
-
if (cliVersion) {
|
|
47
|
-
return cliVersion.replace('^', '').replace('~', '');
|
|
48
|
-
}
|
|
49
|
-
return 'unknown';
|
|
50
|
-
}
|
|
51
|
-
catch (e) {
|
|
52
|
-
return 'unknown';
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
// Exported for testing
|
|
56
|
-
export async function fetchDocs(version, isV2) {
|
|
57
|
-
const branch = isV2 ? 'v2' : 'v1', treeUrl = `https://api.github.com/repos/tauri-apps/tauri-docs/git/trees/${branch}?recursive=1`, rawBaseUrl = `https://raw.githubusercontent.com/tauri-apps/tauri-docs/${branch}`;
|
|
58
|
-
try {
|
|
59
|
-
// Fetching file tree from ${treeUrl}...
|
|
60
|
-
const treeResponse = await fetch(treeUrl, {
|
|
61
|
-
headers: {
|
|
62
|
-
'User-Agent': 'mcp-server-tauri', // GitHub API requires User-Agent
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
if (!treeResponse.ok) {
|
|
66
|
-
throw new Error(`Failed to fetch file tree: ${treeResponse.status} ${treeResponse.statusText}`);
|
|
67
|
-
}
|
|
68
|
-
const treeData = (await treeResponse.json()), relevantFiles = filterRelevantFiles(treeData.tree, isV2);
|
|
69
|
-
// Found ${relevantFiles.length} relevant documentation files.
|
|
70
|
-
let combinedDocs = `# Tauri ${isV2 ? 'v2' : 'v1'} Documentation (Dynamically Fetched)\n\n`;
|
|
71
|
-
combinedDocs += `Version Detected: ${version}\n`;
|
|
72
|
-
combinedDocs += `Source: ${rawBaseUrl}\n\n`;
|
|
73
|
-
// Fetch content in batches to be polite and avoid timeouts
|
|
74
|
-
const batchSize = 5;
|
|
75
|
-
for (let i = 0; i < relevantFiles.length; i += batchSize) {
|
|
76
|
-
const batch = relevantFiles.slice(i, i + batchSize), results = await Promise.all(batch.map((file) => { return fetchContent(rawBaseUrl, file); }));
|
|
77
|
-
combinedDocs += results.join('\n\n');
|
|
78
|
-
}
|
|
79
|
-
return combinedDocs;
|
|
80
|
-
}
|
|
81
|
-
catch (e) {
|
|
82
|
-
// Error fetching dynamic docs: ${e}
|
|
83
|
-
return `Error fetching dynamic docs: ${e}\n\n` + getStaticFallback(version, isV2);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
function isExcludedPath(filePath) {
|
|
87
|
-
// Check for common exclusions
|
|
88
|
-
if (filePath.includes('/blog/') || filePath.includes('/_') || filePath.includes('/translations/')) {
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
// Check file extensions
|
|
92
|
-
if (!filePath.endsWith('.md') && !filePath.endsWith('.mdx')) {
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
// Check for hidden or node_modules
|
|
96
|
-
if (filePath.startsWith('.') || filePath.includes('/node_modules/')) {
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
// Check for blog posts
|
|
100
|
-
if (filePath.startsWith('blog/') || filePath.includes('/blog/')) {
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
function isTranslationPath(filePath) {
|
|
106
|
-
const langCodes = ['fr', 'es', 'it', 'ja', 'ko', 'zh-cn', 'zh-tw', 'pt-br', 'ru', 'de'];
|
|
107
|
-
for (const lang of langCodes) {
|
|
108
|
-
const hasLang = filePath.includes(`/${lang}/`) || filePath.includes(`/_${lang}/`) ||
|
|
109
|
-
filePath.startsWith(`${lang}/`) || filePath.startsWith(`_${lang}/`);
|
|
110
|
-
if (hasLang) {
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
function filterRelevantFiles(tree, isV2) {
|
|
117
|
-
return tree.filter((item) => {
|
|
118
|
-
if (item.type !== 'blob') {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
const file = item;
|
|
122
|
-
if (isExcludedPath(file.path) || isTranslationPath(file.path)) {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
if (isV2) {
|
|
126
|
-
// v2 docs are in src/content/docs
|
|
127
|
-
if (!file.path.startsWith('src/content/docs/')) {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
// Exclude fragments and templates
|
|
131
|
-
if (file.path.includes('/_fragments/') || file.path.includes('/.templates/')) {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
// v1 docs are in docs/
|
|
137
|
-
if (!file.path.startsWith('docs/')) {
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
// Exclude templates
|
|
141
|
-
if (file.path.includes('/.templates/')) {
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return true;
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
async function fetchContent(baseUrl, file) {
|
|
149
|
-
try {
|
|
150
|
-
const url = `${baseUrl}/${file.path}`, response = await fetch(url);
|
|
151
|
-
if (!response.ok) {
|
|
152
|
-
return `## ${file.path}\n\n(Failed to fetch: ${response.status})\n`;
|
|
153
|
-
}
|
|
154
|
-
const text = await response.text();
|
|
155
|
-
// Remove frontmatter
|
|
156
|
-
const cleanText = text.replace(/^---[\s\S]*?---\n/, '');
|
|
157
|
-
return `## ${file.path}\n\n${cleanText}\n\n---\n`;
|
|
158
|
-
}
|
|
159
|
-
catch (e) {
|
|
160
|
-
return `## ${file.path}\n\n(Error fetching content: ${e})\n`;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
function getStaticFallback(version, isV2) {
|
|
164
|
-
if (isV2) {
|
|
165
|
-
return `# Tauri v2 Static Fallback
|
|
166
|
-
(Dynamic fetching failed. This is a minimal fallback.)
|
|
167
|
-
|
|
168
|
-
## Core Concepts
|
|
169
|
-
- **Frontend**: Web technologies (HTML/CSS/JS).
|
|
170
|
-
- **Backend**: Rust.
|
|
171
|
-
- **IPC**: Use \`invoke\` to call Rust commands.
|
|
172
|
-
|
|
173
|
-
## Security
|
|
174
|
-
- Enable capabilities in \`src-tauri/capabilities\`.
|
|
175
|
-
- Configure permissions in \`tauri.conf.json\`.
|
|
176
|
-
`;
|
|
177
|
-
}
|
|
178
|
-
return `# Tauri v1 LLM Cheat Sheet
|
|
179
|
-
Version Detected: ${version}
|
|
180
|
-
Documentation: https://tauri.app/v1/api/
|
|
181
|
-
|
|
182
|
-
## Core Concepts
|
|
183
|
-
- **Frontend**: Web technologies.
|
|
184
|
-
- **Backend**: Rust.
|
|
185
|
-
- **IPC**: \`invoke\` and \`#[tauri::command]\`.
|
|
186
|
-
|
|
187
|
-
## Key APIs (Frontend)
|
|
188
|
-
\`\`\`typescript
|
|
189
|
-
import { invoke } from '@tauri-apps/api/tauri';
|
|
190
|
-
|
|
191
|
-
// Call Rust command
|
|
192
|
-
await invoke('my_command', { arg: 'value' });
|
|
193
|
-
\`\`\`
|
|
194
|
-
|
|
195
|
-
## Key APIs (Rust)
|
|
196
|
-
\`\`\`rust
|
|
197
|
-
#[tauri::command]
|
|
198
|
-
fn my_command(arg: String) -> String {
|
|
199
|
-
format!("Hello {}", arg)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
fn main() {
|
|
203
|
-
tauri::Builder::default()
|
|
204
|
-
.invoke_handler(tauri::generate_handler![my_command])
|
|
205
|
-
.run(tauri::generate_context!())
|
|
206
|
-
.expect("error while running tauri application");
|
|
207
|
-
}
|
|
208
|
-
\`\`\`
|
|
209
|
-
|
|
210
|
-
## Configuration
|
|
211
|
-
- **tauri.conf.json**: Uses \`allowlist\` to enable features.
|
|
212
|
-
`;
|
|
213
|
-
}
|