diff --git a/.claude/skills/a0-bootstrap-plugin b/.claude/skills/a0-bootstrap-plugin new file mode 120000 index 0000000..4bb69d4 --- /dev/null +++ b/.claude/skills/a0-bootstrap-plugin @@ -0,0 +1 @@ +../../tests/_testkit/skills/a0-bootstrap-plugin \ No newline at end of file diff --git a/.claude/skills/a0-plugin-architecture b/.claude/skills/a0-plugin-architecture new file mode 120000 index 0000000..9680c68 --- /dev/null +++ b/.claude/skills/a0-plugin-architecture @@ -0,0 +1 @@ +../../tests/_testkit/skills/a0-plugin-architecture \ No newline at end of file diff --git a/.claude/skills/a0-plugin-e2e-bdd b/.claude/skills/a0-plugin-e2e-bdd new file mode 120000 index 0000000..415284f --- /dev/null +++ b/.claude/skills/a0-plugin-e2e-bdd @@ -0,0 +1 @@ +../../tests/_testkit/skills/a0-plugin-e2e-bdd \ No newline at end of file diff --git a/.claude/skills/a0-plugin-testkit b/.claude/skills/a0-plugin-testkit new file mode 120000 index 0000000..31ffd6f --- /dev/null +++ b/.claude/skills/a0-plugin-testkit @@ -0,0 +1 @@ +../../tests/_testkit/skills/a0-plugin-testkit \ No newline at end of file diff --git a/.claude/skills/author-plugin-from-template b/.claude/skills/author-plugin-from-template new file mode 120000 index 0000000..61d2104 --- /dev/null +++ b/.claude/skills/author-plugin-from-template @@ -0,0 +1 @@ +../../tests/_testkit/skills/author-plugin-from-template \ No newline at end of file diff --git a/.claude/skills/plugin-manifest-contract b/.claude/skills/plugin-manifest-contract new file mode 120000 index 0000000..72f0fdc --- /dev/null +++ b/.claude/skills/plugin-manifest-contract @@ -0,0 +1 @@ +../../tests/_testkit/skills/plugin-manifest-contract \ No newline at end of file diff --git a/.claude/skills/rotate-plugin-credentials b/.claude/skills/rotate-plugin-credentials new file mode 120000 index 0000000..fd1f837 --- /dev/null +++ b/.claude/skills/rotate-plugin-credentials @@ -0,0 +1 @@ +../../tests/_testkit/skills/rotate-plugin-credentials \ No newline at end of file diff --git a/.claude/skills/troubleshoot-plugin-deployment b/.claude/skills/troubleshoot-plugin-deployment new file mode 120000 index 0000000..56cea9d --- /dev/null +++ b/.claude/skills/troubleshoot-plugin-deployment @@ -0,0 +1 @@ +../../tests/_testkit/skills/troubleshoot-plugin-deployment \ No newline at end of file diff --git a/.devkit.yml b/.devkit.yml new file mode 100644 index 0000000..a10356f --- /dev/null +++ b/.devkit.yml @@ -0,0 +1,5 @@ +plugin_dir: usr/plugins/share_chat +display_name: Share Chat +# If the plugin has agent-driven behaviour needing an e2e seam, enable it here: +# e2e_pod_env: +# A0_SHARE_CHAT_TEST_PROBE: "1" diff --git a/.gemini/config.yaml b/.gemini/config.yaml new file mode 100644 index 0000000..4d3b209 --- /dev/null +++ b/.gemini/config.yaml @@ -0,0 +1,20 @@ +# Gemini Code Assist configuration for the A0 plugin devkit (and, via the +# template, every plugin repo). https://developers.google.com/gemini-code-assist/docs/customize-repo-review +have_fun: false + +code_review: + disable: false + comment_severity_threshold: LOW + max_review_comments: -1 + pull_request_opened: + help: false + summary: true + code_review: true + include_drafts: true # the merge-guard drafts red PRs — still review them + +ignore_patterns: + - "tests/_testkit/**" # the vendored devkit (reviewed in its own repo) + - "**/node_modules/**" + - "**/.features-gen/**" # generated by bddgen + - "**/test-results/**" # playwright artifacts + - "dist/**" diff --git a/.gemini/styleguide.md b/.gemini/styleguide.md new file mode 100644 index 0000000..5f88c29 --- /dev/null +++ b/.gemini/styleguide.md @@ -0,0 +1,62 @@ +# A0 plugin — Code Review Style Guide + +Conventions and quality gates every PR to an Agent Zero plugin (or this devkit) must comply with. +Gemini Code Assist applies these during PR review — a **second, plain-language line of defense** in +front of the machine-checked CI gates (devkit `docs/BDD-GATES.md`, SPEC §5.14 / DEC-059–066). CI is the +hard gate; this review catches the same violations earlier and explains them. **Flag, don't rubber-stamp.** + +The threat model is laziness — human *and* AI. If a diff looks like it's routing *around* a gate +(loosening a check, adding a bare skip, wrapping an assertion in try/catch), say so explicitly. + +## Behaviour-first BDD — the `.feature` files (`tests/e2e/features/*.feature`) + +- **Feature-purity (flag as HIGH):** a `Given/When/Then` step must read as plain behaviour. Flag any + selector (`.kebab-class`, `#id`), DOM/Playwright API (`querySelector`, `evaluate`, `dispatchEvent`), + store/internal name (`showModal`, `Alpine`, `getContext`, `callJsonApi`, `chat_create`), or framework + directive (`x-…`) appearing in a scenario. The "how" belongs in the step layer, never the feature. +- Scenarios assert **observable behaviour in domain language**, one behaviour per scenario, proper + Given/When/Then order. Behaviour is provoked by **real actions**, never by setting an internal flag. + +## Honesty (flag as HIGH — these are the lies that pass CI) + +- **No bare `@skip`.** Every skipped scenario must carry a `#` comment with the reason + a tracked + ref/issue. Flag any `@skip` without one. +- **No swallowed failures** in step files: an empty `catch {}`, or a `.catch(() => …)` / `try/catch` + that recovers instead of failing or re-asserting. Reserve try/catch for genuinely un-enableable env, + and even then assert *something*. +- **The four `docs/spec/` docs must exist** for a BDD plugin: `behaviour-spec.md`, + `implementation-plan.md`, `e2e.feature.md`, `e2e-steps-spec.md`. Flag a PR that adds + `tests/e2e/features/` without them. +- **Traceability:** every `BEH-n` in `behaviour-spec.md` must be covered in `e2e.feature.md` or listed + as a tracked skip. Flag orphans. +- **No fake green:** a scenario must genuinely assert. A suite that would pass with the plugin + uninstalled is fake-green (CI's seam-off red-proof catches it; flag designs that look hollow). + +## The deterministic seam (`api/_probe.py`) + +- Must be **env-gated** (`A0__TEST_PROBE`), off in production, and call the plugin's **real** + code path — never reimplement behaviour in the probe. Flag a seam that's ungated or that fakes logic. +- Seam calls belong in the **step layer**, never in a `.feature`. + +## Fork-robustness (the tests run on the deployed fork, not stock A0) + +- Flag a step that creates a **synthetic** chat context (`newContext()` with no backing chat) for the + plugin's polling path — the fork's chat-restore deselects it. Use a **real** chat (`chat_create`). +- Flag clicking a control without handling the no-LLM `composer-banner` overlay (hide it, then real + click; `dispatchEvent` does not trigger the framework handler). + +## Plugin-specific vs common + +- Plugins ship **only their own behaviour** features/steps. Flag any copy of the common lifecycle + (install/uninstall/boot/probe-enable) into a plugin — it ships from the devkit via `tests/_testkit`. + +## Manifest & shipping + +- `plugin.yaml` ↔ `.meta.yaml` version match; declared `env[]` actually read in source; no UI + prompts for secrets (operator provides via chart). To ship verified, the gate meta needs + `source_repo` + `source_commit` with a green `plugin-e2e`. + +## General + +- No plaintext secrets. Idempotent lifecycle. Commit messages explain the *why*. Don't weaken a gate to + make a red build green — fix the underlying issue (see `docs/BDD-GATES.md` for each gate's fix). diff --git a/.github/workflows/plugin-e2e.yml b/.github/workflows/plugin-e2e.yml index 0f93f20..32f76c2 100644 --- a/.github/workflows/plugin-e2e.yml +++ b/.github/workflows/plugin-e2e.yml @@ -8,7 +8,9 @@ # (.devkit.yml `plugin_dir` → else canonical usr/plugins/), so this # template is identical across all repos. # -# Needs the shared sync-App secrets to clone the private devkit submodule. +# Needs the shared sync-App secrets to clone the private devkit submodule, and +# (DEC-055) GHCR_PULL_TOKEN to pull the private fork image. `secrets: inherit` +# forwards all repo secrets, so new shared secrets need no caller change. name: plugin-e2e on: @@ -16,6 +18,10 @@ on: branches: ["main", "master"] workflow_dispatch: +permissions: + contents: read + pull-requests: write # merge-guard drafts a PR whose plugin-e2e is red + jobs: e2e: uses: agent-zero-plugins/agent-zero-plugin-development-testkit/.github/workflows/plugin-e2e.yml@main diff --git a/tests/_testkit b/tests/_testkit index e38f967..9823617 160000 --- a/tests/_testkit +++ b/tests/_testkit @@ -1 +1 @@ -Subproject commit e38f967147ed6f21381621f537d53a814aa94f17 +Subproject commit 9823617d5dd8fd44808ded4f4f8295f2aa4700e5