mempalace/tests
undeadindustries bf156fb010 feat: add Antigravity IDE support (plugin, MCP, skill, hooks, docs, tests)
Adds first-class integration with Google's Antigravity IDE
(https://antigravity.google/) as a third sibling to the existing
Claude Code and Codex hook integrations. Strictly additive — no
existing files in main are restructured.

What ships
----------

* `.antigravity-plugin/` — verified-minimal plugin package:
  * `plugin.json` with `{"name": "mempalace"}` (no fabricated fields)
  * `mcp_config.json` registering the `mempalace-mcp` stdio server
  * `hooks.json.tmpl` templated with `__PLUGIN_DIR__` substitution
  * `skills/mempalace/SKILL.md` (real file — no symlinks)
* `hooks/antigravity/`:
  * `lib/common.sh` — shared bash 3.2.57-compatible helpers with
    sentinel-guarded camelCase JSON parser, antigravity_*-namespaced
    state files, every existing kill switch, `MEMPAL_SAVE_INTERVAL >= 1`
    floor (no /0), and fail-open emitters
  * `mempal_save_hook_antigravity.sh` — Stop event handler:
    increments per-conversation counter, defers when fullyIdle=False
    or terminationReason=error, validates transcriptPath against
    `..` traversal, spawns `mempalace mine --mode convos` in a
    detached subprocess with a per-conversation pending marker,
    ALWAYS emits `{}` (never `{"decision":"continue"}` — that would
    force an infinite agent loop)
  * `mempal_wake_hook_antigravity.sh` — PreInvocation handler gated
    to invocationNum==1 with an atomic mkdir loop guard, runs
    `mempalace wake-up` with a 500ms hard timeout, emits verbatim
    output as `{"injectSteps":[{"ephemeralMessage":"..."}]}` or
    `{}` on any failure
  * `install.sh` — idempotent installer with cmp-gated copies,
    `__PLUGIN_DIR__` substitution, relative path absolutization,
    `--dry-run`, and basename-guarded `--uninstall` (refuses to
    wipe a directory whose basename isn't `mempalace`)
  * `INVESTIGATION.md` — verbatim quotes + URLs + dates from the
    five official Antigravity doc pages, recording every surface
    shipped and every surface deliberately omitted
    (PreCompact equivalent, slash-commands, rules/, plugin
    permissions field — the latter is third-party fabrication)
  * `STDIN_SHAPE.md` — exact stdin/stdout contract per event with
    worked examples
  * `README.md` — local hook docs + troubleshooting
* `examples/antigravity/{hooks.json,mcp_config.json,README.md}` —
  standalone configs for users who don't want the full installer
* `website/guide/antigravity.md` + sidebar entry — VitePress guide
* Updates to `README.md`, `CHANGELOG.md` (Unreleased), `hooks/README.md`

Tests (56 new, all passing)
---------------------------

* `tests/test_antigravity_plugin_manifest.py` (11 tests) — schema
  contract on the in-repo `.antigravity-plugin/` directory, including
  guards against re-introducing the fabricated `permissions` field
  and against any symlink leak.
* `tests/test_antigravity_hooks_shell.py` (31 tests) — invokes the
  bash hooks via subprocess with synthetic camelCase stdin, asserts
  `{}` on every failure path, kill-switch coverage (env vars +
  config.json + palace nuke), divide-by-zero floor, transcript
  traversal rejection, namespacing, wing inference, and the hard
  refusal to ever emit `decision=continue` from the Stop hook.
* `tests/test_antigravity_hooks_install.py` (14 tests) — `--dry-run`
  side-effect-free, real install layout, executable bits preserved,
  byte-identical idempotent re-runs (md5 + filecmp), basename-match
  uninstall safety, refusal when plugin.json is missing or names a
  different plugin, relative path absolutization. Skipped on Windows.

Verification
------------

* `uv run pytest tests/ --ignore=tests/benchmarks -v` → 2314 passed,
  3 skipped (Windows), 1 unrelated warning
* `uv run ruff check .` → all checks passed
* `uv run ruff format --check .` → 139 files already formatted
* `bash -n` clean on common.sh, both hook scripts, install.sh
* Local install at `~/.gemini/config/plugins/mempalace/` verified end-
  to-end: layout correct, paths absolutized in hooks.json, both hooks
  fire with realistic camelCase JSON in <1s, wing inference picks
  `wing_mempalace` from workspacePaths[0], state files all
  `antigravity_*`-namespaced, second `install.sh` run produces
  byte-identical output (md5 snapshots match), uninstall removes
  only the mempalace plugin and leaves all 6 sibling Google plugins
  untouched.

Constraints honoured
--------------------

bash 3.2.57 (no mapfile / readarray / declare -A / `${var^^}`),
verbatim guarantee on all wake injections, hooks <500ms / startup
injection <100ms target (kill-switch path returns in <1.5s in CI),
zero new runtime dependencies, no telemetry, no external API,
strictly additive (existing Claude/Codex hooks unchanged).

Refs: hooks/antigravity/INVESTIGATION.md for the full audit.
2026-05-27 19:19:17 +10:00
..
benchmarks test(mcp): migrate _kg monkeypatches to _get_kg (#1136) 2026-05-03 17:43:00 +05:00
conftest.py refactor(mcp): move lone-surrogate strip into shared sanitizers (#1235) 2026-05-24 12:12:52 -03:00
test_antigravity_hooks_install.py feat: add Antigravity IDE support (plugin, MCP, skill, hooks, docs, tests) 2026-05-27 19:19:17 +10:00
test_antigravity_hooks_shell.py feat: add Antigravity IDE support (plugin, MCP, skill, hooks, docs, tests) 2026-05-27 19:19:17 +10:00
test_antigravity_plugin_manifest.py feat: add Antigravity IDE support (plugin, MCP, skill, hooks, docs, tests) 2026-05-27 19:19:17 +10:00
test_backends.py Merge origin/develop into feat/benchmark-multilingual 2026-05-18 17:58:05 -03:00
test_chroma_collection_lock.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_claude_plugin_hook_config.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_claude_plugin_hook_wrappers.py test: normalize wrapper script path for bash on Windows 2026-04-19 10:34:11 +02:00
test_clean_lone_surrogates.py refactor(mcp): move lone-surrogate strip into shared sanitizers (#1235) 2026-05-24 12:12:52 -03:00
test_cli.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_closet_llm.py style: ruff format tests/test_hooks_cli.py with CI-pinned ruff 0.4.x 2026-05-23 12:05:34 -04:00
test_closets.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_collection_metric_invariant.py fix(test): use tmp_path for full-stack invariant test (Windows CI) 2026-04-25 00:39:37 -03:00
test_config.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_config_extra.py test(config): make palace_path tests portable across POSIX and Windows 2026-04-24 11:13:51 +02:00
test_convo_miner.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_convo_miner_size_cap.py Raise convo_miner MAX_FILE_SIZE cap 10 MB → 500 MB 2026-04-18 12:52:01 -03:00
test_convo_miner_unit.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_convo_scanner.py fix(llm): tighter refinement — word boundaries, JSON extraction, authoritative sources 2026-04-24 01:30:40 -03:00
test_corpus_origin.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_corpus_origin_integration.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_dedup.py refactor: route all chromadb access through ChromaBackend 2026-04-14 00:31:16 -03:00
test_dialect.py fix: align cmd_compress dict keys with compression_stats() return values (#569) 2026-04-11 16:16:31 -07:00
test_dynamics.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_embedding.py test: isolate embedding module state with monkeypatch 2026-04-24 23:11:29 +00:00
test_embeddinggemma.py Merge origin/develop into feat/benchmark-multilingual 2026-05-18 17:58:05 -03:00
test_empty_chromadb_results.py fix(searcher): guard against empty ChromaDB query results (#195) (#865) 2026-04-15 00:26:38 -07:00
test_entity_detector.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_entity_registry.py fix(entity_registry): clean up .tmp sidecar on write or rename failure (#1373) 2026-05-10 12:56:50 +02:00
test_exporter.py fix(exporter): refuse symlinks at file targets and skip tests on Windows 2026-05-07 12:51:47 -03:00
test_fact_checker.py fix(cli, fact-checker): per-stream stdio errors policy on Windows 2026-05-03 21:37:12 +05:00
test_format_miner.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_general_extractor.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_hall_detection.py fix: README audit — 42 TDD tests + hall detection + 7 claim fixes (#835) 2026-04-13 17:11:11 -07:00
test_hallways.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_hnsw_capacity.py fix: use configured collection in recovery paths 2026-05-07 09:10:00 -03:00
test_hnsw_payload_health.py style: ruff format test_hnsw_payload_health.py (#1461 follow-up) 2026-05-14 19:17:26 -03:00
test_hooks_bash_compat.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_hooks_cli.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_hooks_shell.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_hybrid_candidate_union.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_hybrid_search.py merge: pr/closet-llm-generic + harden LLM regen path for production 2026-04-13 18:40:36 -03:00
test_i18n.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_i18n_lang_case.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_init.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_init_gitignore_protection.py fix(init): auto-add per-project files to .gitignore in git repos (#185) (#866) 2026-04-15 00:26:41 -07:00
test_instructions_cli.py fix: add explicit UTF-8 encoding to read_text() calls (#776) 2026-04-16 16:00:29 +05:00
test_kg_thread_safety.py fix: add missing self._lock to KnowledgeGraph.close() 2026-04-14 13:09:10 -07:00
test_knowledge_graph.py fix(kg): close sqlite connections during cleanup 2026-05-08 14:44:04 +00:00
test_knowledge_graph_extra.py test: bring coverage to 85%, set threshold to 85, reset version to 3.0.11 2026-04-08 21:38:12 +03:00
test_known_entities_registry.py feat(graph): cross-wing tunnels by shared topics (#1180) 2026-04-24 23:06:26 -03:00
test_layers.py fix: guard None metadata/doc in tool_check_duplicate and Layer1/Layer2 2026-04-19 11:13:50 +03:00
test_line_numbers.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_llm_client.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_llm_refine.py feat(graph): cross-wing tunnels by shared topics (#1180) 2026-04-24 23:06:26 -03:00
test_mcp_server.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_mcp_stdio_protection.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_migrate.py fix(migrate): close SQLite connection and clean temp palace on exception 2026-05-10 13:06:40 +02:00
test_miner.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_miner_fts5_validation.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_miner_jsonl_visibility.py Harden sweeper for production: verbatim tool blocks, full session_id, logged failures 2026-04-18 13:14:32 -03:00
test_normalize.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_onboarding.py feat(onboarding): multilingual embedder by default for new installs 2026-05-14 06:40:27 -03:00
test_palace.py fix(palace): stratify state messages for empty/missing palace (#1498) 2026-05-17 03:57:19 +05:00
test_palace_graph.py fix(palace_graph): skip None metadata in build_graph 2026-04-25 11:06:32 -07:00
test_palace_graph_tunnels.py Merge origin/develop into feat/benchmark-multilingual 2026-05-24 13:18:08 -03:00
test_palace_locks.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_project_scanner.py feat(graph): cross-wing tunnels by shared topics (#1180) 2026-04-24 23:06:26 -03:00
test_query_sanitizer.py fix: make quote trimming explicit 2026-04-12 22:19:58 -03:00
test_readme_claims.py style: ruff format tests/test_hooks_cli.py with CI-pinned ruff 0.4.x 2026-05-23 12:05:34 -04:00
test_repair.py fix: VACUUM + FTS5 rebuild after repair to reclaim SQLite space 2026-05-18 16:10:16 -03:00
test_room_detector_local.py fix: skip unreachable reparse points in detect_rooms_from_folders (#558) 2026-04-11 16:16:06 -07:00
test_save_hook_mines.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_save_hook_verbose.py feat: add MEMPAL_VERBOSE toggle — developers see diaries in chat (#871) 2026-04-14 10:55:56 -07:00
test_searcher.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_sources.py chore(tests): wrap sqlite3 connections in contextlib.closing 2026-05-09 20:25:47 -03:00
test_spellcheck.py style: format test files with ruff 2026-04-08 21:08:49 +03:00
test_spellcheck_extra.py test: bring coverage to 85%, set threshold to 85, reset version to 3.0.11 2026-04-08 21:38:12 +03:00
test_split_mega_files.py test: expand coverage to 70%, fix mcp_server CI crash (threshold 60%) 2026-04-08 21:07:03 +03:00
test_sweeper.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_sync.py style: reformat tree with ruff 0.15.9 2026-05-17 23:20:01 -03:00
test_version_consistency.py fix: unify package and MCP version reporting 2026-04-07 08:53:25 +01:00