@dk/jolly 0.1.11 → 0.2.0

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.
package/README.md CHANGED
@@ -4,9 +4,13 @@ Ahoy, agent. Go build a store.
4
4
 
5
5
  Jolly is a homepage + `npx` CLI + agent setup workflow that helps a customer's own agent set up and iterate on an end-to-end Saleor Cloud storefront.
6
6
 
7
+ Jolly is a tool by Dmytri Kleiner that helps agents set up a store quickly using
8
+ Saleor, Vercel and Stripe. It is not an official product of Saleor, Vercel, or
9
+ Stripe. The package is `@dk/jolly`; the homepage is https://jolly.cool.
10
+
7
11
  ## Agent workflow
8
12
 
9
- This repository uses Shipshape for its three-role, spec-driven agent workflow.
13
+ This repository uses [Shipshape](https://github.com/dmytri/shipshape) for its three-role, spec-driven agent workflow.
10
14
 
11
15
  Before substantive agent work, install or load Shipshape:
12
16
 
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: jolly
3
+ description: End-to-end playbook for setting up a Saleor Cloud storefront with Jolly — teaches the customer's own agent to drive the official CLIs (Vercel, @saleor/configurator, git, pnpm) plus Jolly's thin helpers, from `jolly start` to a live, deployed store.
4
+ ---
5
+
6
+ # Jolly setup playbook
7
+
8
+ You are the customer's own agent. **Jolly does not replace you** — it gives you a thin CLI
9
+ for plumbing (auth, store provisioning, secret writing, diagnostics) and this playbook. You
10
+ run the official CLIs yourself. Jolly never shells out to the Vercel CLI or
11
+ `@saleor/configurator`; you do.
12
+
13
+ Reach the goal — a real, deployed, working storefront (browsing, cart, and checkout to the
14
+ Stripe test payment step) — in as few human interruptions as possible. Pause only for the
15
+ unavoidable human steps: new-account creation, browser OAuth/login consent, and pasting secret
16
+ values. Everything else, automate.
17
+
18
+ > Exact upstream commands and flags (Vercel CLI, `@saleor/configurator`, Paper's
19
+ > `saleor/storefront`) change over time. Re-check the current upstream docs/`--help` at run
20
+ > time rather than trusting memorized invocations. The Jolly skill describes the *flow*; the
21
+ > tools own the *specifics*.
22
+
23
+ ## Before each action
24
+
25
+ Every Jolly command emits one structured envelope (`command`, `status`, `summary`, `data`,
26
+ `checks`, `nextSteps`, `errors`) and, before any create/modify/deploy action, a `riskContext`
27
+ (`action`, `target`, `riskLevel`, `categories`, `reversible`, `sideEffects`, `dryRunAvailable`).
28
+ **You** decide whether to seek the customer's approval based on that risk context and the
29
+ customer's policies — Jolly never hardcodes the decision. Parse `--json` output to branch.
30
+
31
+ ## Stages
32
+
33
+ 1. **Bootstrap** — the customer ran `jolly start` (or you did). It installed this skill and the
34
+ Saleor agent-skills via `npx skills add`, wrote `.mcp.json` (local mcp-graphql against the
35
+ customer's own endpoint), scaffolded, ran `jolly doctor`, and emitted the playbook. Read its
36
+ `data` and `nextSteps`.
37
+
38
+ 2. **Authenticate to Saleor Cloud** — if not already authed, run `jolly login`. It prefers the
39
+ browser OAuth flow and falls back to a pasted token; pause for the human's browser consent.
40
+ The Saleor Cloud token is stored as `JOLLY_SALEOR_CLOUD_TOKEN` in `.env`.
41
+
42
+ 3. **Provision the store** — run `jolly create store` (creates/reuses the Saleor Cloud
43
+ organization, project, and environment via the Cloud API). For a brand-new Saleor account,
44
+ direct the human to sign up at cloud.saleor.io first, then resume with the store URL.
45
+
46
+ 4. **App token** — run `jolly create app-token` to acquire a Saleor app token (all permissions
47
+ in v1) for configuration.
48
+
49
+ 5. **Storefront** — clone the Paper template yourself:
50
+ `git clone https://github.com/saleor/storefront.git ./storefront` (the `main` branch),
51
+ remove the upstream `.git`, run `git init`, `cp .env.example .env`, and `pnpm install`. If the
52
+ local Node version is incompatible with Paper, tell the human (don't switch Node yourself). In
53
+ the storefront's `.env`, set `NEXT_PUBLIC_SALEOR_API_URL` to your store's GraphQL endpoint and
54
+ `NEXT_PUBLIC_DEFAULT_CHANNEL=us` (the channel the starter recipe creates).
55
+
56
+ 6. **Configure the store** — the Jolly starter recipe ships with this skill as `recipe.yml`
57
+ (alongside this `SKILL.md`): a pirate-themed US/USD/English catalog with shipping and the `us`
58
+ channel Paper points at. Copy it into the storefront repo as `saleor-config.yml` (keep it
59
+ version-controlled and reviewable), then apply it with `@saleor/configurator`'s safe
60
+ workflow — `diff` to preview, then `deploy` — passing
61
+ `--url "$NEXT_PUBLIC_SALEOR_API_URL" --token "$JOLLY_SALEOR_APP_TOKEN" --config saleor-config.yml`
62
+ (or set `SALEOR_URL`/`SALEOR_TOKEN`). Add `--fail-on-breaking` on `deploy`. Show the diff and
63
+ seek the customer's approval before deploying writes. Jolly never runs the configurator; you do.
64
+
65
+ 7. **Stripe (test mode)** — get the test keys the fast way, via the official Stripe CLI's
66
+ browser OAuth login (no hunting through the Dashboard):
67
+ - Run `npx @stripe/cli login` — it prints a URL; have the human open it and approve in the
68
+ browser (one click). If they have no Stripe account, send them to
69
+ https://dashboard.stripe.com/register first (test mode works immediately after signup —
70
+ no business details needed). The CLI cannot create the account; that signup is the human's.
71
+ - Read the test-mode keys from the CLI config (`npx @stripe/cli config --list` /
72
+ `~/.config/stripe/config.toml`): `test_mode_pub_key` (`pk_test_…`) and `test_mode_api_key`
73
+ (`sk_test_…`). Pass them to `jolly create stripe --publishable-key … --secret-key …`, which
74
+ writes them to `.env` (never printed). Jolly never runs the Stripe CLI itself — you do.
75
+ - **These CLI-issued keys are test-mode and expire (~90 days — see `test_mode_key_expires_at`).**
76
+ That is the right tradeoff to get started fast, but the expiry is yours to handle: before it
77
+ hits, generate durable keys in the Stripe Dashboard (Developers → API keys), re-run
78
+ `jolly create stripe`, and update the Saleor Stripe app config. Flag the expiry date to the
79
+ human now and own the follow-up — do not let checkout silently break at the 90-day mark.
80
+ - Durable-from-the-start alternative: if the human prefers, skip the CLI and paste standard
81
+ Dashboard keys straight into `jolly create stripe`. Live mode (out of v1 scope) always uses
82
+ Dashboard keys.
83
+ Then configure Saleor's **Stripe app** — the Saleor-supported payment path, *not* the
84
+ configurator (which manages catalog only): in the Saleor Dashboard → Extensions, install or
85
+ open the Stripe app, add a configuration with those keys, and **map it to the `us` channel**.
86
+ The Stripe app registers its own Stripe webhooks automatically. This Dashboard step needs the
87
+ human's click — guide them through it.
88
+
89
+ 8. **Deploy to Vercel** — deploy with the official Vercel CLI: `npx vercel`. Authentication is
90
+ the Vercel CLI's own `vercel login` session — if `npx vercel whoami` fails, pause and have
91
+ the human run `npx vercel login` (browser), then resume. Set the project's env vars
92
+ (`NEXT_PUBLIC_SALEOR_API_URL`, `NEXT_PUBLIC_DEFAULT_CHANNEL=us`) with the Vercel CLI
93
+ (`npx vercel env add …`), deploy to production (`npx vercel --prod`), and capture the deployed
94
+ URL. Do not use any other deployment mechanism.
95
+
96
+ 9. **Wire trusted origins** — update Saleor's allowed/trusted origins to include the deployed
97
+ storefront URL.
98
+
99
+ 10. **Verify** — run `jolly doctor` (all groups) to confirm operational readiness: Saleor
100
+ connectivity, storefront env, deployment reachability, and that checkout reaches the Stripe
101
+ test payment step. Report the live URL, the doctor results, and any remaining manual steps.
102
+
103
+ ## If a step fails or you're unsure
104
+
105
+ Run `npx @dk/jolly doctor` — it tells you what is wrong and the concrete next action (a
106
+ command to run, a CLI to authenticate, a value to ask your human for). Fix that, then
107
+ continue. Re-running `jolly start` is safe: Jolly detects what you (and it) already did —
108
+ the cloned storefront, the configured store, the deployment — and resumes from the first
109
+ outstanding step rather than redoing work. Never treat a failed command as success.
110
+
111
+ ## Honesty
112
+
113
+ Never claim a step succeeded that you did not actually perform and confirm. If a CLI is missing
114
+ or unauthenticated, stop and tell the human exactly what to do (e.g. `npx vercel login`) — do
115
+ not fabricate success or invent a fallback. Jolly's own commands follow the same rule.
@@ -0,0 +1,307 @@
1
+ # Jolly starter recipe — a @saleor/configurator config that turns a freshly
2
+ # created Saleor Cloud environment into a working, browsable, checkout-ready
3
+ # storefront for the Paper template. Playful pirate-themed demo catalog, single
4
+ # US / USD / English market (v1).
5
+ #
6
+ # This file ships with the Jolly skill. The agent copies it into the cloned
7
+ # storefront repo (keep it version-controlled and reviewable) and applies it
8
+ # with the official Configurator safe workflow — Jolly never runs Configurator:
9
+ #
10
+ # npx @saleor/configurator diff --url "$NEXT_PUBLIC_SALEOR_API_URL" \
11
+ # --token "$JOLLY_SALEOR_APP_TOKEN" --config saleor-config.yml
12
+ # npx @saleor/configurator deploy --url "$NEXT_PUBLIC_SALEOR_API_URL" \
13
+ # --token "$JOLLY_SALEOR_APP_TOKEN" --config saleor-config.yml --fail-on-breaking
14
+ #
15
+ # Then point the Paper storefront at this channel: NEXT_PUBLIC_DEFAULT_CHANNEL=us
16
+ #
17
+ # Customize freely — rename the shop, swap in your own catalog. If Configurator
18
+ # rejects a field, re-check its current example.yml schema; the tool owns the
19
+ # specifics, this recipe owns the starting point.
20
+
21
+ shop:
22
+ defaultMailSenderName: "Jolly Roger Outfitters"
23
+ displayGrossPrices: true
24
+ trackInventoryByDefault: false # demo catalog sells without stock counts
25
+ defaultWeightUnit: KG
26
+
27
+ # Single US / USD market. CHARGE flow so test-mode Stripe captures immediately.
28
+ channels:
29
+ - name: United States
30
+ slug: us
31
+ currencyCode: USD
32
+ defaultCountry: US
33
+ isActive: true
34
+ settings:
35
+ automaticallyConfirmAllNewOrders: true
36
+ markAsPaidStrategy: TRANSACTION_FLOW
37
+ defaultTransactionFlowStrategy: CHARGE
38
+ taxConfiguration:
39
+ taxCalculationStrategy: FLAT_RATES
40
+ chargeTaxes: false
41
+ displayGrossPrices: true
42
+ pricesEnteredWithTax: true
43
+
44
+ # One simple shippable product type — no custom attributes to keep the happy
45
+ # path robust. Add attributes/variants later when you customize.
46
+ productTypes:
47
+ - name: Pirate Goods
48
+ isShippingRequired: true
49
+
50
+ categories:
51
+ - name: Weapons
52
+ slug: weapons
53
+ - name: Navigation
54
+ slug: navigation
55
+ - name: Apparel
56
+ slug: apparel
57
+ - name: Treasure
58
+ slug: treasure
59
+ - name: Ship Supplies
60
+ slug: ship-supplies
61
+
62
+ warehouses:
63
+ - name: Port Royal Warehouse
64
+ slug: port-royal
65
+ email: quartermaster@jolly.example
66
+ isPrivate: false
67
+ clickAndCollectOption: DISABLED
68
+ address:
69
+ streetAddress1: "1 Mallory Square"
70
+ city: Key West
71
+ postalCode: "33040"
72
+ country: US
73
+ countryArea: FL
74
+ companyName: "Jolly Roger Outfitters"
75
+
76
+ # A default US shipping zone so checkout can reach the payment step.
77
+ shippingZones:
78
+ - name: United States
79
+ description: "Shipping within the United States"
80
+ default: true
81
+ countries:
82
+ - US
83
+ warehouses:
84
+ - port-royal
85
+ channels:
86
+ - us
87
+ shippingMethods:
88
+ - name: Standard Shipping
89
+ type: PRICE
90
+ minimumDeliveryDays: 3
91
+ maximumDeliveryDays: 7
92
+ channelListings:
93
+ - channel: us
94
+ price: 5.00
95
+ minimumOrderPrice: 0
96
+ - name: Free Shipping
97
+ type: PRICE
98
+ minimumDeliveryDays: 5
99
+ maximumDeliveryDays: 10
100
+ channelListings:
101
+ - channel: us
102
+ price: 0
103
+ minimumOrderPrice: 50
104
+
105
+ # Pirate catalog — single-variant products, each published and priced in USD so
106
+ # Paper can list, cart, and check them out immediately.
107
+ products:
108
+ - name: "Cutlass"
109
+ slug: cutlass
110
+ description: "A trusty curved blade, forged for close-quarters boarding actions."
111
+ productType: Pirate Goods
112
+ category: weapons
113
+ channelListings:
114
+ - channel: us
115
+ isPublished: true
116
+ visibleInListings: true
117
+ isAvailableForPurchase: true
118
+ variants:
119
+ - name: Default
120
+ sku: CUTLASS-001
121
+ channelListings:
122
+ - channel: us
123
+ price: 89.00
124
+
125
+ - name: "Flintlock Pistol"
126
+ slug: flintlock-pistol
127
+ description: "One shot, one chance — make it count, then swing the cutlass."
128
+ productType: Pirate Goods
129
+ category: weapons
130
+ channelListings:
131
+ - channel: us
132
+ isPublished: true
133
+ visibleInListings: true
134
+ isAvailableForPurchase: true
135
+ variants:
136
+ - name: Default
137
+ sku: FLINTLOCK-001
138
+ channelListings:
139
+ - channel: us
140
+ price: 149.00
141
+
142
+ - name: "Brass Spyglass"
143
+ slug: brass-spyglass
144
+ description: "Spot the king's frigates — and the merchantmen — long before they spot you."
145
+ productType: Pirate Goods
146
+ category: navigation
147
+ channelListings:
148
+ - channel: us
149
+ isPublished: true
150
+ visibleInListings: true
151
+ isAvailableForPurchase: true
152
+ variants:
153
+ - name: Default
154
+ sku: SPYGLASS-001
155
+ channelListings:
156
+ - channel: us
157
+ price: 59.00
158
+
159
+ - name: "Pirate's Compass"
160
+ slug: pirates-compass
161
+ description: "Points not north, but toward what your heart wants most. Usually rum."
162
+ productType: Pirate Goods
163
+ category: navigation
164
+ channelListings:
165
+ - channel: us
166
+ isPublished: true
167
+ visibleInListings: true
168
+ isAvailableForPurchase: true
169
+ variants:
170
+ - name: Default
171
+ sku: COMPASS-001
172
+ channelListings:
173
+ - channel: us
174
+ price: 39.00
175
+
176
+ - name: "Tricorne Hat"
177
+ slug: tricorne-hat
178
+ description: "Three corners of pure intimidation. Feather not included."
179
+ productType: Pirate Goods
180
+ category: apparel
181
+ channelListings:
182
+ - channel: us
183
+ isPublished: true
184
+ visibleInListings: true
185
+ isAvailableForPurchase: true
186
+ variants:
187
+ - name: Default
188
+ sku: TRICORNE-001
189
+ channelListings:
190
+ - channel: us
191
+ price: 45.00
192
+
193
+ - name: "Leather Eyepatch"
194
+ slug: leather-eyepatch
195
+ description: "Keeps one eye dark-adapted for going below decks. Also: very dashing."
196
+ productType: Pirate Goods
197
+ category: apparel
198
+ channelListings:
199
+ - channel: us
200
+ isPublished: true
201
+ visibleInListings: true
202
+ isAvailableForPurchase: true
203
+ variants:
204
+ - name: Default
205
+ sku: EYEPATCH-001
206
+ channelListings:
207
+ - channel: us
208
+ price: 12.00
209
+
210
+ - name: "Treasure Map (Authentic Replica)"
211
+ slug: treasure-map
212
+ description: "X marks the spot. We make no guarantees about what's under the X."
213
+ productType: Pirate Goods
214
+ category: treasure
215
+ channelListings:
216
+ - channel: us
217
+ isPublished: true
218
+ visibleInListings: true
219
+ isAvailableForPurchase: true
220
+ variants:
221
+ - name: Default
222
+ sku: MAP-001
223
+ channelListings:
224
+ - channel: us
225
+ price: 25.00
226
+
227
+ - name: "Pieces of Eight (Coin Set)"
228
+ slug: pieces-of-eight
229
+ description: "A handful of gleaming doubloons. Spend them, bury them, bite them to check."
230
+ productType: Pirate Goods
231
+ category: treasure
232
+ channelListings:
233
+ - channel: us
234
+ isPublished: true
235
+ visibleInListings: true
236
+ isAvailableForPurchase: true
237
+ variants:
238
+ - name: Default
239
+ sku: COINS-001
240
+ channelListings:
241
+ - channel: us
242
+ price: 30.00
243
+
244
+ - name: "Oak Rum Barrel"
245
+ slug: oak-rum-barrel
246
+ description: "Provisions for a long voyage. The most important supply on any ship."
247
+ productType: Pirate Goods
248
+ category: ship-supplies
249
+ channelListings:
250
+ - channel: us
251
+ isPublished: true
252
+ visibleInListings: true
253
+ isAvailableForPurchase: true
254
+ variants:
255
+ - name: Default
256
+ sku: RUMBARREL-001
257
+ channelListings:
258
+ - channel: us
259
+ price: 120.00
260
+
261
+ - name: "Jolly Roger Flag"
262
+ slug: jolly-roger-flag
263
+ description: "Run it up the mast and watch the prices — and the prizes — surrender."
264
+ productType: Pirate Goods
265
+ category: ship-supplies
266
+ channelListings:
267
+ - channel: us
268
+ isPublished: true
269
+ visibleInListings: true
270
+ isAvailableForPurchase: true
271
+ variants:
272
+ - name: Default
273
+ sku: FLAG-001
274
+ channelListings:
275
+ - channel: us
276
+ price: 35.00
277
+
278
+ # A featured collection for Paper's storefront merchandising.
279
+ collections:
280
+ - name: "Crew Favorites"
281
+ slug: crew-favorites
282
+ description: "What every well-equipped pirate carries aboard."
283
+ products:
284
+ - cutlass
285
+ - brass-spyglass
286
+ - tricorne-hat
287
+ - jolly-roger-flag
288
+ channelListings:
289
+ - channelSlug: us
290
+ isPublished: true
291
+
292
+ menus:
293
+ - name: Main Navigation
294
+ slug: main-nav
295
+ items:
296
+ - name: Weapons
297
+ category: weapons
298
+ - name: Navigation
299
+ category: navigation
300
+ - name: Apparel
301
+ category: apparel
302
+ - name: Treasure
303
+ category: treasure
304
+ - name: Ship Supplies
305
+ category: ship-supplies
306
+ - name: Crew Favorites
307
+ collection: crew-favorites
package/bin/jolly CHANGED
@@ -1,2 +1,49 @@
1
- #!/usr/bin/env bun
2
- import "../src/index.ts";
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // Jolly CLI launcher (feature 006, decision 2026-06-12): the published Jolly
5
+ // CLI is a Node.js program. This launcher runs `src/index.ts` under
6
+ // Node.js >= 23 via native type stripping and never invokes or requires Bun
7
+ // (Bun is the project's development environment only).
8
+ //
9
+ // Deliberately plain CommonJS-compatible JavaScript so that an old Node can
10
+ // parse it and reach the version guard below instead of dying with a raw
11
+ // syntax or module error.
12
+
13
+ var MIN_NODE_MAJOR = 23;
14
+
15
+ var nodeVersion = process.versions.node;
16
+ var nodeMajor = parseInt(nodeVersion.split(".")[0], 10);
17
+
18
+ if (!(nodeMajor >= MIN_NODE_MAJOR)) {
19
+ console.error(
20
+ "jolly requires Node.js >= " +
21
+ MIN_NODE_MAJOR +
22
+ ", but this is Node.js " +
23
+ nodeVersion +
24
+ ". Please upgrade Node.js (https://nodejs.org) and try again.",
25
+ );
26
+ process.exit(1);
27
+ }
28
+
29
+ import("../src/index.ts").catch(function (error) {
30
+ if (error && error.code === "ERR_UNKNOWN_FILE_EXTENSION") {
31
+ // Node >= 23 but before 23.6: type stripping exists behind a flag rather
32
+ // than by default. Re-run the entry point with the flag enabled.
33
+ rerunWithStripTypes();
34
+ return;
35
+ }
36
+ throw error;
37
+ });
38
+
39
+ function rerunWithStripTypes() {
40
+ var path = require("node:path");
41
+ var spawnSync = require("node:child_process").spawnSync;
42
+ var entry = path.join(__dirname, "..", "src", "index.ts");
43
+ var result = spawnSync(
44
+ process.execPath,
45
+ ["--experimental-strip-types", entry].concat(process.argv.slice(2)),
46
+ { stdio: "inherit" },
47
+ );
48
+ process.exit(result.status === null ? 1 : result.status);
49
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dk/jolly",
3
- "version": "0.1.11",
3
+ "version": "0.2.0",
4
4
  "description": "Ahoy, agent. Go build a Saleor storefront.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,13 +9,14 @@
9
9
  "files": [
10
10
  "bin/",
11
11
  "src/",
12
+ "assets/skills/",
12
13
  "README.md"
13
14
  ],
14
15
  "publishConfig": {
15
16
  "access": "public"
16
17
  },
17
18
  "engines": {
18
- "bun": ">=1.1.0"
19
+ "node": ">=23.0.0"
19
20
  },
20
21
  "scripts": {
21
22
  "dev": "bun run --watch src/index.ts",