diff --git a/docs/plans/plugin-marketplace-attribution/plan.md b/docs/plans/plugin-marketplace-attribution/plan.md new file mode 100644 index 0000000000..96d86b800a --- /dev/null +++ b/docs/plans/plugin-marketplace-attribution/plan.md @@ -0,0 +1,115 @@ +--- +spec: docs/specs/plugins/marketplace.md +created: 2026-08-22 +status: building +--- + +# Implementation Plan: Correct plugin marketplace attribution + +## Overview + +Correct the release manifests that feed the marketplace's visible author and +repository metadata. The Kandev host registry pointer remains unchanged: the +Bitbucket entry is already a first-party `kdlbs` repository, and the YouTrack +entry must continue to point to the external contributor's repository. The +changes land in the two plugin repositories, then the existing release +workflows and registry builder verify that the catalog displays the corrected +identities. + +## Repository boundaries + +- `kdlbs/kandev-plugin-bitbucket` owns the first-party Bitbucket manifest. +- `ahmedbally/kandev-plugin-youtrack` owns the community YouTrack manifest. +- `kdlbs/kandev` owns only the marketplace contract and verification. No new + author override is added to `plugin-registry/plugins.yaml`; release manifest + metadata remains authoritative. + +## Plugin repository changes + +### First-party Bitbucket attribution + +In `kdlbs/kandev-plugin-bitbucket/manifest.yaml`, change the author from +`kdlbs` to `kandev` and preserve the existing repository URL. Produce the next +release through that repository's existing release workflow so the latest +release tag and tarball contain the corrected manifest. + +### Community YouTrack attribution + +In `ahmedbally/kandev-plugin-youtrack/manifest.yaml`, change the author to the +contributor handle `ahmedbally` and change `repo_url` to +`https://github.com/ahmedbally/kandev-plugin-youtrack`. Produce a new release +through the repository's existing release workflow so the registry's latest +release lookup sees the corrected manifest. + +## Tests + +- **What:** The registry builder preserves a release manifest's declared author + and emits the repository selected by the registry pointer. + **File:** `plugin-registry/build-index.test.mjs` (existing coverage) and the + generated `plugin-registry/index.json` after release publication. + **How:** Run the focused Node test suite, then rebuild the live catalog and + inspect the Bitbucket and YouTrack records for `author` and `repo_url`. +- **What:** The first-party plugin still packages successfully after its + manifest metadata change. + **File:** `kdlbs/kandev-plugin-bitbucket` repository tests and package gate. + **How:** Run `make test` and `make package-host verify-package-host`. +- **What:** The community plugin still builds and passes its existing checks + after its manifest metadata change. + **File:** `ahmedbally/kandev-plugin-youtrack` repository tests. + **How:** Run `go test ./...`, `go vet ./...`, and the release workflow's + package step when publishing the new release. +- **What:** The unchanged marketplace card renders the corrected author and + repository link values. + **File:** `apps/web/components/settings/plugins/marketplace-entry-row.test.tsx`. + **How:** Run the existing focused component test after the catalog records + are rebuilt; no component or layout change is expected. + +## E2E and mobile parity + +The repair changes release metadata only. It does not change the marketplace +card's markup, interaction, navigation, responsive composition, or touch +targets. The existing component test plus the post-release catalog inspection +are the appropriate evidence; a new desktop or mobile Playwright flow would +duplicate unchanged UI behavior. + +## Verification Results + +- 2026-08-22: Bitbucket branch `fix/marketplace-author` changes only + `manifest.yaml`, declaring `author: "kandev"` while preserving the official + repository URL. `make test`, `make package-host verify-package-host`, + `make fmt`, and `make vet` pass. The package gate produced + `kandev-plugin-bitbucket-0.2.1.tar.gz` with the corrected manifest. +- 2026-08-22: YouTrack fork branch + `fix/correct-marketplace-attribution` changes `manifest.yaml` to version + `0.1.1`, author `ahmedbally`, and the external repository URL. README build + references were updated for the new release version. `go test ./...` + passes all 25 tests and `go vet ./...` passes. The temporary local SDK + replacement and generated `go.sum` used for verification were removed. +- 2026-08-22: Kandev verification passes with 8 registry-builder tests and 3 + marketplace-entry-row tests. `pnpm install --frozen-lockfile` also passes. +- Live catalog records remain pending the two release publications. The + existing registry pointer file was not changed; once the releases are + published, rebuild the catalog and verify both author and repository fields. + +## Implementation Waves And Parallel Candidates + +Wave 1 contains two disjoint plugin-repository changes. They are marked as +parallel-safe for planning purposes, but the primary session executes them +sequentially unless the user explicitly authorizes delegation. + +- [ ] [task-01-bitbucket-attribution](task-01-bitbucket-attribution.md) - + in progress; local fix complete, release publication follows merge +- [ ] [task-02-youtrack-attribution](task-02-youtrack-attribution.md) - + in progress; local fix complete, upstream maintainer release publication + follows merge + +Wave 2 verifies the published releases and regenerated catalog: + +- [ ] [task-03-registry-verification](task-03-registry-verification.md) - + pending; blocked until the two corrected releases are published + +## Open Questions + +- The YouTrack repository is controlled by an external contributor. The source + change can be prepared in an attached branch, but merging it and publishing + its release remain subject to that repository's maintainer access. diff --git a/docs/plans/plugin-marketplace-attribution/task-01-bitbucket-attribution.md b/docs/plans/plugin-marketplace-attribution/task-01-bitbucket-attribution.md new file mode 100644 index 0000000000..a20e5c62d4 --- /dev/null +++ b/docs/plans/plugin-marketplace-attribution/task-01-bitbucket-attribution.md @@ -0,0 +1,77 @@ +--- +id: "01-bitbucket-attribution" +title: "Correct Bitbucket attribution" +status: in_progress +wave: 1 +depends_on: [] +plan: "plan.md" +spec: "../../specs/plugins/marketplace.md" +--- + +# Task 01: Correct Bitbucket attribution + +## Acceptance + +- `kdlbs/kandev-plugin-bitbucket/manifest.yaml` declares `author: "kandev"`. +- The manifest continues to point at + `https://github.com/kdlbs/kandev-plugin-bitbucket` and keeps its plugin id, + capabilities, and package contract unchanged. +- A newly published release contains the corrected manifest, so the official + catalog can display `by kandev`. + +## Verification + +From the attached Bitbucket plugin worktree: + +```bash +make test +make package-host verify-package-host +``` + +Then run the repository's existing release workflow to publish the next +release. Do not hand-edit generated changelog or release metadata when the +workflow owns those files. + +## Files likely touched + +- `kdlbs/kandev-plugin-bitbucket/manifest.yaml` +- Release metadata generated by the plugin repository's existing release + workflow, if that workflow is run as part of implementation. + +## Dependencies + +None. + +## Parallelism + +parallel-safe with task 02 because it uses a separate repository and no shared +registry files. The primary session remains sequential by default. + +## Inputs + +- `docs/specs/plugins/marketplace.md`, catalog attribution scenarios. +- `docs/plans/plugin-marketplace-attribution/plan.md`, repository boundary and + release requirements. +- The plugin repository's `manifest.yaml`, `Makefile`, and release workflow. + +## Output contract + +Report the branch/repository, exact files changed, release tag or publication +blocker, commands and results, package path, and task/plan status update. + +## Results + +2026-08-22: Updated `manifest.yaml` on branch `fix/marketplace-author` in +`kdlbs/kandev-plugin-bitbucket` to declare `author: "kandev"`. The existing +plugin id, capabilities, version, and repository URL are unchanged. + +Verification passed: + +- `make test` +- `make package-host verify-package-host` +- `make fmt` +- `make vet` + +The package gate produced `kandev-plugin-bitbucket-0.2.1.tar.gz` and confirmed +the packaged manifest. The next release still must be published through the +repository workflow after the PR is merged. diff --git a/docs/plans/plugin-marketplace-attribution/task-02-youtrack-attribution.md b/docs/plans/plugin-marketplace-attribution/task-02-youtrack-attribution.md new file mode 100644 index 0000000000..2388803897 --- /dev/null +++ b/docs/plans/plugin-marketplace-attribution/task-02-youtrack-attribution.md @@ -0,0 +1,80 @@ +--- +id: "02-youtrack-attribution" +title: "Correct YouTrack attribution" +status: in_progress +wave: 1 +depends_on: [] +plan: "plan.md" +spec: "../../specs/plugins/marketplace.md" +--- + +# Task 02: Correct YouTrack attribution + +## Acceptance + +- `ahmedbally/kandev-plugin-youtrack/manifest.yaml` declares + `author: "ahmedbally"`. +- The manifest declares + `repo_url: "https://github.com/ahmedbally/kandev-plugin-youtrack"` and keeps + the plugin id, capabilities, and package contract unchanged. +- A newly published release contains the corrected manifest, so the official + catalog displays the external contributor and links to the external repo. + +## Verification + +From the attached YouTrack plugin worktree: + +```bash +go test ./... +go vet ./... +``` + +Then run the repository's existing release workflow to publish a new release +containing the manifest. If the external repository cannot be attached or its +maintainer cannot publish the release, report that as the task blocker instead +of changing the Kandev registry to misrepresent ownership. + +## Files likely touched + +- `ahmedbally/kandev-plugin-youtrack/manifest.yaml` +- Release metadata generated by the plugin repository's existing release + workflow, if that workflow is run as part of implementation. + +## Dependencies + +None. + +## Parallelism + +parallel-safe with task 01 because it uses a separate repository and no shared +registry files. The primary session remains sequential by default. + +## Inputs + +- `docs/specs/plugins/marketplace.md`, catalog attribution scenarios. +- `docs/plans/plugin-marketplace-attribution/plan.md`, external ownership and + release requirements. +- The plugin repository's `manifest.yaml`, `Makefile`, and release workflow. + +## Output contract + +Report the branch/repository, exact files changed, release tag or maintainer +access blocker, commands and results, package path, and task/plan status update. + +## Results + +2026-08-22: Updated the external contributor fork branch +`fix/correct-marketplace-attribution` in `ahmedbally/kandev-plugin-youtrack`. +The manifest now uses version `0.1.1`, author `ahmedbally`, and +`https://github.com/ahmedbally/kandev-plugin-youtrack`. README build references +were updated for the new release version; plugin behavior and capabilities are +unchanged. + +Verification passed: + +- `go test ./...` (25 tests) +- `go vet ./...` + +The fork cannot publish the upstream release directly. The upstream maintainer +must merge the PR and run the existing release workflow before the official +catalog can observe the corrected metadata. diff --git a/docs/plans/plugin-marketplace-attribution/task-03-registry-verification.md b/docs/plans/plugin-marketplace-attribution/task-03-registry-verification.md new file mode 100644 index 0000000000..17190220d8 --- /dev/null +++ b/docs/plans/plugin-marketplace-attribution/task-03-registry-verification.md @@ -0,0 +1,76 @@ +--- +id: "03-registry-verification" +title: "Verify regenerated catalog attribution" +status: pending +wave: 2 +depends_on: ["01-bitbucket-attribution", "02-youtrack-attribution"] +plan: "plan.md" +spec: "../../specs/plugins/marketplace.md" +--- + +# Task 03: Verify regenerated catalog attribution + +## Acceptance + +- The generated official catalog record for Bitbucket has + `author: "kandev"` and `repo_url: "https://github.com/kdlbs/kandev-plugin-bitbucket"`. +- The generated official catalog record for YouTrack has + `author: "ahmedbally"` and + `repo_url: "https://github.com/ahmedbally/kandev-plugin-youtrack"`. +- `plugin-registry/plugins.yaml` remains a pointer list with no author override + or ownership rewrite. + +## Verification + +From the Kandev repository: + +```bash +node --test plugin-registry/build-index.test.mjs +cd apps && pnpm install --frozen-lockfile +pnpm --filter @kandev/web test -- --run components/settings/plugins/marketplace-entry-row.test.tsx +``` + +After both releases are published, run `node plugin-registry/build-index.mjs` +with the normal GitHub API credentials and inspect the two records in the +generated `plugin-registry/index.json`. Preserve or remove the generated file +according to the existing registry workflow and `.gitignore` policy. Finish +with `git diff --check`. + +## Files likely touched + +- No Kandev production source files are expected. +- `plugin-registry/index.json` is a generated verification artifact only. + +## Dependencies + +Tasks 01 and 02, including their release artifacts. + +## Parallelism + +sequential. The task depends on both external release outputs and reads the +shared official catalog. + +## Inputs + +- `docs/specs/plugins/marketplace.md`, author and repository scenarios. +- `plugin-registry/build-index.mjs`, release-manifest enrichment behavior. +- `apps/web/components/settings/plugins/marketplace-entry-row.tsx`, unchanged + presentation consumer. + +## Output contract + +Report the exact catalog records, commands and results, generated-artifact +handling, `git diff --check` result, and synchronized task/plan statuses. + +## Results + +2026-08-22: Local verification passed with: + +- `node --test plugin-registry/build-index.test.mjs` (8 tests) +- `cd apps && pnpm install --frozen-lockfile` +- `pnpm --filter @kandev/web test -- --run components/settings/plugins/marketplace-entry-row.test.tsx` (3 tests) +- `git diff --check` + +The live catalog rebuild is blocked until the Bitbucket and YouTrack release +publications exist. `plugin-registry/plugins.yaml` remains unchanged and +contains no author override. diff --git a/docs/specs/plugins/marketplace.md b/docs/specs/plugins/marketplace.md index f2996a77b0..a392e3dff1 100644 --- a/docs/specs/plugins/marketplace.md +++ b/docs/specs/plugins/marketplace.md @@ -36,6 +36,18 @@ while keeping install-by-URL and sideloading as escape hatches. or actively-maintained plugins are not buried under older high-star incumbents. - Each catalog entry shows: display name, description, author, categories, the source repository link, the latest published version, and its star count. +- Release authors and registry reviewers SHALL apply the attribution convention: + first-party `kdlbs/kandev-plugin-*` releases declare `author: "kandev"`, + community releases declare the contributor's stable identity, and a plugin is + not labeled `kandev` only because a maintainer curated it into the official + source. This is a release and curation check, not an index-builder ownership + validation rule. The builder preserves a declared manifest author and falls + back to the repository owner for legacy releases without one. +- The catalog source repository link SHALL identify the repository named by the + registry entry. The index builder derives this value from the registry pointer. + A release manifest's `repo_url`, when present, SHOULD identify the same + repository so installed and marketplace views do not disagree; release and + registry review is responsible for flagging mismatches. - Installing from the catalog SHALL be **one click**: it resolves to the plugin's latest release tarball URL and runs the existing verified install pipeline (`POST /api/plugins/install`). No new install mechanism is introduced. @@ -119,7 +131,7 @@ This is the fetch contract between a marketplace source and kandev. Additional "id": "agent-stats", "name": "Agent Stats", // from manifest display_name "description": "Per-session token & LOC dashboard", - "author": "kandev", + "author": "kandev", // from the release manifest "categories": ["analytics"], "icon_url": "https://raw.githubusercontent.com/kdlbs/kandev-plugin-agent-stats/v1.4.0/icon.svg", "repo_url": "https://github.com/kdlbs/kandev-plugin-agent-stats", @@ -300,6 +312,14 @@ response but stays `enabled`. - **GIVEN** a PR that adds an entry to `plugins.yaml` whose `id` does not match the target repo's latest-release manifest `id`, **WHEN** registry CI runs, **THEN** the schema/consistency check fails and the PR is blocked. +- **GIVEN** the latest release of the first-party Bitbucket plugin declares + `author: "kandev"` and its `repo_url` points to `kdlbs/kandev-plugin-bitbucket`, + **WHEN** the official index is built, **THEN** the catalog shows **by kandev** and + links to the `kdlbs` Bitbucket repository. +- **GIVEN** the latest release of the community YouTrack plugin is owned by + `ahmedbally` and declares `author: "ahmedbally"` with its matching repository URL, + **WHEN** the official index is built, **THEN** the catalog shows **by ahmedbally** + and links to `ahmedbally/kandev-plugin-youtrack`, not a `kdlbs` repository. ## Auto-update (opt-in) diff --git a/plugin-registry/build-index.test.mjs b/plugin-registry/build-index.test.mjs index b0d4680bde..4a213aabbe 100644 --- a/plugin-registry/build-index.test.mjs +++ b/plugin-registry/build-index.test.mjs @@ -89,7 +89,7 @@ test("buildEntry resolves release, manifest, icon_url and stars", async () => { published_at: "2026-01-01T00:00:00Z", assets: [{ name: "foo-1.2.0.tar.gz", browser_download_url: "https://dl/foo-1.2.0.tar.gz" }], }, - manifestText: "display_name: Foo\ndescription: A foo\nicon: icon.svg\ncategories: [x]", + manifestText: "display_name: Foo\ndescription: A foo\nauthor: kandev\nicon: icon.svg\ncategories: [x]", repoMeta: { stargazers_count: 42, pushed_at: "2026-02-02T00:00:00Z", owner: { login: "acme" } }, }); @@ -97,6 +97,7 @@ test("buildEntry resolves release, manifest, icon_url and stars", async () => { assert.equal(error, undefined); assert.equal(record.name, "Foo"); assert.equal(record.version, "1.2.0"); + assert.equal(record.author, "kandev"); assert.equal(record.package_url, "https://dl/foo-1.2.0.tar.gz"); assert.equal(record.icon_url, "https://raw.githubusercontent.com/acme/foo/v1.2.0/icon.svg"); assert.equal(record.stars, 42); @@ -119,6 +120,7 @@ test("buildEntry keeps stars null (never 0) when repo metadata lookup fails", as }); const { record } = await buildEntry({ id: "foo", repo: "acme/foo" }); assert.equal(record.stars, null); + assert.equal(record.author, "acme"); // legacy fallback when the manifest has no author assert.equal(record.icon_url, null); // no manifest icon });