promptgraph-mcp 2.4.6 → 2.4.7
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/github-import.js +4 -4
- package/index.js +47 -14
- package/indexer.js +14 -7
- package/package.json +1 -1
- package/parser.js +21 -115
- package/registry/training/bad/accepts-HISTORY.md +250 -0
- package/registry/training/bad/argparse-CHANGELOG.md +185 -0
- package/registry/training/bad/balanced-match-LICENSE.md +23 -0
- package/registry/training/bad/better-sqlite3-README.md +99 -0
- package/registry/training/bad/bindings-LICENSE.md +22 -0
- package/registry/training/bad/bl-LICENSE.md +13 -0
- package/registry/training/bad/body-parser-README.md +494 -0
- package/registry/training/bad/bytes-HISTORY.md +97 -0
- package/registry/training/bad/camelcase-README.md +135 -0
- package/registry/training/bad/chai-README.md +162 -0
- package/registry/training/bad/cli-progress-LICENSE.md +24 -0
- package/registry/training/bad/content-type-HISTORY.md +29 -0
- package/registry/training/bad/cookie-SECURITY.md +25 -0
- package/registry/training/bad/cookie-signature-HISTORY.md +70 -0
- package/registry/training/bad/cors-README.md +277 -0
- package/registry/training/bad/cross-spawn-README.md +89 -0
- package/registry/training/bad/deep-extend-CHANGELOG.md +46 -0
- package/registry/training/bad/depd-HISTORY.md +103 -0
- package/registry/training/bad/esprima-README.md +46 -0
- package/registry/training/bad/etag-HISTORY.md +83 -0
- package/registry/training/bad/expect-type-SECURITY.md +14 -0
- package/registry/training/bad/finalhandler-HISTORY.md +239 -0
- package/registry/training/bad/fresh-HISTORY.md +80 -0
- package/registry/training/bad/glob-LICENSE.md +63 -0
- package/registry/training/bad/hono-README.md +85 -0
- package/registry/training/bad/http-errors-HISTORY.md +186 -0
- package/registry/training/bad/jose-LICENSE.md +21 -0
- package/registry/training/bad/jose-README.md +153 -0
- package/registry/training/bad/js-yaml-README.md +299 -0
- package/registry/training/bad/json-schema-typed-LICENSE.md +57 -0
- package/registry/training/bad/json-stringify-safe-CHANGELOG.md +14 -0
- package/registry/training/bad/lru-cache-LICENSE.md +55 -0
- package/registry/training/bad/media-typer-HISTORY.md +50 -0
- package/registry/training/bad/minimatch-LICENSE.md +55 -0
- package/registry/training/bad/minimist-CHANGELOG.md +298 -0
- package/registry/training/bad/minimist-README.md +121 -0
- package/registry/training/bad/ms-LICENSE.md +21 -0
- package/registry/training/bad/negotiator-HISTORY.md +114 -0
- package/registry/training/bad/on-finished-HISTORY.md +98 -0
- package/registry/training/bad/pkce-challenge-CHANGELOG.md +114 -0
- package/registry/training/bad/postcss-README.md +28 -0
- package/registry/training/bad/prebuild-install-CHANGELOG.md +131 -0
- package/registry/training/bad/proxy-addr-HISTORY.md +161 -0
- package/registry/training/bad/qs-CHANGELOG.md +822 -0
- package/registry/training/bad/rc-README.md +227 -0
- package/registry/training/bad/readable-stream-CONTRIBUTING.md +38 -0
- package/registry/training/bad/router-HISTORY.md +228 -0
- package/registry/training/bad/semver-README.md +680 -0
- package/registry/training/bad/send-README.md +317 -0
- package/registry/training/bad/serve-static-README.md +253 -0
- package/registry/training/bad/statuses-HISTORY.md +87 -0
- package/registry/training/bad/type-is-HISTORY.md +292 -0
- package/registry/training/bad/vary-HISTORY.md +39 -0
- package/registry/training/bad/vite-LICENSE.md +2230 -0
- package/registry/training/bad/which-CHANGELOG.md +166 -0
- package/registry/training/bad/zod-README.md +191 -0
- package/registry/training/good/skills-store-autopilot.md +85 -0
- package/registry/training/good/skills-store-bot-builder.md +70 -0
- package/registry/training/good/skills-store-chain.md +136 -0
- package/registry/training/good/skills-store-evolve.md +100 -0
- package/registry/training/good/skills-store-game.md +27 -0
- package/registry/training/good/skills-store-hunt.md +102 -0
- package/registry/training/good/skills-store-intel.md +56 -0
- package/registry/training/good/skills-store-memory-gc.md +58 -0
- package/registry/training/good/skills-store-pcsort.md +207 -0
- package/registry/training/good/skills-store-pickup.md +60 -0
- package/registry/training/good/skills-store-recon.md +141 -0
- package/registry/training/good/skills-store-remember.md +64 -0
- package/registry/training/good/skills-store-report.md +117 -0
- package/registry/training/good/skills-store-router.md +225 -0
- package/registry/training/good/skills-store-search.md +168 -0
- package/registry/training/good/skills-store-surface.md +53 -0
- package/registry/training/good/skills-store-token-scan.md +141 -0
- package/registry/training/good/skills-store-triage.md +97 -0
- package/registry/training/good/skills-store-unity.md +733 -0
- package/registry/training/good/skills-store-validate.md +135 -0
- package/registry/training/good/skills-store-web3-audit.md +217 -0
- package/src/filter/classifier.js +88 -0
- package/src/filter/cluster.js +52 -0
- package/src/filter/dedup.js +36 -0
- package/src/filter/hard-filter.js +57 -0
- package/src/filter/train.js +64 -0
package/github-import.js
CHANGED
|
@@ -6,6 +6,7 @@ import { globSync } from 'glob';
|
|
|
6
6
|
import { indexAll, indexSource } from './indexer.js';
|
|
7
7
|
import { loadConfig, saveConfig, PROMPTGRAPH_DIR, SKILLS_STORE_DIR } from './config.js';
|
|
8
8
|
import { validateSkill } from './validator.js';
|
|
9
|
+
import { isSkillFile } from './parser.js';
|
|
9
10
|
|
|
10
11
|
const SKILL_DIRS = ['skills', 'commands', 'prompts', 'agents', 'skills-store', 'slash-commands', 'custom-commands', 'templates'];
|
|
11
12
|
|
|
@@ -366,17 +367,16 @@ export async function importFromGitHub(repoUrl) {
|
|
|
366
367
|
// Remove doc files anywhere in the cloned tree
|
|
367
368
|
cleanupRepoRoot(dest);
|
|
368
369
|
|
|
369
|
-
// Validate every .md file — delete
|
|
370
|
+
// Validate every .md file via isSkillFile — delete low-quality files
|
|
370
371
|
const allMd = globSync(`${dest}/**/*.md`);
|
|
371
372
|
let removedInvalid = 0;
|
|
372
373
|
for (const fp of allMd) {
|
|
373
|
-
|
|
374
|
-
if (!v.ok) {
|
|
374
|
+
if (!isSkillFile(fp)) {
|
|
375
375
|
try { fs.unlinkSync(fp); removedInvalid++; } catch {}
|
|
376
376
|
}
|
|
377
377
|
}
|
|
378
378
|
if (removedInvalid > 0) {
|
|
379
|
-
console.log(`Removed ${removedInvalid}
|
|
379
|
+
console.log(`Removed ${removedInvalid} low-quality .md files (isSkillFile)`);
|
|
380
380
|
// Clean up empty dirs left behind
|
|
381
381
|
removeEmptyDirs(dest);
|
|
382
382
|
}
|
package/index.js
CHANGED
|
@@ -16,7 +16,7 @@ const args = process.argv.slice(2);
|
|
|
16
16
|
const rawBin = process.argv[1]?.split(/[\\/]/).pop()?.replace(/\.js$/, '');
|
|
17
17
|
const bin = (rawBin && rawBin !== 'index') ? rawBin : 'pg';
|
|
18
18
|
|
|
19
|
-
const KNOWN_COMMANDS = new Set(['init', 'reindex', 'update', 'import', 'setup', 'validate', 'marketplace', 'doctor', 'search', 'help', '--help', '-h', 'bundle', 'status']);
|
|
19
|
+
const KNOWN_COMMANDS = new Set(['init', 'reindex', 'update', 'import', 'setup', 'validate', 'marketplace', 'doctor', 'search', 'help', '--help', '-h', 'bundle', 'status', 'train']);
|
|
20
20
|
|
|
21
21
|
function showHelp() {
|
|
22
22
|
console.log(
|
|
@@ -319,24 +319,41 @@ if (args[0] === 'validate') {
|
|
|
319
319
|
|
|
320
320
|
const raw = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : null;
|
|
321
321
|
|
|
322
|
-
// Show indexing score breakdown
|
|
323
322
|
if (raw) {
|
|
324
|
-
const {
|
|
325
|
-
const
|
|
323
|
+
const { filterWithClassifier, isSkillFile: _isSkill } = await import('./parser.js');
|
|
324
|
+
const { hardFilter } = await import('./src/filter/hard-filter.js');
|
|
325
|
+
const { loadModel } = await import('./src/filter/train.js');
|
|
326
|
+
const { embed } = await import('./embedder.js');
|
|
327
|
+
const { classify } = await import('./src/filter/classifier.js');
|
|
328
|
+
|
|
329
|
+
const hfResult = hardFilter(file, raw);
|
|
330
|
+
const willIndex = _isSkill(file, raw);
|
|
326
331
|
const scoreLabel = willIndex ? chalk.green('✓ will be indexed') : chalk.red('✗ will be skipped by indexer');
|
|
327
332
|
console.log(chalk.bold('\n Indexing check: ') + scoreLabel);
|
|
328
333
|
|
|
329
|
-
// Show which signals were detected
|
|
330
|
-
const lines = raw.split('\n').filter(l => l.trim());
|
|
331
334
|
const signals = [];
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
if (
|
|
335
|
+
if (!hfResult.pass) {
|
|
336
|
+
signals.push(chalk.red(`✗ hard filter: ${hfResult.reason}`));
|
|
337
|
+
} else {
|
|
338
|
+
signals.push(chalk.green('✓ hard filter passed'));
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const centroids = loadModel();
|
|
342
|
+
if (centroids) {
|
|
343
|
+
try {
|
|
344
|
+
const vec = await embed(raw);
|
|
345
|
+
const decision = classify(vec, centroids, raw, file);
|
|
346
|
+
const pct = (decision.score * 100).toFixed(0);
|
|
347
|
+
if (decision.label === 'skill') signals.push(chalk.green(`✓ classifier: skill (${pct}%)`));
|
|
348
|
+
else if (decision.label === 'unsure') signals.push(chalk.yellow(`? classifier: unsure (${pct}%)`));
|
|
349
|
+
else signals.push(chalk.red(`✗ classifier: reject (${pct}%)`));
|
|
350
|
+
} catch {
|
|
351
|
+
signals.push(chalk.gray(' classifier: embed failed (skip)'));
|
|
352
|
+
}
|
|
353
|
+
} else {
|
|
354
|
+
signals.push(chalk.gray(' classifier: no model (run `pg train`)'));
|
|
355
|
+
}
|
|
356
|
+
|
|
340
357
|
if (signals.length) {
|
|
341
358
|
signals.forEach(s => console.log(' ' + s));
|
|
342
359
|
}
|
|
@@ -355,6 +372,22 @@ if (args[0] === 'validate') {
|
|
|
355
372
|
}
|
|
356
373
|
}
|
|
357
374
|
|
|
375
|
+
if (args[0] === 'train') {
|
|
376
|
+
const { train: trainModel } = await import('./src/filter/train.js');
|
|
377
|
+
const spin = (await import('./cli.js')).spinner('Training classifier...');
|
|
378
|
+
spin.start();
|
|
379
|
+
try {
|
|
380
|
+
const model = await trainModel();
|
|
381
|
+
spin.stop();
|
|
382
|
+
success(`Classifier trained (${model.counts.good} good, ${model.counts.bad} bad examples)`);
|
|
383
|
+
} catch (e) {
|
|
384
|
+
spin.stop();
|
|
385
|
+
error(`Training failed: ${e.message}`);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
process.exit(0);
|
|
389
|
+
}
|
|
390
|
+
|
|
358
391
|
if (args[0] === 'search') {
|
|
359
392
|
const query = args.slice(1).join(' ');
|
|
360
393
|
if (!query) { error('Usage: ' + bin + ' search <query>'); process.exit(1); }
|
package/indexer.js
CHANGED
|
@@ -2,8 +2,8 @@ import { globSync } from 'glob';
|
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import { parseSkillFile, isSkillFile } from './parser.js';
|
|
6
|
-
import { embedBatch, BATCH_SIZE } from './embedder.js';
|
|
5
|
+
import { parseSkillFile, isSkillFile, filterWithClassifier } from './parser.js';
|
|
6
|
+
import { embedBatch, cosineSimilarity, BATCH_SIZE } from './embedder.js';
|
|
7
7
|
import { getDb, skillId, vecToBlob } from './db.js';
|
|
8
8
|
import { loadConfig } from './config.js';
|
|
9
9
|
import { chunkText } from './chunker.js';
|
|
@@ -138,6 +138,7 @@ export async function indexAll({ fast = false } = {}) {
|
|
|
138
138
|
let count = 0;
|
|
139
139
|
let errors = 0;
|
|
140
140
|
let skipped = 0;
|
|
141
|
+
let classifierRemoved = 0;
|
|
141
142
|
let batch = [];
|
|
142
143
|
const start = Date.now();
|
|
143
144
|
|
|
@@ -174,8 +175,10 @@ export async function indexAll({ fast = false } = {}) {
|
|
|
174
175
|
batch.push({ ...parsed, hash });
|
|
175
176
|
|
|
176
177
|
if (batch.length >= BATCH_SIZE) {
|
|
177
|
-
await
|
|
178
|
-
|
|
178
|
+
const filtered = await filterWithClassifier(batch);
|
|
179
|
+
classifierRemoved += batch.length - filtered.length;
|
|
180
|
+
await indexBatch(db, filtered, { fast });
|
|
181
|
+
count += filtered.length;
|
|
179
182
|
batch = [];
|
|
180
183
|
const eta = count > 0 ? Math.round((total - count) * (Date.now() - start) / count / 1000) : '?';
|
|
181
184
|
progress(count, total, { skipped, eta, errors });
|
|
@@ -196,8 +199,10 @@ export async function indexAll({ fast = false } = {}) {
|
|
|
196
199
|
}
|
|
197
200
|
|
|
198
201
|
if (batch.length > 0) {
|
|
199
|
-
await
|
|
200
|
-
|
|
202
|
+
const filtered = await filterWithClassifier(batch);
|
|
203
|
+
classifierRemoved += batch.length - filtered.length;
|
|
204
|
+
await indexBatch(db, filtered, { fast });
|
|
205
|
+
count += filtered.length;
|
|
201
206
|
}
|
|
202
207
|
|
|
203
208
|
progress(total, total, { skipped, errors });
|
|
@@ -208,7 +213,9 @@ export async function indexAll({ fast = false } = {}) {
|
|
|
208
213
|
await buildAnnIndex();
|
|
209
214
|
spin.stop();
|
|
210
215
|
}
|
|
211
|
-
|
|
216
|
+
const stats = [`${errors} errors`, `${skipped} skipped`, `${removed} removed`];
|
|
217
|
+
if (classifierRemoved > 0) stats.push(`${classifierRemoved} filtered`);
|
|
218
|
+
success(`Indexed ${chalk.white.bold(count)} skills ${chalk.gray(`(${stats.join(', ')})`)}`);
|
|
212
219
|
if (fast) info(chalk.yellow('Fast mode: keyword search only. Run `pg reindex` for semantic search.'));
|
|
213
220
|
const elapsed = ((Date.now() - start) / 1000).toFixed(1);
|
|
214
221
|
info(chalk.gray(`Time: ${elapsed}s`));
|
package/package.json
CHANGED
package/parser.js
CHANGED
|
@@ -1,136 +1,42 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import matter from 'gray-matter';
|
|
4
|
+
import { hardFilter } from './src/filter/hard-filter.js';
|
|
5
|
+
import { classify } from './src/filter/classifier.js';
|
|
6
|
+
import { loadModel } from './src/filter/train.js';
|
|
4
7
|
|
|
5
|
-
// match /skill-name but not URLs (http://, https://, etc.)
|
|
6
8
|
const SKILL_REF_RE = /(?<!https?:|ftp:)(?<![a-zA-Z0-9])\/([a-z0-9][a-z0-9-]{2,})/g;
|
|
7
9
|
|
|
8
|
-
// Filenames that are never skills — docs, meta, legal files
|
|
9
|
-
const SKIP_FILENAMES = new Set([
|
|
10
|
-
'readme', 'changelog', 'license', 'contributing', 'code-of-conduct',
|
|
11
|
-
'security', 'authors', 'credits', 'install', 'installation', 'usage',
|
|
12
|
-
'engagements', 'contributors', 'maintainers', 'acknowledgements',
|
|
13
|
-
'faq', 'glossary', 'index', 'overview', 'summary', 'roadmap', 'todo',
|
|
14
|
-
'notes', 'template', 'example', 'sample', 'demo', 'getting-started',
|
|
15
|
-
'quickstart', 'guide', 'tutorial', 'walkthrough', 'architecture',
|
|
16
|
-
'design', 'spec', 'specification', 'requirements', 'privacy', 'terms',
|
|
17
|
-
'disclaimer', 'notice', 'copying', 'warranty', 'codeofconduct',
|
|
18
|
-
'pull_request_template', 'issue_template', 'funding',
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
// Filename patterns that are never skills — readme* catches ALL variants (readme_de, readme_zh-CN, etc.)
|
|
22
|
-
const SKIP_FILENAME_RE = /^(_|\.)|^v?\d+[\.\-]\d+|^\d{4}[\-_]\d{2}|^readme|^license|^changelog|^contributing|^code.of.conduct|^security|^authors|^credits|^disclaimer|^notice|^copying|^warranty|^promotion|^funding/i;
|
|
23
|
-
|
|
24
|
-
// Path segments that indicate the file is NOT a skill
|
|
25
|
-
const SKIP_DIRS = new Set([
|
|
26
|
-
'.github', 'docs', 'doc', 'documentation', 'examples', 'example',
|
|
27
|
-
'tests', 'test', '__tests__', 'spec', 'fixtures', 'assets', 'images',
|
|
28
|
-
'img', 'screenshots', 'media', 'static', 'public', 'dist', 'build',
|
|
29
|
-
'node_modules', 'vendor', 'third_party',
|
|
30
|
-
]);
|
|
31
|
-
|
|
32
|
-
// First-header values that signal documentation, not a skill
|
|
33
|
-
const DOC_FIRST_HEADERS = /^(overview|introduction|about|background|welcome|getting started|what is|why |table of contents|toc|foreword|preface|readme)/i;
|
|
34
|
-
|
|
35
|
-
// Imperative verbs commonly found in skill headers
|
|
36
|
-
const IMPERATIVE_HEADERS = /\b(run|use|apply|execute|check|debug|fix|create|add|remove|deploy|test|write|generate|analyze|review|refactor|optimize|configure|setup|install|scan|audit|validate|search|find|extract|parse)\b/i;
|
|
37
|
-
|
|
38
|
-
// Instructional section headers
|
|
39
|
-
const INSTRUCTION_HEADERS = /^#{1,3}\s+(steps?|usage|instructions?|how\s+to|when\s+to\s+use|workflow|process|procedure|example|examples?|commands?|output|result)/i;
|
|
40
|
-
|
|
41
|
-
// ── scoring ───────────────────────────────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
function skillScore(raw, base) {
|
|
44
|
-
let score = 0;
|
|
45
|
-
|
|
46
|
-
// Fast path: frontmatter with name = definitely a skill
|
|
47
|
-
try {
|
|
48
|
-
const { data } = matter(raw);
|
|
49
|
-
if (data.name && typeof data.name === 'string') return 10;
|
|
50
|
-
} catch {}
|
|
51
|
-
|
|
52
|
-
const lines = raw.split('\n');
|
|
53
|
-
const nonEmpty = lines.filter(l => l.trim());
|
|
54
|
-
const headers = nonEmpty.filter(l => /^#{1,3}\s/.test(l));
|
|
55
|
-
|
|
56
|
-
// Minimum viable content
|
|
57
|
-
if (raw.length < 150) return -99;
|
|
58
|
-
if (headers.length < 1) return -99;
|
|
59
|
-
|
|
60
|
-
// ── positive signals ──────────────────────────────────────────────────────
|
|
61
|
-
|
|
62
|
-
// Instructional section names (## Steps, ## Usage, etc.)
|
|
63
|
-
if (lines.some(l => INSTRUCTION_HEADERS.test(l))) score += 2;
|
|
64
|
-
|
|
65
|
-
// Headers with imperative verbs
|
|
66
|
-
if (headers.some(h => IMPERATIVE_HEADERS.test(h))) score += 2;
|
|
67
|
-
|
|
68
|
-
// Code block
|
|
69
|
-
if (raw.includes('```') || raw.includes(' ')) score += 1;
|
|
70
|
-
|
|
71
|
-
// Numbered list (step-by-step)
|
|
72
|
-
if (nonEmpty.some(l => /^\d+\.\s/.test(l))) score += 1;
|
|
73
|
-
|
|
74
|
-
// Bullet list
|
|
75
|
-
if (nonEmpty.some(l => /^[-*+]\s/.test(l))) score += 1;
|
|
76
|
-
|
|
77
|
-
// Multiple headers (structure)
|
|
78
|
-
if (headers.length >= 2) score += 1;
|
|
79
|
-
if (headers.length >= 4) score += 1;
|
|
80
|
-
|
|
81
|
-
// ── negative signals ──────────────────────────────────────────────────────
|
|
82
|
-
|
|
83
|
-
// First header looks like documentation
|
|
84
|
-
const firstHeader = headers[0]?.replace(/^#+\s*/, '') || '';
|
|
85
|
-
if (DOC_FIRST_HEADERS.test(firstHeader)) score -= 3;
|
|
86
|
-
|
|
87
|
-
// Content is mostly long prose paragraphs (narrative, not instructional)
|
|
88
|
-
const paragraphs = raw.split(/\n\n+/).filter(p => p.trim() && !p.trim().startsWith('#'));
|
|
89
|
-
const longProse = paragraphs.filter(p => p.split(' ').length > 60 && !/```/.test(p));
|
|
90
|
-
if (longProse.length > paragraphs.length * 0.6 && paragraphs.length > 3) score -= 2;
|
|
91
|
-
|
|
92
|
-
// Filename looks like a version, date, or index
|
|
93
|
-
if (SKIP_FILENAME_RE.test(base)) score -= 3;
|
|
94
|
-
|
|
95
|
-
// Very high word repetition (filler content)
|
|
96
|
-
const words = raw.toLowerCase().split(/\s+/).filter(w => w.length > 3);
|
|
97
|
-
if (words.length > 80) {
|
|
98
|
-
const unique = new Set(words);
|
|
99
|
-
if (unique.size / words.length < 0.22) score -= 2;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return score;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ── public API ────────────────────────────────────────────────────────────────
|
|
106
|
-
|
|
107
10
|
export function isSkillFile(filePath, raw) {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// Hard-reject by filename
|
|
112
|
-
if (SKIP_FILENAMES.has(base)) return false;
|
|
113
|
-
if (SKIP_FILENAME_RE.test(base)) return false;
|
|
114
|
-
|
|
115
|
-
// Hard-reject by parent directory
|
|
116
|
-
for (const part of parts.slice(0, -1)) {
|
|
117
|
-
if (SKIP_DIRS.has(part.toLowerCase())) return false;
|
|
118
|
-
}
|
|
11
|
+
const result = hardFilter(filePath, raw);
|
|
12
|
+
if (!result.pass) return false;
|
|
119
13
|
|
|
120
14
|
try {
|
|
121
15
|
if (!raw) raw = fs.readFileSync(filePath, 'utf8');
|
|
122
|
-
|
|
123
|
-
// Hard-reject: content starts with README header or badge lines
|
|
124
16
|
const firstLines = raw.trimStart().slice(0, 300);
|
|
125
17
|
if (/^#\s*readme\b/i.test(firstLines)) return false;
|
|
126
18
|
if (/!\[.*\]\(https?:\/\/(img\.shields\.io|badge\.fury|travis-ci|github\.com\/[^)]+\/badge)/i.test(firstLines)) return false;
|
|
127
19
|
|
|
128
|
-
return
|
|
20
|
+
return true;
|
|
129
21
|
} catch {
|
|
130
|
-
return
|
|
22
|
+
return true;
|
|
131
23
|
}
|
|
132
24
|
}
|
|
133
25
|
|
|
26
|
+
export async function filterWithClassifier(skills) {
|
|
27
|
+
const centroids = loadModel();
|
|
28
|
+
if (!centroids) return skills;
|
|
29
|
+
|
|
30
|
+
const { embedBatch } = await import('./embedder.js');
|
|
31
|
+
const texts = skills.map(s => s.content || '');
|
|
32
|
+
const embeddings = await embedBatch(texts);
|
|
33
|
+
|
|
34
|
+
return skills.filter((_, i) => {
|
|
35
|
+
const decision = classify(embeddings[i], centroids, skills[i].content, skills[i].path);
|
|
36
|
+
return decision.label === 'skill' || decision.label === 'unsure';
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
134
40
|
export function parseSkillFile(filePath, source, opts = {}) {
|
|
135
41
|
const raw = opts.raw ?? fs.readFileSync(filePath, 'utf8');
|
|
136
42
|
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
2.0.0 / 2024-08-31
|
|
2
|
+
==================
|
|
3
|
+
|
|
4
|
+
* Drop node <18 support
|
|
5
|
+
* deps: mime-types@^3.0.0
|
|
6
|
+
* deps: negotiator@^1.0.0
|
|
7
|
+
|
|
8
|
+
1.3.8 / 2022-02-02
|
|
9
|
+
==================
|
|
10
|
+
|
|
11
|
+
* deps: mime-types@~2.1.34
|
|
12
|
+
- deps: mime-db@~1.51.0
|
|
13
|
+
* deps: negotiator@0.6.3
|
|
14
|
+
|
|
15
|
+
1.3.7 / 2019-04-29
|
|
16
|
+
==================
|
|
17
|
+
|
|
18
|
+
* deps: negotiator@0.6.2
|
|
19
|
+
- Fix sorting charset, encoding, and language with extra parameters
|
|
20
|
+
|
|
21
|
+
1.3.6 / 2019-04-28
|
|
22
|
+
==================
|
|
23
|
+
|
|
24
|
+
* deps: mime-types@~2.1.24
|
|
25
|
+
- deps: mime-db@~1.40.0
|
|
26
|
+
|
|
27
|
+
1.3.5 / 2018-02-28
|
|
28
|
+
==================
|
|
29
|
+
|
|
30
|
+
* deps: mime-types@~2.1.18
|
|
31
|
+
- deps: mime-db@~1.33.0
|
|
32
|
+
|
|
33
|
+
1.3.4 / 2017-08-22
|
|
34
|
+
==================
|
|
35
|
+
|
|
36
|
+
* deps: mime-types@~2.1.16
|
|
37
|
+
- deps: mime-db@~1.29.0
|
|
38
|
+
|
|
39
|
+
1.3.3 / 2016-05-02
|
|
40
|
+
==================
|
|
41
|
+
|
|
42
|
+
* deps: mime-types@~2.1.11
|
|
43
|
+
- deps: mime-db@~1.23.0
|
|
44
|
+
* deps: negotiator@0.6.1
|
|
45
|
+
- perf: improve `Accept` parsing speed
|
|
46
|
+
- perf: improve `Accept-Charset` parsing speed
|
|
47
|
+
- perf: improve `Accept-Encoding` parsing speed
|
|
48
|
+
- perf: improve `Accept-Language` parsing speed
|
|
49
|
+
|
|
50
|
+
1.3.2 / 2016-03-08
|
|
51
|
+
==================
|
|
52
|
+
|
|
53
|
+
* deps: mime-types@~2.1.10
|
|
54
|
+
- Fix extension of `application/dash+xml`
|
|
55
|
+
- Update primary extension for `audio/mp4`
|
|
56
|
+
- deps: mime-db@~1.22.0
|
|
57
|
+
|
|
58
|
+
1.3.1 / 2016-01-19
|
|
59
|
+
==================
|
|
60
|
+
|
|
61
|
+
* deps: mime-types@~2.1.9
|
|
62
|
+
- deps: mime-db@~1.21.0
|
|
63
|
+
|
|
64
|
+
1.3.0 / 2015-09-29
|
|
65
|
+
==================
|
|
66
|
+
|
|
67
|
+
* deps: mime-types@~2.1.7
|
|
68
|
+
- deps: mime-db@~1.19.0
|
|
69
|
+
* deps: negotiator@0.6.0
|
|
70
|
+
- Fix including type extensions in parameters in `Accept` parsing
|
|
71
|
+
- Fix parsing `Accept` parameters with quoted equals
|
|
72
|
+
- Fix parsing `Accept` parameters with quoted semicolons
|
|
73
|
+
- Lazy-load modules from main entry point
|
|
74
|
+
- perf: delay type concatenation until needed
|
|
75
|
+
- perf: enable strict mode
|
|
76
|
+
- perf: hoist regular expressions
|
|
77
|
+
- perf: remove closures getting spec properties
|
|
78
|
+
- perf: remove a closure from media type parsing
|
|
79
|
+
- perf: remove property delete from media type parsing
|
|
80
|
+
|
|
81
|
+
1.2.13 / 2015-09-06
|
|
82
|
+
===================
|
|
83
|
+
|
|
84
|
+
* deps: mime-types@~2.1.6
|
|
85
|
+
- deps: mime-db@~1.18.0
|
|
86
|
+
|
|
87
|
+
1.2.12 / 2015-07-30
|
|
88
|
+
===================
|
|
89
|
+
|
|
90
|
+
* deps: mime-types@~2.1.4
|
|
91
|
+
- deps: mime-db@~1.16.0
|
|
92
|
+
|
|
93
|
+
1.2.11 / 2015-07-16
|
|
94
|
+
===================
|
|
95
|
+
|
|
96
|
+
* deps: mime-types@~2.1.3
|
|
97
|
+
- deps: mime-db@~1.15.0
|
|
98
|
+
|
|
99
|
+
1.2.10 / 2015-07-01
|
|
100
|
+
===================
|
|
101
|
+
|
|
102
|
+
* deps: mime-types@~2.1.2
|
|
103
|
+
- deps: mime-db@~1.14.0
|
|
104
|
+
|
|
105
|
+
1.2.9 / 2015-06-08
|
|
106
|
+
==================
|
|
107
|
+
|
|
108
|
+
* deps: mime-types@~2.1.1
|
|
109
|
+
- perf: fix deopt during mapping
|
|
110
|
+
|
|
111
|
+
1.2.8 / 2015-06-07
|
|
112
|
+
==================
|
|
113
|
+
|
|
114
|
+
* deps: mime-types@~2.1.0
|
|
115
|
+
- deps: mime-db@~1.13.0
|
|
116
|
+
* perf: avoid argument reassignment & argument slice
|
|
117
|
+
* perf: avoid negotiator recursive construction
|
|
118
|
+
* perf: enable strict mode
|
|
119
|
+
* perf: remove unnecessary bitwise operator
|
|
120
|
+
|
|
121
|
+
1.2.7 / 2015-05-10
|
|
122
|
+
==================
|
|
123
|
+
|
|
124
|
+
* deps: negotiator@0.5.3
|
|
125
|
+
- Fix media type parameter matching to be case-insensitive
|
|
126
|
+
|
|
127
|
+
1.2.6 / 2015-05-07
|
|
128
|
+
==================
|
|
129
|
+
|
|
130
|
+
* deps: mime-types@~2.0.11
|
|
131
|
+
- deps: mime-db@~1.9.1
|
|
132
|
+
* deps: negotiator@0.5.2
|
|
133
|
+
- Fix comparing media types with quoted values
|
|
134
|
+
- Fix splitting media types with quoted commas
|
|
135
|
+
|
|
136
|
+
1.2.5 / 2015-03-13
|
|
137
|
+
==================
|
|
138
|
+
|
|
139
|
+
* deps: mime-types@~2.0.10
|
|
140
|
+
- deps: mime-db@~1.8.0
|
|
141
|
+
|
|
142
|
+
1.2.4 / 2015-02-14
|
|
143
|
+
==================
|
|
144
|
+
|
|
145
|
+
* Support Node.js 0.6
|
|
146
|
+
* deps: mime-types@~2.0.9
|
|
147
|
+
- deps: mime-db@~1.7.0
|
|
148
|
+
* deps: negotiator@0.5.1
|
|
149
|
+
- Fix preference sorting to be stable for long acceptable lists
|
|
150
|
+
|
|
151
|
+
1.2.3 / 2015-01-31
|
|
152
|
+
==================
|
|
153
|
+
|
|
154
|
+
* deps: mime-types@~2.0.8
|
|
155
|
+
- deps: mime-db@~1.6.0
|
|
156
|
+
|
|
157
|
+
1.2.2 / 2014-12-30
|
|
158
|
+
==================
|
|
159
|
+
|
|
160
|
+
* deps: mime-types@~2.0.7
|
|
161
|
+
- deps: mime-db@~1.5.0
|
|
162
|
+
|
|
163
|
+
1.2.1 / 2014-12-30
|
|
164
|
+
==================
|
|
165
|
+
|
|
166
|
+
* deps: mime-types@~2.0.5
|
|
167
|
+
- deps: mime-db@~1.3.1
|
|
168
|
+
|
|
169
|
+
1.2.0 / 2014-12-19
|
|
170
|
+
==================
|
|
171
|
+
|
|
172
|
+
* deps: negotiator@0.5.0
|
|
173
|
+
- Fix list return order when large accepted list
|
|
174
|
+
- Fix missing identity encoding when q=0 exists
|
|
175
|
+
- Remove dynamic building of Negotiator class
|
|
176
|
+
|
|
177
|
+
1.1.4 / 2014-12-10
|
|
178
|
+
==================
|
|
179
|
+
|
|
180
|
+
* deps: mime-types@~2.0.4
|
|
181
|
+
- deps: mime-db@~1.3.0
|
|
182
|
+
|
|
183
|
+
1.1.3 / 2014-11-09
|
|
184
|
+
==================
|
|
185
|
+
|
|
186
|
+
* deps: mime-types@~2.0.3
|
|
187
|
+
- deps: mime-db@~1.2.0
|
|
188
|
+
|
|
189
|
+
1.1.2 / 2014-10-14
|
|
190
|
+
==================
|
|
191
|
+
|
|
192
|
+
* deps: negotiator@0.4.9
|
|
193
|
+
- Fix error when media type has invalid parameter
|
|
194
|
+
|
|
195
|
+
1.1.1 / 2014-09-28
|
|
196
|
+
==================
|
|
197
|
+
|
|
198
|
+
* deps: mime-types@~2.0.2
|
|
199
|
+
- deps: mime-db@~1.1.0
|
|
200
|
+
* deps: negotiator@0.4.8
|
|
201
|
+
- Fix all negotiations to be case-insensitive
|
|
202
|
+
- Stable sort preferences of same quality according to client order
|
|
203
|
+
|
|
204
|
+
1.1.0 / 2014-09-02
|
|
205
|
+
==================
|
|
206
|
+
|
|
207
|
+
* update `mime-types`
|
|
208
|
+
|
|
209
|
+
1.0.7 / 2014-07-04
|
|
210
|
+
==================
|
|
211
|
+
|
|
212
|
+
* Fix wrong type returned from `type` when match after unknown extension
|
|
213
|
+
|
|
214
|
+
1.0.6 / 2014-06-24
|
|
215
|
+
==================
|
|
216
|
+
|
|
217
|
+
* deps: negotiator@0.4.7
|
|
218
|
+
|
|
219
|
+
1.0.5 / 2014-06-20
|
|
220
|
+
==================
|
|
221
|
+
|
|
222
|
+
* fix crash when unknown extension given
|
|
223
|
+
|
|
224
|
+
1.0.4 / 2014-06-19
|
|
225
|
+
==================
|
|
226
|
+
|
|
227
|
+
* use `mime-types`
|
|
228
|
+
|
|
229
|
+
1.0.3 / 2014-06-11
|
|
230
|
+
==================
|
|
231
|
+
|
|
232
|
+
* deps: negotiator@0.4.6
|
|
233
|
+
- Order by specificity when quality is the same
|
|
234
|
+
|
|
235
|
+
1.0.2 / 2014-05-29
|
|
236
|
+
==================
|
|
237
|
+
|
|
238
|
+
* Fix interpretation when header not in request
|
|
239
|
+
* deps: pin negotiator@0.4.5
|
|
240
|
+
|
|
241
|
+
1.0.1 / 2014-01-18
|
|
242
|
+
==================
|
|
243
|
+
|
|
244
|
+
* Identity encoding isn't always acceptable
|
|
245
|
+
* deps: negotiator@~0.4.0
|
|
246
|
+
|
|
247
|
+
1.0.0 / 2013-12-27
|
|
248
|
+
==================
|
|
249
|
+
|
|
250
|
+
* Genesis
|