promptgraph-mcp 2.2.0 → 2.2.2
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/index.js +47 -19
- package/package.json +1 -1
- package/tui.js +2 -6
package/index.js
CHANGED
|
@@ -196,31 +196,31 @@ if (args[0] === 'marketplace') {
|
|
|
196
196
|
const installedSet = new Set();
|
|
197
197
|
try {
|
|
198
198
|
const cfg = _lcMkt();
|
|
199
|
-
for (const s of cfg.sources) {
|
|
200
|
-
if (s.source.startsWith('github:')) installedSet.add(s.source.replace('github:', ''));
|
|
201
|
-
if (s.source === 'marketplace') installedSet.add('marketplace');
|
|
202
|
-
}
|
|
203
199
|
const db = _getDbMkt();
|
|
204
|
-
|
|
205
|
-
//
|
|
200
|
+
|
|
201
|
+
// Collect installed skill IDs from DB
|
|
202
|
+
const dbSkillIds = new Set(db.prepare('SELECT id FROM skills').all().map(r => r.id));
|
|
203
|
+
|
|
204
|
+
// Build set of cloned repo names from config sources (exact: github:owner-repo)
|
|
205
|
+
const githubSources = new Set(
|
|
206
|
+
cfg.sources.filter(s => s.source.startsWith('github:')).map(s => s.source.replace('github:', '').toLowerCase())
|
|
207
|
+
);
|
|
208
|
+
|
|
206
209
|
for (const b of (Array.isArray(bundles) ? bundles : [])) {
|
|
207
210
|
if (b.repo_url) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
// match github sources to bundle ids
|
|
215
|
-
for (const s of cfg.sources) {
|
|
216
|
-
if (!s.source.startsWith('github:')) continue;
|
|
217
|
-
const srcName = s.source.replace('github:', '').toLowerCase();
|
|
218
|
-
for (const b of (Array.isArray(bundles) ? bundles : [])) {
|
|
219
|
-
if (srcName.toLowerCase().includes(b.id.toLowerCase()) || b.id.toLowerCase().includes(srcName.split('-')[0])) {
|
|
211
|
+
// repo_url = "owner/repo" → cloned as "owner-repo" in github: source
|
|
212
|
+
const clonedName = b.repo_url.replace('/', '-').toLowerCase();
|
|
213
|
+
if (githubSources.has(clonedName)) installedSet.add(b.id);
|
|
214
|
+
} else if (Array.isArray(b.skills)) {
|
|
215
|
+
// skill-list bundle: installed if ALL skills are in DB
|
|
216
|
+
if (b.skills.length > 0 && b.skills.every(sid => dbSkillIds.has(sid))) {
|
|
220
217
|
installedSet.add(b.id);
|
|
221
218
|
}
|
|
222
219
|
}
|
|
223
220
|
}
|
|
221
|
+
|
|
222
|
+
// Individual skills
|
|
223
|
+
for (const id of dbSkillIds) installedSet.add(id);
|
|
224
224
|
} catch {}
|
|
225
225
|
|
|
226
226
|
const { runTUI } = await import('./tui.js');
|
|
@@ -246,12 +246,40 @@ if (args[0] === 'marketplace') {
|
|
|
246
246
|
|
|
247
247
|
if (args[0] === 'validate') {
|
|
248
248
|
const { validateSkill } = await import('./validator.js');
|
|
249
|
+
const { isSkillFile } = await import('./parser.js');
|
|
249
250
|
const file = args[1];
|
|
250
251
|
if (!file) { error('Usage: ' + bin + ' validate <skill.md>'); process.exit(1); }
|
|
252
|
+
|
|
253
|
+
const raw = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : null;
|
|
254
|
+
|
|
255
|
+
// Show indexing score breakdown
|
|
256
|
+
if (raw) {
|
|
257
|
+
const { skillScore: _score } = await import('./parser.js').catch(() => ({}));
|
|
258
|
+
const willIndex = isSkillFile(file, raw);
|
|
259
|
+
const scoreLabel = willIndex ? chalk.green('✓ will be indexed') : chalk.red('✗ will be skipped by indexer');
|
|
260
|
+
console.log(chalk.bold('\n Indexing check: ') + scoreLabel);
|
|
261
|
+
|
|
262
|
+
// Show which signals were detected
|
|
263
|
+
const lines = raw.split('\n').filter(l => l.trim());
|
|
264
|
+
const signals = [];
|
|
265
|
+
try { const { data } = (await import('gray-matter')).default(raw); if (data.name) signals.push(chalk.green('+4 frontmatter name:')); } catch {}
|
|
266
|
+
if (/^#{1,3}\s+(steps?|usage|instructions?|how\s+to|when\s+to\s+use|workflow)/im.test(raw)) signals.push(chalk.green('+2 instructional headers (## Steps / ## Usage)'));
|
|
267
|
+
if (lines.filter(l => /^#{1,3}\s/.test(l)).some(h => /\b(run|use|fix|debug|check|create|deploy|scan|audit)\b/i.test(h))) signals.push(chalk.green('+2 imperative verbs in headers'));
|
|
268
|
+
if (raw.includes('```')) signals.push(chalk.green('+1 code block'));
|
|
269
|
+
if (lines.some(l => /^\d+\.\s/.test(l))) signals.push(chalk.green('+1 numbered list'));
|
|
270
|
+
if (lines.some(l => /^[-*+]\s/.test(l))) signals.push(chalk.green('+1 bullet list'));
|
|
271
|
+
const firstH = lines.find(l => /^#{1,3}\s/.test(l))?.replace(/^#+\s*/, '') || '';
|
|
272
|
+
if (/^(overview|introduction|about|background|welcome)/i.test(firstH)) signals.push(chalk.red('-3 first header looks like docs ("' + firstH + '")'));
|
|
273
|
+
if (signals.length) {
|
|
274
|
+
signals.forEach(s => console.log(' ' + s));
|
|
275
|
+
}
|
|
276
|
+
console.log();
|
|
277
|
+
}
|
|
278
|
+
|
|
251
279
|
const result = validateSkill(file);
|
|
252
280
|
result.warnings.forEach(w => console.log(chalk.yellow('⚠') + ' ' + chalk.gray(w)));
|
|
253
281
|
if (result.ok) {
|
|
254
|
-
success('Skill is valid');
|
|
282
|
+
success('Skill is valid — ready to publish');
|
|
255
283
|
process.exit(0);
|
|
256
284
|
} else {
|
|
257
285
|
error('Validation failed:');
|
package/package.json
CHANGED
package/tui.js
CHANGED
|
@@ -143,9 +143,7 @@ function render(state, installedSet = new Set()) {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
// item row
|
|
146
|
-
const isInstalled = item.
|
|
147
|
-
? installedSet.has(item.id) || installedSet.has(item.id.toLowerCase())
|
|
148
|
-
: installedSet.has(item.id) || installedSet.has(item.code);
|
|
146
|
+
const isInstalled = installedSet.has(item.id) || (item.code && installedSet.has(item.code));
|
|
149
147
|
const arrow = selected ? cyan('▶') : ' ';
|
|
150
148
|
const type = item.type === 'bundle' ? blue('⊞') : dim('·');
|
|
151
149
|
const badge = isInstalled ? green('✓') : ' ';
|
|
@@ -171,9 +169,7 @@ function render(state, installedSet = new Set()) {
|
|
|
171
169
|
write(dim('─'.repeat(cols)) + CLEAR_EOL + '\n');
|
|
172
170
|
const sel = items[cursor];
|
|
173
171
|
if (sel && !searching) {
|
|
174
|
-
const isInst = sel.
|
|
175
|
-
? installedSet.has(sel.id) || installedSet.has(sel.id.toLowerCase())
|
|
176
|
-
: installedSet.has(sel.id) || installedSet.has(sel.code);
|
|
172
|
+
const isInst = installedSet.has(sel.id) || (sel.code && installedSet.has(sel.code));
|
|
177
173
|
const installCmd = sel.type === 'bundle' ? `bundle install ${sel.id}` : `install ${sel.code || sel.id}`;
|
|
178
174
|
const instLabel = isInst ? green(' ✓ installed') + dim(' ') : dim(' Enter') + chalk.white(' install') + dim(' ');
|
|
179
175
|
write(instLabel + dim('Tab') + ' switch ' + dim('/') + ' search ' + dim('q') + ' quit' + CLEAR_EOL + '\n');
|