promptgraph-mcp 2.9.57 → 2.9.59
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 +50 -5
- package/commands/bundle.js +2 -1
- package/github-import.js +34 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,10 +11,11 @@ Instead of loading every `.md` skill into context, Claude calls `pg_search` and
|
|
|
11
11
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
14
|
-
- **Semantic search** — BGE-Small-EN embeddings, local, no API key required
|
|
14
|
+
- **Semantic search** — BGE-Small-EN embeddings (fastembed), local, no API key required
|
|
15
15
|
- **Token savings** — loads one skill on demand instead of all `.md` files (~20k+ tokens/session)
|
|
16
16
|
- **Fast reindex** — persistent embed cache makes re-indexing unchanged skills near-instant
|
|
17
|
-
- **
|
|
17
|
+
- **Flexible layouts** — finds skills in nested subfolders and in `.github/`, `.claude/`, `.opencode/` dot-folders (GitHub Copilot / agent conventions)
|
|
18
|
+
- **Any local folder** — `pg add-dir <path>` indexes a folder that isn't a default source
|
|
18
19
|
- **Marketplace** — browse and install community skill bundles via TUI or MCP tools
|
|
19
20
|
- **Publishing** — publish skills/bundles to the registry hands-off via GitHub CLI
|
|
20
21
|
- **Multi-platform** — Claude Code, OpenCode, Claude Desktop, Cursor, Windsurf, Cline, Codex
|
|
@@ -87,6 +88,44 @@ pg bundle add-repo <owner/repo> # Publish your GitHub repo to the registry (requ
|
|
|
87
88
|
|
|
88
89
|
---
|
|
89
90
|
|
|
91
|
+
## Where your skills can live
|
|
92
|
+
|
|
93
|
+
PromptGraph scans each registered source folder **recursively**, so any layout works:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
my-skills/
|
|
97
|
+
commit-message.md # flat file — name from filename
|
|
98
|
+
refactor/SKILL.md # folder skill — name from the folder ("refactor")
|
|
99
|
+
cloud/deploy/SKILL.md # nested categories — all found
|
|
100
|
+
.github/skills/my-skill/SKILL.md # GitHub Copilot / agent convention
|
|
101
|
+
.claude/skills/... # Claude dot-folder
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- **Subfolders** at any depth are scanned.
|
|
105
|
+
- **Generic filenames** (`SKILL.md`, `index.md`, `agent.md`, …) take their name from the parent folder, so `cloud/deploy/SKILL.md` and `cloud/infra/SKILL.md` stay distinct instead of colliding.
|
|
106
|
+
- **Dot-folders** `.github/{skills,prompts,agents,commands}`, `.claude/`, `.opencode/` are indexed. Other `.github` paths (`workflows`, `plugins`, …) are skipped.
|
|
107
|
+
- **Doc/meta files** (`README`, `CHANGELOG`, `LICENSE`, files in `docs/`, `tests/`, `assets/`, …) are filtered out automatically.
|
|
108
|
+
|
|
109
|
+
To index a folder that isn't a configured source:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pg add-dir /path/to/skills # registers it + indexes recursively
|
|
113
|
+
pg status # confirm it shows up with the right count
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Data & config location
|
|
119
|
+
|
|
120
|
+
PromptGraph stores its config, SQLite DB, and ANN index in:
|
|
121
|
+
|
|
122
|
+
- `~/.promptgraph/` — fresh installs on any platform
|
|
123
|
+
- `~/.claude/.promptgraph/` — kept for existing Claude Code installs (not migrated, so the index isn't orphaned)
|
|
124
|
+
|
|
125
|
+
Your **skill files** stay wherever you put them (the platform skills dir or any `add-dir` folder) — only the derived index lives here.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
90
129
|
## OpenCode — `/pg` slash commands
|
|
91
130
|
|
|
92
131
|
After `pg setup opencode`, two slash commands are available inside OpenCode:
|
|
@@ -135,12 +174,12 @@ The registry bot reads the submitted JSON and publishes within minutes.
|
|
|
135
174
|
|
|
136
175
|
## Skill bundles with tools
|
|
137
176
|
|
|
138
|
-
A bundle can ship both skill files (`.md`) and tool scripts (`.py`, `.sh`, `.js`,
|
|
177
|
+
A bundle can ship both skill files (`.md`) and tool scripts (`.py`, `.sh`, `.bash`, `.js`, `.ts`, `.rb`). When installed:
|
|
139
178
|
- All `.md` files go to the skills directory
|
|
140
|
-
- Script files are
|
|
179
|
+
- Script files are cloned alongside them (sparse-checkout fetches them with the skills)
|
|
141
180
|
- On Linux/macOS scripts are made executable (`chmod +x`)
|
|
142
181
|
|
|
143
|
-
|
|
182
|
+
For **repo bundles** (`pg bundle add-repo <owner/repo>`), scripts are detected automatically — `has_tools` and the 🔧 badge are set from the real files in the repo, no manifest needed. For **skill-list bundles**, list scripts explicitly in `tool_files`.
|
|
144
183
|
|
|
145
184
|
---
|
|
146
185
|
|
|
@@ -157,6 +196,12 @@ Bundle authors: set `has_tools: true` and include `tool_files` entries in your b
|
|
|
157
196
|
|
|
158
197
|
## Troubleshooting
|
|
159
198
|
|
|
199
|
+
**Only some of my skills got indexed:**
|
|
200
|
+
Check `pg status` for the `Found N files` count. If it's lower than expected:
|
|
201
|
+
- The skills live outside a registered source → `pg add-dir <that-folder>`.
|
|
202
|
+
- Generic `SKILL.md` files used to collide on name (fixed) — make sure you're on the latest version (`pg update`).
|
|
203
|
+
- Files named like docs (`README`, `01-intro`, …) or under `docs/`/`tests/` are filtered by design.
|
|
204
|
+
|
|
160
205
|
**Marketplace shows no bundles:**
|
|
161
206
|
```bash
|
|
162
207
|
pg doctor --reset-dead
|
package/commands/bundle.js
CHANGED
|
@@ -137,7 +137,8 @@ export default async function handler(args, bin) {
|
|
|
137
137
|
const hasScripts = hasScriptsQuick || deepResult.hasScripts;
|
|
138
138
|
console.log(chalk.green(` ✓ ${deepResult.passed}/${deepResult.total} skills valid${hasScripts ? ' 🔧 scripts detected' : ''}`));
|
|
139
139
|
|
|
140
|
-
const
|
|
140
|
+
const { bundleDisplayName } = await import('../github-import.js');
|
|
141
|
+
const name = bundleDisplayName(repo);
|
|
141
142
|
const id = repo.replace('/', '-').toLowerCase();
|
|
142
143
|
const bundle = {
|
|
143
144
|
id, name, repo_url: repo, author: repo.split('/')[0],
|
package/github-import.js
CHANGED
|
@@ -22,6 +22,25 @@ export const SCRIPT_GLOBS = ['**/*.py', '**/*.sh', '**/*.bash', '**/*.js', '**/*
|
|
|
22
22
|
// (e.g. microsoft/skills). Recognized as skill locations despite .github being a skip dir.
|
|
23
23
|
const COPILOT_SKILL_DIRS = new Set(['skills', 'prompts', 'agents', 'commands']);
|
|
24
24
|
|
|
25
|
+
// Repo names too generic to make a good bundle title on their own — prefix the owner.
|
|
26
|
+
const GENERIC_REPO_NAMES = new Set([
|
|
27
|
+
'skills', 'skill', 'prompts', 'prompt', 'agents', 'agent', 'commands', 'command',
|
|
28
|
+
'tools', 'toolkit', 'mcp', 'ai', 'claude', 'plugins', 'plugin', 'templates', 'library',
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
// Build a human-friendly bundle name from "owner/repo". For generic repo names
|
|
32
|
+
// (owner/skills → "Owner Skills") the owner is prefixed so titles aren't all "Skills".
|
|
33
|
+
export function bundleDisplayName(ownerRepo) {
|
|
34
|
+
const [owner, repo = ''] = ownerRepo.replace(/^https?:\/\/github\.com\//, '').replace(/\.git$/, '').split('/');
|
|
35
|
+
const titlecase = (s) => s.replace(/[-_.]+/g, ' ').replace(/\s+/g, ' ').trim().replace(/\b\w/g, (c) => c.toUpperCase());
|
|
36
|
+
const repoName = titlecase(repo);
|
|
37
|
+
if (GENERIC_REPO_NAMES.has(repo.toLowerCase())) {
|
|
38
|
+
const ownerName = titlecase(owner);
|
|
39
|
+
return repoName ? `${ownerName} ${repoName}` : ownerName;
|
|
40
|
+
}
|
|
41
|
+
return repoName || titlecase(owner);
|
|
42
|
+
}
|
|
43
|
+
|
|
25
44
|
// ── helpers ───────────────────────────────────────────────────────────────────
|
|
26
45
|
|
|
27
46
|
const repoStats = new Map()
|
|
@@ -225,9 +244,14 @@ async function detectSkillsDirFromAPI(ownerRepo) {
|
|
|
225
244
|
return null; // repo not found or inaccessible
|
|
226
245
|
}
|
|
227
246
|
if (!tree || !Array.isArray(tree.tree)) return null;
|
|
247
|
+
const paths = tree.tree.filter(f => f.type === 'blob').map(f => f.path);
|
|
248
|
+
return selectSkillSubdir(paths);
|
|
249
|
+
}
|
|
228
250
|
|
|
229
|
-
|
|
230
|
-
|
|
251
|
+
// Pure subdir-selection logic over a flat list of repo file paths (no network).
|
|
252
|
+
// Returns { subdir, label, validMdCount, hasScripts } or null. Exported for tests.
|
|
253
|
+
export function selectSkillSubdir(allPaths) {
|
|
254
|
+
if (!Array.isArray(allPaths) || allPaths.length === 0) return null;
|
|
231
255
|
|
|
232
256
|
// A path is a valid skill .md if the filename isn't meta (readme/license/…) and no
|
|
233
257
|
// path segment is a skip dir (docs/tests/assets/…). Exception: .github/{skills,
|
|
@@ -245,17 +269,17 @@ async function detectSkillsDirFromAPI(ownerRepo) {
|
|
|
245
269
|
}
|
|
246
270
|
return true;
|
|
247
271
|
};
|
|
248
|
-
const
|
|
249
|
-
if (
|
|
272
|
+
const mdPaths = allPaths.filter(isValidMd);
|
|
273
|
+
if (mdPaths.length === 0) return null;
|
|
250
274
|
|
|
251
|
-
const countUnder = (prefix) =>
|
|
252
|
-
const scriptUnder = (prefix) =>
|
|
275
|
+
const countUnder = (prefix) => mdPaths.filter(p => p.startsWith(prefix)).length;
|
|
276
|
+
const scriptUnder = (prefix) => allPaths.some(p => p.startsWith(prefix) && SCRIPT_EXTS_API.has(path.extname(p).toLowerCase()));
|
|
253
277
|
|
|
254
278
|
// Map of top-level dir names (lowercase -> real casing)
|
|
255
279
|
const topDirs = new Map();
|
|
256
|
-
for (const
|
|
257
|
-
const idx =
|
|
258
|
-
if (idx > 0) { const d =
|
|
280
|
+
for (const p of allPaths) {
|
|
281
|
+
const idx = p.indexOf('/');
|
|
282
|
+
if (idx > 0) { const d = p.slice(0, idx); topDirs.set(d.toLowerCase(), d); }
|
|
259
283
|
}
|
|
260
284
|
|
|
261
285
|
// 1. Known skill dir names (priority order) — counted recursively
|
|
@@ -280,7 +304,7 @@ async function detectSkillsDirFromAPI(ownerRepo) {
|
|
|
280
304
|
}
|
|
281
305
|
|
|
282
306
|
// 2. Root-level .md files (skills kept directly at repo root)
|
|
283
|
-
const rootMd =
|
|
307
|
+
const rootMd = mdPaths.filter(p => !p.includes('/')).length;
|
|
284
308
|
|
|
285
309
|
// 3. Best non-skip top-level subdir by recursive .md count
|
|
286
310
|
let best = null, bestCount = 0;
|