diff --git a/.claude/commands/add-portal.md b/.claude/commands/add-portal.md index ef8e2fb7..be02af1f 100644 --- a/.claude/commands/add-portal.md +++ b/.claude/commands/add-portal.md @@ -86,7 +86,7 @@ These conventions are what make portal skills interchangeable for `/scrape` and ### File specifics -- **`SKILL.md` frontmatter:** `name`, `version: 1.0.0`, a `description` written for skill triggering - it must name the portal, the market, and include trigger phrases in English **and** the market's language; `context: fork`; `allowed-tools: Bash(bun run skills//cli/src/cli.ts *)`. +- **`SKILL.md` frontmatter:** `name`, `version: 1.0.0`, a `description` written for skill triggering - it must name the portal, the market, and include trigger phrases in English **and** the market's language; `context: fork`; `allowed-tools: Bash(bun run .agents/skills//cli/src/cli.ts *)`. - **`SKILL.md` body:** what the skill searches, the personal-use warning if Step 2 found terms restrictions, command reference with flags, 4-6 usage examples using the user's market (real cities, realistic roles), output-format table, and a Notes section recording portal quirks found in Step 2. If Step 2.5 found the portal needs a credential, add a **Setup** section naming the service, the exact environment variable to export, and the fact that every call is billed - stated where the user reads it before running the skill, not after. - **`url-reference.md`:** the endpoints, parameters table, and response-structure notes from Step 2 - this is the file a future maintainer needs when the portal changes its markup. - **`package.json`:** name `-cli`, `"type": "module"`, scripts `start`, `test` (`bun test --timeout 30000`), and `typecheck` (`tsc --noEmit`); dev-only dependencies in the zero-dependency default. diff --git a/CHANGELOG.md b/CHANGELOG.md index 73a07cf2..648dc484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,14 @@ per-file diff commands. ### Fixed +- **`/add-portal` includes the `.agents` prefix in generated `allowed-tools`** (#545, + `.claude/commands/add-portal.md`, `tests/test_add_portal_command.py`) - the specification template + for the new portal's `SKILL.md` frontmatter wrote `allowed-tools: Bash(bun run skills//cli/src/cli.ts *)` + without `.agents/`, the one path in the file without it. A skill's `allowed-tools` grants the + listed command when that skill is invoked, so a generated portal invoked on its own granted a + command that does not exist and prompted instead; the string now names the real path, matching + the six shipped `SKILL.md` files. + - **`robots_check` unquotes incoming query strings and restricts `$` anchors to pattern end** (#543, `tools/robots_check.py`, `tests/test_robots_check.py`) - two path-matching edge cases in the robots.txt gate failed open. First, `gate(url)` called `unquote(parts.path)` but concatenated diff --git a/tests/test_add_portal_command.py b/tests/test_add_portal_command.py new file mode 100644 index 00000000..f6c0a6c0 --- /dev/null +++ b/tests/test_add_portal_command.py @@ -0,0 +1,22 @@ +"""Guards for the /add-portal command spec.""" +import unittest +from pathlib import Path + +REPO = Path(__file__).resolve().parent.parent +COMMAND = REPO / ".claude" / "commands" / "add-portal.md" + + +class TestAddPortalCommand(unittest.TestCase): + def test_allowed_tools_specifies_agents_skills_path(self): + content = COMMAND.read_text(encoding="utf-8") + self.assertIn( + "allowed-tools: Bash(bun run .agents/skills//cli/src/cli.ts *)", + content, + ) + self.assertNotIn( + "allowed-tools: Bash(bun run skills//cli/src/cli.ts *)", content + ) + + +if __name__ == "__main__": + unittest.main()