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:
@@ -46,16 +46,16 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
HOOKS = Path(__file__).resolve().parents[1] / "plugin" / "hooks"
|
||||
SESSION_START = HOOKS / "scribe_session_context.sh"
|
||||
DEFS = HOOKS / "scribe_defs.sh"
|
||||
SESSION_START = HOOKS / "grimoire_session_context.sh"
|
||||
DEFS = HOOKS / "grimoire_defs.sh"
|
||||
|
||||
# Every ledger the hooks write today, and where. Named here so a failure READS
|
||||
# as "this one survived", but never used to build the hook's own delete list —
|
||||
# the convention tests below are what keep this roster honest as it grows.
|
||||
LEDGERS = {
|
||||
"scribe-priorart": (".ids", ".rules.ids", ".opened.ids", ".sync.ids",
|
||||
"grimoire-priorart": (".ids", ".rules.ids", ".opened.ids", ".sync.ids",
|
||||
".derive.ids", ".shapes.ids", ".reportcheck.ids"),
|
||||
"scribe-autoinject": (".ids",),
|
||||
"grimoire-autoinject": (".ids",),
|
||||
}
|
||||
|
||||
|
||||
@@ -66,15 +66,15 @@ def _swept_dirs() -> set[str]:
|
||||
agree with itself forever, which is precisely the failure that let the
|
||||
auto-inject ledger sit in a directory nothing cleared.
|
||||
"""
|
||||
line = re.search(r'SCRIBE_LEDGER_DIRS="([^"]*)"', DEFS.read_text())
|
||||
assert line, "SCRIBE_LEDGER_DIRS is gone; the clear has no roster"
|
||||
line = re.search(r'GRIMOIRE_LEDGER_DIRS="([^"]*)"', DEFS.read_text())
|
||||
assert line, "GRIMOIRE_LEDGER_DIRS is gone; the clear has no roster"
|
||||
return set(line.group(1).split())
|
||||
|
||||
|
||||
def _run_session_start(source: str, tmp: Path, extra: list[str] | None = None) -> Path:
|
||||
"""Run the SessionStart hook for real, with the ledger directories filled.
|
||||
|
||||
`extra` names further files to plant in `scribe-priorart` — used to put
|
||||
`extra` names further files to plant in `grimoire-priorart` — used to put
|
||||
an evidence twin in front of the sweep.
|
||||
"""
|
||||
for tool in ("bash",):
|
||||
@@ -87,9 +87,9 @@ def _run_session_start(source: str, tmp: Path, extra: list[str] | None = None) -
|
||||
for suffix in suffixes:
|
||||
(state / f"s1{suffix}").write_text("42\t1789600000\n")
|
||||
# Not a ledger: an outage marker that must outlive the clear.
|
||||
(tmp / "scribe-priorart" / "s1.unreached").write_text("1\n")
|
||||
(tmp / "grimoire-priorart" / "s1.unreached").write_text("1\n")
|
||||
for name in extra or ():
|
||||
(tmp / "scribe-priorart" / name).write_text("42\t1789600000\n")
|
||||
(tmp / "grimoire-priorart" / name).write_text("42\t1789600000\n")
|
||||
|
||||
env = {"PATH": os.environ["PATH"], "HOME": str(tmp), "TMPDIR": str(tmp)}
|
||||
out = subprocess.run(
|
||||
@@ -139,7 +139,7 @@ def test_the_outage_marker_is_not_swept_with_them(tmp_path):
|
||||
the second with the first.
|
||||
"""
|
||||
root = _run_session_start("compact", tmp_path)
|
||||
assert (root / "scribe-priorart" / "s1.unreached").exists()
|
||||
assert (root / "grimoire-priorart" / "s1.unreached").exists()
|
||||
|
||||
|
||||
# ── the two assumptions the sweep rests on ─────────────────────────────────
|
||||
@@ -162,9 +162,9 @@ def _session_paths(text: str):
|
||||
def test_every_directory_holding_a_ledger_is_one_the_clear_visits():
|
||||
"""The failure that shipped once already, in the same step that fixed it.
|
||||
|
||||
The first cut swept `scribe-priorart` alone. Every ledger NAMED in the
|
||||
hooks was there, so it read as complete — and `scribe_autoinject.sh` keeps
|
||||
its note ledger in `scribe-autoinject`, which meant the arm that fires most
|
||||
The first cut swept `grimoire-priorart` alone. Every ledger NAMED in the
|
||||
hooks was there, so it read as complete — and `grimoire_autoinject.sh` keeps
|
||||
its note ledger in `grimoire-autoinject`, which meant the arm that fires most
|
||||
was the only one still carrying the bug. Nothing said so: the clear ran,
|
||||
found nothing to remove, and exited 0.
|
||||
"""
|
||||
@@ -183,7 +183,7 @@ def test_every_directory_holding_a_ledger_is_one_the_clear_visits():
|
||||
assert not offenders, (
|
||||
"these ledgers live in directories the compaction clear never visits, "
|
||||
f"so they outlive the context they describe: {offenders}. Add the "
|
||||
"directory to SCRIBE_LEDGER_DIRS in scribe_defs.sh."
|
||||
"directory to GRIMOIRE_LEDGER_DIRS in grimoire_defs.sh."
|
||||
)
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ def test_the_clear_is_derived_and_not_a_list_of_names():
|
||||
"""
|
||||
sh = SESSION_START.read_text()
|
||||
block = sh.split('case "$source" in')[1].split("esac")[0]
|
||||
assert "scribe_clear_session_ledgers" in block
|
||||
assert "grimoire_clear_session_ledgers" in block
|
||||
for suffix in {s for suffixes in LEDGERS.values() for s in suffixes}:
|
||||
assert suffix not in block, (
|
||||
f"the clear names {suffix} again — a list, not a convention"
|
||||
@@ -233,7 +233,7 @@ def test_the_clear_is_derived_and_not_a_list_of_names():
|
||||
def test_the_evidence_twin_is_not_swept_with_them(tmp_path):
|
||||
"""The second thing that survives, and for the `.unreached` reason.
|
||||
|
||||
`scribe_rules_append` writes each ledger twice: `<sid>.<kind>.ids`, which
|
||||
`grimoire_rules_append` writes each ledger twice: `<sid>.<kind>.ids`, which
|
||||
says what this context HOLDS and must be forgotten here, and
|
||||
`<sid>.<kind>.keep.ids`, which says what HAPPENED and no compaction makes
|
||||
untrue. The session-end readout is built on the second, and it runs AT the
|
||||
@@ -249,7 +249,7 @@ def test_the_evidence_twin_is_not_swept_with_them(tmp_path):
|
||||
either mistake.
|
||||
"""
|
||||
root = _run_session_start("compact", tmp_path, extra=["s1.rules.keep.ids"])
|
||||
assert (root / "scribe-priorart" / "s1.rules.keep.ids").exists(), (
|
||||
assert (root / "grimoire-priorart" / "s1.rules.keep.ids").exists(), (
|
||||
"the evidence twin was swept with the exclusion ledgers — the readout "
|
||||
"at this seam now reports a session it cannot see"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user