From 6e408e2240110ecb8ca6a72aaa174f826fe69bdd Mon Sep 17 00:00:00 2001 From: Luan van der Westhuizen Date: Thu, 24 Sep 2026 05:17:09 +0200 Subject: [PATCH 1/2] feat: add Composer build-and-deploy plugin preview --- .agents/plugins/marketplace.json | 2 +- .gitignore | 6 + README.md | 134 +++++++- assets/prisma-icon.svg | 19 +- docs/validation.md | 288 ++++++++++++++++++ plugins/prisma/plugin.json | 37 +++ .../skills/prisma-build-and-deploy/SKILL.md | 142 +++++++++ .../references/toolchain.md | 205 +++++++++++++ scripts/package-plugin.mjs | 121 ++++++++ scripts/package-plugin.test.mjs | 70 +++++ 10 files changed, 1013 insertions(+), 11 deletions(-) create mode 100644 docs/validation.md create mode 100644 plugins/prisma/plugin.json create mode 100644 plugins/prisma/skills/prisma-build-and-deploy/SKILL.md create mode 100644 plugins/prisma/skills/prisma-build-and-deploy/references/toolchain.md create mode 100644 scripts/package-plugin.mjs create mode 100644 scripts/package-plugin.test.mjs diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index f1f48a6..533547e 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -8,7 +8,7 @@ "name": "prisma", "source": { "source": "local", - "path": "./" + "path": "./plugins/prisma" }, "policy": { "installation": "AVAILABLE", diff --git a/.gitignore b/.gitignore index 4fb006c..31c4564 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,9 @@ node_modules/ .env .env.* !.env.example + +# Generated by scripts/package-plugin.mjs from the pinned Composer release. +/plugins/prisma/skills/prisma-composer-core-concepts/ +/plugins/prisma/assets/ +/plugins/prisma/LICENSE +/plugins/prisma/upstream.json diff --git a/README.md b/README.md index 7b7a2d2..d6e81d2 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,140 @@ # Prisma Plugin +## Composer plugin: desktop-local preview + +The first focused preview builds apps with **Prisma Composer** and deploys them to +**Prisma Compute**. Its portable [Agent Plugins 1.0.0](https://agent-plugins.org/) +manifest lives in `plugins/prisma/plugin.json`. It includes two skills: + +- `prisma-build-and-deploy`: this repository's short workflow for installation, + local verification, authentication, targeting, deployment, and recovery. +- `prisma-composer-core-concepts`: copied unchanged from the published + `@prisma/composer@0.21.0` package, with its upstream license and provenance. + +The workflow reads the Composer reference for API concepts. Composer remains the +source of truth for those concepts; this repository owns completing the journey. + +The `0.4.0-dev.4` onboarding revision is prepared but **not activated**: it needs +a released CLI containing `auth login --ui-context prisma-plugin`, followed by a +verified exact version pin. The installed `0.4.0-dev.3` remains the working +preview. Do not refresh it from this checkout until that release gate is cleared. +See [validation](docs/validation.md) for completed checks and remaining acceptance. + +### Package and install + +These are contributor packaging instructions, not steps for plugin users. +Prerequisites: Node.js 22.18+ (or a newer supported release), `tar`, internet access +to the npm registry, and a current Codex CLI with `codex plugin` support. The +packager uses Node's standard library; there is no dependency-install step in this +repository. It checks the pinned archive's integrity and never runs npm lifecycle +scripts or installs Composer into this repository. + +From this repository's root: + +```bash +node scripts/package-plugin.mjs +node scripts/package-plugin.mjs --check +codex plugin marketplace add "$PWD" +codex plugin add prisma@prisma +codex plugin list --marketplace prisma --json +``` + +This registers the local `prisma` marketplace and installs its Prisma plugin into +Codex's cache. Open a **new Codex task in an empty app folder** after installation +so the new skill is available. Select the Prisma plugin if needed; confirm that +both `prisma:prisma-build-and-deploy` and `prisma:prisma-composer-core-concepts` +are available (Codex prefixes skills with their plugin name). + +### First test + +Select the Prisma plugin for the task, then use: + +> Build a simple Todo app and deploy it + +Use **ChatGPT's desktop app with local execution**. Web and cloud execution, +including cloud tasks launched from desktop, are deferred. Initial validation +uses macOS; other operating systems have not been verified. + +Selecting Prisma supplies the Composer/Compute defaults, including local and live +verification. The agent handles tooling, dependencies, and commands. The user +completes browser signup/consent when needed and answers unresolved target +questions; they never need a terminal, copied authentication codes, or manual +credential configuration. Explicit stack or hosting choices +still take precedence. Merely installing the plugin does not make Prisma the +default for unrelated tasks. + +The skill guides the agent's use of the desktop's local capabilities. Its workflow +defaults to the project-local **unified `prisma` CLI** for new interactive apps. +The bundled +[toolchain reference](plugins/prisma/skills/prisma-build-and-deploy/references/toolchain.md) +contains the verified installation set, required peer, runtime checks, and command +sequence, managed browser login, and verification before confirming a connection. + +Local Composer development needs no cloud credentials. Before deployment the +workflow checks for an existing CLI session and verifies workspace access; browser +login is needed only if that session is missing or expired. New users can create +an account during sign-in. If the browser does not open, the agent shares the +authorization link from the same pending attempt. After successful login it checks +authenticated identity and remote workspace access, then reuses the authorized +workspace unless another was explicitly requested. Browser signup alone is not +proof of a working connection. Local work continues while login is pending. + +Installing this plugin does not deploy or provision anything. A new demo targets the named `demo` stage +unless another target is requested. The workflow checks the live app, and reports +partial provisioning separately from a successful deployment. +Service-token setup is not a workaround for unsupported web/cloud execution. + +See [validation and upstream findings](docs/validation.md) for the acceptance +scenarios, recorded evidence, and remaining limits of this preview. + +### What's maintained here + +| File | Responsibility | +| --- | --- | +| `plugins/prisma/plugin.json` | Portable identity, display metadata, and starter prompts | +| `plugins/prisma/skills/prisma-build-and-deploy/` | Authored workflow and its version-specific toolchain reference | +| `scripts/package-plugin.mjs` | Refreshes only imported content, preserves the authored skill, and verifies the full bundle | +| `.agents/plugins/marketplace.json` | Points the local Codex marketplace at `./plugins/prisma` | +| `.gitignore` | Excludes generated bundle content from this initial local preview | + +The plugin's `skills/` directory is discovered automatically. There is no MCP +server in this focused bundle. The older root skills and tool manifests below +remain available in the repository, but this local marketplace installs only the +Composer bundle. + +To iterate, edit the maintained files, bump `version` in +`plugins/prisma/plugin.json`, rerun the packager and `--check`, then run +`codex plugin add prisma@prisma` again and start a new task. Codex uses its +installed copy, so edits to this checkout alone do not update active tasks. +`--check` is offline and detects missing, changed, or additional bundle files. +To update Composer, review the new upstream skill and change the package version, +tarball URL, and npm `dist.integrity` together in the packaging script. + +Run `node --test scripts/package-plugin.test.mjs` for packaging regression tests +(requires access to the npm registry). These build an isolated temporary copy and +verify repeatability, preservation of authored content, and integrity failures. + +This is a **local preview**, not a published directory listing. A fresh clone must +run the packager before installing from this marketplace. Public distribution +will need to include the complete generated bundle in a release or repository +and go through the [OpenAI plugin submission](https://platform.openai.com/plugins) +process. The generated `upstream.json` records exactly which release and files +were packaged. + +## Existing broad plugin + Prisma plugin for agent tools, including curated skills for Prisma ORM, Prisma Client, Prisma Postgres, Prisma Compute, driver adapters, migrations, upgrades, and official Prisma MCP workflows. -## Install +### Existing installer + +This is the repository's previous install route. For the focused Composer preview, +use the local packaging and installation steps above. ```bash npx plugins add prisma/prisma-plugin ``` -## Supported Tools +### Supported Tools | Tool | Support | | --- | --- | @@ -16,7 +142,7 @@ npx plugins add prisma/prisma-plugin | Claude Code | Skills and Prisma MCP | | Cursor | Rules, skills, and Prisma MCP metadata | -## What's Included +### What's Included - Prisma CLI guidance for setup, migrations, database commands, Studio, and MCP - Prisma Client guidance for querying, relations, transactions, raw SQL, and configuration @@ -28,7 +154,7 @@ npx plugins add prisma/prisma-plugin - Prisma ORM 7 upgrade guidance - Cursor rules for Prisma schema and migration best practices -## Skills +### Skills - `prisma-cli` - `prisma-client-api` diff --git a/assets/prisma-icon.svg b/assets/prisma-icon.svg index c16f1a1..3dfadb8 100644 --- a/assets/prisma-icon.svg +++ b/assets/prisma-icon.svg @@ -1,7 +1,14 @@ - - - - - - + + + + + + + + + + + + + diff --git a/docs/validation.md b/docs/validation.md new file mode 100644 index 0000000..2840739 --- /dev/null +++ b/docs/validation.md @@ -0,0 +1,288 @@ +# Local preview validation + +Prepared source/bundle: `0.4.0-dev.4`, 2026-09-24. Installed working preview remains +`0.4.0-dev.3+codex.20260924021431`. **Desktop v1 is not yet complete:** the new +onboarding needs a released CLI with the context option and fresh-user acceptance. +The published `prisma@8.0.0-rc.15` pin is retained as the previous verified baseline, +not represented as supporting the new option. Application/deployment results below +remain the `0.4.0-dev.2` baseline. Agent-reported evidence is labeled separately. + +## Desktop onboarding revision (`0.4.0-dev.4`) + +The authored workflow now requires desktop-local execution, agent-managed setup, +one managed browser login, a real emitted authorization link when opening fails, +and successful login/identity/remote-access checks before confirming connection. +It preserves the workspace selected during consent and keeps local work moving +while signup is pending. Recovery retains app progress and never requests codes, +tokens, or callback URLs. Web/cloud execution is explicitly deferred. + +Upstream implementation: [Prisma CLI PR #281](https://github.com/prisma/prisma-cli/pull/281), +commit `b50b587`, based on main `6a34270`. The optional context is validated by the +normal argument parser and propagated only to browser completion rendering. OAuth, +scopes, consent, callback validation, credential persistence, and terminal output +are unchanged. No source changes were made to Composer or the authentication service. +PR #281 was marked ready for review, approved by CodeRabbit with no actionable +findings, and merged as `12c9663` on 2026-09-24 after all checks passed, including +the repository's end-to-end job and Ubuntu/Windows package tests. No Prisma bot +review appeared; the user explicitly authorized proceeding with CodeRabbit's +approval. Its advisory docstring-coverage warning was assessed without adding +boilerplate to existing callbacks and test helpers. These CI results do not +establish a fresh desktop signup or Windows/Linux plugin journey. No review +requirement was bypassed. The coordinated release remains a separate human gate; +the plugin must still wait for an exact released and verified CLI version. + +The version-only [release PR #282](https://github.com/prisma/prisma-cli/pull/282) +prepares `8.0.0-rc.16` from merged main and is deliberately left unmerged with +auto-merge disabled. Its checks passed for build, types, lint, 80 versioning/script +tests, skill packaging, CLI tests (1,019 passed; 2 skipped), wrapper tests (3 +passed), and clean tarball installs. Release conformance reports zero failures +and six allowed findings under main's existing engine `0.4.0`/`0.6.0` transition +exceptions. The PR also records a local macOS engine prompt-test timeout that +reproduces before the bump at `b50b587`; this requires coordinated review rather +than being reported as a fully green release. No published CLI pin or installed +plugin was changed during this release preparation. + +Directly executed checks on the available macOS desktop, Node `24.16.0` and pnpm +`11.6.0` (not Windows/Linux acceptance): + +| Check | Observed result | +| --- | --- | +| CLI static checks | `pnpm typecheck` and `pnpm lint` passed | +| CLI package regression suite | 1,019 passed, 2 skipped | +| Focused auth suite | 85 passed, including context propagation, invalid/missing values before login, unchanged credential/session shape, success/failure wording, OAuth denial, workspace escaping, and abort handling | +| Default browser page | Compared rendered output with main for known, missing, and escaped workspace names: byte-for-byte identical | +| Browser-opening failure | A simulated opener failure in a persistent TTY attempt completed through the same listener; the exact verification URL was emitted once and token exchange ran once, without a pasted callback | +| End-to-end runner | After building the `prisma` wrapper: 7 local checks passed, 48 cloud lifecycle tests skipped without isolated test credentials; this is not a real OAuth or cloud acceptance result | +| Built CLI help | Unified `prisma auth login --help` exposes `--ui-context` with `prisma-plugin` as its supported value | +| Skill/package checks | Authored skill format, rebuild, offline integrity check, and existing packaging regression test passed; both skills and the single supporting reference are in the six-file bundle | +| Preservation | Imported Composer `0.21.0` SHA-256 remains `67b50e78fbb6cafd00bb99b0e56fe8a49e4a7190219474bf1b9be933f08bbcbb`; branding and starter prompts unchanged | +| Installed copy | Both v3 skills and all installed files still match their provenance; deliberately not refreshed with the release-gated v4 draft | + +The first auth test run could not bind local callback servers in the sandbox; +rerunning with local-server permission passed. The first end-to-end runner attempt +required the wrapper build; after building it, local checks passed. Neither is +recorded as an authentication/product defect. No personal Prisma session was +changed and no live deployment or cloud resource creation was performed. + +Still required before activating this revision: + +1. Release the merged CLI change through the coordinated maintainer process. Select an + exact published version containing the flag, clean-install it alongside the + unchanged Composer/cloud `0.21.0` and ORM peer `8.0.0-rc.11`, and verify it. + Then replace the reference's old CLI pin/install command and remove its release + gate; do not use a guessed version, local package patch, or floating dependency. +2. With isolated credential storage and a human completing signup/consent, test an + ordinary prompt from a fresh desktop account and clean local setup. Verify + pending signup never triggers provisioning, cancelled/expired login can retry + without duplicate processes, a returning session is reused, explicit workspace + choices are respected, and an empty authorized workspace succeeds. The unit + simulations above do not replace this acceptance run. +3. Verify actual local restart persistence and live service version, reachable + URL, database-backed actions, and browser behavior with that released CLI. +4. Record the exact version/results here, clear the README's pending notice, + rebuild with a fresh dev.4 cache suffix, refresh the installed copy, and verify + both installed skills and their references. A fresh task must pick up the copy. + +## Listing and branding follow-up (2026-09-24) + +Applied the approved platform description, 26-character listing subtitle, and +new/existing-app starter prompts. Display name and publisher remain Prisma. +Both listing accents use the website's coral `#F34A60`; contrast checks passed +against white and `#212121`. Preserved the supplied logo in the source asset and +centred its unchanged artwork on a 264 × 264 canvas. + +The rebuilt bundle passed integrity checks and the existing packaging regression +test. Removed a Finder `.DS_Store` file from the bundle after integrity validation +identified it. All skill files remained byte-for-byte unchanged, including the +Composer `0.21.0` reference. Codex installation succeeded; all six installed +bundle files and provenance matched the source. No cloud deployment was run. + +## Generic-prompt follow-up (2026-09-23) + +This revision introduced “Build a simple Todo app and deploy it” as the starter +prompt and README example; the listing prompts were broadened on 2026-09-24. +The authored workflow's discovery metadata and introduction explicitly interpret +Prisma selection as the Composer/Compute default, retaining local and live checks. +An independent offline routing evaluation selected this workflow for the generic +prompt with Prisma selected, preserved local-only scope and existing Next.js/pnpm +conventions, and did not route explicit Vercel or unrelated SQL requests to it. +An unselected installed plugin was not treated as the user's provider choice. +Skill-format and bundle-integrity checks passed; installed files matched the +bundle and the upstream Composer reference remained unchanged. This evaluated +routing decisions, not another live deployment or the host's plugin-selection UI. + +## Previous revision checks (`0.4.0-dev.3`) + +The skill-format validator, bundle rebuild and integrity check, and existing +packaging regression test passed. All six installed bundle files and provenance +matched the checkout; fresh native Codex discovery found both enabled skills at +`0.4.0-dev.3`. The Composer reference matched the original `0.21.0` archive +byte-for-byte. Packaging code, its tests, marketplace configuration, README, and +ignore rules were unchanged by this revision. + +An independent agent evaluated 13 supplied scenarios (including failure variants) +using only the authored workflow and its reference. It executed no Prisma +commands, network calls, or mutations. The resulting decisions covered: + +| Supplied evidence | Observed decision | +| --- | --- | +| Explicit target; a different workspace is active | Select the chosen session, then verify the effective workspace; no repeated target question | +| Authoritative single/multiple memberships | Select the sole workspace or ask among multiple; combine missing region selection | +| One stored session with unknown membership; membership lookup fails | Ask once, offer known sessions as suggestions, and preserve the distinction between a discovery failure and an empty result | +| New project; existing region; conflicting requested region | Present all supplied supported regions for the new project, preserve the existing region, or clarify the conflict before provisioning | +| Pending target/login; local-only request | Continue local work; neither case permits cloud provisioning | +| Changed command runtime; DNS-only failure | Restore the verified executable pair in the actual context; handle network access separately from dependency resolution | +| Exact gzip/JSON failure; generic container, quota, authentication, or startup failures | Apply Bun only to the matching signature, preserve state/reports, and diagnose the other failures independently | +| Bun recovery succeeds with an existing build-and-deploy script | Retain the working invocation while preserving the npm build step, target configuration, and external credentials | +| Running verified app without Console history | Report live success and unavailable history separately; create no Git commit | + +Review clarified selection-before-access-validation ordering, existing-region +precedence, and a distinct retry-report filename. A focused follow-up found those +ambiguities resolved. These are offline behavioral evaluations, not new live +deployments or tests of actual account-wide workspace discovery. + +## Baseline checks (`0.4.0-dev.2`) + +| Check | Evidence | +| --- | --- | +| Clean installation | In an empty temporary project, npm installed Composer/cloud `0.21.0`, ORM Postgres `8.0.0-rc.11`, and `prisma` `8.0.0-rc.15` without `--force` or `--legacy-peer-deps`; Node `24.16.0`, npm `11.13.0` | +| Required peer | `npm ls --depth=0` showed all four exact versions; imports of `@prisma/composer`, `@prisma/composer-prisma-cloud/control`, and `@prisma/orm-postgres/control` succeeded | +| CLI surface | Installed dev, deploy, project-list, and service-show help loaded; deploy supports `--stage` and `--report` | +| Existing authentication | `auth whoami --json` identified a stored session; `project list --json` successfully verified remote access without new credentials or browser login | +| Packaging | `node --test scripts/package-plugin.test.mjs` passed: repeat builds preserve authored files, additional authored references, and identical provenance; changed/missing files and unexpected skills fail verification | +| Skill format | The skill-creator validator accepted the authored workflow | +| Installed plugin | Native Codex plugin inspection and fresh skill discovery found exactly two enabled Prisma skills at `0.4.0-dev.2`, no MCP servers; installed content matched the source bundle | +| Upstream preservation | Installed Composer SKILL.md matched the original pinned npm archive byte-for-byte | + +The clean install's npm audit reported 14 upstream dependency advisories (10 +moderate, 4 high). This check did not assess exploitability or change the pinned +dependency tree. Installation success is not a security or production-readiness +assessment. + +## Baseline offline workflow scenarios (`0.4.0-dev.2`) + +An independent fresh agent read the installed skills and reference, then evaluated +these supplied scenarios without executing Prisma commands or making cloud calls. +All five produced the intended actions: + +| Scenario | Observed behavior | +| --- | --- | +| Existing Next.js/pnpm app with newer Composer and ORM migrations | Preserves framework, manager, versions, and schema strategy; consults matching installed documentation | +| Stored session and remote access work; token variables unset | Reuses the session without requesting service tokens or login | +| Local-only request with no session | Continues local verification without cloud authentication or provisioning | +| Quota refusal after project/database/service creation; no live version | Reports partial provisioning and known IDs, preserves state, stops retries, avoids inventing quota limits | +| Failed update while an earlier version still serves | Reports the failed update and still-live previous version separately; does not claim outage or successful rollout | + +These are behavioral checks against supplied evidence, not live failure injection. + +## Application acceptance baseline (`0.4.0-dev.2`) + +Use a fresh task and this ordinary prompt with the installed Prisma plugin: + +> Build a simple Todo app with Prisma Composer and Postgres persistence. Run it +> locally, then deploy it to Prisma Compute and verify it works. + +Pass criteria: + +- Locally: typecheck/build pass; add/list/complete/delete work in the API and UI; + data survives a service restart without resetting the database. +- Remotely: the resolved project/stage has a live version and reachable URL; + a database-backed user action and browser interaction succeed. +- If deployment fails, record the actual state and blocker; do not mark the live + test passed because local tests or resource creation succeeded. + +### Local result: passed + +An independent fresh agent received only the installed plugin and the local +portion of the ordinary request above. It built a Todo app in an empty temporary +directory using Composer, a Node HTTP service, and raw Postgres with `pg`. It did +not read the plugin source repository or parent conversation. It consulted public +Composer documentation and installed package types where needed. No cloud +credentials or resources were needed for local development. + +- Typecheck and build passed. API create/list/complete/delete passed, and a blank + title was rejected with HTTP 400. +- Chrome UI create/complete/delete passed. After an actual service-process + restart, the same row ID, title, and completed state remained in Postgres and + appeared on browser reload. +- The local service was stopped after verification; its database and shared + emulators were preserved. The in-app browser refused localhost, so browser + verification used Chrome. + +The existing-app and absent-session cases above remain offline scenario checks; +this test does not claim a separate existing-app migration or real login exercise. + +### Cloud result: passed + +The same app was deployed in a user-selected empty workspace, region `us-east-1`, +stage `demo`, reusing the existing authenticated session. The first Node-based +attempt failed before creating a project; the confirmed runtime recovery is +recorded below. Retrying the same target with Bun succeeded. + +- The structured deployment report recorded success with database and Compute + service IDs. Service inspection independently showed a `running`, live version + and a public URL. +- The live HTML returned HTTP 200. API create/list/complete/delete passed, with + updated state retained by a subsequent read and invalid input rejected. +- Chrome UI create/complete/delete passed, with completion retained on page + reload. Only disposable smoke-test rows were removed. + +The smoke project and database remain available for manual review. The app is an +anonymous shared Todo demo without accounts or per-user ownership. This is a +release smoke test, never part of packaging or an automatic cloud deployment on +every change. Persistence across service restart was verified locally; no cloud +restart was performed. Quota failure recovery was evaluated offline, not induced +against the workspace. + +## Second run: agent-reported evidence + +A user-supplied report, reviewed on 2026-09-23, describes another successful Todo +deployment in the selected workspace, Frankfurt (`eu-central-1`), stage `demo`. +It reports local CRUD and persistence across an actual service restart, a running +live version, deployed database/API/browser checks, and cleanup of its test rows. +It also reports successful recovery from the same npm resolver and gzip/JSON +failures, plus a live app without a Console history entry because Git metadata +was absent. These outcomes were not rerun or independently inspected for dev.3. + +The report's cookie-ownership and cross-origin checks apply to that app's design; +they do not impose an authentication model on plugin-generated applications. +No starter or generic smoke-test helper was added based on this report. + +## Upstream findings kept outside the workflow + +1. **Composer 0.21.0's bundled reference has stale CLI packaging language.** The + core package's manifest has no binary and points to `@prisma/composer-cli`, + while the skill says the core carries the CLI. The plugin toolchain reference + corrects the installation path without editing the imported skill. +2. **Authentication guidance needs CLI scope.** Unified `prisma@8.0.0-rc.15` + successfully reused a stored session. The standalone/control-API token path + remains separate. A direct invocation of only the upstream concepts skill can + still miss this distinction; use the build-and-deploy workflow for the journey. +3. **The missing ORM peer was not reproduced with normal installation.** Cloud + `0.21.0` declares `@prisma/orm-postgres@8.0.0-rc.11` as a required peer. The clean + install and cloud-control import passed with it present. The earlier failure + after bypassing peer resolution does not establish an undeclared-dependency bug. +4. **The npm resolution failure reproduced in the fresh Todo test.** Node + `23.11.0`/npm `10.9.2` failed with `Cannot read properties of null (reading + 'edgesOut')`. A process-scoped Node `24.16.0`/npm `11.13.0` invocation completed + installation without bypass flags. The toolchain reference records this + conditional recovery; it does not prescribe a global runtime change. +5. **The compressed-response failure reproduced during the cloud smoke test.** + With the pinned package set and Node `24.16.0`, `prisma deploy module.ts --stage + demo --report ...` failed with `DEPLOY.CONTAINER_FAILED`, a Management API + container-resolution JSON parse error, and leading gzip bytes. The report had + no resource nodes; a remote project listing confirmed the workspace was still + empty. The failed report and target were preserved. Project-local Bun `1.4.2` + with `bun run --bun prisma deploy ...` successfully deployed the same target. + Both parent and child runtime probes reported Bun `1.4.2`. This is a verified + conditional recovery, not an established root cause or a default runtime change. +6. **Local CLI exit did not stop the service in the tested invocation.** With + unified CLI `8.0.0-rc.15`, Node `24.16.0`, and a Bun `1.1.18` service, Ctrl-C + exited `npm exec -- prisma dev module.ts` while its listener still served. + Inspection verified that the process belonged to this app. A supervised + process restart proved persistence; the installed local target's app-scoped + stop operation then stopped it without deleting data or shared emulators. + The workflow requires observing the actual service restart. It does not + prescribe the internal emulator endpoint as a general public command. + +No upstream repository or platform changes are part of this revision. diff --git a/plugins/prisma/plugin.json b/plugins/prisma/plugin.json new file mode 100644 index 0000000..1b0259b --- /dev/null +++ b/plugins/prisma/plugin.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", + "name": "prisma", + "version": "0.4.0-dev.4", + "description": "Build and deploy your apps with Prisma.", + "author": { + "name": "Prisma", + "url": "https://www.prisma.io" + }, + "homepage": "https://www.prisma.io", + "repository": "https://github.com/prisma/prisma-plugin", + "license": "Apache-2.0", + "keywords": ["prisma", "composer", "compute", "deployment"], + "extensions": { + "com.openai": { + "interface": { + "displayName": "Prisma", + "shortDescription": "Build and deploy your apps", + "longDescription": "Take your app from idea to a live URL with Prisma. Prisma brings together app hosting with Prisma Compute, managed databases with Prisma Postgres, and type-safe data access with Prisma ORM.\n\nBuild a new app with Prisma Composer or get an existing app ready for Compute. The plugin guides you through setup, local testing, and deployment, then checks that your live app works.", + "developerName": "Prisma", + "category": "Coding", + "capabilities": ["Interactive", "Write", "Deployment"], + "websiteURL": "https://www.prisma.io", + "privacyPolicyURL": "https://www.prisma.io/privacy", + "termsOfServiceURL": "https://www.prisma.io/terms", + "defaultPrompt": [ + "Build a new app and deploy it", + "Deploy my existing app" + ], + "brandColor": "#F34A60", + "brandColorDark": "#F34A60", + "composerIcon": "./assets/prisma-icon.svg", + "logo": "./assets/prisma-icon.svg" + } + } + } +} diff --git a/plugins/prisma/skills/prisma-build-and-deploy/SKILL.md b/plugins/prisma/skills/prisma-build-and-deploy/SKILL.md new file mode 100644 index 0000000..c3dfb81 --- /dev/null +++ b/plugins/prisma/skills/prisma-build-and-deploy/SKILL.md @@ -0,0 +1,142 @@ +--- +name: prisma-build-and-deploy +description: >- + Build and deploy applications when the user selects or invokes the Prisma + plugin, including requests like "Build a simple Todo app and deploy it" that + do not name a stack. Use Prisma Composer for new apps and Prisma Compute for + deployment. Also use for explicit Composer/Compute requests and recovering + Composer deployments. Does not cover unrelated ORM or database administration. +--- + +# Build and deploy with Prisma + +Guide the requested application from working code to a verified deployment. +Selecting Prisma for this task supplies the default: Composer for a new app and +Compute for deployment. The user need not name either product or separately ask +for local and live verification. State that choice briefly and follow this +workflow. Respect explicit stack/hosting choices and local-only requests; +installation alone is not a provider choice. + +This journey requires ChatGPT's desktop app with local execution. Check the +actual execution environment: a cloud task launched from desktop is still out of +scope. In web/cloud execution, explain that the user must continue in a desktop +task running locally; do not offer manual credentials as a workaround. + +For Composer declarations, wiring, builds, and database concepts, read the bundled +[Composer core concepts](../prisma-composer-core-concepts/SKILL.md). Reuse its +guidance rather than re-deriving the API. For CLI installation and authentication, +read [the version-specific toolchain reference](references/toolchain.md): the +bundled core reference describes the standalone CLI, while this workflow defaults +to the unified Prisma CLI for new interactive projects. + +## Establish the project and toolchain + +- Inspect the app, package manifest, lockfile, existing Composer configuration, + and scripts. Preserve the framework, package manager, and database strategy of + an existing app. If it is not Composer-ready, explain the concrete adaptation + needed before undertaking a substantial rewrite. +- Resolve Node and the package-manager executable together, plus Bun when used. + Check paths and versions against package requirements and project pins. Preserve + the selected executables across install, build, dev, and deploy; recheck them + when commands switch execution contexts. Use available host capabilities to + supply supported tooling and install project-local dependencies yourself. + Explain progress or genuine blockers in plain language; the user should not + need to open a terminal, run commands, or configure credentials. +- For a new project, use the dependency set in the toolchain reference, including + required peers, and prefer its verified Node/npm pair when available. For an + existing project, inspect its installed versions and + their matching skill/documentation; do not downgrade it to the bundled version. +- Choose a simple implementation suited to the request. Do not turn a small Todo + request into a design interview. Make the schema and persistence approach + explicit; do not accidentally mix raw SQL initialization with ORM migrations. + +## Resolve authentication and the deployment target + +When deployment is requested, start this after project inspection while local +work continues. Combine outstanding workspace and region questions when possible. + +1. Check the existing connection early and verify remote workspace access. Reuse + a valid session. If login is needed, explain: "To put your app online, connect + Prisma. If you don't have an account, you can create one during sign-in. Return + here when you're finished; I'll handle the setup." Describe only providers + offered by the actual page. Start one managed login using the reference's + plugin context option and keep it alive. If the browser does not open, share + the actual authorization link emitted by that attempt. Leave signup and + consent to the user; never request passwords, tokens, or callback URLs in chat. +2. After login, require successful process completion, authenticated identity, + and a successful remote workspace read from the deployment environment before + saying "You're connected to Prisma." An empty project list is valid; browser + signup or "I'm done" alone is not proof. Reuse the workspace authorized during + login unless another was explicitly requested. Honor explicit choices and + validate access without asking again. If a target still cannot be resolved, + use authoritative membership when available (sole workspace automatically, + multiple by asking); otherwise ask once with known sessions as suggestions, + allowing another name. Stored sessions are not an account-wide inventory and + failed discovery does not establish a workspace count. +3. Preserve an existing project's region; clarify an explicitly conflicting + region before provisioning. For a new project, honor the chosen region or ask, + "Select the region closest to your users." Show the complete supported choices + with geographic labels and IDs from the reference's region link; do not infer + a recommendation from the developer's location. +4. Resolve any ambiguous application/project identity. Preserve the requested + stage; a new demo defaults to `demo`. State the resolved target as a progress + update, not another approval request. Provision only after target selection and + local verification are complete. Omitting the stage targets production. + +Check quota information only through an available supported read-only capability. +Otherwise note briefly that deployment may still fail after creating resources; +do not invent a quota endpoint or promise a comprehensive preflight. + +For cancelled, expired, or failed login, explain the outcome and offer a fresh +attempt after the old process has ended. Preserve app progress; distinguish +authentication failure from network, permission, and quota problems. Continue +independent local work while login or answers are pending, then resume deployment +automatically once connection, target, and local verification are ready. + +## Build and verify locally + +Follow install → typecheck → build → local dev → verification. The app owns its +build; Composer's dev and deploy operations consume that output. + +For a Todo app, exercise adding, listing, completing, and deleting a todo. Verify +data survives an actual service restart without resetting its database; exiting +the dev CLI alone is not proof that its service stopped. Check the actual UI in a +browser and inspect failures in the running service. For a different app, test +the equivalent core user action and persistence when relevant. + +Local Composer development does not need cloud credentials. Keep building and +testing locally when cloud login or target selection is still pending. Report +any unperformed verification explicitly. + +## Deploy, verify, and recover + +Build before deploying. Use the same resolved project and stage throughout the +attempt. Capture a structured deploy report if the installed CLI supports it; +otherwise retain the relevant command output and inspect the platform read-only. + +Success requires a live service version, a reachable URL, a working core user +action backed by the database when applicable, and a browser check. Use the +project's supported service inspection commands to distinguish an allocated +service from a live version. A zero exit code or created project is not enough. +For Todo, check CRUD against the deployed application as well as locally. + +On failure: + +- Record the failed step, reported error, resolved target, and available resource + IDs. Check whether an existing version is still serving traffic, whether a new + version is live, or whether nothing is serving. Do not infer this from the + failure alone. +- Preserve the app configuration, deployment identity, and recorded deploy state. + Explain what exists and what remains incomplete. Fix the reported cause before + retrying the same target so Composer can converge existing resources. If state + cannot be verified, stop and investigate instead of creating a renamed app. +- A quota or entitlement refusal needs resolution, not a retry loop. Do not + guess the quota amount or limit from a generic `quota-exceeded` error. +- Treat cleanup as a separate action requiring the user's intent. Do not delete + resources or deployment state as an automatic recovery step. + +Finish with the local/deployed URLs, what was actually verified, any remaining +blocker, and material demo limitations (for example, cookie-only ownership or +lack of cross-device access). If Console deployment history was unavailable, +report it separately from the live result; do not create Git commits to suppress +that warning. Keep unverified work clearly separate from success. diff --git a/plugins/prisma/skills/prisma-build-and-deploy/references/toolchain.md b/plugins/prisma/skills/prisma-build-and-deploy/references/toolchain.md new file mode 100644 index 0000000..0661ca0 --- /dev/null +++ b/plugins/prisma/skills/prisma-build-and-deploy/references/toolchain.md @@ -0,0 +1,205 @@ +# Toolchain for the local preview + +Read this when installing dependencies or choosing the CLI/authentication path. +Composer API concepts live in the bundled upstream skill; this reference owns +the plugin's version-specific installation and command guidance. + +## Verified installation set + +**Desktop onboarding release gate:** the set below is the previous verified +baseline. `prisma@8.0.0-rc.15` does not support `--ui-context`. The new login +handoff must not be activated until the CLI change is released, an exact version +containing it is verified with this dependency set, and the CLI pin and this +notice are updated. Do not run the unsupported option, patch installed packages, +or use a floating version. Until then, continue independent local work and report +the release dependency if a new login is needed. + +| Package | Version | Purpose | +| --- | --- | --- | +| `@prisma/composer` | `0.21.0` | Composer authoring and the bundled concepts skill | +| `@prisma/composer-prisma-cloud` | `0.21.0` | Compute and Postgres target | +| `@prisma/orm-postgres` | `8.0.0-rc.11` | Required peer declared by this cloud-target release | +| `prisma` | `8.0.0-rc.15` | Unified CLI for interactive development and deployment | + +Verified on 2026-09-23: a clean npm install of these four exact versions succeeded +under Node 24.16.0 and npm 11.13.0, without peer-dependency bypass flags. The +Composer, cloud-control, and ORM-control imports loaded, and the unified CLI's +dev, deploy, and project-list help commands ran. This verifies installation and +command loading; it does not by itself verify an app or cloud deployment. + +For a new npm project (translate to the existing package manager when relevant): + +```sh +npm install --save-exact @prisma/composer@0.21.0 @prisma/composer-prisma-cloud@0.21.0 @prisma/orm-postgres@8.0.0-rc.11 +npm install --save-dev --save-exact prisma@8.0.0-rc.15 +``` + +Installing the peer does not require the app to use Prisma ORM. It satisfies the +cloud package's declared dependency; a raw Postgres app can retain its client and +schema strategy. Add the app's own build/typecheck/runtime dependencies as needed +and retain its lockfile. Do not use `--legacy-peer-deps` or `--force` as default +installation instructions. + +The core package does not supply the `prisma-composer` executable. That executable +belongs to `@prisma/composer-cli`. The unified `prisma` package supplies the +`prisma` executable and brings its own Composer CLI dependency; do not force all +packages, including that internal dependency, to share the same version number. + +## Runtime and command path + +Composer and the unified CLI require Node **22.18.0 or newer**. Prefer a supported +Node release satisfying the app's pins. On POSIX, inspect `command -v node`, +`node --version`, `command -v npm`, and `npm --version` together (substitute the +project's package manager and platform equivalents). For Bun builds or services, +also check `command -v bun` and `bun --version`. + +Run these checks and setup operations yourself. Prefer the desktop host's bundled +runtime or a supported host installation capability when a runtime is missing; +do not assume the user prepared a developer environment. Install dependencies in +the app, preserving existing conventions. If the host cannot supply required +tooling or permission, state the concrete blocker without handing the user shell +commands. Initial acceptance is macOS only; other operating systems are unverified. + +Use project-local commands and inspect `prisma --help`, `prisma dev --help`, and +`prisma deploy --help` for the installed version. The unified commands are +`prisma dev module.ts` and `prisma deploy module.ts`; there is no `composer` +command group. Preserve the selected Node/package-manager pair, including PATH +and child processes, across installation, build, dev, and deploy. When commands +switch shell, sandbox, or network-access contexts, recheck there or inspect the +failing command's runtime in its logs; an earlier version check is insufficient. +Resolve DNS or network-access failures through the host's supported access path, +not dependency overrides. Investigate resolution errors before changing versions. + +After installation, use the project's npm scripts and local CLI: + +```sh +npm run typecheck +npm run build +npm exec -- prisma dev module.ts +# Verify the app locally; stop dev when done. +# Deploy only once local verification and target selection are complete. +npm exec -- prisma deploy module.ts --stage demo --report deploy-report.json +``` + +Start the authentication/target checks below early when deployment is requested; +they are not a prerequisite for local development. Keep deploy reports out of +source control. Use the installed CLI, not floating `prisma@latest`. Existing apps +keep their validated versions and matching package-shipped Composer skill. + +## Authentication and targeting + +Use the selected project-local CLI and the same environment/credential store for +login, verification, and deployment. First run `npm exec -- prisma auth whoami +--json`, inspect the authenticated result (exit zero alone is insufficient), and +verify access with `npm exec -- prisma project list --json`. An empty successful +list is valid. Network or permission failures do not by themselves justify login. +Explicit service credentials override stored sessions; check the effective +workspace without printing secrets or silently changing credential modes. + +For a missing or expired session, after the release gate above is satisfied: + +```sh +npm exec -- prisma auth login --ui-context prisma-plugin --json +``` + +Use a persistent **PTY/interactive process** in the desktop-local environment; +the current CLI keeps its callback listener open after a browser-launch failure +only when stdin is a TTY. Retain its process/session handle and poll with short +waits while doing independent local work. Keep one attempt active: do not restart +because it is still waiting, close stdin, background-and-forget it, or give it a +short total timeout. Capture the `verification` endpoint event (or the emitted +authorization URL) before browser opening. If opening fails, make that exact URL +a clickable chat link while the same attempt remains pending. Never substitute +the Console homepage, construct an OAuth URL, or pass the local callback URL to +the user. Do not relay the CLI's terminal/paste instructions to chat. + +The user completes signup and consent in their browser. Describe providers only +after inspecting that page, not from a hard-coded list. A browser success page or +user message does not prove credentials reached this process. Require login exit +success, `auth whoami --json` showing authentication, and a successful `project +list --json` from the deployment environment before confirming the connection or +provisioning. Preserve the workspace returned by login and verify it matches the +effective workspace. If an explicit different target was requested, select its +stored session with `prisma auth workspace use ` and verify remotely; +if none exists, explain that sign-in must authorize that workspace. + +`prisma auth workspace list` lists local sessions only, not all account memberships. +Do not repeat the workspace question after consent selected it, infer counts, or +treat failed discovery as an empty account. On denial, expiry, or cancellation, +retain app progress and offer a new attempt. Stop and confirm the previous process +has exited before starting one, using a fresh emitted URL. Never ask the user to +copy codes, credentials, or callback URLs. Keep connection failure separate from +remote permission, network, or quota errors. Do not log out existing sessions as +recovery; acceptance tests must use isolated credential storage. + +Read the complete supported region list in [Compute limitations](https://www.prisma.io/docs/compute/limitations) +(the `.md` version is available for text retrieval). Configure the selected region +through `prismaCloud({ region })` or `PRISMA_REGION`; config wins if both are set. +An existing project retains its region. Use `--stage demo` for a new demo; omitting +it targets production. The module's application name selects the project; inspect +`--name` for an explicit override. Reuse the same name and stage on retries. + +For CI, the standalone Composer CLI, or operations imported from +`@prisma/composer/control`, provide `PRISMA_SERVICE_TOKEN` and +`PRISMA_WORKSPACE_ID` through the environment. The control API does not inherit +the unified CLI's browser session. The unified CLI does not expose all standalone +verbs, so do not invent `prisma destroy` or `prisma log`; inspect the supported +surface before attempting cleanup or log inspection. +Those credential paths are technical context, not a fallback for this novice +journey. Web/cloud execution, including desktop-launched cloud tasks, is deferred; +direct the user to desktop-local execution without manual credential workarounds. + +## Evidence before workarounds + +The fresh Todo test reproduced `Cannot read properties of null (reading +'edgesOut')` during installation with Node 23.11.0/npm 10.9.2. Selecting Node +24.16.0/npm 11.13.0 for the same project allowed installation to complete without +peer-bypass flags. Prefer an already available supported runtime matching the +verified pair; a process-scoped selection is also possible: + +```sh +npm exec --yes --package=node@24.16.0 --package=npm@11.13.0 -- npm install +``` + +Run that recovery only in the affected project, retaining its manifest and +lockfile. Inspect the error before changing an existing app's toolchain. This is +evidence for the tested versions, not a claim that every other runtime fails. + +The cloud smoke test also reproduced `DEPLOY.CONTAINER_FAILED` with +`Prisma Management API error resolving containers: SyntaxError: Unexpected token` +and a response beginning with gzip bytes (`0x1f 0x8b`). This occurred under Node +24.16.0 with the package set above. The deploy report had no resource nodes and a +remote project listing confirmed no project had been created. After preserving +that report, the same application, workspace, region, and stage deployed +successfully with project-local Bun 1.4.2, including its CLI child processes. + +Only for this reproduced failure, inspect the remote state and preserve the +failed report before retrying; use a different retry-report path as shown below. +In an npm project, the tested recovery invocation is: + +```sh +npm install --save-dev --save-exact bun@1.4.2 +# Keep the previously resolved workspace, region, application name, and stage. +./node_modules/.bin/bun run --bun prisma deploy module.ts --stage demo --report deploy-retry-report.json +``` + +Replace `demo` with the already resolved stage if different; preserve the region +in configuration or `PRISMA_REGION`. Bun's [`--bun` option](https://bun.com/docs/runtime/bunfig#run-bun) +also routes child `node` commands through Bun. Verify the parent and relevant +child runtime when diagnosing this error; running only the parent CLI with Bun +does not establish what its children use. This is a conditional recovery verified +for the tested releases, not the default deployment runtime or a root-cause fix. +Authentication, quota, configuration, and startup failures require their own +diagnosis; `DEPLOY.CONTAINER_FAILED` alone does not justify switching runtimes. + +After this recovery succeeds, retain the working project-local invocation in the +app's existing deployment script or run instructions, with a brief reason. Keep +existing build steps, package-manager conventions, and target configuration. +Record the tested Bun version, not machine-specific executable paths or credentials. +Avoid global runtime changes and undocumented credential extraction. + +Primary references: [CLI authentication](https://www.prisma.io/docs/cli/auth), +[Composer deployment](https://www.prisma.io/docs/cli/deploy), +[Composer getting started](https://www.prisma.io/docs/composer/getting-started). +When live documentation and an installed release differ, inspect that release's +help and package metadata; do not guess flags from newer documentation. diff --git a/scripts/package-plugin.mjs b/scripts/package-plugin.mjs new file mode 100644 index 0000000..a32c671 --- /dev/null +++ b/scripts/package-plugin.mjs @@ -0,0 +1,121 @@ +#!/usr/bin/env node +import { createHash } from 'node:crypto'; +import { execFileSync } from 'node:child_process'; +import { cp, lstat, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +// Update the version, tarball and npm dist.integrity together after reviewing an upstream release. +const source = { + name: '@prisma/composer', + version: '0.21.0', + tarball: 'https://registry.npmjs.org/@prisma/composer/-/composer-0.21.0.tgz', + integrity: 'sha512-IIoDrcyz9ttkd7auUWgpEr6jGbSmnJF+PkKdxxgFmcSll6jnNIcHyJVLyrg1ZhthKbMmqymJmKCorkFPHKAiXA==', +}; +const skill = 'prisma-composer-core-concepts'; +const workflow = 'prisma-build-and-deploy'; +const expectedSkills = [workflow, skill].sort(); +const root = dirname(dirname(fileURLToPath(import.meta.url))); +const output = join(root, 'plugins/prisma'); +const generated = [`skills/${skill}`, 'assets', 'LICENSE', 'upstream.json']; +const hash = (data) => createHash('sha256').update(data).digest('hex'); +const json = (value) => `${JSON.stringify(value, null, 2)}\n`; + +async function fileHashes(directory, prefix = '') { + const result = {}; + for (const entry of (await readdir(directory)).sort()) { + const relative = prefix ? `${prefix}/${entry}` : entry; + if (relative === 'upstream.json') continue; + const path = join(directory, entry); + const stat = await lstat(path); + if (stat.isDirectory()) Object.assign(result, await fileHashes(path, relative)); + else if (stat.isFile()) result[relative] = hash(await readFile(path)); + else throw new Error(`Unexpected non-regular file: ${relative}`); + } + return result; +} + +async function check() { + const provenance = JSON.parse(await readFile(join(output, 'upstream.json'), 'utf8')); + if (JSON.stringify(provenance.source) !== JSON.stringify(source)) { + throw new Error('The bundle uses a different upstream release. Rebuild it.'); + } + if (JSON.stringify((await readdir(join(output, 'skills'))).sort()) !== JSON.stringify(expectedSkills)) { + throw new Error(`The bundle must contain exactly these skills: ${expectedSkills.join(', ')}.`); + } + const actual = await fileHashes(output); + if (JSON.stringify(actual) !== JSON.stringify(provenance.files)) { + throw new Error('Bundle files changed, are missing, or were added. Rebuild it.'); + } + if (actual['assets/prisma-icon.svg'] !== hash(await readFile(join(root, 'assets/prisma-icon.svg')))) { + throw new Error('The source icon changed. Rebuild the bundle.'); + } + console.log(`Verified prisma: ${workflow} plus ${skill} from ${source.name}@${source.version}; ${Object.keys(actual).length} files.`); +} + +async function build() { + // Authored files are required inputs, never generated or replaced by the packager. + await readFile(join(output, 'skills', workflow, 'SKILL.md')); + await readFile(join(output, 'skills', workflow, 'references/toolchain.md')); + const temporary = await mkdtemp(join(tmpdir(), 'prisma-plugin-')); + try { + console.log(`Downloading ${source.name}@${source.version}…`); + const response = await fetch(source.tarball, { signal: AbortSignal.timeout(60_000) }); + if (!response.ok) throw new Error(`Download failed: HTTP ${response.status}`); + const archive = Buffer.from(await response.arrayBuffer()); + const integrity = `sha512-${createHash('sha512').update(archive).digest('base64')}`; + if (integrity !== source.integrity) throw new Error('The npm archive failed its integrity check.'); + const archivePath = join(temporary, 'composer.tgz'); + await writeFile(archivePath, archive); + + // Extract only the skill, license and package identity. Never install or execute package code. + execFileSync('tar', [ + '-xzf', archivePath, '-C', temporary, + 'package/package.json', 'package/LICENSE', `package/skills/${skill}`, + ], { stdio: 'pipe' }); + const upstream = join(temporary, 'package'); + const pkg = JSON.parse(await readFile(join(upstream, 'package.json'), 'utf8')); + if (pkg.name !== source.name || pkg.version !== source.version || pkg.license !== 'Apache-2.0') { + throw new Error('Unexpected upstream package identity or license.'); + } + const skillText = await readFile(join(upstream, 'skills', skill, 'SKILL.md'), 'utf8'); + if (!skillText.startsWith(`---\nname: ${skill}\n`)) throw new Error('Unexpected upstream skill name.'); + + const staged = join(temporary, 'bundle'); + await mkdir(join(staged, 'skills'), { recursive: true }); + await mkdir(join(staged, 'assets')); + await cp(join(upstream, 'skills', skill), join(staged, 'skills', skill), { recursive: true }); + await cp(join(output, 'skills', workflow), join(staged, 'skills', workflow), { recursive: true }); + await cp(join(upstream, 'LICENSE'), join(staged, 'LICENSE')); + await cp(join(root, 'assets/prisma-icon.svg'), join(staged, 'assets/prisma-icon.svg')); + await cp(join(output, 'plugin.json'), join(staged, 'plugin.json')); + await writeFile(join(staged, 'upstream.json'), json({ + source, + skill, + repository: 'https://github.com/prisma/composer', + license: pkg.license, + files: await fileHashes(staged), + })); + + // Finish downloading and validating before replacing the previous generated content. + for (const entry of generated) { + await rm(join(output, entry), { recursive: true, force: true }); + await cp(join(staged, entry), join(output, entry), { recursive: true }); + } + await check(); + console.log(`Packaged ${output}`); + } finally { + await rm(temporary, { recursive: true, force: true }); + } +} + +try { + const args = process.argv.slice(2); + if (args.length === 0) await build(); + else if (args.length === 1 && args[0] === '--check') await check(); + else throw new Error('Usage: node scripts/package-plugin.mjs [--check]'); +} catch (error) { + console.error(`Packaging failed: ${error.message}`); + process.exitCode = 1; +} diff --git a/scripts/package-plugin.test.mjs b/scripts/package-plugin.test.mjs new file mode 100644 index 0000000..7bf36a8 --- /dev/null +++ b/scripts/package-plugin.test.mjs @@ -0,0 +1,70 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { cp, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import test from 'node:test'; +import { fileURLToPath } from 'node:url'; + +const root = dirname(dirname(fileURLToPath(import.meta.url))); +const workflow = 'plugins/prisma/skills/prisma-build-and-deploy'; + +test('packaging preserves authored files and verifies the complete bundle', async () => { + const temporary = await mkdtemp(join(tmpdir(), 'prisma-plugin-test-')); + try { + for (const relative of [ + 'scripts/package-plugin.mjs', 'plugins/prisma/plugin.json', + 'assets/prisma-icon.svg', workflow, + ]) { + await mkdir(dirname(join(temporary, relative)), { recursive: true }); + await cp(join(root, relative), join(temporary, relative), { recursive: true }); + } + const run = (...args) => spawnSync(process.execPath, + [join(temporary, 'scripts/package-plugin.mjs'), ...args], + { encoding: 'utf8', timeout: 90_000 }); + const pass = (result) => assert.equal(result.status, 0, result.stderr || result.error?.message); + const skillPath = join(temporary, workflow, 'SKILL.md'); + const referencePath = join(temporary, workflow, 'references/toolchain.md'); + const authored = await readFile(skillPath); + const reference = await readFile(referencePath); + // A maintainer's additional supporting file must survive too. + const extraReference = join(temporary, workflow, 'references/local-note.md'); + await writeFile(extraReference, 'Authored content must survive packaging.\n'); + + pass(run()); + pass(run('--check')); + const provenancePath = join(temporary, 'plugins/prisma/upstream.json'); + const provenance = await readFile(provenancePath); + pass(run()); + assert.deepEqual(await readFile(provenancePath), provenance); + assert.deepEqual(await readFile(skillPath), authored); + assert.deepEqual(await readFile(referencePath), reference); + assert.equal(await readFile(extraReference, 'utf8'), 'Authored content must survive packaging.\n'); + + const upstreamPath = join(temporary, 'plugins/prisma/skills/prisma-composer-core-concepts/SKILL.md'); + for (const path of [skillPath, referencePath, upstreamPath]) { + const before = await readFile(path); + await writeFile(path, Buffer.concat([before, Buffer.from('\nmodified\n')])); + assert.notEqual(run('--check').status, 0); + await writeFile(path, before); + } + const unexpected = join(temporary, 'plugins/prisma/skills/unexpected'); + await mkdir(unexpected); + assert.notEqual(run('--check').status, 0); + await rm(unexpected, { recursive: true }); + + await rm(referencePath); + assert.notEqual(run('--check').status, 0); + assert.notEqual(run().status, 0, 'Missing authored input must fail before rebuilding.'); + assert.deepEqual(await readFile(provenancePath), provenance); + assert.deepEqual(await readFile(skillPath), authored); + await writeFile(referencePath, reference); + pass(run('--check')); + + // The tracked workflow must not be accidentally covered by a generated-content ignore. + const ignored = spawnSync('git', ['check-ignore', `${workflow}/SKILL.md`], { cwd: root }); + assert.equal(ignored.status, 1); + } finally { + await rm(temporary, { recursive: true, force: true }); + } +}); From 0f9ff15a1283a272dbb94afebf9722e122ff8f80 Mon Sep 17 00:00:00 2001 From: Luan van der Westhuizen Date: Thu, 24 Sep 2026 05:41:47 +0200 Subject: [PATCH 2/2] fix: isolate the release-gated plugin preview --- .agents/plugins/marketplace.json | 2 +- README.md | 28 +++++++++++++++--------- docs/validation.md | 18 +++++++++++++++ plugins/.agents/plugins/marketplace.json | 20 +++++++++++++++++ scripts/package-plugin.test.mjs | 2 +- 5 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 plugins/.agents/plugins/marketplace.json diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 533547e..f1f48a6 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -8,7 +8,7 @@ "name": "prisma", "source": { "source": "local", - "path": "./plugins/prisma" + "path": "./" }, "policy": { "installation": "AVAILABLE", diff --git a/README.md b/README.md index d6e81d2..a828f4e 100644 --- a/README.md +++ b/README.md @@ -29,21 +29,28 @@ packager uses Node's standard library; there is no dependency-install step in th repository. It checks the pinned archive's integrity and never runs npm lifecycle scripts or installs Composer into this repository. -From this repository's root: +From this repository's root, build and check the bundle: ```bash node scripts/package-plugin.mjs node scripts/package-plugin.mjs --check -codex plugin marketplace add "$PWD" -codex plugin add prisma@prisma -codex plugin list --marketplace prisma --json ``` -This registers the local `prisma` marketplace and installs its Prisma plugin into +After the onboarding release gate above is cleared, install the preview explicitly: + +```bash +codex plugin marketplace add "$PWD/plugins" +codex plugin add prisma@prisma-preview +codex plugin list --marketplace prisma-preview --json +``` + +This registers the local `prisma-preview` marketplace and installs its Prisma plugin into Codex's cache. Open a **new Codex task in an empty app folder** after installation so the new skill is available. Select the Prisma plugin if needed; confirm that both `prisma:prisma-build-and-deploy` and `prisma:prisma-composer-core-concepts` -are available (Codex prefixes skills with their plugin name). +are available (Codex prefixes skills with their plugin name). Enable only the +focused Prisma preview for acceptance testing, so another Prisma installation +does not supply additional skills. ### First test @@ -94,17 +101,18 @@ scenarios, recorded evidence, and remaining limits of this preview. | `plugins/prisma/plugin.json` | Portable identity, display metadata, and starter prompts | | `plugins/prisma/skills/prisma-build-and-deploy/` | Authored workflow and its version-specific toolchain reference | | `scripts/package-plugin.mjs` | Refreshes only imported content, preserves the authored skill, and verifies the full bundle | -| `.agents/plugins/marketplace.json` | Points the local Codex marketplace at `./plugins/prisma` | +| `plugins/.agents/plugins/marketplace.json` | Opt-in local preview marketplace, pointing at `./prisma` relative to `plugins/` | +| `.agents/plugins/marketplace.json` | Preserves the existing root plugin for default repository installs | | `.gitignore` | Excludes generated bundle content from this initial local preview | The plugin's `skills/` directory is discovered automatically. There is no MCP server in this focused bundle. The older root skills and tool manifests below -remain available in the repository, but this local marketplace installs only the -Composer bundle. +remain the default repository install. The separate `prisma-preview` marketplace +installs only the Composer bundle after packaging. To iterate, edit the maintained files, bump `version` in `plugins/prisma/plugin.json`, rerun the packager and `--check`, then run -`codex plugin add prisma@prisma` again and start a new task. Codex uses its +`codex plugin add prisma@prisma-preview` again and start a new task. Codex uses its installed copy, so edits to this checkout alone do not update active tasks. `--check` is offline and detects missing, changed, or additional bundle files. To update Composer, review the new upstream skill and change the package version, diff --git a/docs/validation.md b/docs/validation.md index 2840739..40bcae9 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -7,6 +7,24 @@ The published `prisma@8.0.0-rc.15` pin is retained as the previous verified base not represented as supporting the new option. Application/deployment results below remain the `0.4.0-dev.2` baseline. Agent-reported evidence is labeled separately. +## Local PR review (2026-09-24) + +Review of PR #7 found and resolved two issues before merging the preview source: + +- The default repository marketplace pointed at an incomplete, release-gated + bundle. It now remains byte-for-byte identical to main's existing root-plugin + route. The opt-in `prisma-preview` marketplace lives under `plugins/`; its + documented installation step is conditional on the onboarding release gate. +- The ignore-rule regression assertion skipped tracked files. It now uses + `git check-ignore --no-index`; an isolated tracked-file fixture reproduced the + original false negative and confirmed the corrected command detects it. + +The packaging regression test, skill-format validator, bundle integrity check, +marketplace target/asset/skill checks, and diff whitespace check passed. Composer's +imported reference is unchanged. No installed plugin, personal credentials, or +cloud resources were changed. This repository currently has no GitHub CI checks; +these are locally executed results, not hosted CI or fresh-user acceptance. + ## Desktop onboarding revision (`0.4.0-dev.4`) The authored workflow now requires desktop-local execution, agent-managed setup, diff --git a/plugins/.agents/plugins/marketplace.json b/plugins/.agents/plugins/marketplace.json new file mode 100644 index 0000000..4ed4da8 --- /dev/null +++ b/plugins/.agents/plugins/marketplace.json @@ -0,0 +1,20 @@ +{ + "name": "prisma-preview", + "interface": { + "displayName": "Prisma Local Preview" + }, + "plugins": [ + { + "name": "prisma", + "source": { + "source": "local", + "path": "./prisma" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Coding" + } + ] +} diff --git a/scripts/package-plugin.test.mjs b/scripts/package-plugin.test.mjs index 7bf36a8..bc599f0 100644 --- a/scripts/package-plugin.test.mjs +++ b/scripts/package-plugin.test.mjs @@ -62,7 +62,7 @@ test('packaging preserves authored files and verifies the complete bundle', asyn pass(run('--check')); // The tracked workflow must not be accidentally covered by a generated-content ignore. - const ignored = spawnSync('git', ['check-ignore', `${workflow}/SKILL.md`], { cwd: root }); + const ignored = spawnSync('git', ['check-ignore', '--no-index', `${workflow}/SKILL.md`], { cwd: root }); assert.equal(ignored.status, 1); } finally { await rm(temporary, { recursive: true, force: true });