diff --git a/repotests/contract_clarity_integration_test.go b/repotests/contract_clarity_integration_test.go index b55cd1c2..4748e812 100644 --- a/repotests/contract_clarity_integration_test.go +++ b/repotests/contract_clarity_integration_test.go @@ -218,7 +218,24 @@ func TestContractClarity_RuntimeMetadataAndDocsStayAligned(t *testing.T) { t.Fatal(err) } - mustContain(t, string(rootReadme), "Build one plugin and ship it to many AI agents was the legacy authoring goal.") + // The root README separates the installer and unreleased standard preview + // from preserved v1 capabilities. Keep legacy claims inside that boundary. + currentReadme, historicalReadme, found := cutHistoricalReadme(string(rootReadme)) + if !found { + t.Fatal("README missing historical authoring boundary") + } + mustContain(t, currentReadme, "## Use plugins") + mustContain(t, currentReadme, "## Build plugins — unreleased preview") + currentProse := strings.Join(strings.Fields(currentReadme), " ") + mustContain(t, currentProse, "root `plugin.json` with optional `skills/` and `mcp.json`") + mustContain(t, currentProse, "`agentplugins author` and `plugin-kit-ai` are the two prepared entrypoints to one standard authoring engine.") + mustContain(t, currentProse, "Public deployment remains gated on release acceptance") + mustContain(t, currentProse, "There is no implicit YAML fallback or second supported YAML engine.") + mustContain(t, historicalReadme, "[Historical plugin-kit-ai v1, baseline 1.2.4](website/source/en/legacy/v1/index.md)") + mustContain(t, historicalReadme, "Project migration is not available in v2 yet.") + mustContain(t, historicalReadme, "Maintain legacy projects using the v1 1.2.4 command set.") + mustContain(t, strings.Join(strings.Fields(historicalReadme), " "), "All commands, stability labels, and supported-output claims in this section describe the preserved v1 workflow, not the unreleased standard authoring MVP.") + mustContain(t, historicalReadme, "Build one plugin and ship it to many AI agents was the legacy authoring goal.") mustContain(t, string(sdkReadme), "`(*plugin-kit-ai.App).Gemini()`") mustContain(t, string(sdkReadme), "`github.com/777genius/plugin-kit-ai/sdk/gemini`") mustContain(t, string(sdkReadme), "## Gemini Example") @@ -264,32 +281,32 @@ func TestContractClarity_RuntimeMetadataAndDocsStayAligned(t *testing.T) { mustContain(t, string(architectureDoc), "`sdk/gemini`") mustContain(t, string(architectureDoc), "`sdk/internal/platforms/gemini`") mustContain(t, string(architectureDoc), "Gemini runtime hooks use `stdin_json`") - mustContain(t, string(rootReadme), "`plugin-kit-ai` keeps authored source under `plugin/`, generates the supported outputs you need, and helps you validate the repo before handoff.") - mustContain(t, string(rootReadme), "supported outputs for Claude, Codex, Gemini, Cursor, and OpenCode where the repo shape allows it") - mustContain(t, string(rootReadme), "The honest promise is `one repo / many supported outputs`, not fake parity everywhere") - mustContain(t, string(rootReadme), "overview: [plugin-kit-ai documentation](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/index.md)") - mustContain(t, string(rootReadme), "fastest start: [Quickstart](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/guide/quickstart.md)") - mustContain(t, string(rootReadme), "choose by job first: [Choose What You Are Building](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/guide/choose-what-you-are-building.md)") - mustContain(t, string(rootReadme), "one repo, many outputs: [What You Can Build](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/guide/what-you-can-build.md)") - mustContain(t, string(rootReadme), "honest caveat: [Support Boundary](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/reference/support-boundary.md)") - mustContain(t, string(rootReadme), "## Choose What You Are Building") - mustContain(t, string(rootReadme), "### Connect an online service") - mustContain(t, string(rootReadme), "### Connect a local tool") - mustContain(t, string(rootReadme), "### Build custom plugin logic") - mustContain(t, string(rootReadme), "## Quick start") - mustContain(t, string(rootReadme), "brew install 777genius/homebrew-plugin-kit-ai/plugin-kit-ai") - mustContain(t, string(rootReadme), "npm: `npm i -g plugin-kit-ai@1.2.4` or `npx plugin-kit-ai@1.2.4 ...`") - mustContain(t, string(rootReadme), "pipx (`public-beta`, only when that release is published to PyPI): `pipx install plugin-kit-ai==1.2.4`") - mustContain(t, string(rootReadme), "fallback installer: `curl -fsSL https://raw.githubusercontent.com/777genius/plugin-kit-ai/main/scripts/install.sh | sh`") - mustContain(t, string(rootReadme), "plugin-kit-ai init my-plugin --template online-service") - mustContain(t, string(rootReadme), "plugin-kit-ai init my-plugin --template local-tool") - mustContain(t, string(rootReadme), "plugin-kit-ai init my-plugin --template custom-logic") - mustContain(t, string(rootReadme), "plugin-kit-ai init my-plugin") - mustContain(t, string(rootReadme), "plugin-kit-ai generate .") - mustContain(t, string(rootReadme), "plugin-kit-ai validate . --platform codex-runtime --strict") - mustContain(t, string(rootReadme), "## Works Across Multiple Outputs") - mustContain(t, string(rootReadme), "## What To Do Next") - mustContain(t, string(rootReadme), "## Keep This Rule In Mind") + mustContain(t, historicalReadme, "`plugin-kit-ai` keeps authored source under `plugin/`, generates the supported outputs you need, and helps you validate the repo before handoff.") + mustContain(t, historicalReadme, "supported outputs for Claude, Codex, Gemini, Cursor, and OpenCode where the repo shape allows it") + mustContain(t, historicalReadme, "The honest promise is `one repo / many supported outputs`, not fake parity everywhere") + mustContain(t, historicalReadme, "overview: [plugin-kit-ai documentation](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/index.md)") + mustContain(t, historicalReadme, "fastest start: [Quickstart](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/guide/quickstart.md)") + mustContain(t, historicalReadme, "choose by job first: [Choose What You Are Building](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/guide/choose-what-you-are-building.md)") + mustContain(t, historicalReadme, "one repo, many outputs: [What You Can Build](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/guide/what-you-can-build.md)") + mustContain(t, historicalReadme, "honest caveat: [Support Boundary](https://github.com/777genius/universal-agent-plugins/blob/9beca10448ac50fbe526a52101d1433a12471980/website/source/en/reference/support-boundary.md)") + mustContain(t, historicalReadme, "## Choose What You Are Building") + mustContain(t, historicalReadme, "### Connect an online service") + mustContain(t, historicalReadme, "### Connect a local tool") + mustContain(t, historicalReadme, "### Build custom plugin logic") + mustContain(t, historicalReadme, "## Historical Quick Start") + mustContain(t, historicalReadme, "brew install 777genius/homebrew-plugin-kit-ai/plugin-kit-ai") + mustContain(t, historicalReadme, "npm: `npm i -g plugin-kit-ai@1.2.4` or `npx plugin-kit-ai@1.2.4 ...`") + mustContain(t, historicalReadme, "pipx (`public-beta`, only when that release is published to PyPI): `pipx install plugin-kit-ai==1.2.4`") + mustContain(t, historicalReadme, "fallback installer: `curl -fsSL https://raw.githubusercontent.com/777genius/plugin-kit-ai/main/scripts/install.sh | sh`") + mustContain(t, historicalReadme, "plugin-kit-ai init my-plugin --template online-service") + mustContain(t, historicalReadme, "plugin-kit-ai init my-plugin --template local-tool") + mustContain(t, historicalReadme, "plugin-kit-ai init my-plugin --template custom-logic") + mustContain(t, historicalReadme, "plugin-kit-ai init my-plugin") + mustContain(t, historicalReadme, "plugin-kit-ai generate .") + mustContain(t, historicalReadme, "plugin-kit-ai validate . --platform codex-runtime --strict") + mustContain(t, historicalReadme, "## Works Across Multiple Outputs") + mustContain(t, historicalReadme, "## What To Do Next") + mustContain(t, historicalReadme, "## Keep This Rule In Mind") mustContain(t, string(cliReadme), "How To Publish Plugins") mustContain(t, string(cliReadme), "https://777genius.github.io/plugin-kit-ai/docs/en/guide/how-to-publish-plugins.html") mustContain(t, string(publishGuideEn), "codex-marketplace") @@ -304,32 +321,32 @@ func TestContractClarity_RuntimeMetadataAndDocsStayAligned(t *testing.T) { mustContain(t, string(publishGuideRu), "Gemini в v1 использует plan-and-readiness publication, а не local apply.") mustContain(t, string(guideIndexEn), "/en/guide/how-to-publish-plugins") mustContain(t, string(guideIndexRu), "/ru/guide/how-to-publish-plugins") - mustContain(t, string(rootReadme), "## Deep Product Details") - mustContain(t, string(rootReadme), "## Go Deeper By Goal") - mustContain(t, string(rootReadme), "### Fast Local Plugin") - mustContain(t, string(rootReadme), "### Production-Ready Plugin Repo") - mustContain(t, string(rootReadme), "### Already Have Native Config") - mustContain(t, string(rootReadme), "[examples/starters/README.md](examples/starters/README.md)") - mustContain(t, string(rootReadme), "[examples/local/README.md](examples/local/README.md)") - mustContain(t, string(rootReadme), "[docs/CHOOSING_HELPER_DELIVERY_MODE.md](docs/CHOOSING_HELPER_DELIVERY_MODE.md)") - mustContain(t, string(rootReadme), "the stable local Python and Node subset on `codex-runtime` and `claude`") - mustContain(t, string(rootReadme), "`doctor`, `bootstrap`, `validate --strict`, `export`, and bundle handoff for that stable local subset") - mustContain(t, string(rootReadme), "`generate`, `import`, and `normalize` are still `public-beta`") - mustContain(t, string(rootReadme), "[docs/generated/target_support_matrix.md](docs/generated/target_support_matrix.md)") - mustContain(t, string(rootReadme), "[docs/generated/support_matrix.md](docs/generated/support_matrix.md)") - mustContain(t, string(rootReadme), "[docs/SUPPORT.md](docs/SUPPORT.md)") - mustContain(t, string(rootReadme), "## SDK And CLI") - mustContain(t, string(rootReadme), "Go SDK packages:") - mustContain(t, string(rootReadme), "`github.com/777genius/plugin-kit-ai/sdk/claude`") - mustContain(t, string(rootReadme), "`github.com/777genius/plugin-kit-ai/sdk/codex`") - mustContain(t, string(rootReadme), "`github.com/777genius/plugin-kit-ai/sdk/gemini`") - mustContain(t, string(rootReadme), "./bin/plugin-kit-ai doctor ./my-plugin") - mustContain(t, string(rootReadme), "./bin/plugin-kit-ai bootstrap ./my-plugin") - mustContain(t, string(rootReadme), "./bin/plugin-kit-ai import ./native-plugin --from codex-runtime") - mustContain(t, string(rootReadme), "./bin/plugin-kit-ai capabilities --format json") - mustContain(t, string(rootReadme), "`plugin-kit-ai validate --format json` now emits the versioned `plugin-kit-ai/validate-report` contract") - mustContain(t, string(rootReadme), "[docs/CODEX_TARGET_BOUNDARY.md](docs/CODEX_TARGET_BOUNDARY.md)") - mustContain(t, string(rootReadme), "[docs/VALIDATE_JSON_CONTRACT.md](docs/VALIDATE_JSON_CONTRACT.md)") + mustContain(t, historicalReadme, "## Deep Product Details") + mustContain(t, historicalReadme, "## Go Deeper By Goal") + mustContain(t, historicalReadme, "### Fast Local Plugin") + mustContain(t, historicalReadme, "### Production-Ready Plugin Repo") + mustContain(t, historicalReadme, "### Already Have Native Config") + mustContain(t, historicalReadme, "[examples/starters/README.md](examples/starters/README.md)") + mustContain(t, historicalReadme, "[examples/local/README.md](examples/local/README.md)") + mustContain(t, historicalReadme, "[docs/CHOOSING_HELPER_DELIVERY_MODE.md](docs/CHOOSING_HELPER_DELIVERY_MODE.md)") + mustContain(t, historicalReadme, "the stable local Python and Node subset on `codex-runtime` and `claude`") + mustContain(t, historicalReadme, "`doctor`, `bootstrap`, `validate --strict`, `export`, and bundle handoff for that stable local subset") + mustContain(t, historicalReadme, "`generate`, `import`, and `normalize` are still `public-beta`") + mustContain(t, historicalReadme, "[docs/generated/target_support_matrix.md](docs/generated/target_support_matrix.md)") + mustContain(t, historicalReadme, "[docs/generated/support_matrix.md](docs/generated/support_matrix.md)") + mustContain(t, historicalReadme, "[docs/SUPPORT.md](docs/SUPPORT.md)") + mustContain(t, historicalReadme, "## SDK And CLI") + mustContain(t, historicalReadme, "Go SDK packages:") + mustContain(t, historicalReadme, "`github.com/777genius/plugin-kit-ai/sdk/claude`") + mustContain(t, historicalReadme, "`github.com/777genius/plugin-kit-ai/sdk/codex`") + mustContain(t, historicalReadme, "`github.com/777genius/plugin-kit-ai/sdk/gemini`") + mustContain(t, historicalReadme, "./bin/plugin-kit-ai doctor ./my-plugin") + mustContain(t, historicalReadme, "./bin/plugin-kit-ai bootstrap ./my-plugin") + mustContain(t, historicalReadme, "./bin/plugin-kit-ai import ./native-plugin --from codex-runtime") + mustContain(t, historicalReadme, "./bin/plugin-kit-ai capabilities --format json") + mustContain(t, historicalReadme, "`plugin-kit-ai validate --format json` now emits the versioned `plugin-kit-ai/validate-report` contract") + mustContain(t, historicalReadme, "[docs/CODEX_TARGET_BOUNDARY.md](docs/CODEX_TARGET_BOUNDARY.md)") + mustContain(t, historicalReadme, "[docs/VALIDATE_JSON_CONTRACT.md](docs/VALIDATE_JSON_CONTRACT.md)") mustContain(t, string(cliReadme), "## Fast Local Plugin") mustContain(t, string(cliReadme), "## Production-Ready Plugin Repo") mustContain(t, string(cliReadme), "## Already Have Native Config") diff --git a/repotests/readme_boundary_test.go b/repotests/readme_boundary_test.go new file mode 100644 index 00000000..ce61377f --- /dev/null +++ b/repotests/readme_boundary_test.go @@ -0,0 +1,46 @@ +package pluginkitairepo_test + +import ( + "strings" + "testing" +) + +// Normalize only Windows line endings; retain the exact historical heading and +// terminating newline so current and preserved-v1 assertions stay separated. +func cutHistoricalReadme(readme string) (current, historical string, found bool) { + return strings.Cut(strings.ReplaceAll(readme, "\r\n", "\n"), "### Historical authoring and development\n") +} + +func TestHistoricalReadmeBoundaryLineEndings(t *testing.T) { + const heading = "### Historical authoring and development" + for _, newline := range []struct{ name, value string }{{"LF", "\n"}, {"CRLF", "\r\n"}} { + for _, tc := range []struct { + name, boundary string + found bool + }{ + {"exact", heading + newline.value, true}, + {"missing", "", false}, + {"wrong_title", "### Historical authoring" + newline.value, false}, + {"wrong_level", "## Historical authoring and development" + newline.value, false}, + {"trailing_space", heading + " " + newline.value, false}, + {"suffix", heading + " extra" + newline.value, false}, + {"no_newline", heading, false}, + {"bare_CR", heading + "\r", false}, + } { + t.Run(newline.name+"/"+tc.name, func(t *testing.T) { + input := "current" + newline.value + tc.boundary + "historical" + newline.value + current, historical, found := cutHistoricalReadme(input) + if found != tc.found { + t.Fatalf("boundary found = %v, want %v", found, tc.found) + } + if found { + if current != "current\n" || historical != "historical\n" { + t.Fatalf("incorrect sections: current=%q historical=%q", current, historical) + } + } else if current != strings.ReplaceAll(input, "\r\n", "\n") || historical != "" { + t.Fatalf("missing boundary changed sections: current=%q historical=%q", current, historical) + } + }) + } + } +} diff --git a/repotests/starter_template_sync_integration_test.go b/repotests/starter_template_sync_integration_test.go index f9f594aa..c9470566 100644 --- a/repotests/starter_template_sync_integration_test.go +++ b/repotests/starter_template_sync_integration_test.go @@ -49,7 +49,16 @@ func TestStarterTemplateSyncContractFilesStayAligned(t *testing.T) { mustContain(t, workflow, "run: ./scripts/update-starter-template.sh") mustContain(t, workflow, "default: \"all\"") mustContain(t, workflow, "- all-runtime-package") - mustContain(t, rootReadme, "Codex and Claude starters across Go, Python, and") + // Preserved v1 starters remain discoverable without being advertised as + // root plugin.json templates for the unreleased standard authoring MVP. + _, historicalReadme, found := cutHistoricalReadme(rootReadme) + if !found { + t.Fatal("README missing historical authoring boundary") + } + mustContain(t, strings.Join(strings.Fields(historicalReadme), " "), "The repository preserves Codex and Claude starters across Go, Python, and Node/TypeScript.") + mustContain(t, historicalReadme, "[starters](examples/starters/README.md)") + mustContain(t, startersReadme, "Historical plugin-kit-ai v1 managed examples; baseline 1.2.4.") + mustContain(t, startersReadme, "These are not root `plugin.json` starters for the standard MVP.") mustContain(t, cliReadme, "Official starter templates:") mustContain(t, startersReadme, "These starter repos are the fastest way to get one working plugin repo that can later expand to more supported outputs.") mustContain(t, startersReadme, "Use this template")