fix(mem0-agent): accept --session-id after the subcommand
The generated manifest writes 'mem0-agent context --session-id $CLAUDE_SESSION_ID', but the flag was only on the top-level parser, so argparse rejected it and every SessionStart hook exited 2 -- the plugin would install and silently do nothing. Both orders now work, and a new test runs every command line in the manifest through the parser so a manifest/CLI mismatch fails the build. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a2ae930e9f
commit
a07756f6d7
@@ -374,7 +374,23 @@ def cmd_config(args) -> int:
|
|||||||
def main(argv: list[str] | None = None) -> int:
|
def main(argv: list[str] | None = None) -> int:
|
||||||
p = argparse.ArgumentParser(prog="mem0-agent", description="Coding-agent memory")
|
p = argparse.ArgumentParser(prog="mem0-agent", description="Coding-agent memory")
|
||||||
p.add_argument("--session-id")
|
p.add_argument("--session-id")
|
||||||
sub = p.add_subparsers(dest="cmd", required=True)
|
|
||||||
|
# Also accepted AFTER the subcommand, which is how hook manifests naturally write it
|
||||||
|
# ("mem0-agent context --session-id X"). SUPPRESS keeps the subparser from clobbering
|
||||||
|
# a value that was given before the subcommand.
|
||||||
|
common = argparse.ArgumentParser(add_help=False)
|
||||||
|
common.add_argument("--session-id", default=argparse.SUPPRESS,
|
||||||
|
help="session identifier supplied by the editor")
|
||||||
|
|
||||||
|
_add_parser = p.add_subparsers(dest="cmd", required=True).add_parser
|
||||||
|
|
||||||
|
def add(name: str, **kw):
|
||||||
|
return _add_parser(name, parents=[common], **kw)
|
||||||
|
|
||||||
|
class _Sub:
|
||||||
|
add_parser = staticmethod(add)
|
||||||
|
|
||||||
|
sub = _Sub()
|
||||||
|
|
||||||
sp = sub.add_parser("setup", help="apply project configuration")
|
sp = sub.add_parser("setup", help="apply project configuration")
|
||||||
sp.set_defaults(fn=cmd_setup)
|
sp.set_defaults(fn=cmd_setup)
|
||||||
|
|||||||
@@ -139,3 +139,46 @@ def test_hook_manifest_commands_all_exist():
|
|||||||
assert sub in known, f"manifest invokes unknown subcommand {sub!r}"
|
assert sub in known, f"manifest invokes unknown subcommand {sub!r}"
|
||||||
found += 1
|
found += 1
|
||||||
assert found >= 6
|
assert found >= 6
|
||||||
|
|
||||||
|
|
||||||
|
def test_session_id_accepted_on_either_side_of_the_subcommand(monkeypatch):
|
||||||
|
"""The hook manifest writes `mem0-agent context --session-id X`. argparse only
|
||||||
|
accepts a top-level flag BEFORE the subcommand, so without a per-subcommand copy
|
||||||
|
every SessionStart hook exits 2 and the plugin silently does nothing."""
|
||||||
|
seen = []
|
||||||
|
monkeypatch.setattr(cli, "cmd_context", lambda a: seen.append(getattr(a, "session_id", None)) or 0)
|
||||||
|
cli.main(["context", "--session-id", "AFTER"])
|
||||||
|
cli.main(["--session-id", "BEFORE", "context"])
|
||||||
|
assert seen == ["AFTER", "BEFORE"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_every_manifest_command_parses_verbatim(monkeypatch):
|
||||||
|
"""Every command line in the generated manifest must parse.
|
||||||
|
|
||||||
|
This is the test that would have caught SessionStart exiting 2 on install:
|
||||||
|
the manifest wrote the global --session-id flag after the subcommand.
|
||||||
|
"""
|
||||||
|
import pathlib
|
||||||
|
import shlex
|
||||||
|
|
||||||
|
manifest = pathlib.Path(__file__).resolve().parents[1] / "hooks/hooks.json"
|
||||||
|
data = json.loads(manifest.read_text())
|
||||||
|
|
||||||
|
ran = []
|
||||||
|
for name in ("cmd_context", "cmd_observe", "cmd_flush", "cmd_assist_error"):
|
||||||
|
monkeypatch.setattr(cli, name, lambda a, _n=name: ran.append(_n) or 0)
|
||||||
|
|
||||||
|
checked = 0
|
||||||
|
for entries in data["hooks"].values():
|
||||||
|
for entry in entries:
|
||||||
|
for hook in entry.get("hooks", []):
|
||||||
|
raw = hook["command"].strip("() ").split(">/dev/null")[0]
|
||||||
|
tokens = shlex.split(raw)
|
||||||
|
idx = tokens.index("mem0-agent")
|
||||||
|
argv = [t for t in tokens[idx + 1:] if t != "&"]
|
||||||
|
# shell vars like "$CLAUDE_SESSION_ID" become a literal in the test
|
||||||
|
argv = ["session-x" if t.startswith("$") else t for t in argv]
|
||||||
|
assert cli.main(argv) == 0, f"manifest command did not run: {raw}"
|
||||||
|
checked += 1
|
||||||
|
assert checked >= 6
|
||||||
|
assert ran, "the manifest should invoke real subcommands"
|
||||||
|
|||||||
Reference in New Issue
Block a user