@homie-rocks/studio 0.51.4 → 0.51.5
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/CHANGELOG.md +29 -0
- package/README.md +10 -29
- package/apps/APPS.md +1 -1
- package/bin/homie-studio.mjs +28 -30
- package/guides/app/SKILL.md +1 -1
- package/guides/art/SKILL.md +68 -140
- package/guides/art/scripts/art.mjs +6 -79
- package/guides/models/SKILL.md +73 -177
- package/guides/models/references/RIGHTS.md +1 -1
- package/guides/models/scripts/models.mjs +7 -288
- package/guides/music/SKILL.md +74 -183
- package/guides/music/references/COMPOSITION.md +21 -26
- package/guides/music/references/GAME-AUDIO.md +3 -3
- package/guides/music/references/RIGHTS.md +12 -15
- package/guides/music/scripts/music.mjs +11 -202
- package/guides/parts/SKILL.md +1 -1
- package/guides/shop/SKILL.md +68 -77
- package/guides/sound/SKILL.md +70 -1
- package/guides/sound/scripts/player/sound.js +233 -0
- package/guides/studio-setup/SKILL.md +11 -27
- package/guides/studio-setup/references/OFFICIAL-MEDIA.md +66 -0
- package/guides/style/SKILL.md +66 -3
- package/guides/video/SKILL.md +83 -0
- package/guides/video/references/DELIVERY.md +73 -0
- package/guides/video/references/HONESTY.md +40 -0
- package/guides/video/references/METHOD.md +144 -0
- package/guides/video/references/RECORD.md +137 -0
- package/guides/video/references/TRAILER.md +154 -0
- package/guides/video/references/examples/site-walkthrough.json +14 -0
- package/guides/video/references/examples/studio-play-phone.json +15 -0
- package/guides/video/references/examples/studio-play.json +17 -0
- package/guides/video/scripts/capture-game.mjs +175 -0
- package/guides/video/scripts/clock.js +136 -0
- package/guides/video/scripts/drawover/film.js +58 -0
- package/guides/video/scripts/drawover/index.html +9 -0
- package/guides/video/scripts/drawover/look.js +115 -0
- package/guides/video/scripts/drawover/shots.json +12 -0
- package/guides/video/scripts/lib/browser.mjs +87 -0
- package/guides/video/scripts/lib/frames.mjs +170 -0
- package/guides/video/scripts/lib/remix.mjs +159 -0
- package/guides/video/scripts/qa.mjs +127 -0
- package/guides/video/scripts/record-fixed.mjs +403 -0
- package/guides/video/scripts/record-page.mjs +477 -0
- package/guides/video/scripts/tap.js +108 -0
- package/guides/video/scripts/video.mjs +888 -0
- package/lib/build.mjs +12 -9
- package/lib/cloudflare.mjs +6 -11
- package/lib/dev.mjs +1 -2
- package/lib/doctor.mjs +10 -54
- package/lib/mcp-tools.mjs +42 -21
- package/lib/mcp.mjs +1 -1
- package/lib/media-import.mjs +41 -0
- package/lib/media-workflows.mjs +13 -0
- package/lib/official-media.mjs +15 -0
- package/lib/rules-build.mjs +13 -5
- package/lib/scaffold.mjs +2 -2
- package/lib/shop-links.mjs +54 -18
- package/lib/shop-listen.mjs +43 -0
- package/lib/shop-local.mjs +1 -1
- package/lib/shop-mcp.mjs +58 -0
- package/lib/stripe-connect.mjs +36 -15
- package/lib/template-history.json +45 -0
- package/lib/upgrade-media.mjs +13 -0
- package/lib/upgrade.mjs +10 -0
- package/package.json +1 -1
- package/parts/PARTS.md +1 -1
- package/rules/view.ts +4 -0
- package/shop/SHOP.md +66 -34
- package/worker/build-id.mjs +1 -1
- package/worker/index.mjs +5 -1
- package/worker/purchase-reconciliation.mjs +16 -1
- package/worker/shop-subscriptions.mjs +2 -0
- package/worker/shop.mjs +7 -5
- package/worker/stripe-ownership.mjs +7 -0
- package/worker/version.mjs +1 -1
- package/guides/models/references/models.json +0 -175
- package/guides/music/scripts/lib/eleven.mjs +0 -260
- package/lib/projects-env.mjs +0 -68
- package/lib/projects.mjs +0 -311
- package/lib/provider-key.mjs +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,35 @@ To bring a studio up to date, tell Claude: "Upgrade my studio to the newest Homi
|
|
|
17
17
|
`npx -y @homie-rocks/studio@latest upgrade`, which shows what's new since the version your studio pins (from this
|
|
18
18
|
file) and what the upgrade would change, and changes nothing until you agree.
|
|
19
19
|
|
|
20
|
+
## [0.51.5] - 2026-10-14
|
|
21
|
+
|
|
22
|
+
**Plugin 0.51.5**
|
|
23
|
+
|
|
24
|
+
Connect your shop and media through official plugins, keep renewals and free bookings working, and see progress while you build.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **Shop setup:** Stripe's official plugin can configure and verify products, prices, item and menu links, paid bookings, monthly giving and the customer portal. Homie plans only the changes your shop needs. No API keys are requested; webhook installation checks the Stripe account and passes the signing secret privately to Wrangler, never through the model. Local webhook forwarding keeps its secret private too.
|
|
29
|
+
- **Build iteration:** Builds report progress, including during JSON output, and show a heartbeat while generated rules play. `build --quick` keeps type and guard checks while skipping play and snapshot smoke checks.
|
|
30
|
+
- **Media placement:** `media import` places completed media, checks scene references and records file hashes, rights, provenance and explicit cost status. Video guidance and local processing tools now ship with the toolkit.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- **Official media connections:** Art, models, music, sound, video and style use the official fal and ElevenLabs plugins in your AI client. Homie still handles art direction, local processing, placement and provenance. Its own provider generation clients, key-file readers and Stripe Projects credential bridge have been removed.
|
|
35
|
+
- **Connection setup:** Setup reports official connections verified in the current session and explains browser sign-in. Cloudflare inspection uses its official MCP; deployment continues through Wrangler's browser login.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- **Recurring gifts and memberships:** Each renewal reaches your shop and notifies apps once, even when the studio also sells parts. Renewals keep the original purchase reference so apps can identify the cause or member. Subscription updates and cancellations reach the shop; parts payments retain their own route.
|
|
40
|
+
- **Free volunteer shifts and services:** Free bookings in a mixed free/paid app work before Stripe is connected. They confirm locally and enforce capacity; paid checkout still requires a connection.
|
|
41
|
+
|
|
42
|
+
### Upgrade notes
|
|
43
|
+
|
|
44
|
+
- Update the toolkit and Homie plugin together, run upgrade, and connect the official provider plugins in your AI client. Existing media remains usable. Upgrade replaces retired credential instructions without reading or migrating old key files. Available ElevenLabs media capabilities depend on the connected server and are checked before generation.
|
|
45
|
+
- Shop setup starts with `stripe_shop_plan` / `shop plan`, then `stripe_webhook` / `shop webhook`. Private webhook setup may need a separate Stripe CLI browser approval. `shop connect` remains the full CLI alternative; `shop listen` forwards local events privately.
|
|
46
|
+
- Run a full build before release, even if you used `build --quick` while iterating.
|
|
47
|
+
- Remove any temporary subscription-routing postinstall workaround for 0.51.3–0.51.4 after upgrading.
|
|
48
|
+
|
|
20
49
|
## [0.51.4] - 2026-10-14
|
|
21
50
|
|
|
22
51
|
**Plugin 0.51.4** · Studio events through experimental MCP Events.
|
package/README.md
CHANGED
|
@@ -513,17 +513,7 @@ npx homie-studio shop # open (test or live) or what is m
|
|
|
513
513
|
npx homie-studio shop refund ord_… # an ASK: the owner taps once (or Refund in /_studio/office/shop)
|
|
514
514
|
```
|
|
515
515
|
|
|
516
|
-
Connect
|
|
517
|
-
Where the CLI supplies a transferable legacy test key, the toolkit creates the webhook and installs both Worker
|
|
518
|
-
secrets privately. It reports the 90-day expiry; `shop connect --renew` obtains approval again. Current CLI OAuth
|
|
519
|
-
and live mode cannot export an independent Worker's key, so the result names that limitation. Only if the owner
|
|
520
|
-
chooses the fallback does `shop connect --manual` open the old local key page (`--manual --live` for live mode).
|
|
521
|
-
Never request a key in chat. Login is not a verified purchase; complete the test purchase, webhook and refund check.
|
|
522
|
-
|
|
523
|
-
Stripe's optional agent tools (`stripe agent setup`) provide MCP and skills for catalog work (`shop catalog`),
|
|
524
|
-
tax reads and sales questions. They are separate from the Worker's credentials. Never create a webhook through
|
|
525
|
-
MCP because its response contains a secret. From 2026-10-31 Stripe MCP accepts only OAuth or Agent-tagged keys;
|
|
526
|
-
that change does not affect the shop's ordinary restricted API key. [SHOP.md](shop/SHOP.md) describes the flow.
|
|
516
|
+
Connect through Stripe’s official OAuth plugin: `stripe_shop_plan` gives exact catalog, menu, booking and recurring operations for Stripe MCP and verifies its fresh reads. `stripe_webhook` privately installs the signing secret using one separate Stripe CLI browser approval if needed. No owner handles a key. `shop connect` remains the CLI alternative. [SHOP.md](shop/SHOP.md) describes the flow.
|
|
527
517
|
|
|
528
518
|
In a game: `createShop()` from `@homie-rocks/studio/shop` (`has`, `entitlements`, `on('change')`, `open`, `used`, `add`, `checkout`, `buy`); a
|
|
529
519
|
supporter's badge rides on their seat (`peer.badge`). Stripe Checkout (hosted), optional Stripe Tax, or Stripe Managed
|
|
@@ -1185,26 +1175,17 @@ no Wrangler, no rooms, the game alone and offline with its bots) and shoots that
|
|
|
1185
1175
|
there (it needs rooms: use `dev` and `--url`). The result names the build the frames are of, by the hash `build`
|
|
1186
1176
|
printed and the hashed bundle the page loaded.
|
|
1187
1177
|
|
|
1188
|
-
##
|
|
1178
|
+
## Official media and hosting connections
|
|
1189
1179
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1180
|
+
Connect fal and ElevenLabs through their official plugins in your AI client and approve
|
|
1181
|
+
one browser sign-in per provider. Homie never handles their credentials. Cloudflare's
|
|
1182
|
+
plugin provides account inspection; deployment keeps pinned Wrangler's own browser login.
|
|
1183
|
+
See [connection and upgrade guidance](guides/studio-setup/references/OFFICIAL-MEDIA.md).
|
|
1193
1184
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
It stops with a `needs` step at each thing that is the person's (the Stripe CLI and its Projects plugin, Stripe's
|
|
1200
|
-
sign-in, the providers' terms, Cloudflare's own approval page for an existing account); it never adds a paid plan or
|
|
1201
|
-
a payment method. The Cloudflare account id goes in studio.json with `"auth": "stripe-projects"`; the token stays in
|
|
1202
|
-
Projects' vault and the git-ignored `.env` it syncs, and every Wrangler run in the studio takes it from there
|
|
1203
|
-
(`deploy`, `dev`, secrets, the office). It checks read-only what the token can do (Wrangler signed in, D1, Workers AI;
|
|
1204
|
-
R2 is optional) and that `.gitignore` keeps `.env`, `.env.*`, `.projects/vault/` and `.projects/cache/` out of git.
|
|
1205
|
-
With `--with elevenlabs` the music skill finds the ElevenLabs key there too (ElevenLabs' free plan has no commercial
|
|
1206
|
-
licence). Unverified until a real run: the exact JSON of the Projects commands, and the Cloudflare token's permission
|
|
1207
|
-
groups, which the checks measure instead of assuming.
|
|
1185
|
+
`homie-studio media import --file <download> --receipt <receipt.json> --out <studio-path>
|
|
1186
|
+
--used-by <scene-file>` places a completed asset and records its hash, rights, style and
|
|
1187
|
+
cost status in `media/provenance.json`. It makes no provider calls. The scene file must
|
|
1188
|
+
reference the delivered path; also verify the asset in the running scene.
|
|
1208
1189
|
|
|
1209
1190
|
## No payment method needed
|
|
1210
1191
|
|
package/apps/APPS.md
CHANGED
|
@@ -114,7 +114,7 @@ information in a separate private collection. Public roles must not have write
|
|
|
114
114
|
capabilities for slots or bookings. Staff movement is a versioned record update
|
|
115
115
|
containing only `slot`; confirmation and release follow verified Checkout state.
|
|
116
116
|
The default keyless connection uses one Payment Link per published slot. Call
|
|
117
|
-
`
|
|
117
|
+
`stripe_shop_plan` with the complete slot manifest after publishing/changing slots. Pending checkout does not
|
|
118
118
|
block others; payment secures the seat. Use record.booking.full/available/synced
|
|
119
119
|
for slot display. Read SHOP.md for the complete manifest and limitations.
|
|
120
120
|
|
package/bin/homie-studio.mjs
CHANGED
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
* homie-studio app role <id> <role> [--player <account>] [--revoke] [--url <site>]
|
|
18
18
|
* homie-studio game new <id> [--from gem-rush] [--name "<Game Name>"]
|
|
19
19
|
* homie-studio games
|
|
20
|
-
* homie-studio build [<id>] [--maps] [--types] [--long-check] (--maps: also keep each bundle's source map and
|
|
20
|
+
* homie-studio build [<id>] [--maps] [--types] [--long-check] [--quick] (--maps: also keep each bundle's source map and
|
|
21
21
|
* module sizes in .studio/maps/<id>/, never in site/dist: what `perf` reads a
|
|
22
|
-
* CPU profile through; --types: check the games' TypeScript first, with the
|
|
22
|
+
* CPU profile through; --quick: skip rules play and smoke checks; --types: check the games' TypeScript first, with the
|
|
23
23
|
* studio's own `typescript`; a type error stops the build; --long-check: play
|
|
24
24
|
* each rules game eight times as long before it is written (a rules game is
|
|
25
25
|
* always type-checked and played; this is more of the same play, for a
|
|
@@ -183,10 +183,11 @@
|
|
|
183
183
|
* homie-studio shop is the studio's shop selling (its own Stripe), and if not, what is missing
|
|
184
184
|
* homie-studio shop init [--supporter|--giving] [--currency <code>] [--price 500] [--managed] shop.json and SELLING.md
|
|
185
185
|
* homie-studio shop check shop.json against studio settings and provider requirements
|
|
186
|
-
* homie-studio shop
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
186
|
+
* homie-studio shop listen --profile <sandbox> [--port 8787] private local webhook forwarding
|
|
187
|
+
* homie-studio shop plan --have <file> exact next operation for Stripe's official MCP (public reads only)
|
|
188
|
+
* homie-studio shop verify --have <file> verify fresh MCP reads and save the public link configuration
|
|
189
|
+
* homie-studio shop webhook [--live] [--renew] privately install webhook using one Stripe CLI browser approval
|
|
190
|
+
* homie-studio shop connect [--live] [--renew] alternative: full sync through Stripe CLI approval
|
|
190
191
|
* homie-studio shop catalog [--have <file>|-] [--mode test|live] the items as Products in the studio's Stripe,
|
|
191
192
|
* made by the AI through Stripe's own MCP: the read first, then (with what it
|
|
192
193
|
* answered) the exact writes; in sync, shop.json "catalog" records the mode
|
|
@@ -226,14 +227,9 @@
|
|
|
226
227
|
* homie-studio setup attach <hs_…> [--client claude|codex|grok]
|
|
227
228
|
* (this repository is the studio the chat's setup card is making: say so, once,
|
|
228
229
|
* learn its live address, and give a template copy its real name)
|
|
229
|
-
* homie-studio setup --via stripe-projects [--with elevenlabs] [--accept-tos] [--dry-run]
|
|
230
|
-
* (a prototype, 0.24.3: Cloudflare, and ElevenLabs with --with, made or linked
|
|
231
|
-
* through Stripe Projects on their free plans; the person accepts the providers'
|
|
232
|
-
* terms (then --accept-tos) and signs in on Stripe's and the provider's own
|
|
233
|
-
* pages; the account id goes into studio.json, the token stays in Projects'
|
|
234
|
-
* vault and its git-ignored .env, and Wrangler runs with it here. The usual
|
|
235
|
-
* way, npx wrangler login, stays the default. lib/projects.mjs)
|
|
236
230
|
* homie-studio domain <hostname> AI configures DNS/TLS for the next deploy
|
|
231
|
+
* homie-studio media import --file <download> --receipt <receipt.json> --out <studio-path> --used-by <scene-file>
|
|
232
|
+
* Place completed official MCP output with provenance (no provider calls)
|
|
237
233
|
* homie-studio setup prepare AI installs a private Node/npm if missing
|
|
238
234
|
* homie-studio setup status [--connector yes|no] [--client claude|codex|grok] (also: homie-studio doctor)
|
|
239
235
|
* what this computer and the person's accounts have for a studio: Node, the Homie
|
|
@@ -325,6 +321,7 @@
|
|
|
325
321
|
*
|
|
326
322
|
* Every command prints a few lines for a person; --json prints the result.
|
|
327
323
|
*/
|
|
324
|
+
import { importMedia } from '../lib/media-import.mjs';
|
|
328
325
|
// FIRST, before any other file of the toolkit is evaluated: a Node.js that is too old ends here, with the reason.
|
|
329
326
|
import '../lib/node-version.mjs';
|
|
330
327
|
import { spawn, spawnSync } from 'node:child_process';
|
|
@@ -362,8 +359,6 @@ import { agentsBrain, agentsBrainKey, agentsPass, agentsPasses, agentsRevoke, ag
|
|
|
362
359
|
import { AgentSeat } from '../lib/agent-seat.mjs';
|
|
363
360
|
import { shopCheck, shopConnect, shopDisconnect, shopInit, shopLines, shopOrders, shopRefund, shopStatus } from '../lib/shop.mjs';
|
|
364
361
|
import { catalogLines, catalogPlan } from '../lib/shop-catalog.mjs';
|
|
365
|
-
import { projectsLines, setupViaProjects } from '../lib/projects.mjs';
|
|
366
|
-
import { projectsCloudflareEnv } from '../lib/projects-env.mjs';
|
|
367
362
|
import { Feed, currentFeed, currentId, flushProgress, publicFeed, readFeed, recordChange, startProgress } from '../lib/progress.mjs';
|
|
368
363
|
import { formatStatus, setupStatus } from '../lib/doctor.mjs';
|
|
369
364
|
import { codexTarget, newCodex, writeCodexPage } from '../lib/codex.mjs';
|
|
@@ -384,22 +379,23 @@ import { standaloneDeployNotes } from '../lib/standalone.mjs';
|
|
|
384
379
|
|
|
385
380
|
const argv = process.argv.slice(2);
|
|
386
381
|
const flags = new Map();
|
|
387
|
-
|
|
382
|
+
// build --quick keeps compilation and type checks, skips rules generated play/smoke checks.
|
|
383
|
+
const BOOL_FLAGS = ['quick', 'public', 'lan', 'off', 'revoke', 'json', 'yes', 'detach', 'no-install', 'plan', 'stop', 'share', 'apply', 'diff', 'template', 'ci', 'fresh', 'install', 'remove', 'replace', 'artifact', 'open', 'reopen', 'kids', 'remote-ai', 'dry-run', 'verify', 'maps', 'profile', 'hands-on', 'automatic', 'unlock', 'confirm', 'no-library', 'no-validate', 'rigged', 'no-rig', 'supporter', 'giving', 'managed', 'live', 'manual', 'renew', 'send', 'accept-tos', 'quiet', 'no-local-ai', 'timestamps', 'overwrite', 'own-route', 'before', 'release', 'device'];
|
|
388
384
|
const positional = [];
|
|
389
385
|
for (let i = 0; i < argv.length; i++) {
|
|
390
386
|
const a = argv[i];
|
|
391
387
|
if (a.startsWith('--')) {
|
|
392
388
|
const [k, v] = a.slice(2).split(/=(.*)/s, 2);
|
|
393
389
|
if (v !== undefined) flags.set(k, v);
|
|
394
|
-
else if (argv[i + 1] !== undefined && !argv[i + 1].startsWith('--') && !BOOL_FLAGS.includes(k)) flags.set(k, argv[++i]);
|
|
390
|
+
else if (argv[i + 1] !== undefined && !argv[i + 1].startsWith('--') && (!BOOL_FLAGS.includes(k) || k === 'profile' && argv[0] === 'shop')) flags.set(k, argv[++i]);
|
|
395
391
|
else flags.set(k, true);
|
|
396
392
|
} else positional.push(a);
|
|
397
393
|
}
|
|
398
394
|
const asJson = flags.has('json');
|
|
399
|
-
const log = asJson ? () => {} : (line) => process.stderr.write(`${line}\n`);
|
|
395
|
+
const log = asJson && positional[0] !== 'build' ? () => {} : (line) => process.stderr.write(`${line}\n`);
|
|
400
396
|
|
|
401
397
|
function print(result) {
|
|
402
|
-
if (asJson) { process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); return; }
|
|
398
|
+
if (asJson || /^shop (plan|verify)$/.test(result.command ?? '')) { process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); return; }
|
|
403
399
|
// A standalone plan or build says every target, built or not, and what a standalone copy does not have.
|
|
404
400
|
if (/^standalone( |$)/.test(String(result.command ?? ''))) { process.stdout.write(`${standaloneLines(result).join('\n')}\n`); return; }
|
|
405
401
|
// A check that found problems still prints them (its rows say what to fix), never a bare "failed".
|
|
@@ -635,9 +631,6 @@ function print(result) {
|
|
|
635
631
|
case 'shop catalog':
|
|
636
632
|
lines.push(...catalogLines(result));
|
|
637
633
|
break;
|
|
638
|
-
case 'setup':
|
|
639
|
-
lines.push(...projectsLines(result));
|
|
640
|
-
break;
|
|
641
634
|
case 'chat rules':
|
|
642
635
|
case 'chat budget':
|
|
643
636
|
case 'lounge rules':
|
|
@@ -846,6 +839,8 @@ const OUTWARD_FLAGS = {
|
|
|
846
839
|
'chat remove': ['url', 'all'], 'chat budget': ['url'],
|
|
847
840
|
'servers close': ['url', 'reopen'], 'servers level': ['url'], 'servers member': ['url', 'role', 'remove'],
|
|
848
841
|
'parts reissue': ['claim-hash', 'receipt-verified', 'buyer'], 'parts retire': [], 'parts keys': [], 'parts refund': ['game'],
|
|
842
|
+
'shop listen': ['profile','port'],
|
|
843
|
+
'shop webhook': ['live','renew','profile'],
|
|
849
844
|
'shop connect': ['local', 'profile', 'url', 'managed', 'live', 'manual', 'renew', 'from-clipboard'], 'shop disconnect': ['url'], 'shop refund': ['url', 'reason', 'note', 'manual-transaction'],
|
|
850
845
|
'agents pass': ['url', 'label', 'server', 'hands', 'role', 'days'], 'agents revoke': ['url'], 'agents brain': ['url', 'budget', 'remove'],
|
|
851
846
|
'agents sit': ['url', 'server', 'pass', 'label', 'brain'],
|
|
@@ -936,12 +931,7 @@ async function main() {
|
|
|
936
931
|
if (cmd === 'progress') return progressCommand(root, sub);
|
|
937
932
|
if (cmd === 'domain') return studioDomain(root, sub);
|
|
938
933
|
if (cmd === 'setup' && sub === 'attach') return setupAttach(root, positional[2], { homie: flags.get('homie'), client: flags.get('client') });
|
|
939
|
-
if (cmd === '
|
|
940
|
-
if (flags.get('via') !== 'stripe-projects') return { ok: false, command: 'setup', why: '--via stripe-projects is the one other way this version knows (the default is npx wrangler login)' };
|
|
941
|
-
const extra = String(flags.get('with') ?? '').split(',').map((x) => x.trim()).filter(Boolean);
|
|
942
|
-
if (extra.some((x) => x !== 'elevenlabs')) return { ok: false, command: 'setup', why: '--with takes elevenlabs (Cloudflare is always set up)' };
|
|
943
|
-
return setupViaProjects(root, { withElevenlabs: extra.includes('elevenlabs'), acceptTos: flags.has('accept-tos'), dryRun: flags.has('dry-run'), log });
|
|
944
|
-
}
|
|
934
|
+
if (cmd === 'media' && sub === 'import') return importMedia(root, { file: flags.get('file'), receipt: flags.get('receipt'), out: flags.get('out'), usedBy: flags.get('used-by') });
|
|
945
935
|
if (cmd === 'handoff') return handoff(root, sub, { homie: flags.get('homie'), client: flags.get('client') });
|
|
946
936
|
if (cmd === 'port' && sub === 'import') return importPort(root, positional[2], flags.get('id'), { name: flags.get('name'), mode: flags.get('mode') });
|
|
947
937
|
if (cmd === 'port' && sub === 'check') {
|
|
@@ -963,7 +953,7 @@ async function main() {
|
|
|
963
953
|
// go, so an old note, an old card or an agent's memory of the toolkit does not end at "unknown command".
|
|
964
954
|
if (cmd === 'game' && sub === 'remix') return { ok: false, command: 'game remix', why: 'remix was retired: a game is no longer handed over whole, and no studio serves one. Games build on each other through parts, the pieces of a game its studio chose to share: find one with `homie-studio parts find <words>` and bring it in with `homie-studio parts add` (in chat: parts_find, part_add; parts/PARTS.md)' };
|
|
965
955
|
if (cmd === 'games') return { ok: true, command: 'games', games: listGames(root).map(({ dir, ...g }) => ({ ...g, dir: relative(root, dir) })) };
|
|
966
|
-
if (cmd === 'build') return tracked(root, 'build', () => build(root, { only: positional[1] ?? null, log, maps: flags.has('maps'), types: flags.has('types'), longCheck: flags.has('long-check') }), 'build');
|
|
956
|
+
if (cmd === 'build') return tracked(root, 'build', () => build(root, { only: positional[1] ?? null, log, maps: flags.has('maps'), types: flags.has('types'), longCheck: flags.has('long-check'), quick: flags.has('quick') }), 'build');
|
|
967
957
|
if (cmd === 'preview') return preview(root, positional[1] ?? (listGames(root).length === 1 ? listGames(root)[0].id : null));
|
|
968
958
|
if (cmd === 'perf' && sub === 'sizes') return perfSizes(root, positional[2] ?? listGames(root)[0]?.id);
|
|
969
959
|
if (cmd === 'lab') return labCommand(root, sub);
|
|
@@ -1114,7 +1104,15 @@ async function main() {
|
|
|
1114
1104
|
const url = flags.get('url');
|
|
1115
1105
|
if (!sub) return shopStatus(root, { url });
|
|
1116
1106
|
if (sub === 'init') return shopInit(root, { supporter: flags.has('supporter'), giving: flags.has('giving'), currency: flags.get('currency') ?? null, price: flags.get('price') ?? 500, managed: flags.has('managed') });
|
|
1107
|
+
if(sub==='listen')return (await import('../lib/shop-listen.mjs')).shopListen(root,{profile:flags.get('profile'),port:flags.get('port')??8787,log});
|
|
1117
1108
|
if (sub === 'check') return shopCheck(root);
|
|
1109
|
+
if (sub === 'plan' || sub === 'verify') {
|
|
1110
|
+
const {shopMcpPlan,saveMcpVerification}=await import('../lib/shop-mcp.mjs');
|
|
1111
|
+
const file=flags.get('have');
|
|
1112
|
+
const input=file?JSON.parse(readFileSync(file==='-'?0:file,'utf8')):{};
|
|
1113
|
+
return (sub==='verify'?saveMcpVerification:shopMcpPlan)(root,input);
|
|
1114
|
+
}
|
|
1115
|
+
if (sub === 'webhook') return shopConnect(root,{webhookOnly:true,live:flags.has('live'),renew:flags.has('renew'),profile:flags.get('profile'),log:line=>process.stderr.write(`${line}\n`)});
|
|
1118
1116
|
if (sub === 'connect' && flags.has('local')) {
|
|
1119
1117
|
if(flags.has('live'))throw new Error('Local checkout requires test mode');
|
|
1120
1118
|
return (await import('../lib/shop-local.mjs')).shopConnectLocal(root,{url:flags.get('url'),profile:flags.get('profile')});
|
|
@@ -1362,7 +1360,7 @@ function mediaPut(root, file, as) {
|
|
|
1362
1360
|
const key = as ?? (/^(music|videos)\//.test(rel) && !rel.includes('..') ? rel : `${folder}/${basename(file)}`);
|
|
1363
1361
|
const bin = wranglerBin(root);
|
|
1364
1362
|
return new Promise((done) => {
|
|
1365
|
-
const p = spawn(bin, ['r2', 'object', 'put', `${r2}/${key}`, '--file', resolve(file), '--content-type', typeOf(file), '--remote'], { cwd: workerDir(root), env: { ...process.env,
|
|
1363
|
+
const p = spawn(bin, ['r2', 'object', 'put', `${r2}/${key}`, '--file', resolve(file), '--content-type', typeOf(file), '--remote'], { cwd: workerDir(root), env: { ...process.env, CI: '1' }, stdio: ['ignore', 'ignore', 'inherit'] });
|
|
1366
1364
|
p.on('close', (code) => {
|
|
1367
1365
|
if (code !== 0) return done({ ok: false, command: 'media put', why: 'wrangler r2 object put failed' });
|
|
1368
1366
|
// The manifest is committed: it names the file by its path on the site, never the workers.dev address.
|
package/guides/app/SKILL.md
CHANGED
|
@@ -183,7 +183,7 @@ Scaffold businesses with `new <folder> --kind business`; causes with `--kind cau
|
|
|
183
183
|
|
|
184
184
|
For giving, set the studio currency and run `shop init --giving --currency CAD` (use the organisation’s currency). It creates one-time/monthly suggested gifts. The owner supplies `giving.receiptText` in shop.json; Homie supplies no legal or tax text. Before Stripe is connected, local /shop/ previews items and prices with checkout disabled. Run the connection step yourself; the owner approves their Stripe account in the browser.
|
|
185
185
|
|
|
186
|
-
Use `shop.book` and the booking collection declaration in SHOP.md. Default keyless booking links show pending while paying; an unpaid guest does not block others. Stripe limits completed sessions to capacity. The owner’s AI syncs published/changed slots with `
|
|
186
|
+
Use `shop.book` and the booking collection declaration in SHOP.md. Default keyless booking links show pending while paying; an unpaid guest does not block others. Stripe limits completed sessions to capacity. The owner’s AI syncs published/changed slots with `stripe_shop_plan` and the complete slot manifest. Say “Pay to secure your seat.” Exclusive unpaid holds require the explicitly selected optional keyed connection.
|
|
187
187
|
|
|
188
188
|
|
|
189
189
|
## Tell my AI when a booking comes in
|
package/guides/art/SKILL.md
CHANGED
|
@@ -1,154 +1,82 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: art
|
|
3
|
-
description: Make
|
|
4
|
-
compatibility: Node 22
|
|
3
|
+
description: "Make game and app art using the official fal MCP, studio art direction, local capture and asset checks."
|
|
4
|
+
compatibility: Node 22 and the official fal plugin in the AI client. Local media processing uses ffmpeg and Chrome where needed.
|
|
5
5
|
metadata:
|
|
6
6
|
providers: fal
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
# Art for
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
`
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
The local paid script discovers an existing fal key using the lookup below. If none is available, continue
|
|
61
|
-
with local assets or captured footage and explain that this paid-script connection is not ready.
|
|
62
|
-
Do not make account configuration a prerequisite for a live studio. **fal's own MCP server** is how you find a
|
|
63
|
-
model and read its input schema and price (`search_models`, `recommend_model`, `get_model_schema`,
|
|
64
|
-
`get_pricing`): use it rather than memory, because endpoints retire and reprice. Not connected? Offer
|
|
65
|
-
it, and the person signs in on fal's own page (no key): in Claude Code `claude mcp add --transport http
|
|
66
|
-
--scope user fal https://mcp.fal.ai/mcp-relay`, then `/mcp`; in Codex `codex mcp add fal --url
|
|
67
|
-
https://mcp.fal.ai/mcp-relay`, then `codex mcp login fal`. **Paid calls go through `art.mjs gen`,
|
|
68
|
-
never the MCP's `run_model` or `submit_job`**: `gen` prices, caps, receipts and resumes; the MCP's run
|
|
69
|
-
does none of that (the Homie mod in Claude Code, and Homie's hooks in Codex, hold one as a call whose cost cannot be read first).
|
|
70
|
-
|
|
71
|
-
```sh
|
|
72
|
-
node <art.mjs> price --model fal-ai/flux/dev --input art/cover/input.json # free: fal's unit price x this input
|
|
73
|
-
node <art.mjs> budget cover --cap <dollars the person agreed to>
|
|
74
|
-
node <art.mjs> gen cover --model fal-ai/flux/dev --input art/cover/input.json --out cover-painted.jpg --dry-run
|
|
75
|
-
node <art.mjs> gen cover --model fal-ai/flux/dev --input art/cover/input.json --out cover-painted.jpg --yes
|
|
9
|
+
# Art for this studio
|
|
10
|
+
|
|
11
|
+
Read the game's or app's style, codex and existing scene before writing a prompt.
|
|
12
|
+
Use its palette, shape language, materials, lighting and camera. Keep approved references
|
|
13
|
+
and the style revision. Covers must describe what the playable experience really offers.
|
|
14
|
+
A frame from the running game is free and often the best cover.
|
|
15
|
+
|
|
16
|
+
For generated art use fal's `recommend_model` or `search_models`, `get_model_schema`
|
|
17
|
+
and `get_pricing`, then `run_model`. Continue a pending request with `check_job` and
|
|
18
|
+
`get_job_result`. Use `upload_file` only as documented by the official plugin for references.
|
|
19
|
+
Set an explicit image count. Inspect the first result before any dependent generation.
|
|
20
|
+
|
|
21
|
+
Local `scripts/art.mjs` keeps `check`, `frame`, `cover`, `tile`, `fit` and `sheet`.
|
|
22
|
+
Use `cover <game> --from <image>` for a 1600×900 cover and game.json reference;
|
|
23
|
+
`fit <image> --out <file>` for phone-sized delivery. Check tile seams with a repeated
|
|
24
|
+
2×2 preview, transparency against light and dark, readability at phone size, and
|
|
25
|
+
compression after fitting. Do not replace an engine effect with a large image by default.
|
|
26
|
+
|
|
27
|
+
## Official generation workflow
|
|
28
|
+
|
|
29
|
+
The owner's AI uses the provider's official plugin/MCP in its own client. Homie never
|
|
30
|
+
asks for, stores, reads or prints provider credentials. Read the current provider
|
|
31
|
+
skill and discover its available tools and input schemas; host prefixes vary.
|
|
32
|
+
Connection instructions and verified sources: [official integrations](../studio-setup/references/OFFICIAL-MEDIA.md).
|
|
33
|
+
If tools are missing, connect that official plugin once in the client's browser flow.
|
|
34
|
+
Do not fall back to a Homie client, key file, environment key or CLI generation wrapper.
|
|
35
|
+
|
|
36
|
+
Before spending, state the model, count/duration, estimated cost and remaining approved
|
|
37
|
+
budget. Use the owner's existing authorization; ask only if the spend is outside it.
|
|
38
|
+
Record the request ID as soon as accepted. Poll that same request; never resubmit to
|
|
39
|
+
retry a slow job. Unknown cost is unknown, never zero. Provider billing is authoritative;
|
|
40
|
+
Homie's local receipt cannot enforce spending in another client.
|
|
41
|
+
|
|
42
|
+
## Place and prove the result
|
|
43
|
+
|
|
44
|
+
Download the completed tool's output using the AI client's file/download facilities.
|
|
45
|
+
Keep temporary signed URLs out of committed records. Keep the original in the studio's
|
|
46
|
+
art/job folder; put the optimized delivered asset beside its game/app, or in music/ or
|
|
47
|
+
videos/ for a published work. Record a receipt with these fields:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"provider": "fal",
|
|
52
|
+
"tool": "run_model",
|
|
53
|
+
"model": "exact endpoint returned by the provider",
|
|
54
|
+
"requestId": "actual request ID",
|
|
55
|
+
"prompt": "the actual prompt, including style constraints",
|
|
56
|
+
"styleRevision": "revision from the studio's style",
|
|
57
|
+
"rights": {"source": "provider/model terms URL", "checkedAt": "YYYY-MM-DD", "commercial": false, "note": "record the actual plan and permitted use"},
|
|
58
|
+
"cost": {"status": "unknown"}
|
|
59
|
+
}
|
|
76
60
|
```
|
|
77
61
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
the prompt, run it once more. Spend the riskiest image first.
|
|
84
|
-
- No real people, no real brands, no copyrighted characters, no "in the style of" a living artist, in
|
|
85
|
-
prompts or references.
|
|
86
|
-
- **Every prompt starts from the game's derived style prompt** (`homie-studio style prompt <id>`: medium,
|
|
87
|
-
shape, palette hexes, light, framing; computed from the decisions, never edited by hand) and uses the golden
|
|
88
|
-
images as references on a multi-reference model. A picture made under an older palette is listed stale when
|
|
89
|
-
the palette changes (the `style` skill's blast radius).
|
|
90
|
-
- What the provider's terms say about the pictures, with read dates: `references/RIGHTS.md`. Read the live page
|
|
91
|
-
again before anything commercial is published.
|
|
92
|
-
- 3D models (props, characters) are the `models` skill's; mood images for the style board are too
|
|
93
|
-
(`models.mjs mood`).
|
|
62
|
+
For ElevenLabs use its actual discovered tool and model, and its flow/session or request
|
|
63
|
+
identifier. A measured cost uses `{"status":"actual","amount":1,"unit":"credits"}`;
|
|
64
|
+
a quote uses `estimate`. Never claim commercial rights from the fact that generation
|
|
65
|
+
succeeded. Read the provider and model terms for the account's plan; record attribution,
|
|
66
|
+
reference-image permissions and any restrictions. Mark test fixtures `"fixture": true`.
|
|
94
67
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
A procedural gradient sky is the tell that a game was generated; a painted one costs one image at build
|
|
98
|
-
time and loads like any other asset. Good candidates: a skybox or far matte, a ground or wall texture,
|
|
99
|
-
a character plate, a title card. Bad: anything the game generates procedurally for a reason.
|
|
68
|
+
Wire the delivered path into the scene or manifest, then run:
|
|
100
69
|
|
|
101
70
|
```sh
|
|
102
|
-
|
|
103
|
-
node <art.mjs> fit art/floor/floor.png --out games/<id>/public/art/floor.jpg --width 1024 --max-kb 250
|
|
104
|
-
node <art.mjs> sheet art/floor # everything in a job, labelled, to look at
|
|
71
|
+
npx --no-install homie-studio media import --file <downloaded-file> --receipt <receipt.json> --out games/<id>/assets/<name> --used-by games/<id>/view.ts
|
|
105
72
|
```
|
|
106
73
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
asset that doubled the load time made the game worse.
|
|
113
|
-
- Put art where the game's own build puts assets (`games/<id>/public/` for a bundled game, the
|
|
114
|
-
game's folder for a static one) and load it with a relative path.
|
|
115
|
-
|
|
116
|
-
## 4. Art direction: paintovers, then change the game
|
|
117
|
-
|
|
118
|
-
Images do not fix a game that looks unfinished; the best-loved browser games often ship no texture
|
|
119
|
-
files at all. What makes a frame look finished is light, contrast between the subject and the ground,
|
|
120
|
-
detail at more than one scale, and a clear horizon or depth. The method:
|
|
121
|
-
|
|
122
|
-
1. **The style bible is the game's decisions** (the `style` skill): render style, palette with its jobs,
|
|
123
|
-
light, shape language, camera, fonts, drawn in the codex's Art direction tab. An older studio's
|
|
124
|
-
`art/STYLE.md` retires into it: carry what it says into `style set` / `style steer`, then keep only the
|
|
125
|
-
decisions. Paint with the LOCKED palette and light.
|
|
126
|
-
2. **Paintovers**: real frames of the game (`frame`), painted over by an image model with the derived style
|
|
127
|
-
prompt (`npx --no-install homie-studio style prompt <id>`) and the frame as the reference, plus the golden
|
|
128
|
-
images (`style golden`) where there are any. These are the TARGET, never shipped as the game.
|
|
129
|
-
3. **Change the game's own rendering** (lights, materials, fog, the floor, the camera) until frames of
|
|
130
|
-
the running game match the paintover; compare them side by side.
|
|
131
|
-
4. **Judge blind**: frames of the old build, the new one and a reference game the person admires,
|
|
132
|
-
shuffled under random labels, scored by a fresh reviewer before the labels are revealed (the
|
|
133
|
-
`playtest` skill's review). A reference is a bar, not a template.
|
|
134
|
-
|
|
135
|
-
## Tell the person
|
|
136
|
-
|
|
137
|
-
What was made and where it is used, the file sizes, what it cost (from the receipts) against the cap,
|
|
138
|
-
what is a real frame and what is generated, and the pictures themselves.
|
|
139
|
-
|
|
140
|
-
## Never
|
|
141
|
-
|
|
142
|
-
- Never ship generated art as a screenshot of gameplay, or a cover that shows what the game does not have.
|
|
143
|
-
- Never spend without a budget, past it, or without a receipt; never print or store a key.
|
|
144
|
-
- Never replace art a person made without asking.
|
|
145
|
-
|
|
146
|
-
### Existing provider credentials
|
|
74
|
+
This copies bytes, verifies a static reference, hashes the asset and records allowlisted
|
|
75
|
+
provenance in `media/provenance.json`. Reimporting the same output is idempotent; it
|
|
76
|
+
never generates or charges. Include each generation step's receipt for derived assets.
|
|
77
|
+
Run the scene and look/listen: a file and static reference are not proof that it renders
|
|
78
|
+
or plays. Report the placed path, usage evidence, rights and actual/estimated cost.
|
|
147
79
|
|
|
148
|
-
The
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
installs. Checks name the source, never the key. Keep these files private (mode
|
|
152
|
-
0600); never copy them into a studio. ElevenLabs also accepts its CLI browser
|
|
153
|
-
sign-in and the existing Stripe Projects connection. Run the tool’s `check`
|
|
154
|
-
before declaring a provider disconnected.
|
|
80
|
+
The toolkit’s `lib/media-workflows.mjs` declares this skill’s verified tool references.
|
|
81
|
+
Validate them against the host’s current tool inventory before execution; tool discovery
|
|
82
|
+
is required for generation capabilities that have no stable documented name.
|