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 +358 -0
- package/config.js +340 -0
- package/dialog/browser.js +532 -0
- package/dialog/constants.js +68 -0
- package/dialog/http-server.js +95 -0
- package/dialog/index.js +106 -0
- package/dialog/native.js +345 -0
- package/dialog/objc.js +303 -0
- package/dialog/utils.js +140 -0
- package/fetcher.js +56 -0
- package/package.json +49 -0
- package/platform-utils.js +206 -0
- package/prompt-manager.js +1027 -0
- package/resource-manager.js +358 -0
- package/server.js +305 -0
- package/test.js +93 -0
- package/tools.js +701 -0
- package/utils.js +145 -0
package/README.md
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# MCP Prompt Fetcher
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/mcp-prompt-fetcher)
|
|
4
|
+
[](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 };
|