@portel/photon 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/LICENSE +21 -0
- package/README.md +952 -0
- package/dist/base.d.ts +58 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +92 -0
- package/dist/base.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1441 -0
- package/dist/cli.js.map +1 -0
- package/dist/dependency-manager.d.ts +49 -0
- package/dist/dependency-manager.d.ts.map +1 -0
- package/dist/dependency-manager.js +165 -0
- package/dist/dependency-manager.js.map +1 -0
- package/dist/loader.d.ts +86 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +612 -0
- package/dist/loader.js.map +1 -0
- package/dist/marketplace-manager.d.ts +261 -0
- package/dist/marketplace-manager.d.ts.map +1 -0
- package/dist/marketplace-manager.js +767 -0
- package/dist/marketplace-manager.js.map +1 -0
- package/dist/path-resolver.d.ts +21 -0
- package/dist/path-resolver.d.ts.map +1 -0
- package/dist/path-resolver.js +71 -0
- package/dist/path-resolver.js.map +1 -0
- package/dist/photon-doc-extractor.d.ts +89 -0
- package/dist/photon-doc-extractor.d.ts.map +1 -0
- package/dist/photon-doc-extractor.js +228 -0
- package/dist/photon-doc-extractor.js.map +1 -0
- package/dist/readme-syncer.d.ts +33 -0
- package/dist/readme-syncer.d.ts.map +1 -0
- package/dist/readme-syncer.js +93 -0
- package/dist/readme-syncer.js.map +1 -0
- package/dist/registry-manager.d.ts +76 -0
- package/dist/registry-manager.d.ts.map +1 -0
- package/dist/registry-manager.js +220 -0
- package/dist/registry-manager.js.map +1 -0
- package/dist/schema-extractor.d.ts +83 -0
- package/dist/schema-extractor.d.ts.map +1 -0
- package/dist/schema-extractor.js +396 -0
- package/dist/schema-extractor.js.map +1 -0
- package/dist/security-scanner.d.ts +52 -0
- package/dist/security-scanner.d.ts.map +1 -0
- package/dist/security-scanner.js +172 -0
- package/dist/security-scanner.js.map +1 -0
- package/dist/server.d.ts +73 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +474 -0
- package/dist/server.js.map +1 -0
- package/dist/template-manager.d.ts +56 -0
- package/dist/template-manager.d.ts.map +1 -0
- package/dist/template-manager.js +509 -0
- package/dist/template-manager.js.map +1 -0
- package/dist/test-client.d.ts +52 -0
- package/dist/test-client.d.ts.map +1 -0
- package/dist/test-client.js +168 -0
- package/dist/test-client.js.map +1 -0
- package/dist/test-marketplace-sources.d.ts +5 -0
- package/dist/test-marketplace-sources.d.ts.map +1 -0
- package/dist/test-marketplace-sources.js +53 -0
- package/dist/test-marketplace-sources.js.map +1 -0
- package/dist/types.d.ts +108 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/version-checker.d.ts +48 -0
- package/dist/version-checker.d.ts.map +1 -0
- package/dist/version-checker.js +128 -0
- package/dist/version-checker.js.map +1 -0
- package/dist/watcher.d.ts +26 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +72 -0
- package/dist/watcher.js.map +1 -0
- package/package.json +79 -0
- package/templates/photon.template.ts +55 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as crypto from 'crypto';
|
|
5
|
+
/**
|
|
6
|
+
* Manages marketplace documentation templates
|
|
7
|
+
*
|
|
8
|
+
* Templates are stored in .marketplace/_templates/ and can be customized by users.
|
|
9
|
+
* Hash-based detection prevents overwriting user customizations.
|
|
10
|
+
*/
|
|
11
|
+
export class TemplateManager {
|
|
12
|
+
workingDir;
|
|
13
|
+
marketplaceDir;
|
|
14
|
+
templateDir;
|
|
15
|
+
hashFile;
|
|
16
|
+
// Current template version - increment when templates are updated
|
|
17
|
+
static TEMPLATE_VERSION = '1.0.0';
|
|
18
|
+
constructor(workingDir) {
|
|
19
|
+
this.workingDir = workingDir;
|
|
20
|
+
this.marketplaceDir = path.join(workingDir, '.marketplace');
|
|
21
|
+
this.templateDir = path.join(this.marketplaceDir, '_templates');
|
|
22
|
+
this.hashFile = path.join(this.marketplaceDir, '.template-hashes.json');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Ensure templates directory exists and templates are initialized
|
|
26
|
+
*/
|
|
27
|
+
async ensureTemplates() {
|
|
28
|
+
// Create directories
|
|
29
|
+
await fs.mkdir(this.templateDir, { recursive: true });
|
|
30
|
+
// Load or initialize hash tracking
|
|
31
|
+
const hashes = await this.loadHashes();
|
|
32
|
+
// Check and update each template
|
|
33
|
+
await this.ensureTemplate('readme.md', this.getDefaultReadmeTemplate(), hashes);
|
|
34
|
+
await this.ensureTemplate('photon.md', this.getDefaultPhotonTemplate(), hashes);
|
|
35
|
+
// Save updated hashes
|
|
36
|
+
await this.saveHashes(hashes);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if a template has been customized by the user
|
|
40
|
+
*/
|
|
41
|
+
async isTemplateCustomized(templateName) {
|
|
42
|
+
const hashes = await this.loadHashes();
|
|
43
|
+
return hashes[templateName]?.customized || false;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Render a template with provided data
|
|
47
|
+
*/
|
|
48
|
+
async renderTemplate(templateName, data) {
|
|
49
|
+
const templatePath = path.join(this.templateDir, templateName);
|
|
50
|
+
if (!existsSync(templatePath)) {
|
|
51
|
+
throw new Error(`Template not found: ${templateName}`);
|
|
52
|
+
}
|
|
53
|
+
const template = await fs.readFile(templatePath, 'utf-8');
|
|
54
|
+
return this.render(template, data);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Simple template renderer using template literals
|
|
58
|
+
* Safely evaluates ${expression} in templates
|
|
59
|
+
*/
|
|
60
|
+
render(template, data) {
|
|
61
|
+
// Helper functions available in templates
|
|
62
|
+
// Using $ prefix to avoid reserved keywords
|
|
63
|
+
const helpers = {
|
|
64
|
+
// Loop over array
|
|
65
|
+
each: (items, fn) => {
|
|
66
|
+
return items.map((item, index) => fn(item, index)).join('');
|
|
67
|
+
},
|
|
68
|
+
// Conditional rendering
|
|
69
|
+
$if: (condition, truthy, falsy = '') => {
|
|
70
|
+
return condition ? truthy : falsy;
|
|
71
|
+
},
|
|
72
|
+
// Default value
|
|
73
|
+
$default: (value, defaultValue) => {
|
|
74
|
+
return value !== undefined && value !== null && value !== '' ? value : defaultValue;
|
|
75
|
+
},
|
|
76
|
+
// Extract proper name from description (before " - ")
|
|
77
|
+
properName: (desc, fallbackName) => {
|
|
78
|
+
if (desc.includes(' - ')) {
|
|
79
|
+
return desc.split(' - ')[0];
|
|
80
|
+
}
|
|
81
|
+
// Fallback: title case the name
|
|
82
|
+
return fallbackName.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
|
|
83
|
+
},
|
|
84
|
+
// Extract description after " - " separator
|
|
85
|
+
cleanDesc: (desc) => {
|
|
86
|
+
return desc.includes(' - ') ? desc.split(' - ').slice(1).join(' - ') : desc;
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
try {
|
|
90
|
+
// Create function with data and helpers in scope
|
|
91
|
+
const fn = new Function('data', 'helpers', `
|
|
92
|
+
with (data) {
|
|
93
|
+
const { each, $if, $default, properName, cleanDesc } = helpers;
|
|
94
|
+
return \`${template}\`;
|
|
95
|
+
}
|
|
96
|
+
`);
|
|
97
|
+
return fn(data, helpers);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
throw new Error(`Template rendering error: ${error.message}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Ensure a single template exists and is up-to-date
|
|
105
|
+
*/
|
|
106
|
+
async ensureTemplate(name, defaultContent, hashes) {
|
|
107
|
+
const templatePath = path.join(this.templateDir, name);
|
|
108
|
+
const defaultHash = this.calculateHash(defaultContent);
|
|
109
|
+
if (!existsSync(templatePath)) {
|
|
110
|
+
// Template doesn't exist - create it
|
|
111
|
+
await fs.writeFile(templatePath, defaultContent, 'utf-8');
|
|
112
|
+
hashes[name] = {
|
|
113
|
+
version: TemplateManager.TEMPLATE_VERSION,
|
|
114
|
+
hash: defaultHash,
|
|
115
|
+
customized: false,
|
|
116
|
+
};
|
|
117
|
+
console.error(` ✓ Created template: _templates/${name}`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Template exists - check if customized
|
|
121
|
+
const currentContent = await fs.readFile(templatePath, 'utf-8');
|
|
122
|
+
const currentHash = this.calculateHash(currentContent);
|
|
123
|
+
const tracked = hashes[name];
|
|
124
|
+
if (!tracked) {
|
|
125
|
+
// Not tracked yet - assume customized
|
|
126
|
+
hashes[name] = {
|
|
127
|
+
version: TemplateManager.TEMPLATE_VERSION,
|
|
128
|
+
hash: currentHash,
|
|
129
|
+
customized: true,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
else if (currentHash === tracked.hash) {
|
|
133
|
+
// Unchanged from last sync
|
|
134
|
+
if (!tracked.customized && defaultHash !== tracked.hash) {
|
|
135
|
+
// Template was default but we have a new version - update it
|
|
136
|
+
await fs.writeFile(templatePath, defaultContent, 'utf-8');
|
|
137
|
+
hashes[name] = {
|
|
138
|
+
version: TemplateManager.TEMPLATE_VERSION,
|
|
139
|
+
hash: defaultHash,
|
|
140
|
+
customized: false,
|
|
141
|
+
};
|
|
142
|
+
console.error(` ✓ Updated template: _templates/${name} (new version)`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Hash changed - user customized it
|
|
147
|
+
hashes[name] = {
|
|
148
|
+
...tracked,
|
|
149
|
+
hash: currentHash,
|
|
150
|
+
customized: true,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Load template hashes from file
|
|
157
|
+
*/
|
|
158
|
+
async loadHashes() {
|
|
159
|
+
if (!existsSync(this.hashFile)) {
|
|
160
|
+
return {};
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
const content = await fs.readFile(this.hashFile, 'utf-8');
|
|
164
|
+
return JSON.parse(content);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return {};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Save template hashes to file
|
|
172
|
+
*/
|
|
173
|
+
async saveHashes(hashes) {
|
|
174
|
+
await fs.writeFile(this.hashFile, JSON.stringify(hashes, null, 2), 'utf-8');
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Calculate SHA-256 hash of content
|
|
178
|
+
*/
|
|
179
|
+
calculateHash(content) {
|
|
180
|
+
return crypto.createHash('sha256').update(content).digest('hex');
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get default README template
|
|
184
|
+
*/
|
|
185
|
+
getDefaultReadmeTemplate() {
|
|
186
|
+
return `# \${marketplaceName}
|
|
187
|
+
|
|
188
|
+
> **Singular focus. Precise target.**
|
|
189
|
+
|
|
190
|
+
\${$if(marketplaceDescription, \`\${marketplaceDescription}\n\n\`, \`Photons are single-file TypeScript classes that run as [MCP servers](https://modelcontextprotocol.io/introduction). Add them to your favorite AI assistant using the [Photon runtime](https://github.com/portel-dev/photon).\n\n\`)}\${$if(marketplaceName === 'photons', \`## 🏛️ Official Marketplace
|
|
191
|
+
|
|
192
|
+
This is the **official Photon marketplace** maintained by Portel. It comes pre-configured with Photon - no manual setup needed.
|
|
193
|
+
|
|
194
|
+
**Already available to you:**
|
|
195
|
+
- ✅ Pre-installed with Photon
|
|
196
|
+
- ✅ Automatically updated
|
|
197
|
+
- ✅ Production-ready photons
|
|
198
|
+
- ✅ Community-maintained
|
|
199
|
+
|
|
200
|
+
**Want to contribute?**
|
|
201
|
+
We welcome contributions! Submit pull requests for:
|
|
202
|
+
- 🐛 Bug fixes to existing photons
|
|
203
|
+
- ✨ Enhancements and new features
|
|
204
|
+
- 📦 New photons to add to the marketplace
|
|
205
|
+
- 📝 Documentation improvements
|
|
206
|
+
|
|
207
|
+
**Repository:** [github.com/portel-dev/photons](https://github.com/portel-dev/photons)
|
|
208
|
+
|
|
209
|
+
\`, '')}## 📦 Available Photons
|
|
210
|
+
|
|
211
|
+
| Photon | Focus | Tools | Details |
|
|
212
|
+
|--------|-------|-------|---------|
|
|
213
|
+
\${each(photons, (p) => \`| **\${properName(p.description, p.name)}** | \${cleanDesc(p.description)} | \${p.tools ? p.tools.length : 0} | [View →](\${p.name}.md) |\n\`)}
|
|
214
|
+
|
|
215
|
+
**Total:** \${photons.length} photons ready to use
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## 🚀 Quick Start
|
|
220
|
+
|
|
221
|
+
### 1. Install Photon
|
|
222
|
+
|
|
223
|
+
\\\`\\\`\\\`bash
|
|
224
|
+
npm install -g @portel/photon
|
|
225
|
+
\\\`\\\`\\\`
|
|
226
|
+
|
|
227
|
+
### 2. Add Any Photon
|
|
228
|
+
|
|
229
|
+
\\\`\\\`\\\`bash
|
|
230
|
+
photon add filesystem
|
|
231
|
+
photon add git
|
|
232
|
+
photon add aws-s3
|
|
233
|
+
\\\`\\\`\\\`
|
|
234
|
+
|
|
235
|
+
### 3. Use It
|
|
236
|
+
|
|
237
|
+
\\\`\\\`\\\`bash
|
|
238
|
+
# Run as MCP server
|
|
239
|
+
photon mcp filesystem
|
|
240
|
+
|
|
241
|
+
# Get config for your MCP client
|
|
242
|
+
photon get filesystem --mcp
|
|
243
|
+
\\\`\\\`\\\`
|
|
244
|
+
|
|
245
|
+
Output (paste directly into your MCP client config):
|
|
246
|
+
\\\`\\\`\\\`json
|
|
247
|
+
{
|
|
248
|
+
"mcpServers": {
|
|
249
|
+
"filesystem": {
|
|
250
|
+
"command": "photon",
|
|
251
|
+
"args": ["mcp", "filesystem"]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
\\\`\\\`\\\`
|
|
256
|
+
|
|
257
|
+
Add the output to your MCP client's configuration. **Consult your client's documentation** for setup instructions.
|
|
258
|
+
|
|
259
|
+
**That's it!** Your AI assistant now has \${photons.length} focused tools at its fingertips.
|
|
260
|
+
|
|
261
|
+
## ⚛️ What Are Photons?
|
|
262
|
+
|
|
263
|
+
**Photons** are laser-focused modules - each does ONE thing exceptionally well:
|
|
264
|
+
- 📁 **Filesystem** - File operations
|
|
265
|
+
- 🐙 **Git** - Repository management
|
|
266
|
+
- ☁️ **AWS S3** - Cloud storage
|
|
267
|
+
- 📅 **Google Calendar** - Calendar integration
|
|
268
|
+
- 🕐 **Time** - Timezone operations
|
|
269
|
+
- ... and more
|
|
270
|
+
|
|
271
|
+
Each photon delivers **singular focus** to a **precise target**.
|
|
272
|
+
|
|
273
|
+
**Key Features:**
|
|
274
|
+
- 🎯 Each photon does one thing perfectly
|
|
275
|
+
- 📦 \${photons.length} production-ready photons available
|
|
276
|
+
- ⚡ Auto-installs dependencies
|
|
277
|
+
- 🔧 Works out of the box
|
|
278
|
+
- 📄 Single-file design (easy to fork and customize)
|
|
279
|
+
|
|
280
|
+
## 🎯 The Value Proposition
|
|
281
|
+
|
|
282
|
+
### Before Photon
|
|
283
|
+
|
|
284
|
+
For each MCP server:
|
|
285
|
+
1. Find and clone the repository
|
|
286
|
+
2. Install dependencies manually
|
|
287
|
+
3. Configure environment variables
|
|
288
|
+
4. Write MCP client config JSON by hand
|
|
289
|
+
5. Repeat for every server
|
|
290
|
+
|
|
291
|
+
### With Photon
|
|
292
|
+
|
|
293
|
+
\\\`\\\`\\\`bash
|
|
294
|
+
# Install from marketplace
|
|
295
|
+
photon add filesystem
|
|
296
|
+
|
|
297
|
+
# Get MCP config
|
|
298
|
+
photon get filesystem --mcp
|
|
299
|
+
\\\`\\\`\\\`
|
|
300
|
+
|
|
301
|
+
Output (paste directly into your MCP client config):
|
|
302
|
+
\\\`\\\`\\\`json
|
|
303
|
+
{
|
|
304
|
+
"mcpServers": {
|
|
305
|
+
"filesystem": {
|
|
306
|
+
"command": "photon",
|
|
307
|
+
"args": ["mcp", "filesystem"]
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
\\\`\\\`\\\`
|
|
312
|
+
|
|
313
|
+
**That's it.** No dependencies, no environment setup, no configuration files.
|
|
314
|
+
|
|
315
|
+
**Difference:**
|
|
316
|
+
- ✅ One CLI, one command
|
|
317
|
+
- ✅ Zero configuration
|
|
318
|
+
- ✅ Instant installation
|
|
319
|
+
- ✅ Auto-dependencies
|
|
320
|
+
- ✅ Consistent experience
|
|
321
|
+
|
|
322
|
+
## 💡 Use Cases
|
|
323
|
+
|
|
324
|
+
**For Claude Users:**
|
|
325
|
+
\\\`\\\`\\\`bash
|
|
326
|
+
photon add filesystem git github-issues
|
|
327
|
+
photon get --mcp # Get config for all three
|
|
328
|
+
\\\`\\\`\\\`
|
|
329
|
+
Add to Claude Desktop → Now Claude can read files, manage repos, create issues
|
|
330
|
+
|
|
331
|
+
**For Teams:**
|
|
332
|
+
\\\`\\\`\\\`bash
|
|
333
|
+
photon add postgres mongodb redis
|
|
334
|
+
photon get --mcp
|
|
335
|
+
\\\`\\\`\\\`
|
|
336
|
+
Give Claude access to your data infrastructure
|
|
337
|
+
|
|
338
|
+
**For Developers:**
|
|
339
|
+
\\\`\\\`\\\`bash
|
|
340
|
+
photon add docker git slack
|
|
341
|
+
photon get --mcp
|
|
342
|
+
\\\`\\\`\\\`
|
|
343
|
+
Automate your workflow through AI
|
|
344
|
+
|
|
345
|
+
## 🔍 Browse & Search
|
|
346
|
+
|
|
347
|
+
\\\`\\\`\\\`bash
|
|
348
|
+
# List all photons
|
|
349
|
+
photon get
|
|
350
|
+
|
|
351
|
+
# Search by keyword
|
|
352
|
+
photon search calendar
|
|
353
|
+
|
|
354
|
+
# View details
|
|
355
|
+
photon get google-calendar
|
|
356
|
+
|
|
357
|
+
# Upgrade all
|
|
358
|
+
photon upgrade
|
|
359
|
+
\\\`\\\`\\\`
|
|
360
|
+
|
|
361
|
+
## 🏢 For Enterprises
|
|
362
|
+
|
|
363
|
+
Create your own marketplace:
|
|
364
|
+
|
|
365
|
+
\\\`\\\`\\\`bash
|
|
366
|
+
# 1. Organize photons
|
|
367
|
+
mkdir company-photons && cd company-photons
|
|
368
|
+
|
|
369
|
+
# 2. Generate marketplace
|
|
370
|
+
photon sync marketplace
|
|
371
|
+
|
|
372
|
+
# 3. Share with team
|
|
373
|
+
git push origin main
|
|
374
|
+
|
|
375
|
+
# Team members use:
|
|
376
|
+
photon marketplace add company/photons
|
|
377
|
+
photon add your-internal-tool
|
|
378
|
+
\\\`\\\`\\\`
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
**Built with singular focus. Deployed with precise targeting.**
|
|
383
|
+
|
|
384
|
+
Made with ⚛️ by [Portel](https://github.com/portel-dev)
|
|
385
|
+
`;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Get default Photon documentation template
|
|
389
|
+
*/
|
|
390
|
+
getDefaultPhotonTemplate() {
|
|
391
|
+
return `# \${properName(description, name)}
|
|
392
|
+
|
|
393
|
+
\${cleanDesc(description)}
|
|
394
|
+
|
|
395
|
+
## 📋 Overview
|
|
396
|
+
|
|
397
|
+
**Version:** \${version}
|
|
398
|
+
**Author:** \${author || 'Unknown'}
|
|
399
|
+
**License:** \${license || 'MIT'}\${$if(repository, \` \n**Repository:** \${repository}\`, '')}\${$if(homepage, \` \n**Homepage:** \${homepage}\`, '')}
|
|
400
|
+
|
|
401
|
+
## ⚙️ Configuration
|
|
402
|
+
|
|
403
|
+
### Environment Variables
|
|
404
|
+
|
|
405
|
+
\${each(configParams || [], (param) => \`
|
|
406
|
+
- **\\\`\${param.envVar}\\\`** \${param.required ? '[REQUIRED]' : '[OPTIONAL]'}
|
|
407
|
+
- Type: \${param.type}
|
|
408
|
+
- Description: \${param.description}
|
|
409
|
+
\${param.default ? \`- Default: \\\`\${param.default}\\\`\` : ''}
|
|
410
|
+
\`)}
|
|
411
|
+
|
|
412
|
+
\${$if(!configParams || configParams.length === 0, \`
|
|
413
|
+
No configuration required.
|
|
414
|
+
\`)}
|
|
415
|
+
|
|
416
|
+
\${$if(setupInstructions, \`
|
|
417
|
+
### Setup Instructions
|
|
418
|
+
|
|
419
|
+
\${setupInstructions}
|
|
420
|
+
\`)}
|
|
421
|
+
|
|
422
|
+
## 🔧 Tools
|
|
423
|
+
|
|
424
|
+
This photon provides **\${tools ? tools.length : 0}** tools:
|
|
425
|
+
|
|
426
|
+
\${each(tools || [], (tool) => \`
|
|
427
|
+
### \\\`\${tool.name}\\\`
|
|
428
|
+
|
|
429
|
+
\${tool.description || 'No description available'}
|
|
430
|
+
|
|
431
|
+
\${$if(tool.params && tool.params.length > 0, \`
|
|
432
|
+
**Parameters:**
|
|
433
|
+
|
|
434
|
+
\${each(tool.params, (p) => \`
|
|
435
|
+
- **\\\`\${p.name}\\\`** (\${p.type}\${p.optional ? ', optional' : ''}) - \${p.description || 'No description'}
|
|
436
|
+
\`)}
|
|
437
|
+
\`)}
|
|
438
|
+
|
|
439
|
+
\${$if(tool.example, \`
|
|
440
|
+
**Example:**
|
|
441
|
+
|
|
442
|
+
\\\`\\\`\\\`typescript
|
|
443
|
+
\${tool.example}
|
|
444
|
+
\\\`\\\`\\\`
|
|
445
|
+
\`)}
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
\`)}
|
|
450
|
+
|
|
451
|
+
\${$if(!tools || tools.length === 0, \`
|
|
452
|
+
No tools defined.
|
|
453
|
+
\`)}
|
|
454
|
+
|
|
455
|
+
## 📥 Usage
|
|
456
|
+
|
|
457
|
+
### Install Photon CLI
|
|
458
|
+
|
|
459
|
+
\\\`\\\`\\\`bash
|
|
460
|
+
npm install -g @portel/photon
|
|
461
|
+
\\\`\\\`\\\`
|
|
462
|
+
|
|
463
|
+
### Run This Photon
|
|
464
|
+
|
|
465
|
+
**Option 1: Run directly from file**
|
|
466
|
+
|
|
467
|
+
\\\`\\\`\\\`bash
|
|
468
|
+
# Clone/download the photon file
|
|
469
|
+
photon mcp ./\${name}.photon.ts
|
|
470
|
+
\\\`\\\`\\\`
|
|
471
|
+
|
|
472
|
+
**Option 2: Install to ~/.photon/ (recommended)**
|
|
473
|
+
|
|
474
|
+
\\\`\\\`\\\`bash
|
|
475
|
+
# Copy to photon directory
|
|
476
|
+
cp \${name}.photon.ts ~/.photon/
|
|
477
|
+
|
|
478
|
+
# Run by name
|
|
479
|
+
photon mcp \${name}
|
|
480
|
+
\\\`\\\`\\\`
|
|
481
|
+
|
|
482
|
+
**Option 3: Use with Claude Desktop**
|
|
483
|
+
|
|
484
|
+
\\\`\\\`\\\`bash
|
|
485
|
+
# Generate MCP configuration
|
|
486
|
+
photon mcp \${name} --config
|
|
487
|
+
|
|
488
|
+
# Add the output to ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
489
|
+
\\\`\\\`\\\`
|
|
490
|
+
|
|
491
|
+
## 📦 Dependencies
|
|
492
|
+
|
|
493
|
+
\${$if(dependencies, \`
|
|
494
|
+
This photon automatically installs the following dependencies:
|
|
495
|
+
|
|
496
|
+
\\\`\\\`\\\`
|
|
497
|
+
\${dependencies}
|
|
498
|
+
\\\`\\\`\\\`
|
|
499
|
+
\`, \`
|
|
500
|
+
No external dependencies required.
|
|
501
|
+
\`)}
|
|
502
|
+
|
|
503
|
+
## 📄 License
|
|
504
|
+
|
|
505
|
+
\${license || 'MIT'} • Version \${version}
|
|
506
|
+
`;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
//# sourceMappingURL=template-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-manager.js","sourceRoot":"","sources":["../src/template-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Test Client - Automated testing for Photon MCPs
|
|
4
|
+
*
|
|
5
|
+
* Spawns MCP servers, sends protocol messages, validates responses
|
|
6
|
+
*/
|
|
7
|
+
interface MCPResponse {
|
|
8
|
+
jsonrpc: '2.0';
|
|
9
|
+
id: number | string;
|
|
10
|
+
result?: any;
|
|
11
|
+
error?: {
|
|
12
|
+
code: number;
|
|
13
|
+
message: string;
|
|
14
|
+
data?: any;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface TestCase {
|
|
18
|
+
name: string;
|
|
19
|
+
method: string;
|
|
20
|
+
params?: any;
|
|
21
|
+
validate: (response: MCPResponse) => boolean | string;
|
|
22
|
+
}
|
|
23
|
+
export declare class MCPTestClient {
|
|
24
|
+
private process?;
|
|
25
|
+
private requestId;
|
|
26
|
+
private pendingRequests;
|
|
27
|
+
start(command: string, args: string[], env?: Record<string, string>): Promise<void>;
|
|
28
|
+
send(method: string, params?: any): Promise<MCPResponse>;
|
|
29
|
+
initialize(serverInfo?: {
|
|
30
|
+
name: string;
|
|
31
|
+
version: string;
|
|
32
|
+
}): Promise<MCPResponse>;
|
|
33
|
+
listTools(): Promise<MCPResponse>;
|
|
34
|
+
callTool(name: string, args?: any): Promise<MCPResponse>;
|
|
35
|
+
runTests(tests: TestCase[]): Promise<{
|
|
36
|
+
passed: number;
|
|
37
|
+
failed: number;
|
|
38
|
+
errors: string[];
|
|
39
|
+
}>;
|
|
40
|
+
shutdown(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
export declare const validators: {
|
|
43
|
+
hasResult: (response: MCPResponse) => true | "Response missing result field";
|
|
44
|
+
hasError: (response: MCPResponse) => true | "Response missing error field";
|
|
45
|
+
matchesPattern: (pattern: RegExp, field?: string) => (response: MCPResponse) => string | true;
|
|
46
|
+
hasField: (field: string) => (response: MCPResponse) => string | true;
|
|
47
|
+
equals: (expected: any, field?: string) => (response: MCPResponse) => string | true;
|
|
48
|
+
custom: (fn: (result: any) => boolean | string) => (response: MCPResponse) => string | boolean;
|
|
49
|
+
and: (...validators: Array<(response: MCPResponse) => boolean | string>) => (response: MCPResponse) => string | boolean;
|
|
50
|
+
};
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=test-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-client.d.ts","sourceRoot":"","sources":["../src/test-client.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAYH,UAAU,WAAW;IACnB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,GAAG,CAAC;KACZ,CAAC;CACH;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,QAAQ,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,OAAO,GAAG,MAAM,CAAC;CACvD;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAC,CAAe;IAC/B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,eAAe,CAGlB;IAEC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDnF,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;IA4BxD,UAAU,CAAC,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAQhF,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC;IAIjC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC;IAIxD,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA8B1F,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAOhC;AAGD,eAAO,MAAM,UAAU;0BACC,WAAW;yBAGZ,WAAW;8BAGN,MAAM,UAAU,MAAM,MAAM,UAAU,WAAW;sBAOzD,MAAM,MAAM,UAAU,WAAW;uBAYhC,GAAG,UAAU,MAAM,MAAM,UAAU,WAAW;iBAMpD,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,GAAG,MAAM,MAAM,UAAU,WAAW;yBAIpD,KAAK,CAAC,CAAC,QAAQ,EAAE,WAAW,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,UAAU,WAAW;CAOnG,CAAC"}
|