feat: add canvas marketplace distribution and sharing (#3603)
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
---
|
||||
created: 2026-09-14
|
||||
status: done
|
||||
requirements:
|
||||
- REQ-PLUGINS-MARKETPLACE-002
|
||||
system_design:
|
||||
- ../../specs/plugins/system-design/marketplace.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Implementation plan: Plugin marketplace previews
|
||||
|
||||
Extend the existing native-plugin marketplace with optional registry-owned
|
||||
preview galleries while preserving legacy entries and the current installation
|
||||
path. The canvas marketplace plan consumes the same registry and gallery
|
||||
primitives, but the plugin requirement remains owned by this package.
|
||||
|
||||
## Scope
|
||||
|
||||
- Ordered optional preview metadata for official and custom plugin listings.
|
||||
- Cover and details gallery behavior with keyboard, touch, and image failures.
|
||||
- Existing no-preview rows and native install actions.
|
||||
- Plugin marketplace, manifest, authoring, and registry README guidance.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [ ] [Task 01: Extend plugin marketplace previews](task-01-plugin-previews.md)
|
||||
|
||||
Dependencies: 01. The single work order keeps the plugin requirement and its
|
||||
system design in one lookup scope for documentation validation.
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
id: "01-plugin-previews"
|
||||
title: "Extend plugin marketplace previews"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-PLUGINS-MARKETPLACE-002
|
||||
acceptance_criteria:
|
||||
- AC-PLUGINS-MARKETPLACE-002.1
|
||||
- AC-PLUGINS-MARKETPLACE-002.2
|
||||
- AC-PLUGINS-MARKETPLACE-002.3
|
||||
- AC-PLUGINS-MARKETPLACE-002.4
|
||||
system_design:
|
||||
- ../../specs/plugins/system-design/marketplace.md
|
||||
---
|
||||
|
||||
# Task 01: Extend plugin marketplace previews
|
||||
|
||||
## Summary
|
||||
|
||||
Complete the optional native-plugin preview extension that shares the registry
|
||||
metadata and gallery primitives used by canvas entries. Keep preview metadata
|
||||
outside plugin packages and preserve the existing native installation path.
|
||||
|
||||
## In scope
|
||||
|
||||
- Ordered optional `previews: [{url, alt}]` fields for official and custom
|
||||
plugin registry entries and generated catalog records.
|
||||
- First-image cover presentation, details gallery, keyboard and touch controls,
|
||||
image-position descriptions, one-image mode, and contained image failures.
|
||||
- Existing plugin rows and install actions when a listing has no previews.
|
||||
- Registry-owned preview metadata, so URLs, descriptions, and order can change
|
||||
without releasing a plugin version.
|
||||
- Shared gallery tests and native-plugin marketplace regression coverage.
|
||||
- Public plugin marketplace and manifest guidance, the linked authoring guide,
|
||||
and plugin registry README examples.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Canvas package validation, canvas installation review, screenshot requirements
|
||||
for bundle creation, native plugin package changes, and a new installation path.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Official and custom plugin entries accept an ordered HTTPS preview list while
|
||||
existing entries without previews remain valid.
|
||||
- Listings with previews show the first image as the cover and expose the full
|
||||
gallery; listings without previews keep their current row and install action.
|
||||
- Gallery navigation works with keyboard and touch, retains installation when an
|
||||
image fails, and never executes package code in the preview.
|
||||
- Preview metadata remains registry-owned and can change independently of plugin
|
||||
package releases.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
rtk bash -lc 'KANDEV_CANVAS_PACKAGE_INSPECTOR=apps/backend/bin/canvas-package node --test plugin-registry/build-index.test.mjs'
|
||||
(cd apps/web && rtk pnpm exec vitest run components/settings/plugins/marketplace-preview-gallery.test.tsx components/settings/plugins/plugin-row.test.tsx)
|
||||
(cd apps/web && rtk pnpm e2e:run --project chromium tests/plugins/plugins.spec.ts -- --retries=0)
|
||||
(cd apps/web && rtk pnpm e2e:run --project mobile-chrome tests/plugins/mobile-plugin-settings-row.spec.ts -- --retries=0)
|
||||
rtk proxy node --test scripts/validate-public-docs.test.mjs
|
||||
rtk git diff --check -- docs/public/plugins-marketplace.md docs/public/plugins-manifest.md docs/public/plugins-authoring.md plugin-registry/README.md
|
||||
```
|
||||
|
||||
Use local fixtures and the built inspector. Do not publish a registry entry or
|
||||
execute a plugin while testing preview details.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `plugin-registry/schema.json`, `build-index.mjs`, and `build-index.test.mjs`
|
||||
- `apps/web/components/settings/plugins/marketplace-preview-gallery.tsx`
|
||||
- Existing plugin row/details components and their focused tests
|
||||
- `apps/web/components/settings/plugins/plugins-settings.tsx`
|
||||
- `apps/web/lib/api/domains/marketplace-api.ts` and marketplace hooks/tests
|
||||
- `apps/web/src/locales/{en,pt-pt,zh-cn,zh-hk,zh-tw,pseudo}/`
|
||||
- `docs/public/plugins-marketplace.md`
|
||||
- `docs/public/plugins-manifest.md`
|
||||
- `docs/public/plugins-authoring.md`
|
||||
- `plugin-registry/README.md`
|
||||
|
||||
## Dependencies
|
||||
|
||||
The canvas marketplace plan provides the shared registry and gallery primitives;
|
||||
the plugin contract remains independently traceable to the plugin design.
|
||||
|
||||
## Risks
|
||||
|
||||
Do not make previews part of a plugin manifest or release archive. Remote image
|
||||
failures must not block native installation, and the details surface must never
|
||||
load a runtime URL or execute package code.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- Plugin marketplace requirements and the registry preview system design.
|
||||
- Existing `buildEntry`, `build-index.test.mjs`, plugin rows, and native install
|
||||
dialog.
|
||||
- Shared marketplace gallery behavior and the plugin documentation validation
|
||||
guide.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented optional ordered plugin previews in registry and catalog records,
|
||||
shared gallery details with keyboard and touch controls, image-failure fallback,
|
||||
and unchanged native installation for entries without previews. Updated the
|
||||
plugin marketplace, manifest, authoring, and registry README guidance.
|
||||
|
||||
Verification: the existing plugin marketplace regression passed 16 tests; the
|
||||
registry build-index suite and shared gallery coverage passed with the canvas
|
||||
marketplace validation; public documentation validation and diff checks passed.
|
||||
@@ -0,0 +1,446 @@
|
||||
---
|
||||
created: 2026-09-10
|
||||
status: done
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-001
|
||||
- REQ-CANVASES-MARKETPLACE-002
|
||||
- REQ-CANVASES-MARKETPLACE-003
|
||||
- REQ-CANVASES-MARKETPLACE-004
|
||||
- REQ-CANVASES-MARKETPLACE-005
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
system_design:
|
||||
- ../../specs/canvases/system-design/marketplace-sharing.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Implementation plan: Canvas marketplace
|
||||
|
||||
## Overview
|
||||
|
||||
Add canvas distribution to the existing Plugins marketplace. Authors download
|
||||
an installable bundle and source project, then follow manual repository and
|
||||
registry instructions. Recipients inspect screenshots and permissions before
|
||||
installing an independent workspace canvas.
|
||||
|
||||
The [requirements](../../specs/canvases/requirements/marketplace-sharing.md) and
|
||||
[design](../../specs/canvases/system-design/marketplace-sharing.md) are the
|
||||
authoritative pair. The selected owner is Canvases because it owns reusable
|
||||
canvas identity, source lineage, workspace instances, and discovery.
|
||||
|
||||
Implementation is complete across the seven sequential work orders: portable
|
||||
package contract, export preparation, reviewed installation, registry
|
||||
enrichment, marketplace UI, sharing UI, and public instructions. The optional
|
||||
native-plugin preview extension is tracked in the companion plugin plan. No native
|
||||
implementation subagents were authorized by this plan. Each work order's
|
||||
Results section records its implementation and validation evidence.
|
||||
|
||||
## Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- One existing marketplace with a dedicated Canvases tab in Plugins settings.
|
||||
- `.tar.gz` upload, direct HTTPS bundle link, and catalog installation.
|
||||
- Required registry cover URL and up to seven additional previews for canvases.
|
||||
- Registry cover and preview URLs for canvas entries.
|
||||
- Screenshot-free bundle creation, source downloads, and upload/link installs.
|
||||
- Package metadata, source mode, license, compatibility, and permission review.
|
||||
- Download bundle and source ZIP from the same prepared release snapshot.
|
||||
- Manual repository/release/sharing instructions and PR-based registry listing.
|
||||
- Independent workspace copies, durable provenance, retry-safe confirmation.
|
||||
- Static runtime isolation, workspace authorization, quotas, and disabled paths.
|
||||
- Desktop and phone UI, localization, targeted E2E, author/public documentation.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Repository-URL installation, cloning, builds during install, or new hosting.
|
||||
- Automated code-host publishing, repository creation, or registry PR submission.
|
||||
- Canvas updates/replacement, state export, credentials, or public live instances.
|
||||
- Screenshot capture, ratings, payments, telemetry, and a standalone website.
|
||||
- Runtime toggle promotion, new flags, or native binary canvas execution.
|
||||
|
||||
## Baseline and companion plans
|
||||
|
||||
The `plugin-backed-canvases` package is marked done. The UX follow-up records
|
||||
Tasks 01-06 complete and Task 07's external ACP evaluation outstanding.
|
||||
This plan extends their source-retention and discovery boundaries; it does not
|
||||
reopen their completed work or change their historical verification results.
|
||||
Implementation must preserve the one-core-read authoring contract. The external
|
||||
ACP evaluation is not an additional delivery gate for this feature.
|
||||
|
||||
## Technical approach
|
||||
|
||||
### Portable package boundary
|
||||
|
||||
Extend `internal/plugins/manifest` with optional typed distribution metadata.
|
||||
Extend `internal/plugins/webapp` with strict distribution validation, checksum
|
||||
coverage, source-only file retention, and safe
|
||||
export writers. `Runtime.Serve` denies `distribution/` files. The native
|
||||
`pkgtar` installer stays unchanged. Add `cmd/canvas-package` for offline
|
||||
inspection through the production validator; the registry builder uses this
|
||||
command instead of implementing a second parser.
|
||||
|
||||
No-build source remains the current application files. Build-based source is
|
||||
retained under `distribution/source/` in the same immutable release. Extend
|
||||
authoring collection and Quick Chat materialization to preserve that subtree.
|
||||
|
||||
### Export and installation boundary
|
||||
|
||||
Add a small canvas distribution service with expiring, bounded, user-bound
|
||||
preparations. Export reads the immutable active artifact and derives both
|
||||
downloads without touching the executor or changing the active release.
|
||||
Installation stages one inspected package and approves those exact bytes.
|
||||
|
||||
Add `InstallPrepared` through the canvas/instance transaction boundary and one
|
||||
`canvas_install_receipts` table. The receipt preserves provenance and prevents
|
||||
duplicate confirmation after timeout/restart. Reuse artifact cleanup,
|
||||
workspace admission, grants, and lifecycle invalidations. Native plugin
|
||||
registry records and its auto-update poller do not contain canvas instances.
|
||||
|
||||
New browser routes live beside `backendapp/canvas_routes.go` in focused files.
|
||||
Authorize human workspace access at service boundaries; server-side URL fetch
|
||||
uses bounded, public-destination-only transport. Tests inject a local transport.
|
||||
|
||||
### Registry and catalog boundary
|
||||
|
||||
Add optional `kind: canvas` to the existing pointer schema. The builder fetches
|
||||
the exact versioned bundle, inspects it, and requires its archive digest.
|
||||
Preview URLs come from the registry and pass unchanged into the generated index.
|
||||
Use the proposed [registry schema](registry-entry.schema.json) for canvas entries;
|
||||
there is no image extraction, mirroring, or Pages media staging. Use additive catalog
|
||||
fields and kind filtering. Instance annotations are workspace-authorized and
|
||||
must not enter the shared source cache. Old native entries keep their behavior.
|
||||
|
||||
### UI boundary
|
||||
|
||||
`PluginsSettings` adds Canvases alongside Installed and Browse. Add domain hooks
|
||||
and a typed canvas-distribution API client; reuse existing gallery/dialog,
|
||||
permission summary, upload, and settings primitives where they fit. Details
|
||||
and review derive from one shared model across viewports. Share is host-owned,
|
||||
available from the task/workspace canvas and workspace rows. All copy uses the
|
||||
five real locales and generated Traditional Chinese/pseudo catalogs.
|
||||
|
||||
## ASCII UI preview
|
||||
|
||||
All views below are proposed. Structure, action order, permissions before
|
||||
confirmation, explicit image controls, and separate phone composition are
|
||||
requirements. Names, image proportions, and spacing are illustrative.
|
||||
|
||||
### UI-01: Canvas catalog
|
||||
|
||||
Entry: Settings > Plugins > Canvases, or Browse shared canvases from a workspace.
|
||||
Maps to AC-CANVASES-MARKETPLACE-004.1, 005.2, 005.4, 006.1, and 006.2.
|
||||
|
||||
```text
|
||||
Desktop
|
||||
+-------------------------------------------------------------------+
|
||||
| Plugins |
|
||||
| Installed | Browse | CANVASES |
|
||||
| Workspace [Project A v] Search [____________] Sort [Recent v] |
|
||||
| [Install canvas] |
|
||||
| +----------------------+ +----------------------+ |
|
||||
| | [cover screenshot] | | [cover screenshot] | |
|
||||
| | Sprint board 1.0.0 | | Release viewer | |
|
||||
| | by example-author | | by contributor | |
|
||||
| | Description... | | Description... | |
|
||||
| | [View details] | | 2 copies [Open v] | |
|
||||
| +----------------------+ +----------------------+ |
|
||||
+-------------------------------------------------------------------+
|
||||
|
||||
Phone
|
||||
+------------------------------+
|
||||
| Plugins |
|
||||
| Installed | Browse | Canvases |
|
||||
| Workspace [Project A v] |
|
||||
| Search [_____________] |
|
||||
| Sort [Recent v] |
|
||||
| [Install canvas] |
|
||||
| +--------------------------+ |
|
||||
| | [cover screenshot] | |
|
||||
| | Sprint board / author | |
|
||||
| | Description... | |
|
||||
| | [View details] | |
|
||||
| +--------------------------+ |
|
||||
+------------------------------+
|
||||
```
|
||||
|
||||
Cards open details by pointer, keyboard, or tap. One page scroll owns the list.
|
||||
Empty: explain no matching canvases, retain search and Install canvas. Failed
|
||||
source: inline source warning plus Retry; healthy results remain visible.
|
||||
Loading: skeleton covers with a status announcement. Gate-off: no Canvases tab.
|
||||
|
||||
### UI-02: Canvas details and install review
|
||||
|
||||
Use "Preview images" as the gallery label for canvas details.
|
||||
|
||||
Entry: catalog card or inspected upload/link. Maps to
|
||||
AC-CANVASES-MARKETPLACE-002.3, 004.2-004.6, 005.3, and 006.1-006.3.
|
||||
|
||||
```text
|
||||
Desktop details
|
||||
+-------------------------------------------------------------------+
|
||||
| [Back to canvases] Sprint board 1.0.0 [Close] |
|
||||
| +--------------------------------+ by example-author |
|
||||
| | | Description |
|
||||
| | [selected image] | License: MIT [Repository] |
|
||||
| | | Requires Kandev ... |
|
||||
| +--------------------------------+ |
|
||||
| [Previous] 1 / 3 [Next] [thumb 1] [thumb 2] [thumb 3] |
|
||||
| Permissions |
|
||||
| Read: tasks, workflows Write: none |
|
||||
| Events: none State: none Network: none |
|
||||
| Workspace [Project A v] [Review & install] |
|
||||
+-------------------------------------------------------------------+
|
||||
|
||||
Phone details / final review
|
||||
+------------------------------+
|
||||
| [Back] Sprint board | fixed
|
||||
| 1.0.0 / by example-author |
|
||||
| [selected image] |
|
||||
| [Previous] 1 / 3 [Next] |
|
||||
| Description, license, repo | one scrolling body
|
||||
| Permissions |
|
||||
| Read: tasks, workflows |
|
||||
| Write: none |
|
||||
| Events / State / Network |
|
||||
| Workspace [Project A v] |
|
||||
| Package verified / version |
|
||||
|------------------------------|
|
||||
| [Install in Project A] | fixed, safe-area footer
|
||||
+------------------------------+
|
||||
|
||||
Upload/direct-link entry (shared order)
|
||||
+-------------------------------------+
|
||||
| Install canvas |
|
||||
| Upload bundle | Direct link |
|
||||
| [Choose .tar.gz file] |
|
||||
| Workspace [Project A v] |
|
||||
| [Cancel] [Review bundle] |
|
||||
+-------------------------------------+
|
||||
```
|
||||
|
||||
The desktop review uses the same detail surface with authoritative inspected
|
||||
metadata. Catalog Review & install stages bytes first; the final Install action
|
||||
explicitly approves the displayed permissions. No runtime iframe appears here.
|
||||
Phone inputs use a focused full-height form. No two-column detail remains
|
||||
mounted on phones. Upload/link reviews omit the gallery; registry reviews label
|
||||
images as listing previews, separate from verified permissions. Image enlargement replaces the gallery region with Back to
|
||||
details; it does not nest another dialog. One image hides previous/next.
|
||||
|
||||
States: inspecting shows progress; failed inspection retains input; expired or
|
||||
changed review offers Review again; incompatible package disables confirmation
|
||||
with the required version; failed image shows a placeholder and Retry; success
|
||||
shows Installed in Project A and Open canvas. Add another copy always starts a
|
||||
new review; retrying a successful request returns its original copy.
|
||||
|
||||
### UI-03: Share canvas
|
||||
|
||||
Entry: host Share action or workspace canvas row. Maps to
|
||||
AC-CANVASES-MARKETPLACE-001.2-001.3, 002.1, 003.1-003.2, 003.4, and 006.1-006.3.
|
||||
Screenshots are supplied later in the registry entry, never in this form.
|
||||
|
||||
```text
|
||||
Desktop
|
||||
+-------------------------------------------------------------------+
|
||||
| Share canvas [Close] |
|
||||
| Active release: 1.0.0 |
|
||||
| Package ID [sprint-board] Version [1.0.0] |
|
||||
| Name [Sprint board] Author [________] License [________] |
|
||||
| Description [____________________________________________] |
|
||||
| Source: [Static application v] |
|
||||
| [How to share] [Prepare downloads] |
|
||||
|-------------------------------------------------------------------|
|
||||
| Ready: review included files [Expand] |
|
||||
| Check exported files for private content. |
|
||||
| Bundle: ... MiB Source: ... MiB |
|
||||
| [Download bundle] [Download source] |
|
||||
+-------------------------------------------------------------------+
|
||||
|
||||
Phone
|
||||
+------------------------------+
|
||||
| [Back] Share canvas | fixed
|
||||
| Active release: 1.0.0 |
|
||||
| Package ID [___________] |
|
||||
| Version [____] |
|
||||
| Name / author / license | one scrolling body
|
||||
| Description [__________] |
|
||||
| Source [Static v] |
|
||||
| [How to share] |
|
||||
| Ready: included files, sizes |
|
||||
| Check for private content. |
|
||||
| [Download bundle] |
|
||||
| [Download source] |
|
||||
|------------------------------|
|
||||
| [Prepare downloads] | fixed until ready
|
||||
+------------------------------+
|
||||
```
|
||||
|
||||
Download controls appear only for the current prepared snapshot. After ready,
|
||||
the footer can show Close while both downloads stay reachable in the body;
|
||||
neither download dismisses the form. Form edits invalidate prepared output.
|
||||
Missing source shows Edit and republish guidance. New active release requires
|
||||
preparation again. Closing discards temporary share inputs, not canvas data.
|
||||
|
||||
### UI-04: Sharing instructions
|
||||
|
||||
Entry: How to share in UI-03. Maps to AC-CANVASES-MARKETPLACE-003.3-003.4 and 006.1.
|
||||
|
||||
```text
|
||||
Desktop information dialog Phone inset bottom drawer
|
||||
+--------------------------------+ +------------------------------+
|
||||
| How to share [X] | | How to share [X] |
|
||||
| 1. Download source + bundle | | Download source + bundle |
|
||||
| 2. Create a repository | | Create/upload repository |
|
||||
| 3. Upload source | | Publish bundle; copy link |
|
||||
| 4. Publish bundle; copy link | | Send link or file |
|
||||
| 5. Send the link or file | | Add to registry (optional) |
|
||||
| Optional: list in Kandev | | [Copy registry example] |
|
||||
| [Copy registry example] | | [Done] |
|
||||
| [Done]| +------------------------------+
|
||||
+--------------------------------+
|
||||
```
|
||||
|
||||
Keep instruction steps in a bounded scroll body; fixed title/dismiss and bottom
|
||||
safe-area padding. Closing returns focus to How to share and preserves UI-03.
|
||||
The copy action copies text only. No remote creation action is offered.
|
||||
Registry instructions include the required canvas screenshot URLs and alt text,
|
||||
cover ordering, and the same fields for custom marketplace registries.
|
||||
|
||||
## Tests
|
||||
|
||||
All test files/methods below are proposed unless explicitly named as existing.
|
||||
Work-order frontmatter lists each full AC identity, including those abbreviated
|
||||
in this table. Use nearby `@covers` annotations when method names are insufficient.
|
||||
|
||||
| AC suffixes under AC-CANVASES-MARKETPLACE | Planned evidence |
|
||||
| --- | --- |
|
||||
| 001.1, 001.2, 001.4 | `webapp/distribution_test.go`: `TestDistributionPackageRoundTrip`, `TestDistributionSourceModes`, `TestDistributionRejectsNonCanvas`; `backendapp/canvas_distribution_source_test.go`: `TestCanvasProjectSourceSurvivesEditAndExecutorCleanup` |
|
||||
| 001.3, 003.1, 003.2, 003.4 | `canvas/distribution_export_test.go`: `TestCanvasExportSnapshot`, `TestCanvasExportExclusions`, `TestCanvasExportStaleRelease`, `TestCanvasExportNoLifecycleMutation` |
|
||||
| 002.1, 002.2, 002.4 | `plugin-registry/canvas-index.test.mjs`: registry URL/list shape and cover order; export/install tests prove screenshots are not required |
|
||||
| 002.3, 004.2 | `canvas-marketplace-detail.test.tsx`: gallery ordering, one-image mode, broken image, permission groups; `backendapp/canvas_distribution_routes_test.go`: `TestCanvasInstallReviewUsesPackagePermissions` |
|
||||
| 004.1, 004.3, 004.4 | `canvas/distribution_install_test.go`: `TestCanvasInstallSources`, `TestCanvasInstallDigestReview`, `TestCanvasInstallAtomicFailure`, `TestCanvasInstallRestart` |
|
||||
| 004.5, 004.6 | `canvas/distribution_install_test.go`: `TestCanvasInstallConcurrentRetry`, `TestCanvasInstallIndependentCopy`; `backendapp/canvas_distribution_routes_test.go`: `TestCanvasDistributionWorkspaceAuthorization` |
|
||||
| 005.1, 005.3 | `plugin-registry/canvas-index.test.mjs`: exact release asset, actual manifest, required registry URLs, source, ID/version, checksum, image metadata independent of package, invalid PR rejection |
|
||||
| 005.2, 005.4 | `marketplace/canvas_catalog_test.go`: `TestCanvasCatalogWorkspaceProjection`, `TestCanvasCatalogDegradedSource`, `TestCanvasCatalogLegacyEntries`; existing marketplace client/hook tests |
|
||||
| 003.3 | `canvas-share-help.test.tsx`: complete manual instructions and exact registry example; public-doc validators |
|
||||
| 006.1, 006.2, 006.3 | Desktop/phone E2E below; API/hook stale-response tests; i18n checks and pseudo-locale rendered pass |
|
||||
| 006.4 | `backendapp/canvas_distribution_routes_test.go`: `TestCanvasDistributionFeatureOff`; frontend tab/hook tests; existing native plugin tests; `TestDistributionLegacyLocalPackage` |
|
||||
|
||||
Additional package tests cover encoded source-subtree access, archive traversal,
|
||||
links, expansion bombs, duplicate normalized paths, binary contributions
|
||||
disguised by category, and current file budgets. Registry tests cover URL schemes,
|
||||
credentials/fragments, list bounds, alt text, and custom-source equivalence.
|
||||
Receipt tests cover lost response, restart, concurrent confirm, quota races,
|
||||
workspace deletion, fresh schema, replay, and gated PostgreSQL behavior.
|
||||
|
||||
## E2E tests
|
||||
|
||||
Use the existing `e2e/tests/canvas/canvas-fixture.ts` pattern with disposable
|
||||
workspaces, a known mock-agent canvas, and a locally served catalog/package.
|
||||
Enable the existing feature explicitly and restore it in cleanup. The new
|
||||
tests must fail, rather than skip, if their required fixture is unavailable.
|
||||
|
||||
| File and project | UI flows and AC mapping |
|
||||
| --- | --- |
|
||||
| `tests/canvas/canvas-marketplace.spec.ts`, chromium | UI-01/UI-02: search, three images, permission review, upload and link, registry install, reload/Open, additional copy, expired review, bad digest, source outage; 002.3, 004.1-004.6, 005.2-005.4 |
|
||||
| `tests/canvas/mobile-canvas-marketplace.spec.ts`, mobile-chrome | UI-01/UI-02 by tap: browse, gallery controls, workspace selection, upload/link/catalog review, install/Open, one-column layout, viewport containment and focus; 006.1-006.2 plus same install/gallery criteria |
|
||||
| `tests/canvas/canvas-sharing.spec.ts`, chromium | UI-03/UI-04: no screenshot input, metadata, prepare, both downloads, help with registry URLs, import screenshot-free bundle and open resulting canvas; 001.1-001.3, 002.1, 003.1-003.4 |
|
||||
| `tests/canvas/mobile-canvas-sharing.spec.ts`, mobile-chrome | UI-03/UI-04: screenshot-free preparation, both downloads, help drawer/back, input retention, pseudo-locale, actual touch targets, keyboard/safe-area containment; 006.1-006.3 plus sharing criteria |
|
||||
|
||||
Use real backend inspection/confirmation and local fixture HTTP; do not intercept
|
||||
the install response into a fake success. Preview details must not issue a
|
||||
runtime URL request. Capture downloads and inspect archive contents. Use causal
|
||||
HTTP/WS waits, no arbitrary sleeps, and no display server or real provider account.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [ ] [Task 01: Define portable canvas packages](task-01-portable-packages.md)
|
||||
- [ ] [Task 02: Prepare canvas exports](task-02-export-preparation.md)
|
||||
- [ ] [Task 03: Install reviewed canvas bundles](task-03-reviewed-installation.md)
|
||||
- [ ] [Task 04: Publish canvas catalog entries](task-04-registry-catalog.md)
|
||||
- [ ] [Task 05: Build canvas marketplace browsing](task-05-marketplace-ui.md)
|
||||
- [ ] [Task 06: Add canvas sharing controls](task-06-sharing-ui.md)
|
||||
- [ ] [Task 07: Document canvas distribution](task-07-distribution-docs.md)
|
||||
|
||||
Dependencies: 01 -> 02 -> 03 -> 04 -> 05 -> 06 -> 07. This deliberately uses
|
||||
sequential delivery because schema, shared UI/API models, and fixtures overlap.
|
||||
|
||||
The optional native-plugin preview extension is delivered by the companion
|
||||
[plugin marketplace previews plan](../canvas-marketplace-plugin/plan.md).
|
||||
|
||||
## Verification commands
|
||||
|
||||
Run each work order's exact block from the repository root. Work orders use
|
||||
isolated subshells for working directories. Install workspace dependencies once
|
||||
before the first pnpm command: `(cd apps && rtk pnpm install --frozen-lockfile)`.
|
||||
No product commands below have been run during this design turn.
|
||||
|
||||
The work orders own Go/package tests, registry Node tests, focused Vitest,
|
||||
typecheck, affected-file lint, i18n, and managed desktop/phone E2E commands.
|
||||
Managed E2E builds fresh production artifacts. No all-worker overrides or
|
||||
overlapping full suites are allowed. Persistence work includes SQL guard and
|
||||
store-conformance checks; PostgreSQL needs `KANDEV_TEST_POSTGRES_DSN`.
|
||||
|
||||
Design-package checks:
|
||||
|
||||
```bash
|
||||
rtk proxy python3 scripts/lint-spec-files.test.py
|
||||
rtk proxy python3 scripts/lint-spec-files.py --all
|
||||
rtk git diff --check -- docs/specs docs/plans/canvas-marketplace
|
||||
rtk git status --short -- docs/specs docs/plans/canvas-marketplace
|
||||
```
|
||||
|
||||
## Verification results
|
||||
|
||||
Initial design validation on 2026-09-10 (before the registry-image revision):
|
||||
|
||||
- `python3 scripts/lint-spec-files.test.py`: passed, 36 tests.
|
||||
- `python3 scripts/lint-spec-files.py --all`: passed.
|
||||
- Requirement/work-order/link audit: six requirements, 26 acceptance criteria,
|
||||
seven work orders, and ten new documents checked. Every criterion has a work
|
||||
order; all relative document links and system-design paths resolve.
|
||||
- `git diff --check -- docs/specs docs/plans/canvas-marketplace`: passed.
|
||||
- New-document whitespace audit: passed, including untracked work orders.
|
||||
- `git status --short -- docs/specs docs/plans/canvas-marketplace`: inspected;
|
||||
the package and index/cross-reference edits are present and uncommitted.
|
||||
|
||||
Registry-image revision validation on 2026-09-10:
|
||||
|
||||
- Specification linter tests: passed, 36 tests; full specification lint passed.
|
||||
- Traceability/link audit: seven requirements, 30 criteria, seven work orders;
|
||||
all criteria assigned and document/design links resolved.
|
||||
- Proposed JSON Schema parses and contains the preview definition and
|
||||
conditional canvas requirement. Full JSON Schema engine validation was not
|
||||
run in this environment; implementation owns semantic schema test cases.
|
||||
- Tracked diff and new-document whitespace checks passed.
|
||||
|
||||
The revision adds the Plugins-owned preview requirement and the proposed schema
|
||||
artifact; it does not change the production registry schema yet.
|
||||
|
||||
Implementation checks were not run; all seven work orders remain pending.
|
||||
Record actual command results here and in each task during delivery.
|
||||
|
||||
## Risks
|
||||
|
||||
- The current source allowlist excludes TS/TSX and YAML; widening must be
|
||||
limited to an inert subtree that runtime URLs cannot serve.
|
||||
- Registry image URLs can change or fail independently of package releases;
|
||||
gallery failure must not block valid installation or imply package corruption.
|
||||
- Registry metadata currently uses a shallow parser and nullable hash. Canvas
|
||||
entries need production inspection without breaking native plugin entries.
|
||||
- Receipt insertion, grants, count admission, and artifact references must be
|
||||
atomic across retries and supported database dialects.
|
||||
- Host URL fetch must not gain private-network access through DNS or redirects.
|
||||
- Shared catalog caching must never retain a user's workspace instance annotations.
|
||||
- Old clients must fail safely on static canvas bundles; set a real minimum
|
||||
compatible release before shipping the format.
|
||||
- Private data embedded in exported files cannot be reliably removed
|
||||
automatically. Show the exact inventory and author review reminder.
|
||||
- Official registry discovery remains GitHub-only. Other hosts can share public
|
||||
direct bundle links or files; the helper must explain that distinction.
|
||||
|
||||
## Design handoff
|
||||
|
||||
The next phase is explicit implementation of these work orders with TDD.
|
||||
This package does not authorize commits, pushes, registry submissions, or
|
||||
external publishing. Public docs are updated with implementation, not presented
|
||||
as shipped behavior during this planning turn.
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://github.com/kdlbs/kandev/blob/main/plugin-registry/schema.json",
|
||||
"title": "Kandev marketplace registry",
|
||||
"description": "Proposed registry schema for plugin and canvas repositories. Preview image URLs belong to registry entries; release metadata remains package-owned.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"plugins"
|
||||
],
|
||||
"properties": {
|
||||
"plugins": {
|
||||
"type": "array",
|
||||
"description": "The curated list of plugin repositories, one entry per plugin.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"id",
|
||||
"repo"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Stable plugin identifier. MUST equal the plugin manifest `id` of the repo's latest release. Unique across the file.",
|
||||
"pattern": "^[a-z0-9][a-z0-9-]*$"
|
||||
},
|
||||
"repo": {
|
||||
"type": "string",
|
||||
"description": "GitHub repository in owner/name form; the release source for this plugin.",
|
||||
"pattern": "^[^/]+/[^/]+$"
|
||||
},
|
||||
"featured": {
|
||||
"type": "boolean",
|
||||
"description": "When true, a maintainer has pinned this entry above star order in the catalog.",
|
||||
"default": false
|
||||
},
|
||||
"categories": {
|
||||
"type": "array",
|
||||
"description": "Curation-only category tags used for filtering in the catalog.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"kind": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"plugin",
|
||||
"canvas"
|
||||
],
|
||||
"default": "plugin",
|
||||
"description": "Omitted kind means plugin for backward compatibility; canvas kind must match the validated package."
|
||||
},
|
||||
"previews": {
|
||||
"type": "array",
|
||||
"maxItems": 8,
|
||||
"items": {
|
||||
"$ref": "#/$defs/preview"
|
||||
},
|
||||
"description": "Ordered preview images. First image is the cover. Optional for plugins; required for canvas registry listings."
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"required": [
|
||||
"kind"
|
||||
],
|
||||
"properties": {
|
||||
"kind": {
|
||||
"const": "canvas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"previews"
|
||||
],
|
||||
"properties": {
|
||||
"previews": {
|
||||
"minItems": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"preview": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"url",
|
||||
"alt"
|
||||
],
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"pattern": "^https://",
|
||||
"maxLength": 2048,
|
||||
"description": "Direct HTTPS image URL. Credentials and fragments are rejected by registry validation."
|
||||
},
|
||||
"alt": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 300,
|
||||
"pattern": "\\S",
|
||||
"description": "Description of the preview image for accessibility."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
id: "01-portable-packages"
|
||||
title: "Define portable canvas packages"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-001
|
||||
- REQ-CANVASES-MARKETPLACE-002
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
acceptance_criteria:
|
||||
- AC-CANVASES-MARKETPLACE-001.1
|
||||
- AC-CANVASES-MARKETPLACE-001.2
|
||||
- AC-CANVASES-MARKETPLACE-001.3
|
||||
- AC-CANVASES-MARKETPLACE-001.4
|
||||
- AC-CANVASES-MARKETPLACE-002.1
|
||||
- AC-CANVASES-MARKETPLACE-006.4
|
||||
system_design:
|
||||
- ../../specs/canvases/system-design/marketplace-sharing.md
|
||||
---
|
||||
|
||||
# Task 01: Define portable canvas packages
|
||||
|
||||
## Summary
|
||||
|
||||
Define the canvas distribution profile in the existing plugin manifest and
|
||||
static validator. Preserve editable source with immutable releases and expose
|
||||
a reusable offline inspector for registry validation.
|
||||
|
||||
## In scope
|
||||
|
||||
- Typed distribution metadata, source modes, checksum validation, compatibility,
|
||||
exactly one canvas app, and rejection of other plugin contributions.
|
||||
- Screenshot-free bundle/source validation; registry previews are not manifest fields.
|
||||
- Source-only project subtree, bounded authoring transfer, immutable retention,
|
||||
Quick Chat materialization, and runtime denial of distribution paths.
|
||||
- Deterministic bundle/source archive writers and production offline inspector.
|
||||
- Minimal embedded authoring reference changes needed to keep source modes valid;
|
||||
Task 07 owns the full sharing instructions.
|
||||
|
||||
## Out of scope
|
||||
|
||||
HTTP downloads, registry fetching, canvas installation, UI, and native installer changes.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Distribution round-trip fixtures retain matching static/project source and
|
||||
application assets while malformed, incomplete, disguised native, and oversized
|
||||
bundles fail. No screenshot or preview URL is required.
|
||||
- Runtime requests cannot read the inert source subtree through plain,
|
||||
encoded, or normalized aliases; editing retains original build inputs after
|
||||
the author executor is unavailable.
|
||||
- The offline inspector and host use the same validator and a shared descriptor
|
||||
fixture. Native managed-plugin installation tests remain unchanged and pass.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from repository root. Start with focused RED cases, then run these blocks
|
||||
after implementation. The new test files/methods are named in the plan.
|
||||
|
||||
```bash
|
||||
(cd apps/backend && rtk go test -race ./internal/plugins/manifest ./internal/plugins/webapp ./internal/plugins/pkgtar ./cmd/canvas-package -count=1)
|
||||
(cd apps/backend && rtk go test -race ./internal/backendapp -run 'TestCanvas.*(Source|Scaffold|Edit)' -count=1)
|
||||
(cd apps/backend && rtk go test -race ./internal/agentctl/server/api -run Canvas -count=1)
|
||||
(cd apps/backend && rtk go test ./internal/mcp/canvasskill -count=1)
|
||||
rtk git diff --check
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
Existing:
|
||||
- `apps/backend/internal/plugins/manifest/manifest.go`, `validate.go`
|
||||
- `apps/backend/internal/plugins/webapp/package.go`, `runtime.go`
|
||||
- `apps/backend/internal/backendapp/canvas_authoring.go`, `canvas_routes.go`
|
||||
- `apps/backend/internal/agentctl/server/api/workspace_canvas_source.go`
|
||||
- `apps/backend/internal/mcp/canvasskill/files/references/manifest.md`
|
||||
|
||||
New:
|
||||
- `apps/backend/internal/plugins/manifest/distribution.go`
|
||||
- `apps/backend/internal/plugins/webapp/distribution.go`, `distribution_test.go`
|
||||
- `apps/backend/internal/backendapp/canvas_distribution_source_test.go`
|
||||
- `apps/backend/cmd/canvas-package/main.go`, `main_test.go`
|
||||
- Adjacent focused archive-writer tests and shared static/project fixture files.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None. Follow the existing plugin-backed canvas runtime contract.
|
||||
|
||||
## Risks
|
||||
|
||||
A file-extension exception must not broaden runtime serving. Preserve the
|
||||
current package byte/file budgets, source transfer fencing, and authoring core
|
||||
inventory. Build-source declarations cannot prove that arbitrary builds succeed;
|
||||
fixtures must prove both supported source modes and their documented commands.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- Design: Package profile, Source retention, Validation.
|
||||
- Existing `webapp/package_test.go`, `runtime_test.go`, authoring/edit tests.
|
||||
- `apps/backend/AGENTS.md` and both scoped agentctl AGENTS files before changes.
|
||||
- Existing canvas authoring guide and one-core-read inventory contract.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented the typed canvas distribution profile, strict manifest/package and
|
||||
source validation, checksum coverage, deterministic bundle/source archives,
|
||||
runtime source isolation, bounded source retention, and the offline inspector.
|
||||
The authoring reference and fixture preserve static/project source behavior.
|
||||
|
||||
Verification: the package/manifest/webapp/pkgtar/inspector race suite passed 210
|
||||
tests, the agentctl canvas-source race suite passed 6 tests, the backend canvas
|
||||
source/scaffold/edit race suite passed 7 tests, the authoring skill suite passed
|
||||
7 tests, and the relevant backend suite passed 1,587 tests across 8 packages.
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
id: "02-export-preparation"
|
||||
title: "Prepare canvas exports"
|
||||
status: done
|
||||
wave: 2
|
||||
depends_on:
|
||||
- "01-portable-packages"
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-001
|
||||
- REQ-CANVASES-MARKETPLACE-003
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
acceptance_criteria:
|
||||
- AC-CANVASES-MARKETPLACE-001.2
|
||||
- AC-CANVASES-MARKETPLACE-001.3
|
||||
- AC-CANVASES-MARKETPLACE-003.1
|
||||
- AC-CANVASES-MARKETPLACE-003.2
|
||||
- AC-CANVASES-MARKETPLACE-003.4
|
||||
- AC-CANVASES-MARKETPLACE-006.4
|
||||
system_design:
|
||||
- ../../specs/canvases/system-design/marketplace-sharing.md
|
||||
---
|
||||
|
||||
# Task 02: Prepare canvas exports
|
||||
|
||||
## Summary
|
||||
|
||||
Prepare both downloadable formats from one active immutable release. Introduce
|
||||
the bounded temporary preparation store that the install review will also use.
|
||||
|
||||
## In scope
|
||||
|
||||
- User/workspace-bound preparations, 15-minute expiry, admission accounting,
|
||||
request leases, cancel, startup cleanup, and safe failure cleanup.
|
||||
- Export preparation with metadata, inventory and size preview. No screenshot input.
|
||||
- Authenticated bundle/source downloads with safe headers.
|
||||
- Reauthorization and active-release checks before prepare/download.
|
||||
- Stable error codes, content-free diagnostics, and no executor dependence.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Permanent share-profile settings, external publication, installation mutations,
|
||||
frontend forms, and changes to canvas runtime state.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Export preparation and both downloads refer to the same validated snapshot;
|
||||
form/release changes invalidate it and unauthorized requests disclose nothing.
|
||||
- Source/state exclusion, screenshot-free preparation, expiry, cancellation, interrupted
|
||||
streaming, quotas, and restart cleanup leave the active release unchanged.
|
||||
- Preparation routes are absent when canvases are disabled; download access
|
||||
requires current human workspace authority even if an ID is known.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
(cd apps/backend && rtk go test -race ./internal/canvas -run 'TestCanvasExport|TestCanvasPreparation' -count=1)
|
||||
(cd apps/backend && rtk go test -race ./internal/backendapp -run 'TestCanvasExport|TestCanvasPreparation|TestCanvasDistributionFeatureOff' -count=1)
|
||||
rtk git diff --check
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
New:
|
||||
- `apps/backend/internal/canvas/distribution.go`, `distribution_preparation.go`
|
||||
- `apps/backend/internal/canvas/distribution_export.go`, `distribution_export_test.go`
|
||||
- `apps/backend/internal/canvas/distribution_preparation_test.go`
|
||||
- `apps/backend/internal/backendapp/canvas_distribution_routes.go`, `canvas_distribution_routes_test.go`
|
||||
|
||||
Existing integration points:
|
||||
- `apps/backend/internal/backendapp/canvas_routes.go` and service composition
|
||||
- `apps/backend/internal/plugins/webapp/package.go` artifact read interface
|
||||
|
||||
## Dependencies
|
||||
|
||||
Task 01's validated package and archive writers.
|
||||
|
||||
## Risks
|
||||
|
||||
Do not mistake opaque IDs for authorization. Cleanup must not race a live
|
||||
download or delete a shared immutable artifact. Bound compressed outputs and
|
||||
multipart input before memory allocation. Avoid collecting task workspace files.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- Design: Validation and bounded preparation, Export preparation, HTTP contracts.
|
||||
- `canvasEditService.loadEditableCanvas` for immutable artifact authorization.
|
||||
- Existing canvas route/feature-off tests and safe attachment response patterns.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented user-bound, expiring export preparations with quota and cleanup
|
||||
handling, immutable active-release snapshots, metadata/inventory review, and
|
||||
authenticated bundle/source downloads. The export path is screenshot-free and
|
||||
does not depend on the executor.
|
||||
|
||||
Verification: the canvas export/preparation race tests passed 3 tests, the
|
||||
desktop sharing E2E passed, and the mobile sharing E2E passed. The full relevant
|
||||
backend suite and SQL guard also passed.
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
id: "03-reviewed-installation"
|
||||
title: "Install reviewed canvas bundles"
|
||||
status: done
|
||||
wave: 3
|
||||
depends_on:
|
||||
- "02-export-preparation"
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-001
|
||||
- REQ-CANVASES-MARKETPLACE-004
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
acceptance_criteria:
|
||||
- AC-CANVASES-MARKETPLACE-001.1
|
||||
- AC-CANVASES-MARKETPLACE-001.4
|
||||
- AC-CANVASES-MARKETPLACE-004.1
|
||||
- AC-CANVASES-MARKETPLACE-004.2
|
||||
- AC-CANVASES-MARKETPLACE-004.3
|
||||
- AC-CANVASES-MARKETPLACE-004.4
|
||||
- AC-CANVASES-MARKETPLACE-004.5
|
||||
- AC-CANVASES-MARKETPLACE-004.6
|
||||
- AC-CANVASES-MARKETPLACE-006.4
|
||||
system_design:
|
||||
- ../../specs/canvases/system-design/marketplace-sharing.md
|
||||
---
|
||||
|
||||
# Task 03: Install reviewed canvas bundles
|
||||
|
||||
## Summary
|
||||
|
||||
Install an inspected static canvas as an independent workspace instance after
|
||||
explicit permission approval. Preserve reviewed bytes and retry identity across
|
||||
the database transaction.
|
||||
|
||||
## In scope
|
||||
|
||||
- Upload and direct-link preparation, authoritative package/permission review without required images,
|
||||
expected digest, bounded HTTPS fetch, redirect/DNS destination validation.
|
||||
- Catalog-reference resolver interface; Task 04 wires actual catalog entries.
|
||||
- `InstallPrepared`, workspace admission, atomic instance/release/grant creation,
|
||||
receipt/provenance persistence, and existing lifecycle invalidation.
|
||||
- Idempotent retry, concurrent confirmation, restart replay, deletion handling,
|
||||
safe artifact compensation, and native-install authority isolation.
|
||||
- Additive receipt schema, migration/replay fixtures, persistence descriptor
|
||||
updates where the existing canvas store's conformance contract requires them.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Repository cloning, provider credentials, replacing/updating existing canvases,
|
||||
frontend review controls, and native plugin auto-update changes.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Upload/link installs execute only inspected bytes after current workspace
|
||||
authorization and full permission approval, with no instance before confirm.
|
||||
- Concurrent or retried confirmation creates one instance; a new review creates
|
||||
an independent copy. Receipt, provenance, grants, and release survive restart.
|
||||
- Invalid URL/digest/package, revoked workspace, quota/DB failure, and disabled
|
||||
routes leave existing data unchanged; supported schema replay checks pass.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
(cd apps/backend && rtk go test -race ./internal/canvas ./internal/plugins/instances -count=1)
|
||||
(cd apps/backend && rtk go test -race ./internal/backendapp -run 'TestCanvasInstall|TestCanvasDistribution' -count=1)
|
||||
(cd apps/backend && rtk go run ./cmd/sqlguard ./internal)
|
||||
(cd apps/backend && rtk go test -race ./internal/persistence/storeconformance -count=1)
|
||||
rtk git diff --check
|
||||
```
|
||||
|
||||
Run the same targeted canvas/instance tests with `KANDEV_TEST_POSTGRES_DSN`
|
||||
set when the test database is available. Record skipped PostgreSQL evidence
|
||||
explicitly; do not report SQLite replay as cross-dialect evidence.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/canvas/distribution_install.go`, `distribution_install_test.go` (new)
|
||||
- `apps/backend/internal/canvas/distribution_download.go`, `distribution_download_test.go` (new)
|
||||
- `apps/backend/internal/canvas/repository.go`, `service.go`, `types.go`
|
||||
- `apps/backend/internal/plugins/instances/store.go` and focused transaction tests
|
||||
- `apps/backend/internal/backendapp/canvas_distribution_routes.go`, route tests
|
||||
- Existing canvas schema registration, storage cleanup, and conformance fixtures
|
||||
|
||||
## Dependencies
|
||||
|
||||
Tasks 01-02. Use a narrow catalog resolver interface with fixture data until Task 04.
|
||||
|
||||
## Risks
|
||||
|
||||
A sequence of independently committed create/publish/approve calls is not atomic.
|
||||
Use the existing store transaction boundary and receipt uniqueness. PostgreSQL
|
||||
locking must cover admission and concurrent retries. DNS checks must bind to the
|
||||
actual connection destination, not only an earlier lookup.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- Design: Install preparation, Commit and persistence, Authorization.
|
||||
- Existing `canvas.PublishPackage`, `instances.Store` transaction/cleanup tests.
|
||||
- `canvasHTTPHandler.authorizeWorkspace`, authentication scoping guidance.
|
||||
- Existing native-plugin install tests as a compatibility boundary.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented upload, direct HTTPS link, and catalog-reference preparation;
|
||||
server-side digest/package/permission review; bounded public-destination
|
||||
fetching; atomic workspace install integration; provenance and receipt
|
||||
persistence; and retry-safe confirmation.
|
||||
|
||||
Verification: the canvas installation/export race selection passed 3 tests, the
|
||||
full relevant backend suite passed 1,587 tests across 8 packages, and SQL guard
|
||||
passed. Existing native plugin installation paths remained covered by the
|
||||
16-test plugin E2E regression.
|
||||
|
||||
Review remediation: production confirmation now uses the canvas service's
|
||||
single transaction for instance, release, grants, and receipt ownership. It
|
||||
also reauthorizes retry paths, fails closed on receipt-store errors, and
|
||||
compensates a newly-created artifact when the transaction cannot commit.
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
id: "04-registry-catalog"
|
||||
title: "Publish canvas catalog entries"
|
||||
status: done
|
||||
wave: 4
|
||||
depends_on:
|
||||
- "03-reviewed-installation"
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-002
|
||||
- REQ-CANVASES-MARKETPLACE-004
|
||||
- REQ-CANVASES-MARKETPLACE-005
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
acceptance_criteria:
|
||||
- AC-CANVASES-MARKETPLACE-002.1
|
||||
- AC-CANVASES-MARKETPLACE-002.2
|
||||
- AC-CANVASES-MARKETPLACE-002.3
|
||||
- AC-CANVASES-MARKETPLACE-002.4
|
||||
- AC-CANVASES-MARKETPLACE-004.1
|
||||
- AC-CANVASES-MARKETPLACE-005.1
|
||||
- AC-CANVASES-MARKETPLACE-005.2
|
||||
- AC-CANVASES-MARKETPLACE-005.3
|
||||
- AC-CANVASES-MARKETPLACE-005.4
|
||||
- AC-CANVASES-MARKETPLACE-006.4
|
||||
system_design:
|
||||
- ../../specs/canvases/system-design/marketplace-sharing.md
|
||||
---
|
||||
|
||||
# Task 04: Publish canvas catalog entries
|
||||
|
||||
## Summary
|
||||
|
||||
Extend the existing repository registry and catalog with validated canvas entries
|
||||
and registry-owned preview URLs. Wire registry selection into the same reviewed
|
||||
installation service.
|
||||
|
||||
## In scope
|
||||
|
||||
- Optional pointer kind, exact release asset selection, production inspector,
|
||||
matching package/repository/version and required hash/source.
|
||||
- Shared `previews: [{url, alt}]` on official/custom canvas entries; preserve URL
|
||||
order into the generated index.
|
||||
- Additive catalog descriptor, kind filter, safe degraded-source behavior.
|
||||
- No package screenshot extraction, image fetching, or Pages media staging.
|
||||
- Per-workspace instance annotations after authorization and source-cache lookup.
|
||||
- Catalog source/ID/version/digest resolution for Task 03's prepare endpoint.
|
||||
- PR validation with read-only job permissions and no package code execution.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Submitting a real canvas registry entry, publishing this branch, changing native
|
||||
plugin package rules, a new catalog service, or automated repository creation.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Registry tests reject canvas listings without image URLs and packages without
|
||||
source, mismatched identity/version, ambiguous assets, or invalid archives.
|
||||
Package metadata/hash comes from the archive; images come from the registry.
|
||||
- Catalog preserves preview URL order independently of package versions; failed
|
||||
sources and old native entries remain
|
||||
compatible. Workspace annotations cannot leak through shared cache entries.
|
||||
- Catalog installation checks selected source/version/hash server-side and
|
||||
enters the existing review path. No production canvas executes during indexing.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
(cd apps/backend && rtk go build -o bin/canvas-package ./cmd/canvas-package)
|
||||
rtk bash -lc 'KANDEV_CANVAS_PACKAGE_INSPECTOR=apps/backend/bin/canvas-package node --test plugin-registry/build-index.test.mjs plugin-registry/canvas-index.test.mjs'
|
||||
(cd apps/backend && rtk go test -race ./internal/plugins/marketplace ./cmd/canvas-package -count=1)
|
||||
(cd apps/backend && rtk go test -race ./internal/plugins -run Marketplace -count=1)
|
||||
(cd apps/backend && rtk go test -race ./internal/backendapp -run 'TestCanvasInstall|TestCanvasDistribution' -count=1)
|
||||
rtk git diff --check
|
||||
```
|
||||
|
||||
The new Node test file uses local fixture responses and the built inspector.
|
||||
Do not run a publishing workflow or contact external repositories for test data.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `plugin-registry/schema.json`, `build-index.mjs`, `build-index.test.mjs`
|
||||
- `plugin-registry/canvas-index.mjs`, `canvas-index.test.mjs` (new)
|
||||
- `.github/workflows/plugin-registry-index.yml`
|
||||
- `apps/backend/internal/plugins/marketplace/types.go`, `catalog.go`
|
||||
- `apps/backend/internal/plugins/marketplace/canvas_catalog_test.go` (new)
|
||||
- `apps/backend/internal/plugins/marketplace_handlers.go`, handler tests
|
||||
- `apps/backend/internal/backendapp/canvas_distribution_routes.go` resolver wiring
|
||||
- Canvas receipt projection in `apps/backend/internal/canvas/repository.go`
|
||||
|
||||
## Dependencies
|
||||
|
||||
Tasks 01-03. The inspector must be available on the trusted registry base before
|
||||
accepting the first contributor canvas pointer; the feature PR itself only adds
|
||||
local test fixtures and runs candidate-code tests without publishing privileges.
|
||||
|
||||
## Risks
|
||||
|
||||
Do not parse nested canvas YAML with the current shallow regex helper. Never
|
||||
choose a source archive because it is the first tarball. Preserve native catalog
|
||||
semantics and ensure the built inspector is from trusted registry code when
|
||||
processing contributor pointers. Media/index deployment must stay coherent.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- Design: Registry publication, Catalog projection, Install preparation.
|
||||
- Proposed complete schema: `registry-entry.schema.json` beside this work order.
|
||||
- Existing `buildEntry`, `parseManifestFields`, `build-index.test.mjs`.
|
||||
- Existing marketplace catalog/source-store tests and Pages workflow.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented canvas registry entries, ordered shared previews, exact release
|
||||
asset inspection, archive digest enforcement, kind-aware catalog projection,
|
||||
degraded-source handling, and catalog installation resolution.
|
||||
|
||||
Verification: the registry build-index suite passed 11 tests, the proposed
|
||||
schema parsed successfully, the relevant marketplace/backend suite passed, and
|
||||
desktop/mobile marketplace E2E passed 2 tests total.
|
||||
|
||||
Review remediation: canvas catalog presentation now comes from the inspected
|
||||
archive descriptor, repository identity is checked against the registry
|
||||
pointer, asset inspection is streamed and time-bounded, and pull requests
|
||||
fail when a canvas entry is invalid instead of silently omitting it.
|
||||
@@ -0,0 +1,182 @@
|
||||
---
|
||||
id: "05-marketplace-ui"
|
||||
title: "Build canvas marketplace browsing"
|
||||
status: done
|
||||
wave: 5
|
||||
depends_on:
|
||||
- "04-registry-catalog"
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-002
|
||||
- REQ-CANVASES-MARKETPLACE-004
|
||||
- REQ-CANVASES-MARKETPLACE-005
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
acceptance_criteria:
|
||||
- AC-CANVASES-MARKETPLACE-002.3
|
||||
- AC-CANVASES-MARKETPLACE-004.1
|
||||
- AC-CANVASES-MARKETPLACE-004.2
|
||||
- AC-CANVASES-MARKETPLACE-004.3
|
||||
- AC-CANVASES-MARKETPLACE-004.4
|
||||
- AC-CANVASES-MARKETPLACE-004.5
|
||||
- AC-CANVASES-MARKETPLACE-004.6
|
||||
- AC-CANVASES-MARKETPLACE-005.2
|
||||
- AC-CANVASES-MARKETPLACE-005.3
|
||||
- AC-CANVASES-MARKETPLACE-005.4
|
||||
- AC-CANVASES-MARKETPLACE-006.1
|
||||
- AC-CANVASES-MARKETPLACE-006.2
|
||||
- AC-CANVASES-MARKETPLACE-006.3
|
||||
- AC-CANVASES-MARKETPLACE-006.4
|
||||
system_design:
|
||||
- ../../specs/canvases/system-design/marketplace-sharing.md
|
||||
---
|
||||
|
||||
# Task 05: Build canvas marketplace browsing
|
||||
|
||||
## Summary
|
||||
|
||||
Add the Canvases tab, visual details, and upload/link/catalog installation to
|
||||
Plugins settings. Use one review model across desktop and focused phone views.
|
||||
|
||||
## In scope
|
||||
|
||||
- Workspace selection, catalog cards with required registry cover, search/sort, instance
|
||||
actions, and Browse shared canvases from workspace settings.
|
||||
- Shared canvas gallery with explicit controls, descriptions, one-image mode, image errors,
|
||||
enlargement within details, and keyboard/focus handling.
|
||||
- Upload and direct-link forms, authoritative package/permission review,
|
||||
confirmation, progress/errors, retry, and installed Open canvas action.
|
||||
- Typed API client and domain hooks with stale-response invalidation.
|
||||
- Workspace-owner actions independent of native-plugin administrator gating.
|
||||
- Localized labels/statuses across the canvas catalog; desktop/mobile E2E.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Share/export author forms, canvas updates, and provider UI. Native plugin preview
|
||||
extension is covered by Task 08.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- UI-01/UI-02 support all three input paths through real inspection and explicit
|
||||
workspace permission approval, then show the installed canvas after reload.
|
||||
- Gallery, failure states, per-workspace copies, and late-response handling work
|
||||
without executing the canvas in details or leaking another workspace's data.
|
||||
- Phone composition, keyboard flow, actual touch targets, source outage,
|
||||
localization, and feature-off behavior pass the assigned rendered checks.
|
||||
|
||||
## ASCII UI preview
|
||||
|
||||
Excerpt of [UI-01/UI-02 in the plan](plan.md#ui-01-canvas-catalog).
|
||||
AC-CANVASES-MARKETPLACE-002.3, 004.1, 004.2, 005.2, 006.1, and 006.2.
|
||||
|
||||
```text
|
||||
Desktop
|
||||
Plugins: Installed | Browse | CANVASES
|
||||
Workspace [Project A v] Search [____] [Install canvas]
|
||||
[cover + card] [cover + card] -> View details
|
||||
+------------------------------------------------------+
|
||||
| [Back] Name / version / author |
|
||||
| [selected image] Description / license |
|
||||
| [Prev] 1/3 [Next] [thumbs] Required permissions |
|
||||
| Workspace [Project A v] [Review & install] |
|
||||
+------------------------------------------------------+
|
||||
|
||||
Phone details
|
||||
+------------------------------+
|
||||
| [Back] Name | fixed
|
||||
| [selected image] |
|
||||
| [Previous] 1/3 [Next] |
|
||||
| Description / author | single scroll
|
||||
| License / required version |
|
||||
| Read / Write / Events |
|
||||
| State / exact network hosts |
|
||||
| Workspace [Project A v] |
|
||||
| Package inspected |
|
||||
|------------------------------|
|
||||
| [Install in Project A] | fixed, safe-area
|
||||
+------------------------------+
|
||||
```
|
||||
|
||||
Upload/link opens final review without a gallery or screenshot requirement.
|
||||
Registry canvas listings require preview URLs; broken remote preview shows Retry
|
||||
without blocking installation. Inspecting is
|
||||
announced; stale/expired review requires review again; incompatibility disables
|
||||
confirm with its reason; success shows Open. Empty/degraded catalogs retain
|
||||
Install canvas. Phone catalog uses one-column cards. Copy/layout details are
|
||||
illustrative, action hierarchy and containment are required.
|
||||
|
||||
## Verification
|
||||
|
||||
Install dependencies once from `apps/` if not already installed. E2E fixtures
|
||||
must not skip on missing canvas readiness. Record screenshots/geometry results
|
||||
from the managed test artifacts and compare with UI-01/UI-02.
|
||||
|
||||
```bash
|
||||
(cd apps/web && rtk pnpm exec vitest run lib/api/domains/canvas-distribution-api.test.ts lib/api/domains/marketplace-api.test.ts hooks/domains/canvas/use-canvas-install.test.ts hooks/domains/plugins/use-marketplace.test.ts components/settings/plugins/canvas-marketplace.test.tsx components/settings/plugins/canvas-marketplace-detail.test.tsx components/settings/plugins/marketplace-preview-gallery.test.tsx components/settings/plugins/plugin-row.test.tsx components/settings/plugins/install-plugin-dialog.test.tsx)
|
||||
(cd apps/web && rtk pnpm run typecheck)
|
||||
(cd apps/web && rtk pnpm exec eslint components/settings/plugins lib/api/domains/canvas-distribution-api.ts lib/api/domains/marketplace-api.ts hooks/domains/canvas hooks/domains/plugins/use-marketplace.ts components/settings/workspace-canvases-page.tsx)
|
||||
(cd apps/web && rtk pnpm run i18n:check)
|
||||
(cd apps/web && rtk pnpm run i18n:ratchet)
|
||||
(cd apps/web && rtk pnpm e2e:run --project chromium tests/canvas/canvas-marketplace.spec.ts -- --retries=0)
|
||||
(cd apps/web && rtk pnpm e2e:run --project mobile-chrome tests/canvas/mobile-canvas-marketplace.spec.ts -- --retries=0)
|
||||
(cd apps/web && rtk pnpm e2e:run --project chromium tests/plugins/plugins.spec.ts -- --retries=0)
|
||||
(cd apps/web && rtk pnpm e2e:run --project mobile-chrome tests/plugins/mobile-plugin-settings-row.spec.ts -- --retries=0)
|
||||
rtk git diff --check
|
||||
```
|
||||
|
||||
Create `install-plugin-dialog.test.tsx` only for the native compatibility cases
|
||||
affected by shared entry controls; do not manufacture unrelated tests.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/web/components/settings/plugins/plugins-settings.tsx`
|
||||
- `apps/web/components/settings/plugins/marketplace-browser.tsx`
|
||||
- `apps/web/components/settings/plugins/canvas-marketplace.tsx`, `canvas-marketplace-detail.tsx` (new)
|
||||
- `apps/web/components/settings/plugins/canvas-install-dialog.tsx` (new)
|
||||
- Shared `marketplace-preview-gallery.tsx` (new), its focused unit tests, and
|
||||
canvas detail components
|
||||
- `apps/web/components/settings/workspace-canvases-page.tsx`
|
||||
- `apps/web/lib/api/domains/canvas-distribution-api.ts` and tests (new)
|
||||
- `apps/web/lib/api/domains/marketplace-api.ts` and tests
|
||||
- `apps/web/hooks/domains/canvas/use-canvas-install.ts` and tests (new)
|
||||
- `apps/web/hooks/domains/plugins/use-marketplace.ts` and tests
|
||||
- `apps/web/src/locales/{en,pt-pt,zh-cn,zh-hk,zh-tw,pseudo}/`
|
||||
- `apps/web/e2e/tests/canvas/canvas-marketplace.spec.ts`,
|
||||
`mobile-canvas-marketplace.spec.ts`, shared distribution fixtures (new)
|
||||
|
||||
## Dependencies
|
||||
|
||||
Tasks 01-04 provide real package/catalog/installation routes. Reuse existing
|
||||
canvas permission projections and the current native-plugin install dialog.
|
||||
|
||||
## Risks
|
||||
|
||||
Current plugin management controls are admin-gated; static workspace installs
|
||||
must not inherit that restriction or weaken native controls. Late package and
|
||||
workspace responses must not overwrite the review the user is confirming.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- Design: UI composition, Mobile contract, Catalog projection, Authorization.
|
||||
- Existing `PluginsSettings`, `InstallPluginDialog`, `MarketplaceBrowser`.
|
||||
- Existing canvas lifecycle review, `canvas-host-route.tsx`, `useResponsiveBreakpoint`.
|
||||
- Canvas registry preview contract and current canvas installation controls.
|
||||
- `apps/web/AGENTS.md`, /mobile-parity, /e2e, and existing canvas fixture tests.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented the Canvases marketplace tab, workspace selection, search/category/
|
||||
sort controls, registry cover cards, canvas preview gallery, detail/review
|
||||
surfaces, upload/direct-link/catalog installation entry points, and localized
|
||||
desktop/phone layouts with touch-sized controls. The optional native-plugin
|
||||
preview extension is recorded in Task 08.
|
||||
|
||||
Verification: 8 focused Vitest files passed 21 tests; web typecheck, full lint,
|
||||
i18n checks, and the new-code ratchet passed; desktop and mobile marketplace E2E
|
||||
passed.
|
||||
|
||||
Review remediation: every responsive install-dialog dismissal now cancels the
|
||||
staged review, including drawer and dialog outside-click or Escape handling.
|
||||
@@ -0,0 +1,173 @@
|
||||
---
|
||||
id: "06-sharing-ui"
|
||||
title: "Add canvas sharing controls"
|
||||
status: done
|
||||
wave: 6
|
||||
depends_on:
|
||||
- "05-marketplace-ui"
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-001
|
||||
- REQ-CANVASES-MARKETPLACE-002
|
||||
- REQ-CANVASES-MARKETPLACE-003
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
acceptance_criteria:
|
||||
- AC-CANVASES-MARKETPLACE-001.2
|
||||
- AC-CANVASES-MARKETPLACE-001.3
|
||||
- AC-CANVASES-MARKETPLACE-002.1
|
||||
- AC-CANVASES-MARKETPLACE-003.1
|
||||
- AC-CANVASES-MARKETPLACE-003.2
|
||||
- AC-CANVASES-MARKETPLACE-003.3
|
||||
- AC-CANVASES-MARKETPLACE-003.4
|
||||
- AC-CANVASES-MARKETPLACE-006.1
|
||||
- AC-CANVASES-MARKETPLACE-006.2
|
||||
- AC-CANVASES-MARKETPLACE-006.3
|
||||
- AC-CANVASES-MARKETPLACE-006.4
|
||||
system_design:
|
||||
- ../../specs/canvases/system-design/marketplace-sharing.md
|
||||
---
|
||||
|
||||
# Task 06: Add canvas sharing controls
|
||||
|
||||
## Summary
|
||||
|
||||
Expose bundle/source downloads and manual sharing instructions from published
|
||||
canvas host actions. Let authors prepare distribution metadata without changing the running canvas.
|
||||
Screenshots are provided later through registry URLs, never required for downloads.
|
||||
|
||||
## In scope
|
||||
|
||||
- Share entry in task/workspace host controls and workspace canvas rows.
|
||||
- Release-bound metadata/source form, validation, and temporary draft retention.
|
||||
No screenshot upload, reorder, required cover, or preview URL field.
|
||||
- Preparation, inventory, two downloads, expiry/stale-release recovery, cleanup.
|
||||
- Information dialog/drawer with manual repository/release/direct-link and
|
||||
registry-PR instructions, copyable safe examples, and no external mutations.
|
||||
- Shared domain hook, localized host copy, accessible desktop/phone E2E.
|
||||
- Export-to-import browser round trip with the real installer from Task 05.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Automatic screenshots, drag-only reordering, source editor, permanent publishing
|
||||
profiles, external account connection, remote repository/release/PR writes.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- UI-03 prepares matching bundle/source from the active release, without any
|
||||
screenshot requirement; invalid/stale/expired results retain inputs
|
||||
and cannot download silently substituted content.
|
||||
- UI-04 gives complete manual instructions and copyable registry examples
|
||||
without any external mutation; downloads remain usable without code-host auth.
|
||||
- Desktop/phone tests download both files, inspect their contents, import the
|
||||
bundle, and open the resulting independent canvas; help/back and gallery
|
||||
controls satisfy keyboard, localization, and touch geometry requirements.
|
||||
|
||||
## ASCII UI preview
|
||||
|
||||
Excerpt of [UI-03/UI-04 in the plan](plan.md#ui-03-share-canvas).
|
||||
AC-CANVASES-MARKETPLACE-001.3, 002.1, 003.1-003.4, and 006.1-006.3.
|
||||
|
||||
```text
|
||||
Desktop
|
||||
+-------------------------------------------------------------+
|
||||
| Share canvas [Close] |
|
||||
| Release / package ID / version / author / license |
|
||||
| Description / source mode |
|
||||
| [How to share] [Prepare downloads] |
|
||||
| Ready: file inventory, sizes, private-content reminder |
|
||||
| [Download bundle] [Download source] |
|
||||
+-------------------------------------------------------------+
|
||||
|
||||
Phone
|
||||
+------------------------------+
|
||||
| [Back] Share canvas | fixed
|
||||
| Metadata / source fields |
|
||||
| [How to share] | opens instruction drawer
|
||||
| File inventory / sizes |
|
||||
| Check for private content. |
|
||||
| [Download bundle] |
|
||||
| [Download source] |
|
||||
|------------------------------|
|
||||
| [Prepare downloads] | safe-area footer until ready
|
||||
+------------------------------+
|
||||
|
||||
Help drawer/dialog
|
||||
1. Download source and bundle
|
||||
2. Create repository; upload source
|
||||
3. Publish bundle; copy direct link
|
||||
4. Send link/file to another user
|
||||
Optional: add image URLs to the registry entry; request listing
|
||||
[Copy registry example] [Done]
|
||||
```
|
||||
|
||||
Screenshots are not an export input. Missing project source points
|
||||
to Edit and republish. One-column phone form has one scroll owner. The help
|
||||
drawer has its own bounded scroll only while it is active; closing restores
|
||||
focus/input state. Both downloads remain reachable after either completes.
|
||||
Current source/version changes invalidate prepared output. These structures
|
||||
are required; sample labels and spacing are illustrative.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
(cd apps/web && rtk pnpm exec vitest run hooks/domains/canvas/use-canvas-share.test.ts components/settings/canvas-share-dialog.test.tsx components/settings/canvas-share-help.test.tsx components/settings/canvas-host-components.test.tsx components/settings/workspace-canvases-page.test.tsx lib/api/domains/canvas-distribution-api.test.ts)
|
||||
(cd apps/web && rtk pnpm run typecheck)
|
||||
(cd apps/web && rtk pnpm exec eslint components/settings/canvas-share-dialog.tsx components/settings/canvas-share-help.tsx components/settings/canvas-host-components.tsx components/settings/workspace-canvases-page.tsx hooks/domains/canvas lib/api/domains/canvas-distribution-api.ts)
|
||||
(cd apps/web && rtk pnpm run i18n:check)
|
||||
(cd apps/web && rtk pnpm run i18n:ratchet)
|
||||
(cd apps/web && rtk pnpm e2e:run --project chromium tests/canvas/canvas-sharing.spec.ts -- --retries=0)
|
||||
(cd apps/web && rtk pnpm e2e:run --project mobile-chrome tests/canvas/mobile-canvas-sharing.spec.ts -- --retries=0)
|
||||
rtk git diff --check
|
||||
```
|
||||
|
||||
Use file/download fixtures and browser geometry; no external hosting credentials.
|
||||
Generate Traditional Chinese/pseudo catalogs through the repository generators
|
||||
during implementation, then run the checks above.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/web/components/settings/canvas-share-dialog.tsx`, tests (new)
|
||||
- `apps/web/components/settings/canvas-share-help.tsx`, tests (new)
|
||||
- `apps/web/hooks/domains/canvas/use-canvas-share.ts`, tests (new)
|
||||
- `apps/web/components/settings/canvas-host-components.tsx`, host route/wrappers
|
||||
- `apps/web/components/settings/workspace-canvases-page.tsx`
|
||||
- `apps/web/lib/api/domains/canvas-distribution-api.ts`, tests
|
||||
- All real locales and generated pseudo catalog
|
||||
- `apps/web/e2e/tests/canvas/canvas-sharing.spec.ts`,
|
||||
`mobile-canvas-sharing.spec.ts`, shared distribution fixtures (new)
|
||||
|
||||
## Dependencies
|
||||
|
||||
Tasks 01-05, especially export endpoints and the real bundle import UI.
|
||||
|
||||
## Risks
|
||||
|
||||
Exported application files can contain private data. The UI must
|
||||
show the inventory/review notice without claiming automated sanitization.
|
||||
Do not auto-invalidate source downloads by dismissing the form after the first
|
||||
download. Download and clipboard browser fallbacks must work in current host
|
||||
environments. Keep instructions about GitHub registry versus other-host links clear.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- Design: Export preparation, HTTP contracts, UI composition, Mobile contract.
|
||||
- Existing host lifecycle action drawer and shared copy/download helpers.
|
||||
- Plan UI-03/UI-04 and the /e2e fixture/cleanup guidance.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented host and workspace-row Share actions, responsive share dialog/drawer,
|
||||
release-bound bundle/source preparation and downloads, private-content review
|
||||
notice, and manual repository/release/registry instructions. Sharing accepts no
|
||||
screenshot input and keeps previews separate from package permissions.
|
||||
|
||||
Verification: the focused frontend suite passed 21 tests, desktop sharing E2E
|
||||
passed, mobile sharing E2E passed, and the export/preparation backend race tests
|
||||
passed 3 tests.
|
||||
|
||||
Review remediation: share-dialog dismissal now cancels prepared exports, and
|
||||
stale asynchronous downloads cannot overwrite the current dialog state.
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
id: "07-distribution-docs"
|
||||
title: "Document canvas distribution"
|
||||
status: done
|
||||
wave: 7
|
||||
depends_on:
|
||||
- "06-sharing-ui"
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-002
|
||||
- REQ-CANVASES-MARKETPLACE-005
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
acceptance_criteria:
|
||||
- AC-CANVASES-MARKETPLACE-002.1
|
||||
- AC-CANVASES-MARKETPLACE-002.4
|
||||
- AC-CANVASES-MARKETPLACE-005.1
|
||||
- AC-CANVASES-MARKETPLACE-005.3
|
||||
- AC-CANVASES-MARKETPLACE-006.4
|
||||
system_design:
|
||||
- ../../specs/canvases/system-design/marketplace-sharing.md
|
||||
---
|
||||
|
||||
# Task 07: Document canvas distribution
|
||||
|
||||
## Summary
|
||||
|
||||
Document the implemented canvas package, sharing, installation, and registry
|
||||
workflow. Keep public guides, registry instructions, and the embedded authoring
|
||||
reference consistent with the shipped contract and UI helper.
|
||||
|
||||
## In scope
|
||||
|
||||
- Public canvas how-to: screenshot-free downloads, file/link/registry
|
||||
installation, permissions, independent copies, source modes, failure recovery.
|
||||
- Canvas registry README examples. Previews belong to registry entries, not
|
||||
canvas package manifests.
|
||||
- Manual GitHub repository/release/listing instructions; generic GitLab/Bitbucket
|
||||
bundle-hosting instructions that do not imply official registry support.
|
||||
- Embedded authoring guide for retained source, screenshot-free distribution
|
||||
compatibility, and bounded files; preserve core inventory/read count.
|
||||
- Scoped engineering-guide updates only where implementation changes conventions.
|
||||
- Synchronize the new package's results/status and link related designs after
|
||||
each assigned check passes. Preserve older packages' recorded evidence.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Publishing docs to another repository, submitting a registry entry, creating
|
||||
a remote repository, adding generated promotional images, or a generic QA audit.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- A reader can follow one complete manual export-to-repository-to-registry path,
|
||||
and can alternatively send a bundle file/direct URL without registry admission.
|
||||
- Package examples match the production inspector, source and permissions.
|
||||
Registry examples show required canvas image URLs, including custom sources;
|
||||
docs never require images for bundle creation.
|
||||
- Public/embedded references, UI helper steps, and implemented contract agree;
|
||||
documentation validators and authoring inventory tests pass.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
rtk proxy node --test scripts/validate-public-docs.test.mjs
|
||||
rtk proxy node scripts/validate-public-docs.mjs
|
||||
(cd apps/backend && rtk go test ./internal/mcp/canvasskill ./cmd/canvas-package -count=1)
|
||||
(cd apps/web && rtk pnpm exec vitest run components/settings/canvas-share-help.test.tsx)
|
||||
rtk proxy python3 scripts/lint-spec-files.test.py
|
||||
rtk proxy python3 scripts/lint-spec-files.py --all
|
||||
rtk git diff --check -- docs plugin-registry/README.md apps/backend/internal/mcp/canvasskill
|
||||
```
|
||||
|
||||
Validate documented package examples through inspector fixtures; do not publish
|
||||
anything to prove documentation. Re-run UI E2E only if helper behavior or other
|
||||
rendered UI changed in this task.
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `docs/public/canvases.md` (how-to)
|
||||
- Canvas sections of `plugin-registry/README.md`
|
||||
- `apps/backend/internal/mcp/canvasskill/files/SKILL.md`,
|
||||
`references/manifest.md`, `references/security.md`, inventory tests as needed
|
||||
- `apps/backend/AGENTS.md`, `apps/web/AGENTS.md` if new conventions need recording
|
||||
- `docs/specs/canvases/`, this plan/work orders
|
||||
- Audit root `README.md` and `docs/screenshots.md`; change only stale descriptions.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Tasks 01-06 and their exact recorded results.
|
||||
|
||||
## Risks
|
||||
|
||||
Do not document proposed behavior as shipped before implementation. Existing
|
||||
source download means the retained project, not a reconstruction of missing
|
||||
build inputs. The official registry uses GitHub releases; host-neutral manual
|
||||
sharing does not broaden that registry contract.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- All six requirements and the final system design.
|
||||
- /docs-maintainer and the public-document validation guide.
|
||||
- Current registry README, public canvas page, and UI-04 instructions.
|
||||
- Existing canvas authoring core/scaffold inventory tests.
|
||||
|
||||
## Results
|
||||
|
||||
Updated the public canvas and authoring guides, the canvas portions of the
|
||||
registry README, and the embedded authoring references. The documentation keeps
|
||||
screenshots as registry metadata and documents screenshot-free sharing, source
|
||||
modes, permissions, manual publication, and direct installation.
|
||||
|
||||
Verification: public-doc tests passed 62 tests and validated 46 published docs;
|
||||
specification lint passed; the embedded authoring skill suite passed 7 tests;
|
||||
and diff/whitespace checks passed.
|
||||
@@ -176,6 +176,45 @@ Kandev allows up to 100 workspace canvas instances across scopes. Archived canva
|
||||
|
||||
On desktop, workspace canvases use the workspace Canvases area. On phones, Kandev opens a full-height canvas route and keeps canvas controls in an inset bottom drawer.
|
||||
|
||||
## Share and install a canvas
|
||||
|
||||
Canvas sharing is manual and release-bound. It does not capture screenshots or
|
||||
publish a repository. Screenshots belong to a marketplace registry entry, not
|
||||
to the canvas package.
|
||||
|
||||
1. Open the canvas host or the workspace canvas list.
|
||||
2. Choose **Share canvas**.
|
||||
3. Review the active release, package identity, file inventory, and archive
|
||||
sizes.
|
||||
4. Choose **Prepare downloads**, then download the bundle or source archive.
|
||||
5. Check the downloaded files for private content before sharing them.
|
||||
|
||||
The bundle is an installable `.tar.gz`. The source download is a ZIP of the
|
||||
retained project when the release uses project source mode. The preparation is
|
||||
temporary and expires after 15 minutes. A release change, lost authorization,
|
||||
expiry, or cancellation requires a new preparation. Kandev does not change the
|
||||
running canvas while it prepares these files.
|
||||
|
||||
Recipients can install a bundle from **Settings > Plugins > Canvases** by
|
||||
uploading the file or entering an HTTPS direct link. A registry entry provides
|
||||
an additional catalog path. Kandev fetches and inspects the exact package,
|
||||
shows its manifest and permissions, and requires an explicit confirmation
|
||||
before it creates an independent workspace canvas. A registry preview is only
|
||||
listing metadata. It does not grant permissions and it is not executed during
|
||||
review.
|
||||
|
||||
Canvas registry entries use the same ordered `previews` field as plugin
|
||||
entries. A canvas entry must contain one to eight objects with an HTTPS `url`
|
||||
and non-empty `alt` text. The first object is the cover image. Plugin entries
|
||||
may omit `previews` or include up to eight images. Use **Preview images** in the
|
||||
catalog to move between images and retry a failed image.
|
||||
|
||||
The official registry uses a manually reviewed pull request. Authors publish a
|
||||
versioned bundle as a release asset, add the repository and preview URLs to
|
||||
`plugin-registry/plugins.yaml`, and wait for the registry workflow to inspect
|
||||
the exact asset. Team registries can host an `index.json` with the same shape.
|
||||
Direct file and direct-link sharing does not require registry admission.
|
||||
|
||||
## Related guides
|
||||
|
||||
- [Plugin manifest reference](plugins-manifest.md#isolated-web-applications) defines the `ui.web_apps` manifest fields.
|
||||
|
||||
@@ -172,6 +172,24 @@ Build and test the archive outside Kandev. Kandev validates the archive before
|
||||
it stores or runs a release. Use [Agent-authored Canvases](canvases.md) for
|
||||
creation, permission review, promotion, Quick Chat editing, and recovery.
|
||||
|
||||
### Share a portable canvas
|
||||
|
||||
For a canvas that another workspace can install, add the `distribution` block
|
||||
described in the [manifest reference](plugins-manifest.md#portable-canvas-distribution-metadata).
|
||||
Choose `static` when the packaged application is the only source you want to
|
||||
share. Choose `project` when you retain a bounded editable project under
|
||||
`distribution/source/`. Do not put screenshots in the package.
|
||||
|
||||
After a valid release is active, use **Share canvas** in the host or workspace
|
||||
canvas list. Prepare and download the bundle and source archive, inspect them
|
||||
for private content, and share them as files or HTTPS links. This action does
|
||||
not create a repository, release, registry entry, or pull request.
|
||||
|
||||
To list the canvas, publish the exact bundle as a versioned release asset and
|
||||
add a `kind: canvas` entry with one to eight ordered `previews` objects to a
|
||||
trusted registry. The first preview is the cover. Preview URLs and alt text
|
||||
are registry metadata and are not part of the package manifest.
|
||||
|
||||
There is no separate HTTP server to launch. pluginsdk.Serve owns the
|
||||
go-plugin/gRPC handshake and Host injection. The backend implements
|
||||
pluginsdk.Plugin (OnEvent and/or HandleWebhook) and embeds
|
||||
|
||||
@@ -274,6 +274,31 @@ from the browser. The host tears down the app iframe immediately after a
|
||||
release, grant, scope, archive, disable, or removal authority change, then
|
||||
requires a fresh runtime binding before mounting it again.
|
||||
|
||||
### Portable canvas distribution metadata
|
||||
|
||||
A portable canvas adds a `distribution` block to the manifest. This block is
|
||||
package metadata. It does not contain registry screenshots, repository
|
||||
publication settings, credentials, or a live application URL.
|
||||
|
||||
```yaml
|
||||
distribution:
|
||||
schema_version: 1
|
||||
kind: canvas
|
||||
license: MIT
|
||||
source_mode: static # static or project
|
||||
```
|
||||
|
||||
The distribution validator requires one static web app with a
|
||||
`workspace-canvas` placement, a compatible `min_kandev_version`, a license,
|
||||
`README.md`, and generated `checksums.txt`. It rejects native UI, managed
|
||||
backend, actions, webhooks, tools, repository providers, and other plugin
|
||||
contributions in the same distribution. `static` source mode keeps only the
|
||||
application package. `project` source mode also retains the bounded editable
|
||||
project below `distribution/source/`, including its own manifest and README.
|
||||
|
||||
Registry preview images belong to `plugin-registry/plugins.yaml` or another
|
||||
source's `index.json`. Do not add a `previews` field to `manifest.yaml`.
|
||||
|
||||
## Managed vs. legacy manifests
|
||||
|
||||
Setting `runtime.type: binary` makes a manifest **runtime-managed**: kandev
|
||||
|
||||
@@ -41,6 +41,12 @@ sidebar.
|
||||
Uninstall and an **Update** button when a newer version is available.
|
||||
- **Browse**: the merged catalog across all enabled sources.
|
||||
|
||||
When canvases are enabled, a **Canvases** tab appears beside these tabs. It
|
||||
uses the same configured sources but keeps canvas installation separate from
|
||||
native plugin installation. Canvas installation is workspace-scoped and is
|
||||
available to an authorized workspace user. Native plugin management remains
|
||||
administrator-scoped.
|
||||
|
||||
### Browse and install
|
||||
|
||||
Open **Settings > Plugins > Browse**. Each plugin shows as a card with its
|
||||
@@ -70,6 +76,25 @@ Plugin-provided icons render on the cards. A plugin that ships an icon (via the
|
||||
manifest's `icon` field) shows it; otherwise the card falls back to a neutral
|
||||
letter tile.
|
||||
|
||||
### Browse and install canvases
|
||||
|
||||
Open **Settings > Plugins > Canvases** after the canvas feature is enabled.
|
||||
Choose the target workspace, then search, filter, and sort the catalog. The
|
||||
first registry preview is the cover. Open a card to review its ordered preview
|
||||
gallery, author, license, compatibility, repository, and declared permissions.
|
||||
Use **Review and install** to inspect the exact package before confirmation.
|
||||
|
||||
The install dialog also accepts a local `.tar.gz` upload or an HTTPS direct
|
||||
link. These paths do not need a registry listing or preview images. All three
|
||||
paths inspect the package and show permissions before creating a new workspace
|
||||
canvas. A successful install shows **Open canvas**. A failed or expired review
|
||||
must be reviewed again and cannot silently install different bytes.
|
||||
|
||||
Registry previews are remote listing metadata. Kandev does not execute an image
|
||||
or canvas application in the detail view, and preview URLs are not package
|
||||
permissions. A broken image has a placeholder and **Retry**; it does not block
|
||||
package inspection or installation.
|
||||
|
||||
### Keep plugins updated
|
||||
|
||||
Every row on the **Installed** tab shows the plugin's latest known marketplace
|
||||
|
||||
@@ -11,12 +11,24 @@ last_updated: 2026-09-10
|
||||
|
||||
Canvases own agent-authored task applications and their promotion to workspace
|
||||
applications. The system owns canvas scope, source lineage, release selection,
|
||||
editing sessions, and discovery.
|
||||
editing sessions, discovery, and portable canvas distribution.
|
||||
|
||||
The Plugins system owns the isolated web-application runtime, permissions,
|
||||
Kandev data access, state, events, and package validation. The task system
|
||||
remains authoritative for task data and permissions.
|
||||
|
||||
## Requirements
|
||||
|
||||
- [Agent-authored web-app canvases](requirements/agent-authored-web-apps.md)
|
||||
- [Canvas marketplace and sharing](requirements/marketplace-sharing.md)
|
||||
- [Deprecated collaborative canvases](requirements/collaborative-canvases.md)
|
||||
|
||||
## System design
|
||||
|
||||
- [Agent-authored web-app canvases](system-design/agent-authored-web-apps.md)
|
||||
- [Canvas marketplace and sharing](system-design/marketplace-sharing.md)
|
||||
- [Superseded collaborative canvases](system-design/collaborative-canvases.md)
|
||||
|
||||
## Related context
|
||||
|
||||
- [Runtime and permission fix plan](../../plans/canvas-runtime-permission-fixes/plan.md)
|
||||
@@ -26,4 +38,5 @@ remains authoritative for task data and permissions.
|
||||
- [Plugin-backed web-app canvases decision](../../decisions/2026-08-26-plugin-backed-web-app-canvases.md)
|
||||
- [Plugin-backed canvases implementation plan](../../plans/plugin-backed-canvases/plan.md)
|
||||
- [Canvas UX follow-up implementation plan](../../plans/plugin-backed-canvases-ux-follow-up/plan.md)
|
||||
- [Canvas marketplace implementation plan](../../plans/canvas-marketplace/plan.md)
|
||||
- [Historical declarative canvas plan](../../plans/collaborative-canvases/plan.md)
|
||||
|
||||
@@ -25,8 +25,9 @@ web-application runtime and its data contract.
|
||||
|
||||
- **Task canvas:** A canvas that belongs to one task and appears only in that
|
||||
task.
|
||||
- **Workspace canvas:** A promoted canvas that belongs to one workspace and
|
||||
appears in workspace navigation.
|
||||
- **Workspace canvas:** A canvas that belongs to one workspace and appears in
|
||||
workspace navigation. Agent-authored canvases reach this scope by promotion;
|
||||
[distribution](marketplace-sharing.md) also defines reviewed package installs.
|
||||
- **Draft:** Editable canvas source in an authorized agent workspace.
|
||||
- **Release:** An immutable package that passed validation.
|
||||
- **Promotion:** A user action that changes a task canvas to workspace scope.
|
||||
@@ -321,7 +322,9 @@ including missing references, lookup failures, and passthrough exclusions.
|
||||
- A direct source-code editor in Kandev.
|
||||
- Canvas invitations, collaborator roles, or multi-user live editing.
|
||||
- Demotion from workspace scope to task scope.
|
||||
- A marketplace or cross-instance package import flow.
|
||||
- Automatic permission increases after owner-authorized first publication.
|
||||
- Marketplace and cross-instance distribution are owned by the separate
|
||||
[marketplace and sharing requirements](marketplace-sharing.md).
|
||||
- Automatic permission increases after owner-authorized first publication or
|
||||
automatic publication of a release that requests new permissions.
|
||||
- General top-bar, sidebar-widget, or arbitrary-slot plugin contributions.
|
||||
- A custom server-side runtime for agent-generated backend code.
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
status: draft
|
||||
system: canvases
|
||||
created: 2026-09-10
|
||||
owners:
|
||||
- canvases
|
||||
---
|
||||
|
||||
# Canvas marketplace and sharing requirements
|
||||
|
||||
## Overview
|
||||
|
||||
Users distribute a reusable canvas, discover it in Settings > Plugins, and
|
||||
install a private instance in their workspace. Canvases owns this vertical
|
||||
contract because it owns canvas identity, source lineage, scope, and discovery.
|
||||
Plugins supplies the existing catalog, manifest, validation, and isolated runtime.
|
||||
|
||||
This is the first distribution version. Sharing uses downloads and instructions;
|
||||
Kandev does not create repositories or publish external releases for the user.
|
||||
|
||||
## Terminology
|
||||
|
||||
- **Bundle:** A versioned, installable archive containing a canvas application,
|
||||
editable source and distribution metadata. Registry previews are separate.
|
||||
- **Source download:** A project archive for inspecting, editing, and putting
|
||||
the same application in a repository. It includes build inputs when needed.
|
||||
- **Instance:** One installed canvas with its own workspace, grants, and state.
|
||||
- **Cover:** The first screenshot in the author's ordered image list.
|
||||
- **Registry:** The curated repository list in the Kandev repository that feeds
|
||||
the existing marketplace.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-CANVASES-MARKETPLACE-001: Portable canvas distribution
|
||||
|
||||
**Intent:** A recipient can run and edit a shared canvas without its creator's
|
||||
task, executor, or workspace.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-CANVASES-MARKETPLACE-001.1:** A valid bundle shall contain the application,
|
||||
required local assets, editable source, identity, version, author, description,
|
||||
license information, and declared permissions. Installation shall require no
|
||||
build, package manager, agent, or author-side service.
|
||||
- **AC-CANVASES-MARKETPLACE-001.2:** Downloaded source shall match the selected
|
||||
published release. For a build-based application, it shall include build
|
||||
inputs, dependency declarations, lockfiles, and documented build instructions.
|
||||
For a no-build application, its HTML, CSS, and JavaScript are its source.
|
||||
- **AC-CANVASES-MARKETPLACE-001.3:** Exports shall exclude Kandev instance state,
|
||||
grants, runtime tokens, workspace bindings, task history, dependency caches,
|
||||
and repository history. The author shall see the file inventory and a notice
|
||||
to inspect exported files for embedded private content.
|
||||
- **AC-CANVASES-MARKETPLACE-001.4:** Invalid, oversized, incompatible, incomplete,
|
||||
or unsafe packages shall be rejected before execution. Category labels shall
|
||||
not allow a managed binary or native frontend contribution to run as a canvas.
|
||||
|
||||
### REQ-CANVASES-MARKETPLACE-002: Screenshot presentation
|
||||
|
||||
**Intent:** Recipients can inspect the canvas interface before installing it.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-CANVASES-MARKETPLACE-002.1:** Canvas listings in the official registry
|
||||
or a custom marketplace registry shall require one to eight preview image
|
||||
URLs. Bundle creation, source downloads, upload/link installation, private
|
||||
canvases, and agent drafts shall not require screenshots.
|
||||
- **AC-CANVASES-MARKETPLACE-002.2:** Registry maintainers shall be able to supply,
|
||||
reorder, remove, and describe preview URLs in the listing. The first image
|
||||
shall be its cover. Changes shall not require rebuilding the canvas bundle.
|
||||
- **AC-CANVASES-MARKETPLACE-002.3:** Canvas registry cards shall show the cover;
|
||||
details shall show all listed images in order with descriptions, position,
|
||||
and explicit previous/next controls. A single image shall hide unnecessary
|
||||
navigation. Failed images shall not hide permissions or block installation.
|
||||
- **AC-CANVASES-MARKETPLACE-002.4:** Preview URLs shall use absolute HTTPS
|
||||
addresses without credentials or fragments, with nonempty alternative text.
|
||||
Invalid URL/list metadata shall fail registry validation. Images shall render
|
||||
without executing package code. Unlisted bundle reviews shall work without
|
||||
any gallery.
|
||||
|
||||
### REQ-CANVASES-MARKETPLACE-003: Share downloads and guidance
|
||||
|
||||
**Intent:** Authors can share a canvas without connecting a code-host account.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-CANVASES-MARKETPLACE-003.1:** An authorized user shall be able to open
|
||||
Share from a task or workspace canvas with an available active release,
|
||||
review its metadata and files, and download both its bundle and source.
|
||||
Both downloads shall describe the same prepared version.
|
||||
- **AC-CANVASES-MARKETPLACE-003.2:** Preparation shall report missing source,
|
||||
invalid metadata, or unavailable release files with recovery
|
||||
guidance. A new active release or edited share input shall require preparation
|
||||
again before download. No export shall silently substitute another release.
|
||||
- **AC-CANVASES-MARKETPLACE-003.3:** Share shall include an information dialog
|
||||
explaining how to create a repository, upload the source, publish the bundle,
|
||||
share its direct download URL or file, and request registry inclusion through
|
||||
a pull request to Kandev. Instructions shall distinguish publishing a package
|
||||
from acceptance into the curated marketplace.
|
||||
- **AC-CANVASES-MARKETPLACE-003.4:** Downloading or reading instructions shall not
|
||||
create a repository, push code, publish a release, submit a pull request, or
|
||||
share the author's live canvas instance. Closing or retrying shall preserve
|
||||
the canvas and its active release.
|
||||
|
||||
### REQ-CANVASES-MARKETPLACE-004: Reviewed workspace installation
|
||||
|
||||
**Intent:** Users know what they install and which workspace it can access.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-CANVASES-MARKETPLACE-004.1:** Settings > Plugins shall expose a dedicated
|
||||
Canvases section with installation by bundle upload and direct bundle link.
|
||||
Registry entries shall enter the same installation review from their details.
|
||||
- **AC-CANVASES-MARKETPLACE-004.2:** Before confirmation, users shall see package
|
||||
identity, author, version, description, license, compatibility,
|
||||
destination workspace, and all requested read, write, event, state, and exact
|
||||
network-origin permissions. Registry installs shall also show listing previews.
|
||||
Empty permission groups shall be stated clearly.
|
||||
- **AC-CANVASES-MARKETPLACE-004.3:** Confirmation shall install the exact reviewed
|
||||
bytes and approved declaration in an authorized workspace. A changed package,
|
||||
expired review, revoked access, quota failure, or invalid workspace shall
|
||||
prevent installation and leave existing canvases and grants unchanged.
|
||||
- **AC-CANVASES-MARKETPLACE-004.4:** Successful installation shall create a new
|
||||
workspace canvas with empty instance state and new grants, show Open canvas,
|
||||
and appear in workspace canvas navigation after reload. It shall preserve
|
||||
package version and provenance across backend restart.
|
||||
- **AC-CANVASES-MARKETPLACE-004.5:** Installing the same package intentionally
|
||||
again shall create an independent copy. Retrying the same confirmation shall
|
||||
not create duplicates. Existing copies shall never be overwritten or updated
|
||||
automatically, including after local edits.
|
||||
- **AC-CANVASES-MARKETPLACE-004.6:** Workspace owners shall be able to install
|
||||
static canvases in their own workspaces without native-plugin administrator
|
||||
authority. Native plugin installation and registry-source administration shall
|
||||
retain their current authorization requirements.
|
||||
|
||||
### REQ-CANVASES-MARKETPLACE-005: Curated marketplace discovery
|
||||
|
||||
**Intent:** Authors list their repositories through the existing Kandev registry.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-CANVASES-MARKETPLACE-005.1:** An author shall be able to submit a canvas
|
||||
repository to the existing registry list in Kandev. Admission shall require
|
||||
a valid versioned bundle, matching repository/package identity, required
|
||||
registry preview URLs, source, and permission metadata. Listing shall require maintainer
|
||||
acceptance and successful catalog publication.
|
||||
- **AC-CANVASES-MARKETPLACE-005.2:** Users shall find listed canvases through
|
||||
search and existing catalog sorting, open details, inspect images and
|
||||
permissions, and install without copying a URL. Native plugin entries shall
|
||||
retain their current install behavior.
|
||||
- **AC-CANVASES-MARKETPLACE-005.3:** Package details shall identify the selected
|
||||
version; previews shall come from that registry listing and shall not be used
|
||||
as permission or integrity evidence. Installation shall verify the catalog's
|
||||
expected package digest. A mismatch shall fail before a canvas is created.
|
||||
- **AC-CANVASES-MARKETPLACE-005.4:** A failed catalog source shall show a degraded
|
||||
state without blocking healthy sources or upload/link installation. Installed
|
||||
canvas badges and Open actions shall disclose only the selected authorized
|
||||
workspace's instances.
|
||||
|
||||
### REQ-CANVASES-MARKETPLACE-006: Accessible delivery and compatibility
|
||||
|
||||
**Intent:** Desktop and phone users can complete the same sharing and discovery
|
||||
flows without weakening existing canvas isolation or feature controls.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-CANVASES-MARKETPLACE-006.1:** On desktop and phones, users shall complete
|
||||
upload/link installation, registry discovery, permission review, image
|
||||
navigation, both downloads, and repository guidance. Required actions shall
|
||||
be visible and accessible without hover, drag-and-drop, or swipe alone.
|
||||
- **AC-CANVASES-MARKETPLACE-006.2:** Phone details and sharing shall use focused
|
||||
full-height surfaces with one content scroll owner, safe-area clearance,
|
||||
touch targets of at least 44 CSS pixels, and no document horizontal overflow.
|
||||
Keyboard users shall have predictable focus, dismissal, and image navigation.
|
||||
- **AC-CANVASES-MARKETPLACE-006.3:** Host copy and errors shall use the selected
|
||||
locale. Author descriptions, image descriptions, and identifiers shall remain
|
||||
author data. Loading, preparation, failure, and success shall be announced.
|
||||
- **AC-CANVASES-MARKETPLACE-006.4:** With canvases disabled, new canvas routes,
|
||||
actions, catalog entries, preparation, downloads, and installation shall be
|
||||
unavailable. Ordinary plugin behavior shall remain available according to its
|
||||
existing gate. Existing private canvas releases shall need no migration or
|
||||
screenshot backfill to run.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Repository-URL installation, Git cloning, or install-time builds.
|
||||
- Automated GitHub, GitLab, or Bitbucket repository/release/PR creation.
|
||||
- New code-host integrations, private-host authentication, or hosted sharing.
|
||||
- Public live-instance links, state export, credentials, or data migration.
|
||||
- Automatic screenshots, image editing, ratings, payments, or usage telemetry.
|
||||
- Automatic canvas updates, replacement installs, or upstream merge tooling.
|
||||
- A new plugin runtime, native binary canvases, or a standalone marketplace site.
|
||||
- Changing existing runtime flag identities or shipped defaults.
|
||||
|
||||
## Related records
|
||||
|
||||
- [System design](../system-design/marketplace-sharing.md)
|
||||
- [Implementation plan](../../../plans/canvas-marketplace/plan.md)
|
||||
- [Existing canvas lifecycle](agent-authored-web-apps.md)
|
||||
@@ -32,8 +32,8 @@ The Plugins system owns package validation, iframe isolation, data access,
|
||||
state, events, grants, and runtime tokens. This design uses
|
||||
[the isolated plugin web-application contract](../../plugins/system-design/isolated-web-app-contributions.md).
|
||||
|
||||
This design supersedes
|
||||
[the declarative canvas design](collaborative-canvases.md).
|
||||
See [declarative canvas](collaborative-canvases.md) and
|
||||
[marketplace sharing](marketplace-sharing.md).
|
||||
|
||||
## Requirement mapping
|
||||
|
||||
|
||||
@@ -0,0 +1,487 @@
|
||||
---
|
||||
status: draft
|
||||
system: canvases
|
||||
created: 2026-09-10
|
||||
owners:
|
||||
- canvases
|
||||
requirements:
|
||||
- REQ-CANVASES-MARKETPLACE-001
|
||||
- REQ-CANVASES-MARKETPLACE-002
|
||||
- REQ-CANVASES-MARKETPLACE-003
|
||||
- REQ-CANVASES-MARKETPLACE-004
|
||||
- REQ-CANVASES-MARKETPLACE-005
|
||||
- REQ-CANVASES-MARKETPLACE-006
|
||||
---
|
||||
|
||||
# Canvas marketplace and sharing system design
|
||||
|
||||
## Purpose and boundaries
|
||||
|
||||
Canvases owns distribution of reusable canvas applications and creation of
|
||||
workspace instances. This is one vertical contract, including Settings >
|
||||
Plugins presentation. Plugins continues to own the manifest, static validator,
|
||||
runtime, release artifacts, grants, and catalog machinery.
|
||||
|
||||
Reuse the [plugin-backed canvas decision](../../../decisions/2026-08-26-plugin-backed-web-app-canvases.md).
|
||||
No new runtime or independent marketplace is introduced. The rationale for
|
||||
this additive distribution profile fits this design; a separate ADR is not
|
||||
needed. The [existing lifecycle](agent-authored-web-apps.md) still owns authoring,
|
||||
promotion, editing, rollback, and deletion. The
|
||||
[plugin web-app contract](../../plugins/system-design/isolated-web-app-contributions.md)
|
||||
owns runtime isolation. This document adds portable distribution to both.
|
||||
|
||||
## Requirement mapping
|
||||
|
||||
| Requirement | Design sections |
|
||||
| --- | --- |
|
||||
| REQ-CANVASES-MARKETPLACE-001 | Package profile; Source retention; Validation |
|
||||
| REQ-CANVASES-MARKETPLACE-002 | Registry previews; UI |
|
||||
| REQ-CANVASES-MARKETPLACE-003 | Export preparation; HTTP contracts; Guidance |
|
||||
| REQ-CANVASES-MARKETPLACE-004 | Install preparation; Commit; Authorization |
|
||||
| REQ-CANVASES-MARKETPLACE-005 | Registry; Catalog projection; Failure handling |
|
||||
| REQ-CANVASES-MARKETPLACE-006 | UI; Mobile contract; Feature gates; Verification |
|
||||
|
||||
## Existing implementation and additive changes
|
||||
|
||||
- `internal/plugins/manifest.Manifest` already supports isolated `ui.web_apps`.
|
||||
`IsStaticWebAppOnly` identifies the static runtime form, but the distribution
|
||||
validator must also reject every non-canvas contribution and managed field.
|
||||
- `internal/plugins/pkgtar.validateInstallManifest` requires a managed binary.
|
||||
Leave its native installation path intact. Canvas installs use
|
||||
`internal/plugins/webapp.ValidatePackage` with an additional distribution
|
||||
profile; a category is never permission to call the native installer.
|
||||
- `internal/plugins/webapp.ArtifactStore.ReadFiles` reads immutable releases.
|
||||
`backendapp.canvasEditService.loadEditableCanvas` already uses it for editing.
|
||||
- `backendapp.canvasAuthoringService.PublishCanvas` collects one bounded
|
||||
agentctl tar stream and stores a `webapp.Package`. Extend this path to retain
|
||||
inert build source; do not read an author's live executor during export.
|
||||
- `internal/canvas.Service`, `PublishPackage`, and `internal/plugins/instances.Store`
|
||||
own durable instance/release changes. Add a transactional import entry point
|
||||
here, rather than composing browser create/publish/approve requests.
|
||||
- `plugin-registry/build-index.mjs` currently reads limited flat YAML metadata
|
||||
from a GitHub tag, chooses a release tarball, and emits an advisory null hash.
|
||||
Canvas entries need package inspection and a required digest. Preserve the
|
||||
native-plugin path and do not extend its regex parser to nested canvas data.
|
||||
|
||||
## Package profile
|
||||
|
||||
Use the existing gzip-compressed tar container and root `manifest.yaml`.
|
||||
Add an optional typed `distribution` block to the plugin manifest:
|
||||
|
||||
```yaml
|
||||
id: sprint-board
|
||||
api_version: 2
|
||||
version: 1.0.0
|
||||
display_name: Sprint board
|
||||
description: A workspace board for task progress.
|
||||
author: example-author
|
||||
categories: [canvas]
|
||||
min_kandev_version: <first-version-with-canvas-distribution>
|
||||
distribution:
|
||||
schema_version: 1
|
||||
kind: canvas
|
||||
license: MIT
|
||||
source_mode: static
|
||||
ui:
|
||||
web_apps:
|
||||
- key: main
|
||||
title: Sprint board
|
||||
entry: index.html
|
||||
placements: [workspace-canvas]
|
||||
capabilities:
|
||||
api_read: [tasks, workflows]
|
||||
```
|
||||
|
||||
The minimum-version placeholder is illustrative. Implementation records the
|
||||
first compatible release using the repository's version metadata; exports must
|
||||
never emit this placeholder. Preserve an author's higher minimum version.
|
||||
|
||||
The distribution profile requires exactly one static web app, workspace-canvas
|
||||
placement, and optionally task-canvas placement. Reject binary runtimes, remote
|
||||
backend endpoints, native UI bundles, tools, and all other contributions.
|
||||
`distribution.kind` is an asserted profile, verified against the complete
|
||||
manifest. Categories are presentation tags. Legacy native entries without this
|
||||
block retain their behavior. Local canvases without it remain valid locally.
|
||||
|
||||
Required share metadata: valid stable package ID, SemVer, display name,
|
||||
description, author, nonempty license identifier or custom-license label plus
|
||||
`LICENSE.txt`, `source_mode`, and compatibility. Screenshots and preview URLs
|
||||
are not part of this manifest profile.
|
||||
Do not assign a license on the author's behalf. Preserve declared permissions
|
||||
exactly; editing share metadata cannot add or remove capabilities. Package ID
|
||||
and version are editable for export without renaming the live canvas.
|
||||
|
||||
`<id>-<version>.tar.gz` is the bundle. It contains runtime files, editable source,
|
||||
`README.md`, license information, and a `checksums.txt` covering every other
|
||||
file. `<id>-<version>-source.zip` contains the same project files, with paths
|
||||
preserved, and is explicitly not accepted by the installer. It includes built
|
||||
assets so authors can republish the downloaded version without a build.
|
||||
|
||||
Build source uses the reserved `distribution/source/` subtree. The plugin
|
||||
runtime denies the entire `distribution/` subtree before file lookup, including
|
||||
encoded/traversal forms. Entries and executable runtime asset references cannot
|
||||
target that subtree. Registry images are external listing metadata.
|
||||
|
||||
## Source retention
|
||||
|
||||
Two explicit source modes avoid claiming a built bundle is a complete project:
|
||||
|
||||
- `static`: the retained HTML, CSS, JavaScript, and local assets are the editable
|
||||
application. This is the current no-build scaffold and the legacy default.
|
||||
- `project`: the author places build inputs under `distribution/source/`,
|
||||
including the package manifest, lockfile, build configuration, and README
|
||||
with the command that writes runtime output into the package root. This
|
||||
source is retained in the same immutable artifact as its built output.
|
||||
|
||||
Extend the package file policy only inside that reserved source subtree to
|
||||
allow bounded regular project files, including TS/TSX and YAML lock/config
|
||||
files. Reject executable binaries, links, devices, nested archives, `.git`,
|
||||
`node_modules`, credential files, and `.env` files; a placeholder-only
|
||||
`.env.example` is permitted. Apply exclusions during source collection and
|
||||
again during package validation. Reject an unsafe file rather than silently
|
||||
producing an incomplete project. Existing `.canvas-root` remains internal and
|
||||
is never exported. Authored source or images can still embed private content;
|
||||
the export UI exposes an inventory and a review notice, not a claim of complete
|
||||
secret detection.
|
||||
|
||||
Quick Chat materializes the complete artifact, including the source subtree,
|
||||
and preserves source mode on republish. Update the embedded authoring guide and
|
||||
golden inventory tests with the same contract. No new executor access method is
|
||||
needed: local, Docker, and SSH continue to use the authenticated source stream.
|
||||
|
||||
A legacy retained release can export in static mode with visible wording that
|
||||
these are the retained application files. If its author needs original build
|
||||
inputs that were not retained, project export reports `source_unavailable` and
|
||||
directs them to Edit and republish with source. Never reconstruct missing source
|
||||
from a deleted task workspace or silently label minified output as project source.
|
||||
|
||||
## Registry previews
|
||||
|
||||
Canvas entries in both official and custom marketplace sources require one to
|
||||
eight ordered `previews: [{url, alt}]` objects. The same optional field is
|
||||
available for plugins. The shared shape and gallery behavior belong to the
|
||||
[plugin registry preview contract](../../plugins/system-design/marketplace.md#registry-preview-images).
|
||||
|
||||
Each URL is an absolute HTTPS address, at most 2048 characters, without
|
||||
credentials or fragments. Each alt description has 1-300 non-whitespace
|
||||
characters after trimming. The URL should directly return a PNG, JPEG, or WebP
|
||||
image; content-type and availability failures use the browser's image fallback.
|
||||
Prefer commit/release-pinned URLs for accuracy, but changing listing images
|
||||
does not require a new canvas version.
|
||||
|
||||
Image URLs belong to registry pointers and generated source documents, not to
|
||||
the manifest or bundle. Bundle export, source download, upload/link inspection,
|
||||
and confirmation have no screenshot requirement or screenshot upload step.
|
||||
There is no image collection, decoding, re-encoding, package extraction, or
|
||||
Pages media mirroring in this delivery. Ordinary application image assets
|
||||
remain ordinary bundle files.
|
||||
|
||||
The first listing image is the cover. Preserve registry order through the
|
||||
generated index and UI. Validate list/URL shape during registry admission and
|
||||
custom-source parsing. Do not reject a valid install because a remote preview
|
||||
is temporarily unavailable. A listing image is informational and must never
|
||||
supply permissions, executable content, or evidence of package authenticity.
|
||||
|
||||
## Validation and bounded preparation
|
||||
|
||||
Keep current web-app limits: 10 MiB compressed package, 25 MiB expanded data,
|
||||
512 files, 5 MiB per file, 64 KiB manifest, and 240-byte paths. Authoring transfer
|
||||
retains its existing 30 MiB wire bound. The source ZIP has a separate 30 MiB
|
||||
output ceiling; it is generated, never nested in the installable tarball.
|
||||
|
||||
Distribution validation requires checksum coverage, normalized unique paths,
|
||||
all declared files, source-mode structure, compatibility, and
|
||||
the static canvas profile. An archive hash verifies identity, not publisher
|
||||
trust. No package hooks, scripts, or application code run in inspection.
|
||||
|
||||
Add one small preparation store owned by the canvas distribution service.
|
||||
It stages files under a dedicated Kandev-home temporary directory, with opaque
|
||||
random IDs bound to the authenticated user, target workspace, operation,
|
||||
reviewed digest, and expiration. No token grants access without authentication.
|
||||
Allow at most two preparations per user and 256 MiB of staged data per install;
|
||||
reserve before receiving bytes and release on every failure. Preparations expire
|
||||
after 15 minutes. Remove on cancellation/expiry and clean abandoned files on
|
||||
startup; a restart invalidates uncommitted preparations. Use request-lifetime
|
||||
leases during download/commit so cleanup cannot remove in-use files.
|
||||
|
||||
This is temporary review/download state, not another installed-package database.
|
||||
The persistent installation receipt described below handles commit retries.
|
||||
|
||||
## Export preparation
|
||||
|
||||
1. Authorize access to the canvas workspace and confirm an active, valid,
|
||||
available release. Bind the request to `expected_release_id`.
|
||||
2. Read that immutable artifact using `ReadFiles`; verify its digest.
|
||||
3. Accept bounded author metadata; screenshots are not an export input.
|
||||
Seed the form from the manifest. Retain the current session's inputs after
|
||||
validation errors; do not create a permanent share-profile settings system.
|
||||
4. Build a temporary distribution copy, generate README/checksums, and validate
|
||||
it with the same distribution validator used by imports and registry CI.
|
||||
5. Return metadata, inventory, sizes, digest, and the two
|
||||
authenticated download endpoints. Both formats derive from this one copy.
|
||||
|
||||
Preparing or downloading does not publish a canvas release or mutate runtime
|
||||
state. Before serving either download, reauthorize and compare the active
|
||||
release to the captured one. Stale release or changed form input requires
|
||||
preparation again. Deletion or revoked access prevents subsequent downloads.
|
||||
The dialog preserves unsaved values while open; closing discards this temporary
|
||||
form and best-effort deletes its preparation. Imported packages already retain
|
||||
their distribution metadata, so subsequent sharing starts from those values.
|
||||
|
||||
## Install preparation
|
||||
|
||||
The Canvases section offers two inputs: file upload and a direct HTTPS bundle
|
||||
URL. It does not accept a repository URL as an alternate source form. Public
|
||||
download redirects are supported with a maximum of five validated redirects.
|
||||
No credential-bearing URL, forwarded Kandev cookie, or ambient provider token
|
||||
is sent. Bound connect/read/total time and bytes. Reject non-public destinations
|
||||
including loopback, private, link-local, and metadata networks at DNS resolution
|
||||
and connection time, also after redirects. E2E injects a local test transport;
|
||||
production has no environment switch that disables destination validation.
|
||||
|
||||
Catalog installation sends `{source_id, package_id, expected_version,
|
||||
expected_sha256}`. The server resolves the configured catalog entry itself and
|
||||
rejects stale version/digest selection. It never trusts a browser-supplied
|
||||
catalog package URL or permission list. Download and inspect the selected
|
||||
tarball; the staged bytes are then used for preview and confirmation. Direct
|
||||
URL/file installs compute their own digest and identify the source as unlisted.
|
||||
|
||||
Inspection returns actual manifest permissions via `canvas.ManifestPermissions`,
|
||||
compatibility, license, provenance, and the requested workspace. Registry
|
||||
previews stay attached as separately labeled listing metadata.
|
||||
The catalog details page may show a published summary first, but the final
|
||||
review always uses inspected package bytes. Opening details never executes a
|
||||
preview iframe or grants permissions.
|
||||
|
||||
## Commit and persistence
|
||||
|
||||
`InstallPrepared` is a new canvas service method. It verifies the preparation's
|
||||
user, workspace, expiry, digest, and explicit confirmation. Reauthorize the
|
||||
workspace and enforce canvas/storage limits inside the mutation boundary.
|
||||
|
||||
Create canvas metadata, a workspace plugin instance, immutable release,
|
||||
workspace grants, and an installation receipt in one database transaction.
|
||||
Use the existing instance-store transaction patterns and artifact reservations.
|
||||
Write/reconcile the validated artifact before committing references; a failed
|
||||
transaction schedules or performs safe unreferenced-artifact cleanup without
|
||||
removing a digest still referenced by another instance.
|
||||
|
||||
The instance keeps `plugin_id = kandev.canvas`; the package's stable identity
|
||||
belongs to release metadata and import provenance. Do not add static canvases
|
||||
to the native plugin registry or auto-update poller. A workspace install has
|
||||
no synthetic origin task or creator session. Empty state is created by absence
|
||||
of state rows. Existing runtime issuance enforces current workspace authority.
|
||||
|
||||
Add one canvas-owned `canvas_install_receipts` table with unique preparation
|
||||
ID, user ID, canvas ID, workspace ID, package ID/version, archive digest,
|
||||
optional source ID/repository URL, origin kind (`registry`, `url`, `upload`),
|
||||
and timestamp. Persist only sanitized public provenance; discard signed URL
|
||||
query strings and fragments. The receipt is inserted in the same transaction
|
||||
as the instance and also serves as durable import provenance.
|
||||
|
||||
Retrying a committed preparation returns its original canvas after authorization,
|
||||
including after restart. Concurrent confirmations serialize on that receipt ID.
|
||||
A deliberate second installation uses a new preparation and creates a copy.
|
||||
Canvas removal removes its receipt; an old request with neither receipt nor
|
||||
live preparation cannot resurrect the canvas. Add fresh/migrated/replayed
|
||||
SQLite schema tests and the repository's gated PostgreSQL coverage where supported.
|
||||
|
||||
After commit, emit the existing workspace-scoped canvas lifecycle invalidation
|
||||
and return a canvas route. Keep event payloads content-free. Existing editing
|
||||
may replace a local release, but preserves original import provenance. Display
|
||||
the original version as provenance, not as a claim that an edited copy still
|
||||
matches upstream. V1 has no update/replacement endpoint or new update badges.
|
||||
|
||||
## HTTP contracts
|
||||
|
||||
These proposed routes use the current `/api/v1/canvases` browser API. All require
|
||||
authenticated human workspace authority, not canvas runtime tokens or agent MCP.
|
||||
|
||||
| Method and route | Input and result |
|
||||
| --- | --- |
|
||||
| POST `/:canvasID/exports` | JSON metadata and `expected_release_id`; returns prepared metadata and two download links |
|
||||
| GET `/exports/:id/bundle` | Reauthorized `.tar.gz` attachment |
|
||||
| GET `/exports/:id/source` | Reauthorized `.zip` attachment |
|
||||
| POST `/install-preparations` | Multipart file or JSON URL/catalog reference, plus `workspace_id`; returns immutable review |
|
||||
| GET `/install-preparations/:id` | Reauthorized review metadata |
|
||||
| POST `/install-preparations/:id/confirm` | Reviewed digest and explicit approval; returns installed canvas or prior receipt |
|
||||
| DELETE `/preparations/:id` | Idempotently release an owned temporary preparation |
|
||||
|
||||
Use typed DTOs and stable error codes: `canvas_not_found`, `invalid_package`,
|
||||
`source_unavailable`,
|
||||
`incompatible_version`, `package_digest_mismatch`, `review_expired`,
|
||||
`review_stale`, `invalid_download_url`, and existing quota codes. Foreign and
|
||||
missing preparations return the same not-found result. Attachments use safe
|
||||
filenames, `nosniff`, and private/no-store cache policy. JSON never contains
|
||||
package source, host paths, credentials, or executable HTML.
|
||||
|
||||
## Registry publication
|
||||
|
||||
Extend `plugin-registry/plugins.yaml` entries with optional `kind: canvas`;
|
||||
absence means the current native-plugin route. Keep `id` and `repo` (GitHub
|
||||
owner/name) as the curation source. Canvas authors submit this entry by PR.
|
||||
The repository must have a public release with the exact
|
||||
`<id>-<version>.tar.gz` asset. Do not use the existing first-tarball fallback
|
||||
for canvases, because a source archive can otherwise be chosen accidentally.
|
||||
|
||||
Add a small Go command, `cmd/canvas-package`, exposing bounded offline inspection
|
||||
through the production validator. The Node index builder downloads the exact
|
||||
release asset and invokes this trusted inspector with argument arrays. Do not
|
||||
execute anything from the contributor repository or package. The inspector
|
||||
outputs a safe JSON package descriptor. It does not fetch listing images.
|
||||
The index workflow builds the inspector from trusted
|
||||
base code for untrusted registry PR validation; no deployment credential is
|
||||
available to this validation path.
|
||||
|
||||
Validate registry ID against manifest ID, release tag against manifest version,
|
||||
and declared repository URL (when present) against the listed repository. All
|
||||
package metadata, permission summaries, and hashes come from the validated
|
||||
archive, not a separate branch manifest. Preview URLs and order come from the
|
||||
registry entry. Strict PR validation rejects
|
||||
invalid added/changed canvas entries. Scheduled publication reports invalid
|
||||
entries as skipped/degraded according to the existing builder behavior and
|
||||
continues with valid entries; it never publishes an invalid canvas descriptor.
|
||||
|
||||
Validate `previews` on canvas registry pointers and copy the list directly
|
||||
into the generated catalog. Keep image hosting under the listing maintainer's
|
||||
control. Do not add media output to the Pages workflow. Maintainers can revise
|
||||
previews without rebuilding the package. The proposed complete pointer schema is
|
||||
[`registry-entry.schema.json`](../../../plans/canvas-marketplace/registry-entry.schema.json).
|
||||
|
||||
## Catalog projection
|
||||
|
||||
Keep the current index document and add optional per-entry `kind`, `previews`
|
||||
(`url`, `alt`), `permissions`, `license`, and `source_mode`.
|
||||
For canvas entries, `package_sha256` and these presentation fields are required.
|
||||
Legacy entries with missing kind decode as native plugins. Unknown kinds or
|
||||
incomplete canvas entries cannot be installed. Add a `kind` query without
|
||||
removing category filtering. Reserve `canvas` as the displayed category for
|
||||
validated canvas entries; relabeling a native package cannot change its kind.
|
||||
|
||||
The catalog endpoint accepts an optional authorized `workspace_id` when the
|
||||
requested kind is canvas. Source fetching/cache remains shared, but instance
|
||||
annotations are computed per request after authorization. Query receipts joined
|
||||
to live canvas metadata for that workspace only. Return instance count and
|
||||
authorized routes; never globally join static canvases by package ID into
|
||||
`InstalledForMarketplace`. Label existing copies with Open (or a copy picker)
|
||||
and offer Add another copy. Preserve native installed/update behavior.
|
||||
|
||||
Catalog images use validated HTTPS URLs from the configured index, without a
|
||||
referrer, in contained raster image elements. Preserve previews for registry
|
||||
review, but label them as listing previews, separate from inspected package
|
||||
permissions. Upload/direct-link review omits the gallery completely. Do not
|
||||
find a registry by package ID to attach potentially unrelated images. Failed
|
||||
remote images show a fallback and leave valid installation available.
|
||||
|
||||
The same shared gallery serves native plugin details. Plugins without images
|
||||
keep their existing row and direct install action. A plugin with images offers
|
||||
View details alongside its current install action. This is covered by the
|
||||
Plugins-owned preview requirement; the canvas design does not redefine native
|
||||
plugin permissions or installation.
|
||||
|
||||
## Authorization and feature gates
|
||||
|
||||
Workspace owners can export their canvases and install static canvases into
|
||||
their own workspaces. Apply `task.Service.AuthorizeWorkspaceAccess` at new
|
||||
service boundaries and again on confirmation/download. Installation never
|
||||
inherits grants from the author or another local instance. Reuse synthetic
|
||||
identity behavior when auth is disabled.
|
||||
|
||||
Keep native plugin install and marketplace-source mutation admin-only. Split
|
||||
the frontend's current `useIsAdmin` action gate so it does not hide workspace
|
||||
canvas actions. A details preview grants no permission. An install action
|
||||
explicitly approves the entire displayed declaration; later permission growth
|
||||
uses the existing release approval flow.
|
||||
|
||||
All new canvas entry points require the existing `features.canvases` gate.
|
||||
Settings > Plugins and its catalog also retain the current plugin-page gate.
|
||||
When canvases are off, the catalog filters out canvas entries before returning
|
||||
results, no preparation/receipt lookup is performed, and the frontend mounts no
|
||||
canvas hooks or routes. Share from an existing canvas uses the canvas gate and
|
||||
does not require native-plugin admin authority. No new flag or profile change.
|
||||
|
||||
## UI composition
|
||||
|
||||
Settings > Plugins keeps Installed and Browse and adds a Canvases tab. It has
|
||||
an explicit workspace selector, search/sort, and Install canvas action with
|
||||
upload/direct-link inputs. Cards show cover, name, author, version, and concise
|
||||
description. Card activation opens details, never an immediate installation.
|
||||
Use the existing settings route with a query-selected canvas detail, retaining
|
||||
search/workspace when Back closes it. Add Browse shared canvases on workspace
|
||||
Canvases settings, carrying that workspace into the tab.
|
||||
|
||||
Details shows title, author, version, description, license, repository link,
|
||||
gallery, and grouped requested permissions. The selected image is contained,
|
||||
not cropped, with next/previous and thumbnail selection. Enlarging an image
|
||||
stays within the current details surface. Review & install downloads/inspects
|
||||
the package, then replaces the body with authoritative package review. The
|
||||
primary confirmation names the target workspace. Success offers Open canvas.
|
||||
|
||||
Share sits in host-owned canvas actions and workspace canvas rows. It shows
|
||||
active release, identity/version/author/license fields, source mode, and How
|
||||
to share. Prepare downloads validates the inputs and reveals file inventory,
|
||||
final sizes, and the two download buttons. There is no screenshot field.
|
||||
Form edits invalidate prepared output. Validation failures retain inputs.
|
||||
Read-only inventory and the private-content reminder remain visible beside
|
||||
download actions.
|
||||
|
||||
The helper is an information dialog, not an automation wizard. It explains:
|
||||
download source and bundle; create a repository on the chosen host; upload the
|
||||
source; publish/upload the bundle; share the direct downloadable file URL or
|
||||
send the file; submit the registry pointer with at least one preview image URL for public
|
||||
GitHub-hosted listings. Explain how custom registries use the same `previews`
|
||||
field and how plugins may also supply optional previews.
|
||||
Provide a copyable `plugins.yaml` entry only once repository owner/name is
|
||||
known, with visible placeholders otherwise. Never put credentials in commands.
|
||||
GitLab/Bitbucket instructions describe manual hosting for direct links; their
|
||||
repositories are not accepted by the GitHub-only official registry in v1.
|
||||
|
||||
## Mobile contract
|
||||
|
||||
- Entry points are the Plugins settings page and existing workspace/canvas
|
||||
host actions. The closest shipped domain exemplar is
|
||||
`components/settings/canvas-host-route.tsx` with its host action drawer;
|
||||
`components/kanban-with-preview.tsx` supplies direct detail navigation.
|
||||
- On a phone, show one-column cards and a focused full-height details surface.
|
||||
Keep Back/title fixed, one scrolling body, and the install action in a
|
||||
safe-area-aware footer. Do not mount a desktop split view under the phone UI.
|
||||
- Share uses a full-height form because metadata, inventory, and validation need
|
||||
depth. The short How to share action opens an inset bottom drawer with
|
||||
bounded internal scrolling. Returning preserves the share draft.
|
||||
- Use `useResponsiveBreakpoint`, shared Dialog/Drawer primitives, and existing
|
||||
28px desktop / at-least-44px touch control sizing. No hover-only instructions,
|
||||
swipe-only gallery, or download-only desktop path.
|
||||
- Domain hooks own input state, review generation, selected workspace, image
|
||||
selection, and requests across both presentations. Ignore late responses
|
||||
after input, workspace, detail, or preparation identity changes.
|
||||
- Use dynamic viewport height, keyboard/safe-area clearance, focus return, and
|
||||
one scroll owner per active surface. All interface copy uses i18next; author
|
||||
text remains data. Show localized status/error regions for asynchronous work.
|
||||
|
||||
## Failure handling and observability
|
||||
|
||||
An invalid export leaves the active release untouched. An invalid import creates
|
||||
no instance. On DB failure, compensate unreferenced artifact writes; on lost
|
||||
confirmation response, replay the receipt. After restart, pending previews expire
|
||||
visibly while installed canvases remain usable. Workspace deletion/canvas
|
||||
removal invalidates preparation access and triggers normal artifact cleanup.
|
||||
No failure silently falls back to native install, mutable latest code, or a
|
||||
different release. Catalog outages preserve direct-file/link entry points.
|
||||
|
||||
Log operation, actor/workspace/canvas IDs where authorized, result code, byte
|
||||
counts, digest, and duration. Omit source, screenshot content, titles, tokens,
|
||||
and URL queries. Use content-free diagnostics; add no usage telemetry service.
|
||||
|
||||
## Verification and delivery
|
||||
|
||||
The [implementation plan](../../../plans/canvas-marketplace/plan.md) maps each
|
||||
criterion to proposed unit, integration, registry, and desktop/mobile tests.
|
||||
Tests must prove export-to-import round trips, project-source recovery after
|
||||
executor cleanup, digest-bound review, concurrent retry receipts, isolation,
|
||||
registry URL validation, screenshot-free export/import, plugin galleries,
|
||||
gate-off behavior, and native installer compatibility.
|
||||
|
||||
This package extends completed `plugin-backed-canvases` work and the shipped
|
||||
parts of `plugin-backed-canvases-ux-follow-up`. It does not change their recorded
|
||||
test results or mark the outstanding external ACP evaluation complete. New
|
||||
source-guide changes must preserve that package's one-core-read contract.
|
||||
@@ -36,4 +36,7 @@ canonical requirement and system-design documents. Use the catalog command to fi
|
||||
- [UI](../ui/README.md): renders plugin contributions.
|
||||
- [Canvases](../canvases/README.md): binds isolated web applications to task
|
||||
and workspace canvas lifecycles.
|
||||
- [Canvas distribution](../canvases/system-design/marketplace-sharing.md): owns
|
||||
canvas export/import and the canvas-specific marketplace flow; reuses plugin
|
||||
manifests, static validation, catalog sources, and runtime isolation.
|
||||
- [Integrations](../integrations/README.md): supplies external connections.
|
||||
|
||||
@@ -41,6 +41,29 @@ marketplace — while keeping install-by-URL and sideloading as escape hatches.
|
||||
- **AC-PLUGINS-MARKETPLACE-001.7:** A catalog entry for a plugin that is already installed SHALL show an **Installed** state; when the catalog's latest version is newer than the installed version, it SHALL show an **Update available** affordance (which reinstalls the newer tarball).
|
||||
- **AC-PLUGINS-MARKETPLACE-001.8:** The catalog SHALL be assembled from **one or more marketplace sources**. kandev ships with the **official kandev source** enabled by default; operators MAY add **additional sources** (a team or corporate registry) and the catalog merges them.
|
||||
|
||||
### REQ-PLUGINS-MARKETPLACE-002: Registry preview images
|
||||
|
||||
**Intent:** Registry maintainers can add a visual preview gallery to plugin
|
||||
listings without changing the plugin package.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-PLUGINS-MARKETPLACE-002.1:** Official and custom marketplace entries
|
||||
shall accept an ordered `previews` list of HTTPS image URLs and alternative
|
||||
text. Plugin entries can omit the list; existing entries shall remain valid.
|
||||
- **AC-PLUGINS-MARKETPLACE-002.2:** A plugin listing with screenshots shall show
|
||||
its first image as the preview cover and expose all images in a details
|
||||
gallery. Entries without screenshots shall keep their current presentation.
|
||||
- **AC-PLUGINS-MARKETPLACE-002.3:** Gallery navigation shall support keyboard
|
||||
and touch, display descriptions and image position, and keep install actions
|
||||
available when an image fails. Package code shall not run in the preview.
|
||||
- **AC-PLUGINS-MARKETPLACE-002.4:** Preview metadata shall belong to the registry,
|
||||
not the plugin manifest or release bundle. Maintainers shall be able to change
|
||||
URLs, descriptions, or image order without releasing a new plugin version.
|
||||
|
||||
Canvas listing image requirements are owned by
|
||||
[canvas marketplace and sharing](../../canvases/requirements/marketplace-sharing.md).
|
||||
|
||||
## System design
|
||||
|
||||
The migrated technical source is split into [part 1](../system-design/marketplace.md).
|
||||
|
||||
@@ -34,6 +34,11 @@ This design owns plugin instances, immutable releases, capability grants,
|
||||
runtime tokens, web data access, shared instance state, and live browser
|
||||
events. The Canvases system owns canvas scope changes and user workflows.
|
||||
|
||||
The [canvas distribution design](../../canvases/system-design/marketplace-sharing.md)
|
||||
adds a static distribution profile and an inert retained project-source subtree.
|
||||
Preview images belong to registry listings. The profile reuses this runtime boundary;
|
||||
native plugin package installation does not become a canvas import path.
|
||||
|
||||
This design implements
|
||||
[ADR-2026-08-26-plugin-backed-web-app-canvases](../../../decisions/2026-08-26-plugin-backed-web-app-canvases.md).
|
||||
It extends the data boundary from
|
||||
|
||||
@@ -3,6 +3,7 @@ status: draft
|
||||
system: plugins
|
||||
requirements:
|
||||
- REQ-PLUGINS-MARKETPLACE-001
|
||||
- REQ-PLUGINS-MARKETPLACE-002
|
||||
created: 2026-07-18
|
||||
owners:
|
||||
- jcfs
|
||||
@@ -13,11 +14,52 @@ owners:
|
||||
|
||||
This design preserves the technical source detail for `REQ-PLUGINS-MARKETPLACE-001` during migration.
|
||||
|
||||
The [canvas distribution design](../../canvases/system-design/marketplace-sharing.md)
|
||||
extends this catalog with validated static canvas packages, registry preview URLs,
|
||||
and workspace installation. Its canvas path does not use the managed-binary
|
||||
installer described here. Native plugin behavior remains owned by this document.
|
||||
|
||||
## Requirement mapping
|
||||
|
||||
| Requirement | Design section |
|
||||
| --- | --- |
|
||||
| `REQ-PLUGINS-MARKETPLACE-001` | [Migrated source detail](#migrated-source-detail) |
|
||||
| `REQ-PLUGINS-MARKETPLACE-002` | [Registry preview images](#registry-preview-images) |
|
||||
|
||||
## Registry preview images
|
||||
|
||||
Extend registry pointers and generated catalog entries with an optional ordered
|
||||
`previews` list of `{url, alt}` objects. This is registry-owned presentation
|
||||
metadata for both `kind: plugin` and `kind: canvas`. Omitted kind means plugin.
|
||||
Plugin screenshots are optional; canvas listing admission requires at least one.
|
||||
The same contract applies to official and custom source documents.
|
||||
|
||||
Allow up to eight entries. Each URL must be an absolute HTTPS URL without
|
||||
credentials or a fragment, at most 2048 characters; each alternative description
|
||||
has 1-300 characters after trimming. Reject malformed URLs and executable or
|
||||
inline-data schemes. URLs should return directly displayable PNG, JPEG, or WebP
|
||||
images; a pinned commit/release URL is recommended, not required. Preview
|
||||
availability and content are not evidence of package authenticity or permissions.
|
||||
|
||||
The index builder copies validated registry URLs and their order to `index.json`.
|
||||
Do not download/re-encode media, extract screenshots from packages, or mirror
|
||||
assets into Pages. A registry can change images without changing package version.
|
||||
Custom source readers validate the same fields; invalid canvas listings are
|
||||
omitted with a source diagnostic while valid entries remain usable.
|
||||
|
||||
Use one gallery component for plugin and canvas details: first image as cover,
|
||||
explicit previous/next and thumbnail controls, alt text, position, one-image
|
||||
mode, and a contained image-failure fallback. Load images without referrers;
|
||||
never embed HTML/iframes or run package code. A remote image failure does not
|
||||
block an otherwise valid package install. Plugins without screenshots keep
|
||||
their existing row and install action; screenshots add a View details action
|
||||
without adding a mandatory native-plugin installation step. Phone details use
|
||||
the same focused surface and touch controls as canvas details.
|
||||
|
||||
The proposed complete registry schema is a design artifact at
|
||||
[`registry-entry.schema.json`](../../../plans/canvas-marketplace/registry-entry.schema.json).
|
||||
The [canvas distribution plan](../../../plans/canvas-marketplace/plan.md)
|
||||
Tasks 04-05 implement shared registry validation and gallery rendering.
|
||||
|
||||
## Migrated source detail
|
||||
|
||||
|
||||
Reference in New Issue
Block a user