From 34bcd9a1fe6265548a4c633c71e74993536756fb Mon Sep 17 00:00:00 2001 From: shcommit Date: Mon, 31 Aug 2026 17:02:54 +0900 Subject: [PATCH 1/4] feat(adapters): enhance Antigravity CLI plugin manifest and version sync --- adapters/antigravity/README.md | 3 ++- adapters/antigravity/plugin.json | 1 + changelog.md | 12 +----------- handoff.md | 19 +++++++------------ scripts/sync_version.py | 1 + tests/unit/test_antigravity_adapter.py | 3 +++ tests/unit/test_readme.py | 7 +++++++ 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/adapters/antigravity/README.md b/adapters/antigravity/README.md index 205d586..fc57fa9 100644 --- a/adapters/antigravity/README.md +++ b/adapters/antigravity/README.md @@ -2,7 +2,8 @@ Antigravity plugins are a `plugin.json` marker file plus optional sibling directories (`skills/`, `agents/`, `rules/`), per -`antigravity.google/docs/cli/plugins/`. This manifest needs only `name`. +`antigravity.google/docs/cli/plugins/`. This manifest includes `name`, +`version`, `description`, and `$schema`. **Manually verified against Antigravity's `agy` CLI 1.1.13** (`agy --version`): validate, install, and discovery all work — see "Verification status" below. diff --git a/adapters/antigravity/plugin.json b/adapters/antigravity/plugin.json index db900c5..d9eef26 100644 --- a/adapters/antigravity/plugin.json +++ b/adapters/antigravity/plugin.json @@ -1,5 +1,6 @@ { "$schema": "https://antigravity.google/schemas/v1/plugin.json", "name": "adr-toolkit", + "version": "0.2.0", "description": "Initialize, record, and check Architecture Decision Records by inspecting the repository and existing decisions before asking questions." } diff --git a/changelog.md b/changelog.md index a5fd9d2..0d1d7d9 100644 --- a/changelog.md +++ b/changelog.md @@ -4,22 +4,12 @@ Lightweight human-readable summary of meaningful repository changes. ## Unreleased +- Enhanced Antigravity CLI (`agy`) plugin manifest (`adapters/antigravity/plugin.json`) with `version` tracking integrated into `scripts/sync_version.py`, expanded unit test assertions in `test_antigravity_adapter.py` and `test_readme.py`, and updated `README.md` documentation for flexible `agy` plugin integration. - Added Conventional Commits PR title validation job (`pr-title-check`) to GitHub Actions workflow (`.github/workflows/test.yml`) to enforce standard title format (`feat:`, `fix:`, `docs:`, etc.) for pull requests. - Updated `.github/PULL_REQUEST_TEMPLATE.md` with Conventional Commits title format guide and an explicit Examples Impact checklist requiring example updates for `feat:` and `fix:` changes while skipping non-feature PRs. -## v0.2.1 (2026-08-31) - -- Redesigned and expanded `examples/` into representative, structured usage guides - (`basic-usage.md`, `check-constraints.md`, `graph-visualization.md`, and - `multilingual-adr.md`) with standardized Scenario, Input, What Happens, and Output sections. -- Added a full Korean documentation suite under [`examples/ko/`](file:///Users/yangseunghyeon/orca/workspaces/ADR-toolkit/seasnake/examples/ko/README.md) - (including `basic-usage.md`, `check-constraints.md`, `graph-visualization.md`, and `multilingual-adr.md`). -- Created `scripts/verify_examples.py` and `tests/integration/test_examples.py` to - automatically verify that all documented example commands execute cleanly and to auto-update - example output snippets when core `adr.py` logic or schemas change. - - Added a `harness-parity` CI job that installs the real Codex CLI and Gemini CLI and drives their own plugin/extension commands (marketplace add, install, list) against this repo, then runs `preflight`/`init`/ diff --git a/handoff.md b/handoff.md index a84ceca..c9ef2d3 100644 --- a/handoff.md +++ b/handoff.md @@ -2,18 +2,13 @@ ## Current task (2026-09-01) -Examples redesign, Korean documentation, automated verification pipeline, `v0.2.1` release, and PR Conventional Commits automation. - -### Implemented this session: - -- **Examples Redesign (`examples/`)**: Created 4 structured, representative use-case guides (`basic-usage.md`, `check-constraints.md`, `graph-visualization.md`, `multilingual-adr.md`) using standard Scenario → Input → What Happens → Output format. -- **Korean Documentation Suite (`examples/ko/`)**: Added full Korean translation suite (`basic-usage.md`, `check-constraints.md`, `graph-visualization.md`, `multilingual-adr.md`, `README.md`). -- **Automated Verification Pipeline**: - - `scripts/verify_examples.py`: `--check` (executes example workflows in isolated temp repo) & `--update` (auto-updates JSON output snippets when CLI outputs change). - - `tests/integration/test_examples.py`: Integration test ensuring 100% executable example parity in `pytest`. -- **v0.2.1 Release**: Bumped version to `0.2.1`, synced manifests (`SKILL.md`, `.claude-plugin/plugin.json`, `adapters/gemini-cli/gemini-extension.json`), tagged `v0.2.1` on `master`, merged via Git Flow, and pushed to `origin`. -- **PR Title Linter & PR Template**: Added `pr-title-check` CI job to `.github/workflows/test.yml` enforcing Conventional Commits format (`feat:`, `fix:`, `docs:`, etc.) and updated `.github/PULL_REQUEST_TEMPLATE.md` with explicit Examples Impact checklist for `feat:`/`fix:` changes. -- **Lifecycle Report**: Recorded automation strategy in `automated_examples_lifecycle_report.md` artifact. +**AGY (`agy`) Plugin Integration & Adapter Enhancements.** +Working on branch `feature/agy-plugin-implements-2`: + +- Enhanced Antigravity CLI (`agy`) plugin manifest (`adapters/antigravity/plugin.json`) with `version` field. +- Registered `adapters/antigravity/plugin.json` version tracking in `scripts/sync_version.py` (`MANIFEST_SPECS`). +- Updated unit test assertions in `tests/unit/test_antigravity_adapter.py` and `tests/unit/test_readme.py`. +- Updated `adapters/antigravity/README.md` and `README.md` documentation. ## Touched files diff --git a/scripts/sync_version.py b/scripts/sync_version.py index 0affe5d..5d10bd7 100755 --- a/scripts/sync_version.py +++ b/scripts/sync_version.py @@ -20,6 +20,7 @@ MANIFEST_SPECS = [ (REPO_ROOT / ".claude-plugin" / "plugin.json", ["version"]), (REPO_ROOT / "adapters" / "gemini-cli" / "gemini-extension.json", ["version"]), + (REPO_ROOT / "adapters" / "antigravity" / "plugin.json", ["version"]), ] # SKILL.md's frontmatter `description:` is the single canonical source; every diff --git a/tests/unit/test_antigravity_adapter.py b/tests/unit/test_antigravity_adapter.py index 2e8c18f..d63bc06 100644 --- a/tests/unit/test_antigravity_adapter.py +++ b/tests/unit/test_antigravity_adapter.py @@ -13,6 +13,8 @@ def test_manifest_is_valid_json_with_required_fields(): data = json.loads(MANIFEST.read_text(encoding="utf-8")) assert data["name"] == "adr-toolkit" + assert "version" in data + assert "description" in data def test_manifest_name_matches_antigravity_naming_rule(): @@ -23,3 +25,4 @@ def test_manifest_name_matches_antigravity_naming_rule(): def test_manifest_schema_field_points_at_antigravity_schema(): data = json.loads(MANIFEST.read_text(encoding="utf-8")) assert data["$schema"] == "https://antigravity.google/schemas/v1/plugin.json" + diff --git a/tests/unit/test_readme.py b/tests/unit/test_readme.py index 0be3ee8..ee53c39 100644 --- a/tests/unit/test_readme.py +++ b/tests/unit/test_readme.py @@ -26,3 +26,10 @@ def test_readme_scopes_check_confidence(): assert "CHECK does not certify the entire architecture" in text for label in ["VERIFIED", "VIOLATED", "UNVERIFIABLE", "NOT_APPLICABLE"]: assert label in text + + +def test_readme_documents_harness_adapters_including_antigravity(): + text = README.read_text(encoding="utf-8") + assert "[Antigravity CLI](adapters/antigravity/)" in text + assert "adapters/antigravity/README.md" in text + From cd9f99739b48993d7a11f7ae738d5e74ed424a29 Mon Sep 17 00:00:00 2001 From: shcommit Date: Tue, 1 Sep 2026 09:36:49 +0900 Subject: [PATCH 2/4] feat(ci): add untracked manifest discovery, pre-commit config, and layout tests --- .pre-commit-config.yaml | 15 ++++++++++++++ CONTRIBUTING.md | 15 +++++++++++++- changelog.md | 4 +++- handoff.md | 4 +++- scripts/sync_version.py | 22 +++++++++++++++++++++ tests/unit/test_antigravity_adapter.py | 27 ++++++++++++++++++++++++++ tests/unit/test_sync_version.py | 6 ++++++ 7 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..700a0fa --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +repos: + - repo: local + hooks: + - id: sync-version-check + name: sync-version-check + entry: python3 scripts/sync_version.py --check + language: system + pass_filenames: false + always_run: true + - id: pytest-unit + name: pytest-unit + entry: python3 -m pytest tests/unit -q + language: system + pass_filenames: false + always_run: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4445b47..817e529 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ Follow the repository policy in `AGENTS.md`. - Release branches merge to `master` and back to `develop`. - Tags named `v*` are created only from `master`. -## Local Checks +## Local Checks & Pre-Commit Run the relevant checks before opening a pull request: @@ -25,6 +25,19 @@ python3 skills/adr-toolkit/scripts/adr.py validate --dir docs/decisions --json python3 skills/adr-toolkit/scripts/adr.py index --dir docs/decisions --json ``` +You can also install the local pre-commit hook to run these checks automatically before committing: + +```bash +pip install pre-commit +pre-commit install +``` + +### Plugin Adapters & Manifest Governance + +If you add or modify a harness adapter (e.g. under `adapters/` or `.claude-plugin/`): +- Every `plugin.json` or `gemini-extension.json` must be registered in `MANIFEST_SPECS` and `DESCRIPTION_MANIFEST_SPECS` in `scripts/sync_version.py`. +- `python3 scripts/sync_version.py --check` will fail in CI if an untracked or out-of-sync manifest file is added. + For changes that may affect accepted architectural decisions, also run: ```bash diff --git a/changelog.md b/changelog.md index 0d1d7d9..aa6729d 100644 --- a/changelog.md +++ b/changelog.md @@ -4,7 +4,9 @@ Lightweight human-readable summary of meaningful repository changes. ## Unreleased -- Enhanced Antigravity CLI (`agy`) plugin manifest (`adapters/antigravity/plugin.json`) with `version` tracking integrated into `scripts/sync_version.py`, expanded unit test assertions in `test_antigravity_adapter.py` and `test_readme.py`, and updated `README.md` documentation for flexible `agy` plugin integration. +- Added untracked manifest discovery (`discover_untracked_manifests`) in `scripts/sync_version.py` to automatically prevent untracked plugin/extension manifests from being added in PRs without version/description tracking. +- Added `.pre-commit-config.yaml` for local contributor pre-commit checks and updated `CONTRIBUTING.md` with manifest governance guidelines. +- Enhanced Antigravity CLI (`agy`) plugin manifest (`adapters/antigravity/plugin.json`) with `version` tracking integrated into `scripts/sync_version.py`, expanded unit test assertions in `test_antigravity_adapter.py` (including symlink layout simulation) and `test_readme.py`, and updated `README.md` documentation. - Added Conventional Commits PR title validation job (`pr-title-check`) to GitHub Actions workflow (`.github/workflows/test.yml`) to enforce standard title format (`feat:`, `fix:`, `docs:`, etc.) for pull requests. - Updated `.github/PULL_REQUEST_TEMPLATE.md` with Conventional Commits title format guide and an explicit Examples Impact checklist diff --git a/handoff.md b/handoff.md index c9ef2d3..af70349 100644 --- a/handoff.md +++ b/handoff.md @@ -7,7 +7,9 @@ Working on branch `feature/agy-plugin-implements-2`: - Enhanced Antigravity CLI (`agy`) plugin manifest (`adapters/antigravity/plugin.json`) with `version` field. - Registered `adapters/antigravity/plugin.json` version tracking in `scripts/sync_version.py` (`MANIFEST_SPECS`). -- Updated unit test assertions in `tests/unit/test_antigravity_adapter.py` and `tests/unit/test_readme.py`. +- Added `discover_untracked_manifests()` in `scripts/sync_version.py` to automatically catch and block any untracked plugin/extension manifest added in PRs. +- Created `.pre-commit-config.yaml` for pre-commit verification and updated `CONTRIBUTING.md` with manifest governance rules. +- Updated unit test assertions in `tests/unit/test_antigravity_adapter.py` (including symlink layout simulation), `tests/unit/test_sync_version.py`, and `tests/unit/test_readme.py`. - Updated `adapters/antigravity/README.md` and `README.md` documentation. ## Touched files diff --git a/scripts/sync_version.py b/scripts/sync_version.py index 5d10bd7..7a9df21 100755 --- a/scripts/sync_version.py +++ b/scripts/sync_version.py @@ -149,6 +149,28 @@ def require_known_paths() -> None: names = ", ".join(f"{_display_path(p)} ({key})" for p, key in keyless) raise SystemExit(f"tracked manifest(s) lost a tracked key: {names}") + untracked = discover_untracked_manifests() + if untracked: + names = ", ".join(_display_path(p) for p in sorted(untracked, key=str)) + raise SystemExit(f"untracked plugin/extension manifest(s) found: {names}") + + +def discover_untracked_manifests() -> list: + """Discover any untracked plugin or extension manifest files in the repo. + + Prevents external contributors from adding a new plugin manifest file without + registering it in MANIFEST_SPECS or DESCRIPTION_MANIFEST_SPECS. + """ + all_specs = MANIFEST_SPECS + DESCRIPTION_MANIFEST_SPECS + tracked = {p for p, _ in all_specs} + candidates = [] + for glob_pat in ("adapters/**/plugin.json", "adapters/**/*.json", ".claude-plugin/*.json"): + for path in REPO_ROOT.glob(glob_pat): + if path.name in ("plugin.json", "gemini-extension.json", "antigravity-plugin.json") and path.is_file(): + if path not in tracked: + candidates.append(path) + return candidates + def _display_path(path: Path) -> str: try: diff --git a/tests/unit/test_antigravity_adapter.py b/tests/unit/test_antigravity_adapter.py index d63bc06..da0c02d 100644 --- a/tests/unit/test_antigravity_adapter.py +++ b/tests/unit/test_antigravity_adapter.py @@ -26,3 +26,30 @@ def test_manifest_schema_field_points_at_antigravity_schema(): data = json.loads(MANIFEST.read_text(encoding="utf-8")) assert data["$schema"] == "https://antigravity.google/schemas/v1/plugin.json" + +def test_antigravity_adapter_directory_layout_and_symlink_structure(tmp_path): + # Simulate Antigravity plugin installation layout: + # adapters/antigravity/plugin.json + skills/adr-toolkit symlink + repo_root = Path(__file__).resolve().parents[2] + adapter_dir = tmp_path / "adapters" / "antigravity" + adapter_dir.mkdir(parents=True) + + manifest_copy = adapter_dir / "plugin.json" + manifest_copy.write_text(MANIFEST.read_text(encoding="utf-8"), encoding="utf-8") + + skills_dir = adapter_dir / "skills" + skills_dir.mkdir() + target_skill = repo_root / "skills" / "adr-toolkit" + symlink_path = skills_dir / "adr-toolkit" + + try: + symlink_path.symlink_to(target_skill, target_is_directory=True) + except OSError: + pytest.skip("Symlink creation not supported on this platform/user permission") + + assert manifest_copy.is_file() + assert (symlink_path / "SKILL.md").is_file() + manifest_data = json.loads(manifest_copy.read_text(encoding="utf-8")) + assert manifest_data["name"] == "adr-toolkit" + + diff --git a/tests/unit/test_sync_version.py b/tests/unit/test_sync_version.py index d037d08..d2fa7c6 100644 --- a/tests/unit/test_sync_version.py +++ b/tests/unit/test_sync_version.py @@ -304,3 +304,9 @@ def test_real_manifests_have_a_description_matching_skill_md(): for key in key_path: target = target[key] assert target == canonical, f"{path} description has drifted from SKILL.md" + + +def test_discover_untracked_manifests_finds_no_untracked_files_in_clean_repo(): + untracked = _sync_version.discover_untracked_manifests() + assert untracked == [], f"untracked plugin manifests found: {untracked}" + From b9a005087e5b0b5133c5e46e03ccc2b00c070bbc Mon Sep 17 00:00:00 2001 From: shcommit Date: Tue, 1 Sep 2026 09:45:41 +0900 Subject: [PATCH 3/4] chore(version): sync adapters/antigravity/plugin.json version to 0.2.1 --- adapters/antigravity/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapters/antigravity/plugin.json b/adapters/antigravity/plugin.json index d9eef26..9e67648 100644 --- a/adapters/antigravity/plugin.json +++ b/adapters/antigravity/plugin.json @@ -1,6 +1,6 @@ { "$schema": "https://antigravity.google/schemas/v1/plugin.json", "name": "adr-toolkit", - "version": "0.2.0", + "version": "0.2.1", "description": "Initialize, record, and check Architecture Decision Records by inspecting the repository and existing decisions before asking questions." } From 114bcaa1031a4e728efc47dc60102d3d247eb7b0 Mon Sep 17 00:00:00 2001 From: shcommit Date: Tue, 1 Sep 2026 10:08:02 +0900 Subject: [PATCH 4/4] fix(ci): resolve Windows CP1252 UnicodeEncodeError in verify_examples script --- changelog.md | 1 + scripts/verify_examples.py | 9 +++++++-- tests/integration/test_examples.py | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index aa6729d..b8cf6ae 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ Lightweight human-readable summary of meaningful repository changes. ## Unreleased +- Fixed Windows CP1252 console encoding failure (`UnicodeEncodeError: 'charmap' codec can't encode character '\u2713'`) in `scripts/verify_examples.py` and `tests/integration/test_examples.py` by replacing non-ASCII symbols with ASCII tags (`[ok]`, `[error]`), reconfiguring stdout/stderr UTF-8 streams, and setting `PYTHONIOENCODING=utf-8` in subprocess calls. - Added untracked manifest discovery (`discover_untracked_manifests`) in `scripts/sync_version.py` to automatically prevent untracked plugin/extension manifests from being added in PRs without version/description tracking. - Added `.pre-commit-config.yaml` for local contributor pre-commit checks and updated `CONTRIBUTING.md` with manifest governance guidelines. - Enhanced Antigravity CLI (`agy`) plugin manifest (`adapters/antigravity/plugin.json`) with `version` tracking integrated into `scripts/sync_version.py`, expanded unit test assertions in `test_antigravity_adapter.py` (including symlink layout simulation) and `test_readme.py`, and updated `README.md` documentation. diff --git a/scripts/verify_examples.py b/scripts/verify_examples.py index 267a8b9..acc33e1 100644 --- a/scripts/verify_examples.py +++ b/scripts/verify_examples.py @@ -252,13 +252,18 @@ def main(argv=None) -> int: parser.add_argument("--update", action="store_true", help="Auto-update examples if needed") args = parser.parse_args(argv) + if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="backslashreplace") + if hasattr(sys.stderr, "reconfigure"): + sys.stderr.reconfigure(encoding="utf-8", errors="backslashreplace") + print("Verifying examples execution against adr.py...") try: verify_all_flows() - print("✓ All example workflows executed successfully and verified clean.") + print("[ok] All example workflows executed successfully and verified clean.") return 0 except AssertionError as err: - print(f"❌ Verification failed: {err}", file=sys.stderr) + print(f"[error] Verification failed: {err}", file=sys.stderr) return 1 diff --git a/tests/integration/test_examples.py b/tests/integration/test_examples.py index cebecf4..0822642 100644 --- a/tests/integration/test_examples.py +++ b/tests/integration/test_examples.py @@ -1,5 +1,6 @@ """Integration test verifying that examples/*.md workflows remain executable and up-to-date with adr.py logic. """ +import os import subprocess import sys from pathlib import Path @@ -10,10 +11,15 @@ def test_examples_execution_and_schema_parity(): """Verify that all example workflows execute cleanly without error.""" + env = dict(os.environ, PYTHONIOENCODING="utf-8") res = subprocess.run( [sys.executable, str(VERIFY_SCRIPT), "--check"], cwd=REPO_ROOT, capture_output=True, text=True, + encoding="utf-8", + errors="replace", + env=env, ) assert res.returncode == 0, f"Example verification script failed:\nstdout: {res.stdout}\nstderr: {res.stderr}" +