mcp-osp-prompt 1.0.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 ADDED
@@ -0,0 +1,358 @@
1
+ # MCP Prompt Fetcher
2
+
3
+ [![npm version](https://badge.fury.io/js/mcp-prompt-fetcher.svg)](https://badge.fury.io/js/mcp-prompt-fetcher)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A powerful MCP (Model Context Protocol) server that provides intelligent development prompts for Cursor, VS Code, and other IDE tools. Supports GitHub, GitLab, and local directory sources with automatic platform detection.
7
+
8
+ ## 🌟 Features
9
+
10
+ - **🚀 Multi-Platform Support**: GitHub, GitLab, and local directories
11
+ - **⚡ Auto-Detection**: Automatically detects platform from `RESOURCE_PATH`
12
+ - **🔐 Unified Authentication**: Single `GIT_TOKEN` for both GitHub and GitLab
13
+ - **🎛️ Flexible Dialogs**: Native system dialogs and web-based interfaces
14
+ - **📦 Zero Configuration**: Works out-of-the-box with intelligent defaults
15
+ - **🔄 Smart Caching**: Optimized remote file fetching with TTL-based caching (3-hour default)
16
+ - **⚡ Lazy Loading**: Prompt content loaded on-demand to minimize API calls
17
+ - **🛡️ Rate Limit Protection**: Automatic fallback to cached data and graceful degradation
18
+ - **🎯 Efficient API Usage**: Only fetches file lists on startup, content on tool invocation
19
+ - **🌍 Cross-Platform**: Full macOS and Linux compatibility
20
+
21
+ ## 📦 Installation
22
+
23
+ ```bash
24
+ # Install globally (recommended)
25
+ npm install -g mcp-prompt-fetcher
26
+
27
+ # Or install locally
28
+ npm install mcp-prompt-fetcher
29
+ ```
30
+
31
+ ## ⚙️ Quick Setup
32
+
33
+ ### 1️⃣ Simple Configuration (Only 2 environment variables needed!)
34
+
35
+ Add to your IDE's MCP configuration file (e.g., `~/.cursor/mcp.json`):
36
+
37
+ #### GitHub Repository
38
+ ```jsonc
39
+ {
40
+ "mcpServers": {
41
+ "mcp-prompt-fetcher": {
42
+ "command": "mcp-prompt-fetcher",
43
+ "env": {
44
+ "RESOURCE_PATH": "username/repository",
45
+ "GIT_TOKEN": "ghp_your_github_token_here"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ #### GitLab Repository
53
+ ```jsonc
54
+ {
55
+ "mcpServers": {
56
+ "mcp-prompt-fetcher": {
57
+ "command": "mcp-prompt-fetcher",
58
+ "env": {
59
+ "RESOURCE_PATH": "https://gitlab.com/group/project",
60
+ "GIT_TOKEN": "glpat-your_gitlab_token_here"
61
+ }
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ #### Local Directory
68
+ ```jsonc
69
+ {
70
+ "mcpServers": {
71
+ "mcp-prompt-fetcher": {
72
+ "command": "mcp-prompt-fetcher",
73
+ "env": {
74
+ "RESOURCE_PATH": "/path/to/your/prompts"
75
+ }
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ #### Local Development & Testing
82
+ ```jsonc
83
+ {
84
+ "osp-prompt-dev": {
85
+ "command": "node",
86
+ "args": [
87
+ "/absolute/path/to/osp-prompt/dev-mcp/server.js"
88
+ ],
89
+ "env": {
90
+ "RESOURCE_PATH": "/absolute/path/to/osp-prompt/osp",
91
+ "CACHE_DIR": "/absolute/path/to/osp-prompt/dev-mcp/.cache",
92
+ "AUTOMATED_MODE": "false",
93
+ "DEBUG_LOG": "true"
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ **本地开发配置说明:**
100
+ 1. **克隆项目到本地:**
101
+ ```bash
102
+ git clone https://gitlab.com/your-org/osp-prompt.git
103
+ cd osp-prompt/dev-mcp
104
+ npm install
105
+ ```
106
+
107
+ 2. **目录结构要求:**
108
+ ```
109
+ osp-prompt/
110
+ ├── osp/ # 资源根目录
111
+ │ ├── prompts/ # 提示词文件 (必需)
112
+ │ │ ├── design.prompt.md
113
+ │ │ ├── feature.prompt.md
114
+ │ │ └── ...
115
+ │ ├── projects/ # 项目文档 (可选)
116
+ │ │ ├── kiki-framework-wiki.md
117
+ │ │ └── ...
118
+ │ └── rules/ # 编码规范 (可选)
119
+ │ ├── java-rules.md
120
+ │ └── python-rules.md
121
+ └── dev-mcp/ # MCP 服务端
122
+ ├── server.js
123
+ ├── tests/ # 测试脚本
124
+ └── .cache/ # 本地缓存目录
125
+ ```
126
+
127
+ 3. **配置 Cursor MCP:**
128
+ - 编辑 `~/.cursor/mcp.json` 或项目的 `.cursor/mcp.json`
129
+ - 将上述配置中的路径替换为你的实际绝对路径
130
+ - 重启 Cursor
131
+
132
+ 4. **运行端到端测试:**
133
+ ```bash
134
+ # 测试 dev-design 完整流程
135
+ node tests/test-dev-design-e2e.js
136
+
137
+ # 测试 dev-feature 完整流程
138
+ node tests/test-dev-feature-e2e.js
139
+ ```
140
+
141
+ 5. **验证功能:**
142
+ - 在 Cursor 中打开任意项目
143
+ - 尝试调用 `dev-design` 或 `dev-feature` 工具
144
+ - 检查是否能看到:
145
+ * ✅ 可用的 projects 文档列表
146
+ * ✅ 可用的 rules 规范列表
147
+ * ✅ `load-resource` 工具使用说明
148
+ * ✅ 当前日期上下文
149
+
150
+ **重要提示:**
151
+ - **RESOURCE_PATH**: 本地模式下指向 `osp` 目录(包含 `prompts/`, `projects/`, `rules/` 子目录)
152
+ - **多目录支持**: 系统会自动扫描 `osp/projects/` 和 `osp/rules/` 目录
153
+ - **缓存目录**: 本地模式会将资源复制到 CACHE_DIR 进行缓存
154
+ - **AUTOMATED_MODE**: 设为 `false` 启用交互式确认,`true` 为全自动模式
155
+
156
+ ### 2️⃣ Universal URL Parser - Handle Any Complex URL!
157
+
158
+ Our advanced URL parser supports **any complex** GitLab and GitHub repository structure:
159
+
160
+ #### Complex URL Examples That Work:
161
+
162
+ ```bash
163
+ # GitLab with multi-level projects and complex branches
164
+ "https://gitlab.com/Keccac256-evg/opensocial/osp-prompt/-/tree/master/dev-arch"
165
+ "https://gitlab.com/group/subgroup/project/-/tree/feature/new-ui/src/components"
166
+ "https://gitlab.com/company/team/service/-/tree/v1.2.3/docs/api"
167
+
168
+ # GitHub with deep nested paths and feature branches
169
+ "https://github.com/feast-dev/feast/tree/master/examples/java-demo/feature_repo/data"
170
+ "https://github.com/microsoft/vscode/tree/main/src/vs/editor/contrib"
171
+ "https://github.com/facebook/react/tree/feature/concurrent/packages/react/src"
172
+ ```
173
+
174
+ #### Auto-Detection Results:
175
+
176
+ | RESOURCE_PATH Format | Platform | Parsed As |
177
+ |--------------------|----------|-----------|
178
+ | `user/repo` | GitHub | `user/repo@main:dev-arch` |
179
+ | `https://github.com/owner/repo/tree/branch/path/to/files` | GitHub | `owner/repo@branch:path/to/files` |
180
+ | `https://gitlab.com/group/project/-/tree/branch/path` | GitLab | `group/project@branch:path` |
181
+ | `https://gitlab.com/a/b/c/-/tree/feature/x/deep/nested/path` | GitLab | `a/b/c@feature/x:deep/nested/path` |
182
+ | `/absolute/path` | Local | Local filesystem |
183
+ | `./relative/path` | Local | Local filesystem |
184
+
185
+ #### Smart Features:
186
+ - ✅ **Multi-level projects**: `group/subgroup/project`
187
+ - ✅ **Complex branch names**: `feature/new-ui`, `hotfix/urgent-fix`
188
+ - ✅ **Deep file paths**: `src/main/java/com/example/service`
189
+ - ✅ **Version tags**: `v1.2.3`, `release/2024.1`
190
+ - ✅ **Automatic API URL generation** for both platforms
191
+
192
+ ## 🚀 Usage
193
+
194
+ Once configured, the following tools become available in your IDE:
195
+
196
+ - **`dev-feature`** - 🚀 Complete feature development (TDD workflow)
197
+ - **`dev-design`** - 📐 System architecture design and planning
198
+ - **`dev-refactor`** - 🔧 Code refactoring and optimization
199
+ - **`dev-small`** - ⚡ Quick development and bug fixes
200
+ - **`dev-tests`** - 🧪 Test coverage implementation (90%+ coverage)
201
+ - **`dev-bugfix`** - 🐛 Precise problem analysis and minimal-impact fixes
202
+ - **`dev-manual`** - 📋 Manual development type selection
203
+ - **`dev-feedback`** - 🔄 Interactive step-by-step confirmation
204
+
205
+ ### Command Examples
206
+ ```
207
+ dev-feature: Implement user authentication with email/phone login
208
+ dev-design: Design microservices architecture for e-commerce platform
209
+ dev-refactor: Improve code readability in user management module
210
+ dev-small: Fix login button display issue in Safari browser
211
+ dev-tests: Achieve 90%+ test coverage for user registration feature
212
+ dev-bugfix: Debug intermittent session loss during user login
213
+ ```
214
+
215
+ ## 🔧 Environment Variables
216
+
217
+ | Variable | Default | Description |
218
+ |----------|---------|-------------|
219
+ | `RESOURCE_PATH` | *(required)* | Platform will be auto-detected from this path |
220
+ | `GIT_TOKEN` | *(required for remote)* | GitHub (`ghp_...`) or GitLab (`glpat-...`) token |
221
+ | `DIALOG_MODE` | `auto` | Dialog mode: `auto`\|`native`\|`browser` |
222
+ | `AUTOMATED_MODE` | `true` | `false`=interactive confirmation, `true`=auto-execute |
223
+ | `CACHE_TTL_SEC` | `86400` | Cache TTL in seconds (24 hours) |
224
+ | `FORCE_UPDATE` | `false` | `true`=force remote fetch, bypass cache |
225
+ | `DEBUG_LOG` | `false` | Enable detailed logging |
226
+
227
+ ## 🧪 Testing
228
+
229
+ ### Verify Installation
230
+ ```bash
231
+ # Test local mode
232
+ echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | RESOURCE_PATH="./dev-arch" mcp-prompt-fetcher
233
+
234
+ # Test GitHub mode
235
+ echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | RESOURCE_PATH="user/repo" GIT_TOKEN="your_token" mcp-prompt-fetcher
236
+
237
+ # Test GitLab mode
238
+ echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | RESOURCE_PATH="https://gitlab.com/group/project" GIT_TOKEN="your_token" mcp-prompt-fetcher
239
+ ```
240
+
241
+ ### Run Test Suite
242
+ ```bash
243
+ npm test
244
+ ```
245
+
246
+ ### install npm
247
+ ```
248
+ <!-- 自动递增打包并打git tag -->
249
+ npm version patch|minor|major
250
+ <!-- 本地打包查看即将发布的内容 -->
251
+ npm pack --dry-run
252
+ <!-- 跑测试 + 审计脚本 -->
253
+ npm run test:all
254
+ npm run audit:security
255
+ <!-- 发布包 -->
256
+ npm publish --access public
257
+ <!-- 查看结果 -->
258
+ npm info mcp-prompt-fetcher
259
+ ```
260
+
261
+ ## 📁 Directory Structure
262
+
263
+ For local mode, your prompt directory should contain `.prompt.md` files:
264
+
265
+ ```
266
+ dev-arch/
267
+ ├── feature.prompt.md # → dev-feature tool
268
+ ├── design.prompt.md # → dev-design tool
269
+ ├── refactor.prompt.md # → dev-refactor tool
270
+ ├── small.prompt.md # → dev-small tool
271
+ ├── tests.prompt.md # → dev-tests tool
272
+ └── bugfix.prompt.md # → dev-bugfix tool
273
+ ```
274
+
275
+ ## 🎯 Best Practices
276
+
277
+ ### Recommended Configurations
278
+
279
+ | Use Case | Configuration | Benefits |
280
+ |----------|---------------|----------|
281
+ | **Local Development** | Local mode + Native dialogs | Fast response, offline ready |
282
+ | **Team Collaboration** | Remote mode + Browser dialogs | Beautiful UI, centralized management |
283
+ | **CI/CD Pipeline** | Remote mode + `AUTOMATED_MODE=true` | No GUI dependencies |
284
+ | **Step-by-Step Development** | Any mode + `AUTOMATED_MODE=false` | Interactive confirmation |
285
+
286
+ ### Token Permissions
287
+
288
+ #### GitHub Token Requirements:
289
+ - `public_repo` (for public repositories)
290
+ - `repo` (for private repositories)
291
+
292
+ #### GitLab Token Requirements:
293
+ - `read_repository`
294
+ - `read_api`
295
+
296
+ ## 🔍 Troubleshooting
297
+
298
+ ### Common Issues
299
+
300
+ | Problem | Symptoms | Solution |
301
+ |---------|----------|----------|
302
+ | **Tools not responding** | Click tool, no response | 1. Check MCP config syntax<br/>2. Restart IDE<br/>3. Verify token validity |
303
+ | **Dialog not showing** | Tool calls but no GUI | 1. Check `DIALOG_MODE` setting<br/>2. Try browser mode<br/>3. Check system permissions |
304
+ | **Invalid content returned** | Wrong prompt content | 1. Check repository permissions<br/>2. Verify branch and file paths<br/>3. Clear cache |
305
+ | **API Rate Limit (429 errors)** | Service starts with basic tools only | Normal behavior - basic tools work offline, cached content used when available |
306
+ | **Slow first-time loading** | Long delay on first tool call | Expected - prompt content fetched on-demand, then cached for 3 hours |
307
+
308
+ ### Cache Management
309
+ ```bash
310
+ # Clear cache
311
+ rm -rf ~/.cache/prompts/*.md
312
+
313
+ # Or force update
314
+ export FORCE_UPDATE=true
315
+ ```
316
+
317
+ ### Debug Mode
318
+ Set `DEBUG_LOG=true` to see detailed execution logs for troubleshooting.
319
+
320
+ ## 📋 API Reference
321
+
322
+ ### MCP Methods
323
+ - `initialize` - MCP protocol handshake
324
+ - `tools/list` - Get available tools (config-driven)
325
+ - `tools/call` - Execute specific tool
326
+
327
+ ### Tool Schema
328
+ Each tool follows this input schema:
329
+ ```json
330
+ {
331
+ "type": "object",
332
+ "properties": {
333
+ "source": {
334
+ "type": "string",
335
+ "description": "Development requirements or task description"
336
+ }
337
+ },
338
+ "required": ["source"]
339
+ }
340
+ ```
341
+
342
+ ## 🤝 Contributing
343
+
344
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
345
+
346
+ ## 📄 License
347
+
348
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
349
+
350
+ ## 🙋 Support
351
+
352
+ - **Documentation**: Check this README and inline code comments
353
+ - **Issues**: [GitHub Issues](https://github.com/mcp-community/prompt-fetcher/issues)
354
+ - **Discussions**: [GitHub Discussions](https://github.com/mcp-community/prompt-fetcher/discussions)
355
+
356
+ ---
357
+
358
+ **🎉 Happy Coding with Intelligent Prompts!**
package/config.js ADDED
@@ -0,0 +1,340 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { detectPlatformFromPath, parseRemotePath, createAuthHeaders, validatePlatformConfiguration } from './platform-utils.js';
4
+
5
+ const force = (process.env.FORCE_UPDATE || 'false').toLowerCase() === 'true';
6
+
7
+ // 🔵 REFACTOR: Task 2.1 - 提取Native弹窗宽度解析逻辑
8
+ function parseNativeDialogWidth() {
9
+ const envValue = process.env.NATIVE_DIALOG_WIDTH;
10
+ const defaultWidth = 600; // 默认600px,在各个平台上都比较合适的宽度
11
+ const minWidth = 300; // 最小宽度,确保内容可读
12
+ const maxWidth = 1200; // 最大宽度,避免在小屏幕上过宽
13
+
14
+ if (!envValue) {
15
+ return defaultWidth;
16
+ }
17
+
18
+ const parsed = parseInt(envValue, 10);
19
+
20
+ // 验证有效性和合理范围
21
+ if (isNaN(parsed) || parsed < minWidth || parsed > maxWidth) {
22
+ console.warn(`Warning: Invalid NATIVE_DIALOG_WIDTH value "${envValue}" (must be ${minWidth}-${maxWidth}px), using default ${defaultWidth}px`);
23
+ return defaultWidth;
24
+ }
25
+
26
+ return parsed;
27
+ }
28
+
29
+ // 🔧 系统配置
30
+ export const CFG = {
31
+ debug: process.env.DEBUG_LOG === 'true',
32
+ automatedMode: process.env.AUTOMATED_MODE !== 'false',
33
+ dialogMode: process.env.DIALOG_MODE || 'native',
34
+ defaultAuto: true,
35
+ force: force,
36
+ cacheDir: process.env.CACHE_DIR || path.join(process.env.HOME || '.', '.cache', 'prompts'),
37
+ ttl: parseInt(process.env.CACHE_TTL_SEC || '10800', 10), // 3小时默认TTL
38
+
39
+ // 🔵 REFACTOR: Task 2.1 - Native弹窗宽度配置(仅针对native模式)
40
+ nativeDialogWidth: parseNativeDialogWidth(),
41
+
42
+ tools: [],
43
+
44
+ get config() {
45
+ return this;
46
+ },
47
+
48
+ async initTools() {
49
+ if (!this.tools || this.tools.length === 0) {
50
+ this.tools = await initializeTools();
51
+ }
52
+ return this.tools || [];
53
+ }
54
+ };
55
+
56
+ // 🟢 GREEN: 统一资源配置 - 所有工具都加载完整的projects和rules列表
57
+ // AI将根据具体需求自行选择使用哪些resources
58
+ export const UNIFIED_RESOURCES = ['projects', 'rules'];
59
+
60
+ // 🟢 GREEN: Task 1.1 - 实现目录扫描功能(支持本地和远程)
61
+ export async function scanPromptFiles(devArchPath) {
62
+ try {
63
+ const files = await fs.readdir(devArchPath);
64
+ const promptFiles = files.filter(file => file.endsWith('.prompt.md'));
65
+
66
+ return promptFiles.map(filename => {
67
+ const baseName = filename.replace('.prompt.md', '');
68
+ return {
69
+ filename,
70
+ toolName: `dev-${baseName}`,
71
+ filepath: path.join(devArchPath, filename),
72
+ source: filename // 本地模式下直接使用文件名作为source
73
+ };
74
+ });
75
+ } catch (error) {
76
+ console.warn(`Warning: Could not scan ${devArchPath}:`, error.message);
77
+ return [];
78
+ }
79
+ }
80
+
81
+ // 🟢 GREEN: Task 1.2 - 实现自动配置生成功能(简化版)
82
+ export async function generateAutoPromptTools() {
83
+ try {
84
+ const resourcePath = process.env.RESOURCE_PATH;
85
+ if (!resourcePath) {
86
+ return getBasicPromptTools();
87
+ }
88
+
89
+ const platform = detectPlatformFromPath(resourcePath);
90
+ let scannedFiles;
91
+
92
+ if (platform === 'local') {
93
+ // 本地模式:扫描配置的本地目录
94
+ console.log(`[Config] Using local resource path: ${resourcePath}`);
95
+ scannedFiles = await scanPromptFiles(resourcePath);
96
+
97
+ // 如果本地扫描失败或没有找到文件,回退到基础工具
98
+ if (scannedFiles.length === 0) {
99
+ console.warn(`Warning: No prompt files found in ${resourcePath}, falling back to basic tools`);
100
+ return getBasicPromptTools();
101
+ }
102
+ } else {
103
+ // 远程模式:从GitHub或GitLab获取prompt文件列表
104
+ console.log(`[Config] Using remote ${platform} prompt files from: ${resourcePath}`);
105
+ scannedFiles = await scanRemotePromptFiles();
106
+
107
+ // 如果远程扫描失败或没有找到文件,回退到基础工具
108
+ if (scannedFiles.length === 0) {
109
+ console.warn(`Warning: No prompt files found from remote ${platform}, falling back to basic tools`);
110
+ return getBasicPromptTools();
111
+ }
112
+ }
113
+
114
+ return scannedFiles.map(({ filename, toolName, source }) => ({
115
+ name: toolName,
116
+ type: 'prompt',
117
+ source: source,
118
+ description: `${toolName} prompt direct`,
119
+ schema: {
120
+ type: 'object',
121
+ properties: { source: { type: 'string' } },
122
+ required: ['source']
123
+ }
124
+ }));
125
+ } catch (error) {
126
+ console.error('[Config] Auto prompt tool generation failed:', error.message);
127
+ return getBasicPromptTools();
128
+ }
129
+ }
130
+
131
+ // 基础prompt工具(回退选项)
132
+ function getBasicPromptTools() {
133
+ const basicTools = ['feature', 'bugfix', 'refactor', 'design', 'small', 'tests'];
134
+ return basicTools.map(tool => ({
135
+ name: `dev-${tool}`,
136
+ type: 'prompt',
137
+ source: `${tool}.prompt.md`,
138
+ description: `dev-${tool} prompt direct`,
139
+ schema: {
140
+ type: 'object',
141
+ properties: { source: { type: 'string' } },
142
+ required: ['source']
143
+ }
144
+ }));
145
+ }
146
+
147
+ /**
148
+ * 远程GitHub文件扫描
149
+ * @param {Object} pathInfo - 解析后的路径信息
150
+ * @returns {Array} 扫描到的文件列表
151
+ */
152
+ async function scanRemoteGitHubFiles(pathInfo) {
153
+ if (!pathInfo) {
154
+ throw new Error('Invalid GitHub path info');
155
+ }
156
+
157
+ const url = `${pathInfo.apiUrl}?ref=${pathInfo.branch}`;
158
+ const headers = createAuthHeaders('github', process.env.GIT_TOKEN);
159
+
160
+ const requestOptions = { headers };
161
+ const response = await fetch(url, requestOptions);
162
+ if (!response.ok) {
163
+ // 构建详细的调试信息,隐藏敏感token信息
164
+ const debugHeaders = { ...headers };
165
+
166
+ const requestInfo = `
167
+ REQUEST INFO: \n
168
+ - URL: ${url} \n
169
+ - Method: GET \n
170
+ - Headers: ${JSON.stringify(debugHeaders, null, 2)} \n
171
+ - Response Status: ${response.status} \n
172
+ - Response StatusText: ${response.statusText} \n`;
173
+
174
+ throw new Error(`GitHub API error: ${requestInfo}`);
175
+ }
176
+
177
+ const files = await response.json();
178
+ return files
179
+ .filter(file => file.type === 'file' && file.name.endsWith('.prompt.md'))
180
+ .map(file => {
181
+ const baseName = file.name.replace('.prompt.md', '');
182
+ return {
183
+ filename: file.name,
184
+ toolName: `dev-${baseName}`,
185
+ source: pathInfo.path ? `${pathInfo.path}/${file.name}` : file.name
186
+ };
187
+ });
188
+ }
189
+
190
+ /**
191
+ * 远程GitLab文件扫描
192
+ * @param {Object} pathInfo - 解析后的路径信息
193
+ * @returns {Array} 扫描到的文件列表
194
+ */
195
+ async function scanRemoteGitLabFiles(pathInfo) {
196
+ if (!pathInfo) {
197
+ throw new Error('Invalid GitLab path info');
198
+ }
199
+
200
+ const headers = createAuthHeaders('gitlab', process.env.GIT_TOKEN);
201
+
202
+ const requestOptions = { headers };
203
+ const response = await fetch(pathInfo.apiUrl, requestOptions);
204
+ if (!response.ok) {
205
+ // 构建详细的调试信息,隐藏敏感token信息
206
+ const debugHeaders = { ...headers };
207
+
208
+ const requestInfo = `
209
+ REQUEST INFO: \n
210
+ - URL: ${pathInfo.apiUrl} \n
211
+ - Method: GET \n
212
+ - Headers: ${JSON.stringify(debugHeaders, null, 2)} \n
213
+ - Response Status: ${response.status} \n
214
+ - Response StatusText: ${response.statusText} \n`;
215
+
216
+ throw new Error(`GitLab API error: ${requestInfo}`);
217
+ }
218
+
219
+ const files = await response.json();
220
+ return files
221
+ .filter(file => file.type === 'blob' && file.name.endsWith('.prompt.md'))
222
+ .map(file => {
223
+ const baseName = file.name.replace('.prompt.md', '');
224
+ return {
225
+ filename: file.name,
226
+ toolName: `dev-${baseName}`,
227
+ source: pathInfo.path ? `${pathInfo.path}/${file.name}` : file.name
228
+ };
229
+ });
230
+ }
231
+
232
+ // 统一远程扫描函数 (简化版 + 缓存机制)
233
+ async function scanRemotePromptFiles() {
234
+ validatePlatformConfiguration();
235
+
236
+ const resourcePath = process.env.RESOURCE_PATH;
237
+ const platform = detectPlatformFromPath(resourcePath);
238
+
239
+ if (platform === 'local') {
240
+ throw new Error('scanRemotePromptFiles called for local path');
241
+ }
242
+
243
+ // 检查缓存的文件列表
244
+ const cacheFile = path.join(CFG.cacheDir, 'file-list.json');
245
+
246
+ // 如果不强制更新且缓存存在且未过期,使用缓存
247
+ if (!force) {
248
+ try {
249
+ const stat = await fs.stat(cacheFile);
250
+ const cacheAge = Date.now() - stat.mtimeMs;
251
+ const cacheAgeMinutes = Math.round(cacheAge / 1000 / 60);
252
+
253
+ if (cacheAge < CFG.ttl * 1000) {
254
+ const cachedList = await fs.readFile(cacheFile, 'utf8');
255
+ console.log(`[Config] Using cached file list (age: ${cacheAgeMinutes}min)`);
256
+ return JSON.parse(cachedList);
257
+ }
258
+ } catch (_) {
259
+ // 缓存不存在或无效,继续获取
260
+ }
261
+ }
262
+
263
+ // 从远程获取文件列表
264
+ try {
265
+ console.log(`[Config] Fetching fresh file list from ${platform}...`);
266
+
267
+ let scannedFiles = [];
268
+
269
+ if (platform === 'github') {
270
+ scannedFiles = await scanRemoteGitHubFiles(parseRemotePath(resourcePath));
271
+ } else if (platform === 'gitlab') {
272
+ scannedFiles = await scanRemoteGitLabFiles(parseRemotePath(resourcePath));
273
+ }
274
+
275
+ // 缓存结果
276
+ await fs.writeFile(cacheFile, JSON.stringify(scannedFiles, null, 2), 'utf8');
277
+ console.log(`[Config] Cached ${scannedFiles.length} files to ${cacheFile}`);
278
+
279
+ return scannedFiles;
280
+ } catch (error) {
281
+ // API失败时尝试使用旧缓存
282
+ console.warn(`[Config] Remote scanning failed: ${error.message}`);
283
+ try {
284
+ const cachedList = await fs.readFile(cacheFile, 'utf8');
285
+ console.log(`[Config] Using stale cache due to API failure`);
286
+ return JSON.parse(cachedList);
287
+ } catch (_) {
288
+ console.error('[Config] No cache available, returning empty list');
289
+ return [];
290
+ }
291
+ }
292
+ }
293
+
294
+ // 🟢 GREEN: Task 1.3 - 集成自动工具配置
295
+ async function initializeTools() {
296
+ const autoPromptTools = await generateAutoPromptTools();
297
+
298
+ // Handler-based tools (手动配置的特殊工具)
299
+ const handlerTools = [
300
+ {
301
+ name: 'dev-feedback',
302
+ type: 'handler',
303
+ handler: 'handleDevFeedback',
304
+ description: '反馈确认工具',
305
+ schema: {
306
+ type: 'object',
307
+ properties: {
308
+ title: { type: 'string' },
309
+ message: { type: 'string' },
310
+ options: { type: 'array', items: { type: 'string' } }
311
+ },
312
+ required: ['title', 'message']
313
+ }
314
+ },
315
+ {
316
+ name: 'dev-manual',
317
+ type: 'handler',
318
+ handler: 'handleDevManual',
319
+ description: '手动选择开发类型',
320
+ schema: {
321
+ type: 'object',
322
+ properties: {
323
+ random_string: { description: 'Dummy parameter for no-parameter tools', type: 'string' }
324
+ },
325
+ required: ['random_string']
326
+ }
327
+ }
328
+ ];
329
+
330
+ const allTools = [...autoPromptTools, ...handlerTools];
331
+ console.log(`[Config] Initialized ${allTools.length} tools (${autoPromptTools.length} prompt + ${handlerTools.length} handler)`);
332
+
333
+ return allTools;
334
+ }
335
+
336
+ // Initialize cache directory
337
+ await fs.mkdir(CFG.cacheDir, { recursive: true });
338
+
339
+ // 兼容性导出 - 为prompt-manager提供配置
340
+ export { scanRemotePromptFiles };