promptgraph-mcp 2.9.54 → 2.9.56

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 CHANGED
@@ -77,6 +77,7 @@ pg marketplace # Browse community skill bundles (TUI)
77
77
  # Install
78
78
  pg install <id> # Install a skill by marketplace ID (pg-xxxxxx)
79
79
  pg import <github-url> # Import skills directly from a GitHub repo URL
80
+ pg add-dir <path> # Index skills from a local folder (any platform)
80
81
 
81
82
  # Bundles
82
83
  pg bundle install <id> # Install a bundle by ID
package/config.js CHANGED
@@ -57,7 +57,14 @@ function makeDefaults(skillsDir, platform) {
57
57
 
58
58
  export function loadConfig() {
59
59
  if (fs.existsSync(CONFIG_PATH)) {
60
- return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
60
+ // Strip a UTF-8/UTF-16 BOM if an editor or PowerShell wrote one — JSON.parse
61
+ // rejects a leading BOM and would otherwise crash every command.
62
+ const raw = fs.readFileSync(CONFIG_PATH, 'utf8').replace(/^/, '');
63
+ try {
64
+ return JSON.parse(raw);
65
+ } catch (e) {
66
+ throw new Error(`Config file is corrupted (${CONFIG_PATH}): ${e.message}. Delete it to regenerate defaults.`);
67
+ }
61
68
  }
62
69
  return JSON.parse(JSON.stringify(makeDefaults()));
63
70
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptgraph-mcp",
3
- "version": "2.9.54",
3
+ "version": "2.9.56",
4
4
  "files": [
5
5
  "*.js",
6
6
  "commands/",
package/parser.js CHANGED
@@ -7,6 +7,12 @@ import { loadModel } from './src/filter/train.js';
7
7
 
8
8
  const SKILL_REF_RE = /(?<!https?:|ftp:)(?<![a-zA-Z0-9])\/([a-z0-9][a-z0-9-]{2,})/g;
9
9
 
10
+ // Generic filenames that carry no identity — name comes from the parent folder.
11
+ const GENERIC_SKILL_FILENAMES = new Set([
12
+ 'skill', 'skills', 'index', 'readme', 'agent', 'agents', 'main',
13
+ 'prompt', 'prompts', 'instructions', 'instruction',
14
+ ]);
15
+
10
16
  export function isSkillFile(filePath, raw) {
11
17
  const result = hardFilter(filePath, raw);
12
18
  if (!result.pass) return false;
@@ -51,7 +57,16 @@ export function parseSkillFile(filePath, source, opts = {}) {
51
57
  content = raw;
52
58
  }
53
59
 
54
- name = (name && String(name).trim()) || path.basename(filePath, '.md');
60
+ // Derive name when frontmatter lacks one. For the common "<skill-name>/SKILL.md"
61
+ // layout (anthropics/skills, google/skills, opencode, …) the filename is generic,
62
+ // so every skill would collapse to the same id ("skill") and overwrite each other.
63
+ // Use the parent folder name in that case.
64
+ let derived = path.basename(filePath, '.md');
65
+ if (GENERIC_SKILL_FILENAMES.has(derived.toLowerCase())) {
66
+ const parent = path.basename(path.dirname(filePath));
67
+ if (parent && parent !== '.') derived = parent;
68
+ }
69
+ name = (name && String(name).trim()) || derived;
55
70
  description = (description && String(description).trim()) || extractFirstParagraph(content || raw);
56
71
 
57
72
  const calls = new Set();