@rtrentjones/greenlight 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/assets/skills/deploy-verify-promote/SKILL.md +53 -0
  3. package/assets/skills/provider-cloudflare/SKILL.md +42 -0
  4. package/assets/skills/provider-github/SKILL.md +35 -0
  5. package/assets/skills/provider-hcp/SKILL.md +46 -0
  6. package/assets/skills/provider-oci/SKILL.md +58 -0
  7. package/assets/skills/provider-supabase/SKILL.md +40 -0
  8. package/assets/skills/provider-vercel/SKILL.md +39 -0
  9. package/dist/agent-web-I4LXW4SR.js +7 -0
  10. package/dist/bin.js +1951 -0
  11. package/dist/chunk-6N7MD6FR.js +75 -0
  12. package/dist/chunk-KFKYLGFX.js +271 -0
  13. package/dist/chunk-KP3Y6WRU.js +45 -0
  14. package/dist/chunk-QFKE5JKC.js +12 -0
  15. package/dist/chunk-UXHHLEYO.js +231 -0
  16. package/dist/chunk-WFZTRXBF.js +61 -0
  17. package/dist/chunk-XBDQJVAX.js +94 -0
  18. package/dist/eval-LLQPOEQX.js +9 -0
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.js +16 -0
  21. package/dist/mcp-KU7WKB5K.js +7 -0
  22. package/dist/playwright-CGTTHGIL.js +7 -0
  23. package/dist/test-7GMOU7I5.js +7 -0
  24. package/package.json +51 -0
  25. package/templates/_template-astro/README.md +18 -0
  26. package/templates/_template-astro/astro.config.mjs +9 -0
  27. package/templates/_template-astro/package.json +18 -0
  28. package/templates/_template-astro/src/pages/index.astro +18 -0
  29. package/templates/_template-astro/tsconfig.json +5 -0
  30. package/templates/_template-astro/wrangler.jsonc +12 -0
  31. package/templates/_template-mcp/README.md +28 -0
  32. package/templates/_template-mcp/oci/Dockerfile +11 -0
  33. package/templates/_template-mcp/oci/package.json +12 -0
  34. package/templates/_template-mcp/oci/server.ts +80 -0
  35. package/templates/_template-mcp/workers/README.md +32 -0
  36. package/templates/_template-next/README.md +5 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 RTrentJones
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: deploy-verify-promote
3
+ description: Ship a change through Greenlight's loop — deploy to preview/beta, verify with the shared harness, then gated-promote develop→main to prod. Use when making a change to a Greenlight tool or the blog and you want it shipped with confidence, or when explicitly asked to deploy/verify/promote.
4
+ ---
5
+
6
+ # deploy-verify-promote
7
+
8
+ The execution discipline for changing a Greenlight tool or the blog. The verify
9
+ harness and promote guard are the **same code CI runs**, so passing locally means
10
+ passing in CI. This is what lets a change (or a long string of changes) be shipped
11
+ with objective confidence rather than vibes.
12
+
13
+ ## Input
14
+
15
+ - `<name>` — a manifest entry: `blog`, or a tool name from `greenlight.config.ts`.
16
+
17
+ ## Deterministic URL scheme (never scrape deploy logs)
18
+
19
+ | Subject | prod | beta |
20
+ |---|---|---|
21
+ | tool | `https://<name>.<domain>` | `https://beta.<name>.<domain>` |
22
+ | blog (apex) | `https://<domain>` | `https://beta.<domain>` |
23
+ | mcp connect | *(tool url)* `+ /mcp` | same `+ /mcp` |
24
+
25
+ `preview` is per-target and comes from the adapter's `deploy()` result. Everything
26
+ else is computed by `resolveUrl` in `@rtrentjones/greenlight-shared`.
27
+
28
+ ## Procedure
29
+
30
+ 1. **Branch** — `git checkout -b <type>/<slug>` (e.g. `post/hello`, `fix/mcp-auth`).
31
+ 2. **Make the change.**
32
+ 3. **Preview** — push; the target's git integration produces a preview deploy. Verify it.
33
+ - Local/CI: `runLoop` (build → deploy → verify) from `@rtrentjones/greenlight-loop`.
34
+ - Standalone / local server: `pnpm greenlight verify <name> --url <preview-or-localhost-url>`.
35
+ 4. **Beta** — merge to `develop` → beta deploy. `pnpm greenlight verify <name> --env beta`.
36
+ Mode is chosen by lane: `api`/`playwright` for web, `mcp` for MCP servers.
37
+ 5. **Promote** — `pnpm greenlight promote <name>`. Checks the fast-forward guard
38
+ (`develop → main`). If it refuses (diverged `main`), reconcile and retry — never force-push.
39
+ 6. **Prod** — after promote, `pnpm greenlight verify <name> --env prod`.
40
+
41
+ ## Rules
42
+
43
+ - `verify` exits non-zero if any check fails; the report lists each. **Never promote a
44
+ tool whose beta verify is failing.**
45
+ - Connect URL for MCP tools is the tool URL + `/mcp`; `verify` handles this by lane.
46
+ - Real per-target deploys are wired in phases (greenlight-v1.md §16); the loop, verify,
47
+ and promote guard are stable now.
48
+
49
+ ## Cross-repo note
50
+
51
+ In standalone repos (BAMCP, ejected tools) this skill is delivered by the **Greenlight
52
+ Claude Code plugin** (Phase 7), and the mechanics by the `@rtrentjones/greenlight*` npm
53
+ deps; the per-repo parameters come from that repo's `greenlight.config.ts`.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: provider-cloudflare
3
+ description: How Cloudflare works in a Greenlight setup — the zone/DNS provider for every tool, Workers as the keepalive/blog target, token scoping (Workers Scripts:Edit + Zone DNS:Edit), and the Cloudflare MCP. Use when wiring DNS, the keepalive worker, a workers-target tool, or debugging a Cloudflare apply/token.
4
+ ---
5
+
6
+ # provider-cloudflare
7
+
8
+ Cloudflare is the **always-on** provider in Greenlight: it owns the DNS zone for the
9
+ domain (every tool's `<name>.<domain>` CNAME), hosts the **keepalive** Worker (a Cron
10
+ Trigger, immune to repo-inactivity disable), and is the `target: workers` runtime for the
11
+ blog and throwaway MCP dev targets.
12
+
13
+ ## Token — `CLOUDFLARE_API_TOKEN`
14
+
15
+ One token, **two scopes** (the trap that took down a live apply):
16
+ - **Account · Workers Scripts · Edit** — deploy the keepalive worker / workers-target tools.
17
+ - **Zone · DNS · Edit** — the subdomain CNAMEs.
18
+ - **Account · Account Settings · Read** — read account id.
19
+
20
+ Create at dash → My Profile → API Tokens → Custom Token. Store in `.greenlight/secrets.env`
21
+ (gitignored) and push to GitHub Actions with `greenlight secrets sync`. `greenlight add`
22
+ verifies it against `/user/tokens/verify` (status must be `active`) before you commit.
23
+
24
+ ## Terraform modules
25
+
26
+ - `infra/modules/tool` — the subdomain DNS record. `proxied = target != "vercel"` (Vercel
27
+ needs an unproxied CNAME to `cname.vercel-dns.com`; everything else is proxied).
28
+ - `infra/modules/keepalive` — `cloudflare_workers_script` + `cloudflare_workers_cron_trigger`,
29
+ self-contained (ships its own bundled `worker.js`). One worker aggregates all targets via
30
+ `targets_json`; do **not** emit a worker per tool. Needs a workers.dev subdomain registered
31
+ on the account once (error 10063 if missing).
32
+
33
+ ## MCP
34
+
35
+ `.mcp.json` wires `cloudflare` (Workers/DNS/R2/KV/D1/builds/observability) + `cloudflare-docs`.
36
+ Run `/mcp` to authenticate. For richer help: the `cloudflare@cloudflare` plugin skill.
37
+
38
+ ## Gotchas
39
+ - A DNS record for the apex managed by **wrangler** (Workers custom domain) collides with a
40
+ Terraform `cloudflare_dns_record` for the same name — pick one owner per record.
41
+ - The `observability` block on `cloudflare_workers_script` has a provider bug
42
+ (propagation_policy conversion error) — leave it off.
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: provider-github
3
+ description: How GitHub works in a Greenlight setup — secrets sync target (Actions secrets/environments), the repo/branch/protection Terraform module, the develop→main flow, and OIDC-over-PAT preference. Use when syncing tokens, wiring branch protection/environments, or debugging gh/secrets/CI auth.
4
+ ---
5
+
6
+ # provider-github
7
+
8
+ GitHub is the **always-on** control plane: it holds the Actions **secrets** (provider tokens),
9
+ the **environments** (beta/prod), branch protection, and runs the deploy/promote/infra
10
+ workflows. The `develop → main` flow is standardized (PR → preview, `develop` → beta, `main`
11
+ → prod; promote is a gated fast-forward).
12
+
13
+ ## Token — `GITHUB_TOKEN` (usually you don't set one)
14
+
15
+ - In **CI**, Actions provides `github.token` automatically — the infra.yml maps it to the
16
+ `github` provider. No PAT needed for single-repo infra.
17
+ - For **cross-repo** ops (managing another repo's settings, syncing secrets to a tool repo),
18
+ use a fine-grained **PAT** with the minimal scopes (e.g. `Secrets: write`, `Administration`
19
+ for protection). Prefer **GitHub OIDC → cloud** over long-lived cloud tokens where supported.
20
+
21
+ ## Secrets sync
22
+
23
+ `greenlight secrets sync [--repo o/r] [--env <env>]` pushes `.greenlight/secrets.env` to the
24
+ repo's Actions secrets via `gh` (values piped on stdin — never in argv or logs). Run
25
+ `gh auth login` first. This is the "init writes to provider stores" piece.
26
+
27
+ ## Terraform module — `infra/modules/repo`
28
+
29
+ Branches + protection + required checks (+ optional environments via the `tool` module's
30
+ `manage_github_environments`). For an **external** tool (code in its own repo), set
31
+ `manage_github_environments = false` so the wrapper's CI stays single-repo (no PAT needed).
32
+
33
+ ## Gotcha
34
+ Direct pushes/merges to a protected `main` are blocked — use `gh pr create` + merge, or the
35
+ gated `greenlight promote` fast-forward. Keep to `develop` (not `development`) for the branch.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: provider-hcp
3
+ description: How HCP Terraform works in a Greenlight setup — the remote-state backend (free tier, no credit card), local execution mode (HCP stores state + locks; runs use local/CI creds), the cloud{} block, and TF_API_TOKEN auth. Use when setting up remote state, debugging a backend/init/locking issue, or CI apply-on-push.
4
+ ---
5
+
6
+ # provider-hcp
7
+
8
+ HCP Terraform (app.terraform.io) is the **remote-state backend** for the wrapper's infra —
9
+ free tier, **no credit card**. It replaces local state so CI can `terraform apply` on push
10
+ with state locking (no two applies racing).
11
+
12
+ ## Execution mode — **Local**, deliberately
13
+
14
+ The workspace is set to **Local execution mode**: HCP **stores state + does locking only**;
15
+ `terraform` runs here / in CI with **our own provider creds** (Cloudflare/Vercel/Supabase
16
+ tokens from GitHub Actions secrets). This avoids uploading every provider token to HCP.
17
+
18
+ ## Token — `TF_API_TOKEN`
19
+
20
+ HCP → Account Settings → Tokens (a **user** API token). In CI it maps to the backend-auth env
21
+ var **`TF_TOKEN_app_terraform_io`** (the infra.yml does this mapping). `greenlight add`
22
+ verifies it against `/api/v2/organizations` (HTTP 200).
23
+
24
+ ## The `cloud{}` block
25
+
26
+ ```hcl
27
+ terraform {
28
+ cloud {
29
+ organization = "YOUR_ORG"
30
+ workspaces { name = "your-domain-with-dashes" }
31
+ }
32
+ }
33
+ ```
34
+
35
+ Migrate local → HCP with a plain `terraform init` (answer `yes` to copy state). The
36
+ `-migrate-state` / `-force-copy` flags are **rejected** for the cloud backend — don't pass them.
37
+
38
+ ## CI apply-on-push
39
+
40
+ `infra.yml` (on push to `main`, paths `infra/**`): map GH secrets → `TF_TOKEN_app_terraform_io`
41
+ + the provider tokens + `TF_VAR_*`, then setup-terraform (`terraform_wrapper: false`) → init →
42
+ plan -out → apply. This is the deploy half — the CLI only edits the `.tf`; CI applies.
43
+
44
+ ## Alternatives
45
+ See `docs/terraform-state-r2.md` for the full backend chooser (HCP no-CC · OCI S3-compat ·
46
+ R2 card-required · AWS · local).
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: provider-oci
3
+ description: How Oracle Cloud (OCI) works in a Greenlight setup — the `target: oci` runtime for stateful MCP servers (BAMCP) on a free-tier Ampere A1 Container Instance, the provider-agnostic build-via-GitHub→GHCR model, Greenlight-owned compute + tunnel Terraform, the OCI token CLI, deploy = restart, and the Always-Free idle-reclaim trap (PAYG, manual). Use when wiring/debugging an oci-target tool.
4
+ ---
5
+
6
+ # provider-oci
7
+
8
+ OCI is the `target: oci` runtime for **stateful** services that don't fit serverless — the
9
+ canonical case is **BAMCP** (a stateful MCP server). The split: **the tool is provider-agnostic
10
+ and just builds a container via GitHub; Greenlight owns the OCI infra** (compute + tunnel + DNS),
11
+ configured in the wrapper.
12
+
13
+ ## Free tier — A1 Container Instance + GHCR
14
+
15
+ The Always-Free path is an **OCI Container Instance** on **Ampere A1** (the A1 allotment — 2 OCPU
16
+ / 12 GB as of 2026-06-15 — is shared across VM / Bare-Metal / Container-Instances). No VM to
17
+ provision, no cloud-init, no SSH. The image comes from **GHCR** (free); **OCI's own registry
18
+ (OCIR) is paid** — that was the trap in the old BAMCP pipeline. The container instance runs the
19
+ tool container + a **cloudflared sidecar** (shared netns → localhost), exposed at `<name>.<domain>`.
20
+
21
+ ## Provider-agnostic tool → GHCR
22
+
23
+ The tool repo (BAMCP) has ONE job: a GitHub Actions workflow that **builds + pushes the container
24
+ to GHCR**. No OCI, no SSH, no deploy logic — portable to any provider's infra.
25
+
26
+ ## Greenlight OCI infra (Terraform, in the wrapper)
27
+
28
+ `greenlight add/adopt` emits, per oci tool:
29
+ - **`oci-container-instance`** module — the container instance (tool image from GHCR + cloudflared
30
+ sidecar with the tunnel token), `CI.Standard.A1.Flex` within the free allotment, restart ALWAYS.
31
+ - **`tunnel`** module — cloudflared tunnel + ingress `<name>.<domain> → http://localhost:8000` + token.
32
+ - **`tool`** DNS module — CNAME → the tunnel.
33
+ The `oci` provider (auth below) is added to `infra/main.tf`.
34
+
35
+ ## OCI token CLI
36
+
37
+ `greenlight add`/`init` gather the OCI creds into `.greenlight/secrets.env` (+ GH secrets):
38
+ **provider auth** `TF_VAR_oci_tenancy_ocid`, `TF_VAR_oci_user_ocid`, `TF_VAR_oci_fingerprint`,
39
+ `TF_VAR_oci_private_key` (PEM), `TF_VAR_oci_region`; **placement** `TF_VAR_oci_compartment_id`,
40
+ `TF_VAR_oci_availability_domain`, `TF_VAR_oci_subnet_id`; and `OCI_CONTAINER_INSTANCE_OCID`
41
+ (the Terraform output, for deploy). Auth is API-key request signing — no bearer, so no fetch-verify.
42
+
43
+ ## Deploy = restart (re-pull)
44
+
45
+ `greenlight deploy <tool>` (oci) just runs `oci container-instances container-instance restart
46
+ --container-instance-id <OCID>` — the instance re-pulls the latest GHCR image. The tool's CI
47
+ builds; an event trigger (the chosen deploy option) fires the restart. The adapter does NOT build.
48
+
49
+ ## The idle-reclaim trap — fixed manually, NOT by code
50
+
51
+ OCI **Always-Free reclaims idle compute**; pings don't count, only account standing. Convert the
52
+ tenancy to **Pay-As-You-Go** (+ a low billing budget alarm) — a one-time manual change (see
53
+ `docs/oci-payg-runbook.md`). Keepalive only **health-checks** + nags; it cannot stop reclaim.
54
+
55
+ ## Verify
56
+ The tool is typically an **MCP server**: verify with `mode: mcp`, connect at `<name>.<domain>/mcp`
57
+ (FastMCP's `streamable_http_app()` serves `/mcp` by default — the convention). If auth gates
58
+ `initialize`, supply a token or use an `api`-mode 401 check. Keepalive health-checks `target: oci`.
@@ -0,0 +1,40 @@
1
+ ---
2
+ name: provider-supabase
3
+ description: How Supabase works in a Greenlight setup — the `data: supabase` store (Postgres + auth + storage + realtime), single-project-schema-per-env model, the pause trap solved by keepalive, Management API token, and the read-only Supabase MCP. Use when wiring a tool's database, debugging a paused project, or a Supabase apply.
4
+ ---
5
+
6
+ # provider-supabase
7
+
8
+ `data: supabase` is for tools that need bundled **auth + storage + realtime** together
9
+ (HeistMind). One Supabase **project**, **schema-per-env** (beta/prod share the project —
10
+ NOT project-per-env; branching is paid). The project is **imported** (not recreated):
11
+ name/region are replace-forcing, so the module sets `ignore_changes` to protect the live DB.
12
+
13
+ ## Token — `SUPABASE_ACCESS_TOKEN`
14
+
15
+ Dashboard → Account → Access Tokens (Management API). Store in `.greenlight/secrets.env`;
16
+ `greenlight add` verifies it against `/v1/projects` (HTTP 200). The DB password
17
+ (`TF_VAR_supabase_database_password`) is only used if the project is recreated — ignored on
18
+ import, so `import-placeholder` is fine for an existing project.
19
+
20
+ ## Terraform module — `infra/modules/supabase`
21
+
22
+ Single project, import-safe. Outputs `url`, `anon_key`, `service_role_key`, `project_ref` —
23
+ feed these straight into the consumer (e.g. the Vercel env block). To re-apply from fresh
24
+ state, import first: `terraform import module.<name>_supabase.supabase_project.this <ref>`.
25
+
26
+ ## Keepalive — non-negotiable
27
+
28
+ Supabase **pauses a free project after ~7 days idle** — this is what takes tools down. The
29
+ **keepalive** Worker (cloudflare) pings the project on a cron. Add the tool to the aggregated
30
+ `module.keepalive.targets_json`: `{ name, env, url = module.<name>_supabase.url, anonKey = … }`.
31
+ The ping counts any HTTP response (even 401 on `/rest/v1/`) as alive.
32
+
33
+ ## MCP
34
+
35
+ `.mcp.json` wires `supabase` (hosted, **read-only**): needs `SUPABASE_ACCESS_TOKEN` +
36
+ `SUPABASE_PROJECT_REF` in the env (Claude Code expands `${VAR}` in the url/header). Run `/mcp`.
37
+
38
+ ## Rule
39
+ The **blog must never use Supabase** for state (it must stay up unattended) — use D1/KV or
40
+ external services. Supabase is per-tool, only when the bundled features are needed together.
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: provider-vercel
3
+ description: How Vercel works in a Greenlight setup — the default target for the `next` lane, configure-existing-project model (domains + env vars by project_id; deploys ride git integration), team-scoped token, and the Vercel MCP. Use when wiring a next/vercel tool, env vars, domains, or debugging a Vercel deploy.
4
+ ---
5
+
6
+ # provider-vercel
7
+
8
+ Vercel is the default `target` for the `next` lane. Greenlight does **not** create or deploy
9
+ the project — it **configures an existing** Vercel project (domains + environment variables)
10
+ by `project_id`, and the app's own repo deploys via Vercel's **git integration** (push →
11
+ build). The wrapper owns infra; the tool repo owns deploys.
12
+
13
+ ## Token — `VERCEL_API_TOKEN`
14
+
15
+ Account → Settings → Tokens. **Scope it to the team** that owns the project. The Terraform
16
+ `vercel` provider also takes `team` (the `team_…` id). Store in `.greenlight/secrets.env`;
17
+ `greenlight add` verifies it against `/v2/user` (HTTP 200) before commit.
18
+
19
+ ## Terraform module — `infra/modules/vercel`
20
+
21
+ Manages the **existing** project (nothing to import — it configures by id):
22
+ - `domain` → adds `<name>.<domain>` (production) + `beta.<name>.<domain>` (preview/`beta_branch`).
23
+ - `environment` + `environment_values` → env vars per target (`production` / `preview`).
24
+ Wire Supabase creds straight from the `supabase` module's outputs — no manual copy (that
25
+ manual copy was the old fragility).
26
+
27
+ The DNS CNAME is the **cloudflare** `tool` module, unproxied (`proxied = false`) → `cname.vercel-dns.com`.
28
+
29
+ ## MCP
30
+
31
+ `.mcp.json` wires `vercel` (hosted, OAuth, read-only). Run `/mcp` and authenticate in the
32
+ browser. Use it to read deployments, build logs, runtime logs, projects.
33
+
34
+ ## Gotchas
35
+ - **ENV_CONFLICT** on apply = a var with that key/target already exists on the project. Delete
36
+ the pre-existing ones (Vercel dashboard or API) then re-apply, or import them.
37
+ - The Greenlight `beta_branch` must match the repo's actual pre-prod branch (HeistMind uses
38
+ `development`; new tools use `develop`).
39
+ - `next` can also target `workers` (V0/V2) — default is vercel.
@@ -0,0 +1,7 @@
1
+ import {
2
+ verifyAgentWeb
3
+ } from "./chunk-UXHHLEYO.js";
4
+ import "./chunk-QFKE5JKC.js";
5
+ export {
6
+ verifyAgentWeb
7
+ };