rename(547): the plugin is grimoire — manifest, MCP key, hooks, env, skills
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 1m2s
CI & Build / Python tests (push) Failing after 1m26s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 1m2s
CI & Build / Python tests (push) Failing after 1m26s
CI & Build / Build & push image (push) Skipped
Step 3 of the Scribe -> Grimoire rename. - Plugin `grimoire` in marketplace `grimoire-plugin`, MCP server key `grimoire`, so tools reach a session as mcp__plugin_grimoire_grimoire__*. - hooks/scribe_* -> hooks/grimoire_*, their shell functions and the TMPDIR ledgers with them; SCRIBE_URL / SCRIBE_TOKEN / SCRIBE_HOOK_DIR / SCRIBE_LEDGER_DIRS -> GRIMOIRE_*; the project marker is `.grimoire`. - skills/using-scribe -> using-grimoire, /grimoire:sync, stored processes arrive as grimoire-proc-<slug>; moment_actions names them the same way. - Migration 0124 rewrites stored skill names (rule_moments, rule_moment_judgments, moment_mappings) from scribe:/scribe-proc- to grimoire:/grimoire-proc-, so a rule mounted on a skill keeps firing. - Settings' install commands and MCP-only defaults, the docs and the tests follow. - scripts/check_plugin.py drops the smoke event for a report-check hook that has no file in plugin/hooks. Kept on purpose: the secret-sealing label, and the names that let backups written as Scribe restore and be counted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -25,11 +25,11 @@ def test_compose_tags_lowercases_language_and_dedups():
|
||||
def test_compose_body_includes_fields_and_fence():
|
||||
body = s.compose_body(
|
||||
code="return 1", language="python", signature="f() -> int",
|
||||
when_to_use="always", repo="scribe", path="a.py", symbol="f",
|
||||
when_to_use="always", repo="grimoire", path="a.py", symbol="f",
|
||||
)
|
||||
assert "**When to use:** always" in body
|
||||
assert "**Signature:** `f() -> int`" in body
|
||||
assert "`scribe` · `a.py` · `f`" in body
|
||||
assert "`grimoire` · `a.py` · `f`" in body
|
||||
assert "```python\nreturn 1\n```" in body
|
||||
assert body.rstrip().endswith("```")
|
||||
|
||||
@@ -43,7 +43,7 @@ def test_parse_round_trips_a_composed_snippet():
|
||||
title = "useDebouncedRef"
|
||||
body = s.compose_body(
|
||||
code="const x = 1", language="ts", signature="useDebouncedRef(v, ms)",
|
||||
when_to_use="debounce a reactive ref", repo="scribe",
|
||||
when_to_use="debounce a reactive ref", repo="grimoire",
|
||||
path="frontend/src/composables/x.ts", symbol="useDebouncedRef",
|
||||
)
|
||||
got = s.parse_snippet_fields(title, body, ["ts", "snippet"])
|
||||
@@ -52,7 +52,7 @@ def test_parse_round_trips_a_composed_snippet():
|
||||
assert got["signature"] == "useDebouncedRef(v, ms)"
|
||||
assert got["language"] == "ts"
|
||||
assert got["code"] == "const x = 1"
|
||||
assert got["repo"] == "scribe"
|
||||
assert got["repo"] == "grimoire"
|
||||
assert got["path"] == "frontend/src/composables/x.ts"
|
||||
assert got["symbol"] == "useDebouncedRef"
|
||||
|
||||
@@ -94,33 +94,33 @@ def test_compose_body_multi_location_renders_bullet_list():
|
||||
body = s.compose_body(
|
||||
code="x = 1",
|
||||
locations=[
|
||||
{"repo": "scribe", "path": "a.py", "symbol": "f"},
|
||||
{"repo": "grimoire", "path": "a.py", "symbol": "f"},
|
||||
{"repo": "web", "path": "b.ts", "symbol": "g"},
|
||||
],
|
||||
)
|
||||
assert "**Locations:**" in body
|
||||
assert "- `scribe` · `a.py` · `f`" in body
|
||||
assert "- `grimoire` · `a.py` · `f`" in body
|
||||
assert "- `web` · `b.ts` · `g`" in body
|
||||
assert "**Location:**" not in body.replace("**Locations:**", "")
|
||||
|
||||
|
||||
def test_compose_body_single_location_via_list_uses_singular_label():
|
||||
body = s.compose_body(
|
||||
code="x = 1", locations=[{"repo": "scribe", "path": "a.py", "symbol": "f"}],
|
||||
code="x = 1", locations=[{"repo": "grimoire", "path": "a.py", "symbol": "f"}],
|
||||
)
|
||||
assert "**Location:** `scribe` · `a.py` · `f`" in body
|
||||
assert "**Location:** `grimoire` · `a.py` · `f`" in body
|
||||
assert "**Locations:**" not in body
|
||||
|
||||
|
||||
def test_normalize_locations_drops_empty_and_dedups():
|
||||
got = s._normalize_locations([
|
||||
{"repo": "scribe", "path": "a.py", "symbol": "f"},
|
||||
{"repo": "grimoire", "path": "a.py", "symbol": "f"},
|
||||
{"repo": "", "path": "", "symbol": ""}, # dropped (empty)
|
||||
{"repo": "scribe", "path": "a.py", "symbol": "f"}, # dropped (dup)
|
||||
{"repo": "grimoire", "path": "a.py", "symbol": "f"}, # dropped (dup)
|
||||
{"repo": "web", "path": "", "symbol": ""},
|
||||
])
|
||||
assert got == [
|
||||
{"repo": "scribe", "path": "a.py", "symbol": "f"},
|
||||
{"repo": "grimoire", "path": "a.py", "symbol": "f"},
|
||||
{"repo": "web", "path": "", "symbol": ""},
|
||||
]
|
||||
|
||||
@@ -129,25 +129,25 @@ def test_parse_round_trips_multi_location():
|
||||
body = s.compose_body(
|
||||
code="const x = 1", language="ts",
|
||||
locations=[
|
||||
{"repo": "scribe", "path": "a.ts", "symbol": "f"},
|
||||
{"repo": "grimoire", "path": "a.ts", "symbol": "f"},
|
||||
{"repo": "web", "path": "b.ts", "symbol": "g"},
|
||||
],
|
||||
)
|
||||
got = s.parse_snippet_fields("n — u", body, ["ts", "snippet"])
|
||||
assert got["locations"] == [
|
||||
{"repo": "scribe", "path": "a.ts", "symbol": "f"},
|
||||
{"repo": "grimoire", "path": "a.ts", "symbol": "f"},
|
||||
{"repo": "web", "path": "b.ts", "symbol": "g"},
|
||||
]
|
||||
# repo/path/symbol mirror the first location for back-compat.
|
||||
assert (got["repo"], got["path"], got["symbol"]) == ("scribe", "a.ts", "f")
|
||||
assert (got["repo"], got["path"], got["symbol"]) == ("grimoire", "a.ts", "f")
|
||||
|
||||
|
||||
def test_parse_legacy_single_location_line_still_works():
|
||||
# A body written by the pre-multi-location serializer.
|
||||
body = "**Location:** `scribe` · `a.py` · `f`\n\n```py\nx = 1\n```\n"
|
||||
body = "**Location:** `grimoire` · `a.py` · `f`\n\n```py\nx = 1\n```\n"
|
||||
got = s.parse_snippet_fields("n — u", body, None)
|
||||
assert got["locations"] == [{"repo": "scribe", "path": "a.py", "symbol": "f"}]
|
||||
assert (got["repo"], got["path"], got["symbol"]) == ("scribe", "a.py", "f")
|
||||
assert got["locations"] == [{"repo": "grimoire", "path": "a.py", "symbol": "f"}]
|
||||
assert (got["repo"], got["path"], got["symbol"]) == ("grimoire", "a.py", "f")
|
||||
|
||||
|
||||
def test_merge_snippet_fields_unions_locations_and_tags():
|
||||
|
||||
Reference in New Issue
Block a user