From 2b649782a217041577d041545f79afaa88b30370 Mon Sep 17 00:00:00 2001 From: Defame1297 Date: Sat, 20 Jun 2026 18:41:29 +0000 Subject: [PATCH] fix(kyberforge): resolve plugin-create path bug, validate.sh false positives, and write-skill YAML error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - plugin-create/SKILL.md: fix ${CLAUDE_PLUGIN_ROOT} path (create-plugin → plugin-create, 4 occurrences) - plugin-create/SKILL.md: delegate reserved name validation to new references/reserved-names.md (complete list) - plugin-create/SKILL.md: add displayName reminder in step 4, full-validation pointer in step 7 - plugin-create/references/reserved-names.md: complete reserved name list extracted from claude-code.md - plugin-create/references/manifest-fields.md: quick-ref for both plugin.json manifests and marketplace entry - plugin-create/META.md: update stale when: and references: fields to reflect post-migration paths - plugin-create/assets/plugin-template/hooks.json: unify empty hooks schema to {} (was []) - write-skill/SKILL.md: fix YAML frontmatter parse error — wrap description in >- block scalar - validate.sh: strip backtick spans before ../ check to eliminate documentation false positives - inventory.sh: same backtick-span fix, applied to both outer check and per-line reporting - tests/test_scripts.sh: fix SCRIPTS_DIR path to skills/marketplace-architect/scripts/ Co-Authored-By: Claude Sonnet 4.6 --- .../scripts/inventory.sh | 9 ++- .../marketplace-architect/scripts/validate.sh | 4 +- .../kyberforge/skills/plugin-create/META.md | 10 +-- .../kyberforge/skills/plugin-create/SKILL.md | 18 ++--- .../assets/plugin-template/hooks.json | 2 +- .../references/manifest-fields.md | 72 +++++++++++++++++++ .../references/reserved-names.md | 48 +++++++++++++ .../kyberforge/skills/write-skill/SKILL.md | 8 ++- plugins/kyberforge/tests/test_scripts.sh | 2 +- 9 files changed, 151 insertions(+), 22 deletions(-) create mode 100644 plugins/kyberforge/skills/plugin-create/references/manifest-fields.md create mode 100644 plugins/kyberforge/skills/plugin-create/references/reserved-names.md diff --git a/plugins/kyberforge/skills/marketplace-architect/scripts/inventory.sh b/plugins/kyberforge/skills/marketplace-architect/scripts/inventory.sh index 0fd548c..72255ca 100755 --- a/plugins/kyberforge/skills/marketplace-architect/scripts/inventory.sh +++ b/plugins/kyberforge/skills/marketplace-architect/scripts/inventory.sh @@ -62,13 +62,16 @@ while IFS= read -r -d '' path; do [[ -n "$asset_type" ]] && ROWS+=("$asset_type|$rel") - # Check for cross-references in text files + # Check for cross-references in text files — skip occurrences inside backtick spans case "$name" in *.md|*.json|*.sh) - if grep -q '\.\.\/' "$path" 2>/dev/null; then + if grep '\.\.\/' "$path" 2>/dev/null | sed 's/`[^`]*`//g' | grep -q '\.\.\/'; then while IFS= read -r line; do lineno="${line%%:*}" content="${line#*:}" - CROSS_REFS+=("$rel:$lineno: $content") + stripped=$(echo "$content" | sed 's/`[^`]*`//g') + if echo "$stripped" | grep -q '\.\.\/'; then + CROSS_REFS+=("$rel:$lineno: $content") + fi done < <(grep -n '\.\.\/' "$path" 2>/dev/null | head -20) fi ;; diff --git a/plugins/kyberforge/skills/marketplace-architect/scripts/validate.sh b/plugins/kyberforge/skills/marketplace-architect/scripts/validate.sh index aec062b..e283278 100755 --- a/plugins/kyberforge/skills/marketplace-architect/scripts/validate.sh +++ b/plugins/kyberforge/skills/marketplace-architect/scripts/validate.sh @@ -182,9 +182,9 @@ validate_plugin_dir() { validate_skill_md "$skill_md" done < <(find "$pd" -name "SKILL.md" -print0 2>/dev/null) - # Cross-reference check + # Cross-reference check — skip occurrences inside backtick spans (documentation text) while IFS= read -r -d '' f; do - if grep -q '\.\.\/' "$f" 2>/dev/null; then + if grep '\.\.\/' "$f" 2>/dev/null | sed 's/`[^`]*`//g' | grep -q '\.\.\/'; then local rel="${f#"$pd/"}" error "$rel: contains '../' reference — plugins cannot access files outside their directory after caching" fi diff --git a/plugins/kyberforge/skills/plugin-create/META.md b/plugins/kyberforge/skills/plugin-create/META.md index 648f1e9..50629b0 100644 --- a/plugins/kyberforge/skills/plugin-create/META.md +++ b/plugins/kyberforge/skills/plugin-create/META.md @@ -3,11 +3,11 @@ version: "1.0" updated: 2026-06-20 when: Invoked when the user wants to create a new plugin in the marketplace. Scaffolds the - directory structure from templates/plugin/, substitutes PLUGIN_NAME/PLUGIN_DESCRIPTION/ - AUTHOR_NAME/AUTHOR_EMAIL/AUTHOR_URL placeholders, writes to plugins//, registers - the plugin in .claude-plugin/marketplace.json, runs claude plugin validate ., and hands - off to /marketplace-architect. + directory structure from assets/plugin-template/ (bundled inside this skill), substitutes + PLUGIN_NAME/PLUGIN_DESCRIPTION/AUTHOR_NAME/AUTHOR_EMAIL/AUTHOR_URL placeholders, writes to + plugins//, registers the plugin in .claude-plugin/marketplace.json, runs + claude plugin validate ., and hands off to /marketplace-architect. references: - - docs/research/plugin-marketplace-architecture.md + - "${CLAUDE_PLUGIN_ROOT}/docs/plugin-marketplace-architecture.md" ``` diff --git a/plugins/kyberforge/skills/plugin-create/SKILL.md b/plugins/kyberforge/skills/plugin-create/SKILL.md index cf8540c..2669c4e 100644 --- a/plugins/kyberforge/skills/plugin-create/SKILL.md +++ b/plugins/kyberforge/skills/plugin-create/SKILL.md @@ -16,7 +16,7 @@ metadata: ## Required inputs -- **Plugin name** — kebab-case slug; ask if not stated. Validate: lowercase letters, digits, hyphens only; not already present in `plugins/` or `.claude-plugin/marketplace.json`; not a reserved name (`anthropic-*`, `claude-*`, `agent-skills`, `official-claude-plugins`). +- **Plugin name** — kebab-case slug; ask if not stated. Validate: lowercase letters, digits, hyphens only; not already present in `plugins/` or `.claude-plugin/marketplace.json`; not a reserved name. Load `references/reserved-names.md` for the full reserved list. - **Plugin description** — one sentence; ask if not stated. - **Author name** — ask if not stated. - **Author email** — ask if not stated; used in the Copilot root `plugin.json`. @@ -24,8 +24,8 @@ metadata: ## Constraints -- Load the plugin template from `assets/plugin-template/` bundled inside this skill (`${CLAUDE_PLUGIN_ROOT}/skills/create-plugin/assets/plugin-template/`). Stop if the path is missing — do not generate files from memory. -- Plugin name must be kebab-case and not a reserved name (`anthropic-*`, `claude-*`, `agent-skills`, `official-claude-plugins`) — halt and ask for a replacement before Gate A if violated. +- Load the plugin template from `assets/plugin-template/` bundled inside this skill (`${CLAUDE_PLUGIN_ROOT}/skills/plugin-create/assets/plugin-template/`). Stop if the path is missing — do not generate files from memory. +- Plugin name must be kebab-case and not a reserved name — see `references/reserved-names.md` for the full list; halt and ask for a replacement before Gate A if violated. - Do not write any file until Gate A (plan approval) and Gate B (file contents approval) are both explicitly confirmed. - Replace all five placeholder markers — `PLUGIN_NAME`, `PLUGIN_DESCRIPTION`, `AUTHOR_NAME`, `AUTHOR_EMAIL`, `AUTHOR_URL` — in every copied file before Gate B review. No marker may appear in written output. - Do not generate skill content — `skills/` is scaffolded as an empty directory with README only. Direct the user to `/write-skill` to add skills. @@ -39,19 +39,19 @@ metadata: ## Process -1. **Collect inputs.** Ask for plugin name, description, author name, author email, and author URL — one question at a time. Validate the plugin name: kebab-case format, not a reserved name, not already present in `plugins/` or `.claude-plugin/marketplace.json`. If any validation fails, stop and ask for a replacement before continuing. +1. **Collect inputs.** Ask for plugin name, description, author name, author email, and author URL — one question at a time. Validate the plugin name: kebab-case format, not already present in `plugins/` or `.claude-plugin/marketplace.json`, not a reserved name (load `references/reserved-names.md` to check). If any validation fails, stop and ask for a replacement before continuing. -2. **Check template.** Load the bundled template from `assets/plugin-template/` inside this skill (`${CLAUDE_PLUGIN_ROOT}/skills/create-plugin/assets/plugin-template/`). If the path is missing, stop and report it — do not proceed or generate files from memory. +2. **Check template.** Load the bundled template from `assets/plugin-template/` inside this skill (`${CLAUDE_PLUGIN_ROOT}/skills/plugin-create/assets/plugin-template/`). If the path is missing, stop and report it — do not proceed or generate files from memory. 3. **Gate A — plan review.** Present: the list of files that will be written (derived from `assets/plugin-template/` with `PLUGIN_NAME` substituted into filenames), the new `plugins//` directory path, the marketplace entry that will be added to `.claude-plugin/marketplace.json`, and whether `.github/plugin/marketplace.json` will also be updated. Wait for explicit approval — do not proceed on "looks good" or silence. -4. **Copy and substitute.** Copy `assets/plugin-template/` to `plugins//`. In every copied file, replace all occurrences of `PLUGIN_NAME`, `PLUGIN_DESCRIPTION`, `AUTHOR_NAME`, `AUTHOR_EMAIL`, and `AUTHOR_URL` with the collected values. Rename any file or directory whose name contains `PLUGIN_NAME`. +4. **Copy and substitute.** Copy `assets/plugin-template/` to `plugins//`. In every copied file, replace all occurrences of `PLUGIN_NAME`, `PLUGIN_DESCRIPTION`, `AUTHOR_NAME`, `AUTHOR_EMAIL`, and `AUTHOR_URL` with the collected values. Rename any file or directory whose name contains `PLUGIN_NAME`. Note: after substitution, `displayName` in `.claude-plugin/plugin.json` will equal the kebab slug — remind the user to update it to a human-readable string (e.g. "My Plugin") before publishing. 5. **Gate B — file contents review.** Show every file with its full substituted content. Wait for explicit approval — do not write until confirmed. 6. **Write files.** Write all substituted files to `plugins//`. Append the new plugin entry to `.claude-plugin/marketplace.json`. If `.github/plugin/marketplace.json` exists, append the same entry there. -7. **Validate.** Run `claude plugin validate .` from `plugins//`. Report all output inline — do not suppress warnings. If the command is unavailable, note it and suggest the user run it manually after local install. +7. **Validate.** Run `claude plugin validate .` from `plugins//`. Report all output inline — do not suppress warnings. If the command is unavailable, note it and suggest the user run it manually after local install. For full cross-tool and marketplace validation, direct the user to run `/marketplace-architect validate` after the plugin is installed. 8. **Hand off.** Print: "Plugin `` created and registered in `marketplace.json`. Fill in skill and agent content, then run `/marketplace-architect` to audit the full marketplace." @@ -68,7 +68,7 @@ metadata: ## Failure handling -- `assets/plugin-template/` not found at `${CLAUDE_PLUGIN_ROOT}/skills/create-plugin/assets/plugin-template/` — stop, report the path, do not generate from memory. +- `assets/plugin-template/` not found at `${CLAUDE_PLUGIN_ROOT}/skills/plugin-create/assets/plugin-template/` — stop, report the path, do not generate from memory. - Plugin name already exists in `plugins/` or `marketplace.json` — stop, report the conflict, ask for a different name. - Reserved name detected — stop, report the name and the reserved list, ask for a replacement before continuing. - `claude plugin validate .` unavailable — report that automated validation was skipped; suggest running it manually with `claude --plugin-dir ./plugins/`. @@ -76,7 +76,7 @@ metadata: ## Self-check - [ ] Plugin name validated: kebab-case, not reserved, not already present in `plugins/` or `marketplace.json` -- [ ] `assets/plugin-template/` verified to exist at `${CLAUDE_PLUGIN_ROOT}/skills/create-plugin/assets/plugin-template/` before any file generation +- [ ] `assets/plugin-template/` verified to exist at `${CLAUDE_PLUGIN_ROOT}/skills/plugin-create/assets/plugin-template/` before any file generation - [ ] Gate A presented with file list and marketplace entry — explicit approval received - [ ] All five markers substituted in all files — none appear in written output - [ ] Gate B presented with full substituted file contents — explicit approval received diff --git a/plugins/kyberforge/skills/plugin-create/assets/plugin-template/hooks.json b/plugins/kyberforge/skills/plugin-create/assets/plugin-template/hooks.json index b9820d5..deffac9 100644 --- a/plugins/kyberforge/skills/plugin-create/assets/plugin-template/hooks.json +++ b/plugins/kyberforge/skills/plugin-create/assets/plugin-template/hooks.json @@ -1,3 +1,3 @@ { - "hooks": [] + "hooks": {} } diff --git a/plugins/kyberforge/skills/plugin-create/references/manifest-fields.md b/plugins/kyberforge/skills/plugin-create/references/manifest-fields.md new file mode 100644 index 0000000..9cc55a4 --- /dev/null +++ b/plugins/kyberforge/skills/plugin-create/references/manifest-fields.md @@ -0,0 +1,72 @@ +# Manifest Field Reference + +Quick reference for the two plugin manifests generated by this skill. +Source of truth: `${CLAUDE_PLUGIN_ROOT}/skills/marketplace-architect/references/claude-code.md` +and `copilot-cli.md` in the same directory. + +--- + +## Claude Code — `.claude-plugin/plugin.json` + +Only `name` is required. Add other fields only when needed. + +```json +{ + "name": "my-plugin", + "displayName": "My Plugin", + "description": "What it does", + "author": { "name": "Name", "url": "https://..." }, + "license": "MIT", + "keywords": [] +} +``` + +- `displayName` — human-readable label shown in the Claude Code UI. Update it to a + title-cased string after placeholder substitution — it defaults to the kebab slug. +- `version` — omit to use git SHA per commit (recommended). Set only for explicit release gates. +- Component paths (`skills/`, `agents/`, etc.) are declared in the marketplace entry, not here. + +--- + +## Copilot CLI — `plugin.json` at plugin root + +```json +{ + "name": "my-plugin", + "description": "What it does", + "author": { "name": "Name", "email": "you@example.com" }, + "license": "MIT", + "keywords": [], + "agents": "agents/", + "skills": ["skills/"], + "hooks": "hooks.json", + "mcpServers": ".mcp.json" +} +``` + +- `author.email` (not `url`) — Copilot uses email; Claude uses url. Both manifests diverge here. +- Component paths are declared inline in this manifest (Copilot requires them; Claude ignores them). + +--- + +## Marketplace entry (in `.claude-plugin/marketplace.json`) + +```json +{ + "name": "my-plugin", + "source": "./plugins/my-plugin", + "description": "..." +} +``` + +- `source` must start with `./` for Claude Code compatibility. +- Do not set `version` here if it is also set in `plugin.json` — `plugin.json` wins silently. + +--- + +## Environment variables (for hooks and MCP configs) + +- `${CLAUDE_PLUGIN_ROOT}` — absolute path to the plugin's installation cache. Use for all + in-plugin file references in hooks and `.mcp.json`. Changes on update. +- `${CLAUDE_PLUGIN_DATA}` — persistent directory that survives updates. Use for state, + caches, and `node_modules`. diff --git a/plugins/kyberforge/skills/plugin-create/references/reserved-names.md b/plugins/kyberforge/skills/plugin-create/references/reserved-names.md new file mode 100644 index 0000000..07c1ff7 --- /dev/null +++ b/plugins/kyberforge/skills/plugin-create/references/reserved-names.md @@ -0,0 +1,48 @@ +# Reserved Plugin and Marketplace Names + +These names are blocked for third-party use by the Claude Code marketplace. Reject any +plugin or marketplace name that matches an exact entry or a wildcard pattern below. + +## Exact reserved names + +``` +claude-code-marketplace +claude-code-plugins +claude-plugins-official +claude-plugins-community +claude-community +anthropic-marketplace +anthropic-plugins +agent-skills +anthropic-agent-skills +knowledge-work-plugins +life-sciences +claude-for-legal +claude-for-financial-services +financial-services-plugins +``` + +## Reserved name patterns (prefix match) + +Any name starting with these strings is reserved: + +``` +anthropic- +claude- +official-claude +anthropic-tools +``` + +## Kebab-case requirement + +Plugin names must match `^[a-z0-9]+(-[a-z0-9]+)*$` — lowercase letters, digits, and +hyphens only. No underscores, spaces, or uppercase. The Claude.ai marketplace sync rejects +non-kebab-case names even if the local CLI tolerates them. + +## How to check + +1. Exact match: is the name in the exact reserved list above? +2. Pattern match: does the name start with any reserved prefix? +3. Format: does the name match the kebab-case regex? + +If any check fails, halt and ask the user for a different name before continuing. diff --git a/plugins/kyberforge/skills/write-skill/SKILL.md b/plugins/kyberforge/skills/write-skill/SKILL.md index 8659691..1f6321e 100644 --- a/plugins/kyberforge/skills/write-skill/SKILL.md +++ b/plugins/kyberforge/skills/write-skill/SKILL.md @@ -1,6 +1,12 @@ --- name: write-skill -description: Use when the user wants to author a new skill file or convert an existing placeholder to the canonical authoring standard. Triggers: "write a new skill for X", "create a SKILL.md that does Y", "build a skill to handle Z". Do NOT use when fixing or updating an existing well-formed skill (use upgrade-skill), running existing evals (use write-eval), refactoring application code, or writing documentation for non-skill artifacts. +description: >- + Use when the user wants to author a new skill file or convert an existing + placeholder to the canonical authoring standard. Triggers: "write a new skill + for X", "create a SKILL.md that does Y", "build a skill to handle Z". Do NOT + use when fixing or updating an existing well-formed skill (use upgrade-skill), + running existing evals (use write-eval), refactoring application code, or + writing documentation for non-skill artifacts. metadata: category: factory model: sonnet diff --git a/plugins/kyberforge/tests/test_scripts.sh b/plugins/kyberforge/tests/test_scripts.sh index 1045143..3de91d8 100755 --- a/plugins/kyberforge/tests/test_scripts.sh +++ b/plugins/kyberforge/tests/test_scripts.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -SCRIPTS_DIR="$(cd "$(dirname "$0")/../scripts" && pwd)" +SCRIPTS_DIR="$(cd "$(dirname "$0")/../skills/marketplace-architect/scripts" && pwd)" PASS=0; FAIL=0 # Use += to avoid ((var++)) returning 0 exit code when var was 0 under set -e