makefx 0.1.0 → 0.1.2
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 +120 -128
- package/{dist/cli/makefx.mjs → makefx.mjs} +259 -162
- package/package.json +13 -99
package/README.md
CHANGED
|
@@ -1,62 +1,34 @@
|
|
|
1
|
-
#
|
|
1
|
+
# makefx
|
|
2
2
|
|
|
3
|
-
Make Effects
|
|
4
|
-
|
|
5
|
-
track, and hand off production assets across images, audio, and video.
|
|
3
|
+
Command-line interface for [Make Effects](https://makefx.app), an AI media
|
|
4
|
+
production workspace for game assets, production references, and handoff files.
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
local
|
|
10
|
-
|
|
11
|
-
results, curate variants, and export production handoff data.
|
|
6
|
+
`makefx` lets local developers, scripts, and coding agents create and manage
|
|
7
|
+
website-backed assets from the terminal: generate images, audio, and video;
|
|
8
|
+
upload local media; inspect variants; download outputs; watch real-time space
|
|
9
|
+
events; and export production records.
|
|
12
10
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
- Generate images, audio, and video through website-backed jobs.
|
|
16
|
-
- Track every result as an asset variant with prompt, provider metadata, and
|
|
17
|
-
lineage.
|
|
18
|
-
- Refine an existing variant or derive new assets from references.
|
|
19
|
-
- Upload local media into a collaborative space so generated and hand-made
|
|
20
|
-
assets live together.
|
|
21
|
-
- Let automation agents use the CLI as a stable control surface instead of
|
|
22
|
-
touching database or storage internals.
|
|
23
|
-
- Export production records for downstream render, game, or editorial tools.
|
|
24
|
-
|
|
25
|
-
## Features
|
|
26
|
-
|
|
27
|
-
- **Authentication**: Google OAuth with JWT tokens, OIDC-compliant
|
|
28
|
-
- **Dual-Worker Architecture**: Separate workers for HTTP/frontend and media generation
|
|
29
|
-
- **React 19 Frontend**: Vite, TanStack Router, Zustand, CSS Modules
|
|
30
|
-
- **D1 Database**: SQLite with migrations and Kysely query builder
|
|
31
|
-
- **R2 Media Storage**: Durable media artifacts for generated and uploaded files
|
|
32
|
-
- **Dependency Injection**: InversifyJS for clean architecture
|
|
33
|
-
- **Make Effects CLI**: Command-line access through the `makefx` package and command
|
|
34
|
-
- **TypeScript**: End-to-end type safety
|
|
35
|
-
|
|
36
|
-
## CLI Quick Start
|
|
37
|
-
|
|
38
|
-
Install the CLI from npm:
|
|
11
|
+
## Install
|
|
39
12
|
|
|
40
13
|
```bash
|
|
41
14
|
npm install -g makefx
|
|
15
|
+
makefx --version
|
|
42
16
|
```
|
|
43
17
|
|
|
44
|
-
|
|
18
|
+
Requirements:
|
|
45
19
|
|
|
46
|
-
|
|
47
|
-
makefx
|
|
48
|
-
|
|
20
|
+
- Node.js 20 or newer
|
|
21
|
+
- A Make Effects account at https://makefx.app
|
|
22
|
+
|
|
23
|
+
The npm package installs a bundled executable and does not declare runtime
|
|
24
|
+
dependencies.
|
|
49
25
|
|
|
50
|
-
|
|
26
|
+
## Quick Start
|
|
51
27
|
|
|
52
28
|
```bash
|
|
29
|
+
makefx login
|
|
53
30
|
makefx spaces create "My Game Assets" --init
|
|
54
|
-
makefx init --space YOUR_SPACE_ID
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Generate media and download completed outputs:
|
|
58
31
|
|
|
59
|
-
```bash
|
|
60
32
|
makefx generate "A cozy pixel-art market background" \
|
|
61
33
|
--name "Market Background" \
|
|
62
34
|
--type scene \
|
|
@@ -73,113 +45,133 @@ makefx video generate "A looping idle animation for a tiny robot" \
|
|
|
73
45
|
-o video/robot-idle.mp4
|
|
74
46
|
```
|
|
75
47
|
|
|
76
|
-
|
|
48
|
+
## Authentication
|
|
77
49
|
|
|
78
50
|
```bash
|
|
79
|
-
makefx
|
|
80
|
-
makefx
|
|
81
|
-
makefx assets download VARIANT_ID -o references/variant.png
|
|
82
|
-
makefx listen --space YOUR_SPACE_ID
|
|
83
|
-
makefx rotation --variant VARIANT_ID --config 8-directional
|
|
84
|
-
makefx tileset "cohesive grass, path, and stone terrain tiles" --type terrain --grid 3x3
|
|
51
|
+
makefx login
|
|
52
|
+
makefx logout
|
|
85
53
|
```
|
|
86
54
|
|
|
87
|
-
|
|
55
|
+
`login` opens a browser-based sign-in flow and stores CLI credentials in the
|
|
56
|
+
user config directory. Credentials are separate from project bindings and are
|
|
57
|
+
not written into your repository.
|
|
58
|
+
|
|
59
|
+
## Project Binding
|
|
60
|
+
|
|
61
|
+
Bind the current directory to a Make Effects space:
|
|
88
62
|
|
|
89
63
|
```bash
|
|
90
|
-
makefx
|
|
91
|
-
makefx runs show --latest --debug --json
|
|
64
|
+
makefx init --space YOUR_SPACE_ID
|
|
92
65
|
```
|
|
93
66
|
|
|
67
|
+
This writes `.inventory/config.json` with the target environment and space ID.
|
|
68
|
+
It does not store assets, prompts, media files, provider keys, or auth tokens.
|
|
69
|
+
Inside an initialized project, commands can omit `--space` and `--env`.
|
|
70
|
+
|
|
94
71
|
The CLI defaults to production at `https://makefx.app`. Use `--env stage` for
|
|
95
|
-
staging or `--local` for a local development server.
|
|
96
|
-
|
|
97
|
-
## CLI Commands
|
|
98
|
-
|
|
99
|
-
| Command | Description |
|
|
100
|
-
|---------|-------------|
|
|
101
|
-
| `makefx login` | Authenticate with makefx.app |
|
|
102
|
-
| `makefx spaces` | List, view, or create collaborative spaces |
|
|
103
|
-
| `makefx init` | Bind the current directory to a website space |
|
|
104
|
-
| `makefx generate` | Generate a new image asset |
|
|
105
|
-
| `makefx refine` | Refine an existing image variant |
|
|
106
|
-
| `makefx derive` | Create a new image asset from variant IDs or local refs |
|
|
107
|
-
| `makefx batch` | Generate multiple images and write a debug run manifest |
|
|
108
|
-
| `makefx audio` | Generate speech, dialogue, music, or sound effects |
|
|
109
|
-
| `makefx video` | Generate, refine, or derive video assets |
|
|
110
|
-
| `makefx upload` | Upload local image, audio, or video files |
|
|
111
|
-
| `makefx assets` | List, show, download, rename, delete, and set active assets |
|
|
112
|
-
| `makefx variants` | Retry, star, rate, or delete variants |
|
|
113
|
-
| `makefx rotation` | Generate and monitor rotation views from a completed image variant |
|
|
114
|
-
| `makefx tileset` | Generate and monitor consistent tile sets |
|
|
115
|
-
| `makefx listen` | Stream real-time space events |
|
|
116
|
-
| `makefx productions` | Place, list, and export production records |
|
|
117
|
-
| `makefx runs` | Inspect debug-only local generation manifests |
|
|
118
|
-
|
|
119
|
-
See [docs/cli.md](./docs/cli.md) and
|
|
120
|
-
[docs/cli-generation.md](./docs/cli-generation.md) for the full command guide.
|
|
121
|
-
|
|
122
|
-
## Local Development
|
|
72
|
+
staging, or `--local` for a local development server.
|
|
123
73
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
74
|
+
## Common Workflows
|
|
75
|
+
|
|
76
|
+
Inspect and download tracked assets:
|
|
127
77
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
78
|
+
```bash
|
|
79
|
+
makefx assets
|
|
80
|
+
makefx assets show ASSET_ID --json
|
|
81
|
+
makefx assets download VARIANT_ID -o references/variant.png
|
|
82
|
+
```
|
|
131
83
|
|
|
132
|
-
|
|
133
|
-
pnpm run db:migrate
|
|
84
|
+
Upload local media:
|
|
134
85
|
|
|
135
|
-
|
|
136
|
-
|
|
86
|
+
```bash
|
|
87
|
+
makefx upload hero.png --name "Hero Character" --type character
|
|
88
|
+
makefx upload theme.mp3 --name "Theme Music" --type audio
|
|
89
|
+
makefx upload cutscene.mp4 --name "Cutscene" --type video
|
|
137
90
|
```
|
|
138
91
|
|
|
139
|
-
|
|
92
|
+
Refine or derive from references:
|
|
140
93
|
|
|
141
|
-
|
|
94
|
+
```bash
|
|
95
|
+
makefx refine --variant VARIANT_ID "make it evening, with warmer lights" \
|
|
96
|
+
-o art/market-evening.png
|
|
142
97
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
| `pnpm run typecheck` | TypeScript type checking |
|
|
151
|
-
| `pnpm run lint` | ESLint |
|
|
152
|
-
| `pnpm run deploy:stage` | Deploy to stage environment |
|
|
153
|
-
| `pnpm run deploy:production` | Deploy to production |
|
|
98
|
+
makefx derive \
|
|
99
|
+
--refs CHARACTER_VARIANT_ID,BACKGROUND_VARIANT_ID \
|
|
100
|
+
--name "Hero In Market" \
|
|
101
|
+
--type scene \
|
|
102
|
+
"Place the hero naturally in the market" \
|
|
103
|
+
-o art/hero-market.png
|
|
104
|
+
```
|
|
154
105
|
|
|
155
|
-
|
|
106
|
+
Create production helpers:
|
|
156
107
|
|
|
108
|
+
```bash
|
|
109
|
+
makefx rotation --variant VARIANT_ID --config 8-directional
|
|
110
|
+
makefx tileset "grass and stone path tiles" --type terrain --grid 3x3
|
|
111
|
+
makefx productions export --production-id trailer-01 -o handoff/scenes.args
|
|
157
112
|
```
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
└── worker/ # Cloudflare Worker entry points
|
|
113
|
+
|
|
114
|
+
Watch real-time space activity:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
makefx listen --space YOUR_SPACE_ID
|
|
118
|
+
makefx listen --space YOUR_SPACE_ID --json
|
|
165
119
|
```
|
|
166
120
|
|
|
167
|
-
##
|
|
121
|
+
## Agent And Script Usage
|
|
168
122
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- [docs/architecture.md](./docs/architecture.md) - system architecture
|
|
172
|
-
- [PRD.md](./PRD.md) - product requirements and core concepts
|
|
123
|
+
Many commands support `--json` for stable machine-readable output. Use JSON
|
|
124
|
+
outputs for automation instead of parsing human-readable tables.
|
|
173
125
|
|
|
174
|
-
|
|
126
|
+
```bash
|
|
127
|
+
makefx spaces create "Agent Test Space" --init --json
|
|
128
|
+
makefx assets --json
|
|
129
|
+
makefx runs show --latest --debug --json
|
|
130
|
+
```
|
|
175
131
|
|
|
176
|
-
|
|
177
|
-
- **Database**: Cloudflare D1 (SQLite)
|
|
178
|
-
- **Frontend**: React 19, Vite, Zustand
|
|
179
|
-
- **Backend**: Hono, InversifyJS, Kysely
|
|
180
|
-
- **Auth**: Google OAuth, JWT (jose)
|
|
181
|
-
- **Testing**: Node.js test runner
|
|
132
|
+
Debug run manifests are local troubleshooting traces for generation commands:
|
|
182
133
|
|
|
183
|
-
|
|
134
|
+
```bash
|
|
135
|
+
makefx runs --debug
|
|
136
|
+
makefx runs show --latest --debug
|
|
137
|
+
```
|
|
184
138
|
|
|
185
|
-
|
|
139
|
+
The website remains the source of truth for spaces, assets, variants, recipes,
|
|
140
|
+
lineage, and stored media.
|
|
141
|
+
|
|
142
|
+
## Command Groups
|
|
143
|
+
|
|
144
|
+
| Command | Purpose |
|
|
145
|
+
|---------|---------|
|
|
146
|
+
| `login`, `logout` | Manage CLI authentication |
|
|
147
|
+
| `spaces`, `init` | Create spaces and bind local projects |
|
|
148
|
+
| `generate`, `refine`, `derive`, `batch` | Generate image assets |
|
|
149
|
+
| `audio` | Generate speech, dialogue, music, and sound effects |
|
|
150
|
+
| `video` | Generate, refine, and derive video assets |
|
|
151
|
+
| `upload` | Upload local image, audio, or video files |
|
|
152
|
+
| `assets`, `variants` | Inspect, download, curate, retry, or delete outputs |
|
|
153
|
+
| `rotation`, `tileset` | Generate game-ready reference sets |
|
|
154
|
+
| `productions` | Place and export production handoff records |
|
|
155
|
+
| `listen` | Stream real-time space events |
|
|
156
|
+
| `runs` | Inspect local debug manifests |
|
|
157
|
+
| `billing` | Inspect billing sync and operational status |
|
|
158
|
+
|
|
159
|
+
Run `makefx --help` or `makefx help <command>` for command-specific options.
|
|
160
|
+
|
|
161
|
+
## Troubleshooting
|
|
162
|
+
|
|
163
|
+
- If a command says you are not authenticated, run `makefx login`.
|
|
164
|
+
- If a command cannot find a space, run `makefx init --space YOUR_SPACE_ID` or
|
|
165
|
+
pass `--space YOUR_SPACE_ID`.
|
|
166
|
+
- If a generation command times out after creating a variant, resume with
|
|
167
|
+
`--follow VARIANT_ID` and the same output path.
|
|
168
|
+
- If automation needs stable output, add `--json` where supported.
|
|
169
|
+
|
|
170
|
+
## Links
|
|
171
|
+
|
|
172
|
+
- App: https://makefx.app
|
|
173
|
+
- CLI docs: https://makefx.app/docs/cli
|
|
174
|
+
- Media generation guide: https://makefx.app/docs/media-playbooks
|
|
175
|
+
- Source: https://github.com/krasnoperov/inventory
|
|
176
|
+
|
|
177
|
+
Version: 0.1.2
|
|
@@ -488,6 +488,9 @@ async function handleBilling(parsed) {
|
|
|
488
488
|
case "ops-check":
|
|
489
489
|
await handleBillingOpsCheck(env);
|
|
490
490
|
break;
|
|
491
|
+
case "reconcile":
|
|
492
|
+
await handleBillingReconcile(env, parsed);
|
|
493
|
+
break;
|
|
491
494
|
case "retry":
|
|
492
495
|
case "retry-failed":
|
|
493
496
|
await handleBillingRetry(env);
|
|
@@ -510,6 +513,7 @@ Usage:
|
|
|
510
513
|
Subcommands:
|
|
511
514
|
status Show sync status (pending, failed, synced events)
|
|
512
515
|
check Run operational checks for workers, Polar meters, and sync health
|
|
516
|
+
reconcile Compare local billable usage with Polar usage for one user
|
|
513
517
|
retry-failed Reset failed events for retry (next cron will sync them)
|
|
514
518
|
|
|
515
519
|
Options:
|
|
@@ -520,6 +524,7 @@ Examples:
|
|
|
520
524
|
makefx billing status Show production sync status
|
|
521
525
|
makefx billing status --env stage Show stage sync status
|
|
522
526
|
makefx billing check Run production operational checks
|
|
527
|
+
makefx billing reconcile --user-id 42 Reconcile one customer usage period
|
|
523
528
|
makefx billing retry-failed Reset failed events for retry
|
|
524
529
|
|
|
525
530
|
Note: Requires login first. Run 'makefx login' to authenticate.
|
|
@@ -656,15 +661,35 @@ function secondsSummary(seconds) {
|
|
|
656
661
|
}
|
|
657
662
|
async function handleBillingOpsCheck(env) {
|
|
658
663
|
console.log(`Running billing operational checks for ${env}...\n`);
|
|
659
|
-
const
|
|
664
|
+
const workerChecks = await checkWorkerHealth(env);
|
|
660
665
|
console.log("=== Billing Operational Checks ===\n");
|
|
661
666
|
console.log("Workers:");
|
|
662
667
|
for (const check of workerChecks) console.log(` ${statusLabel(check.status)} ${check.name.padEnd(12)} ${check.message}`);
|
|
668
|
+
let billingChecks;
|
|
669
|
+
try {
|
|
670
|
+
billingChecks = await callBillingApi(env, "/api/billing/operational-checks");
|
|
671
|
+
} catch (error) {
|
|
672
|
+
console.log("\nAuthenticated billing checks:");
|
|
673
|
+
console.log(` ${statusLabel("critical")} ${error instanceof Error ? error.message : String(error)}`);
|
|
674
|
+
console.log("\nResult: CRITICAL - billing checks need an authenticated admin session.");
|
|
675
|
+
process$1.exitCode = 1;
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
663
678
|
const meterCheck = billingChecks.checks.polarMeters;
|
|
664
679
|
console.log("\nPolar meters:");
|
|
665
680
|
console.log(` ${statusLabel(meterCheck.status)} configured=${meterCheck.configured} active=${meterCheck.active.length} expected=${meterCheck.expected.length}`);
|
|
666
681
|
if (meterCheck.error) console.log(` Error: ${meterCheck.error}`);
|
|
667
682
|
if (meterCheck.missing.length > 0) console.log(` Missing: ${meterCheck.missing.join(", ")}`);
|
|
683
|
+
if (meterCheck.invalid.length > 0) console.log(` Invalid: ${meterCheck.invalid.map((meter) => meter.name).join(", ")}`);
|
|
684
|
+
const productCheck = billingChecks.checks.paidGenerationProduct;
|
|
685
|
+
if (productCheck) {
|
|
686
|
+
console.log("\nPaid generation product:");
|
|
687
|
+
const product = productCheck.product;
|
|
688
|
+
console.log(` ${statusLabel(productCheck.status)} configured=${product?.configured ?? false} recurring=${product?.isRecurring ?? "n/a"} archived=${product?.isArchived ?? "n/a"}`);
|
|
689
|
+
if (product?.productId) console.log(` Product: ${product.productId}${product.name ? ` (${product.name})` : ""}`);
|
|
690
|
+
console.log(` Metered prices: ${product?.meteredPriceMeters.length ?? 0}/${productCheck.expectedMeteredPriceMeters.length}`);
|
|
691
|
+
if (productCheck.missingMeteredPriceMeters.length > 0) console.log(` Missing metered prices: ${productCheck.missingMeteredPriceMeters.join(", ")}`);
|
|
692
|
+
}
|
|
668
693
|
const syncCheck = billingChecks.checks.syncHealth;
|
|
669
694
|
console.log("\nSync health:");
|
|
670
695
|
console.log(` ${statusLabel(syncCheck.status)} pending=${syncCheck.events.pending} failed=${syncCheck.events.failed} synced=${syncCheck.events.synced}`);
|
|
@@ -677,11 +702,38 @@ async function handleBillingOpsCheck(env) {
|
|
|
677
702
|
const hasCriticalBilling = billingChecks.status === "critical";
|
|
678
703
|
const hasWarning = workerChecks.some((check) => check.status === "warning") || billingChecks.status === "warning";
|
|
679
704
|
if (hasCriticalWorker || hasCriticalBilling) {
|
|
680
|
-
console.log("\nResult: CRITICAL -
|
|
705
|
+
console.log("\nResult: CRITICAL - billing operations need attention.");
|
|
681
706
|
process$1.exitCode = 1;
|
|
682
707
|
} else if (hasWarning) console.log("\nResult: WARNING - billing is operational but has lag or cleanup work.");
|
|
683
708
|
else console.log("\nResult: OK - billing workers, meters, and sync health are ready.");
|
|
684
709
|
}
|
|
710
|
+
async function handleBillingReconcile(env, parsed) {
|
|
711
|
+
const userId = parsed.options["user-id"] || parsed.options.userId || parsed.positionals[1];
|
|
712
|
+
if (!userId) {
|
|
713
|
+
console.error("Missing user id. Use: makefx billing reconcile --user-id <id>");
|
|
714
|
+
process$1.exitCode = 1;
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
console.log(`Reconciling billing usage for user ${userId} in ${env}...\n`);
|
|
718
|
+
try {
|
|
719
|
+
const data = await callBillingApi(env, `/api/billing/reconcile?user_id=${encodeURIComponent(userId)}`);
|
|
720
|
+
console.log("=== Billing Reconciliation ===\n");
|
|
721
|
+
console.log(`Period: ${data.period.start} → ${data.period.end}`);
|
|
722
|
+
console.log(`Status: ${data.status.toUpperCase()}`);
|
|
723
|
+
console.log("\nMeters:");
|
|
724
|
+
for (const meter of data.meters) {
|
|
725
|
+
const marker = meter.matched ? "OK " : "MISMATCH";
|
|
726
|
+
console.log(` ${marker} ${meter.name.padEnd(22)} local=${meter.local} polar=${meter.polar} delta=${meter.delta}`);
|
|
727
|
+
}
|
|
728
|
+
if (data.mismatches.length > 0) {
|
|
729
|
+
console.log("\nMismatched meters need sync/retry investigation before billing is considered reconciled.");
|
|
730
|
+
process$1.exitCode = 1;
|
|
731
|
+
}
|
|
732
|
+
} catch (error) {
|
|
733
|
+
console.error("Reconciliation failed:", error instanceof Error ? error.message : error);
|
|
734
|
+
process$1.exitCode = 1;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
685
737
|
async function handleBillingRetry(env) {
|
|
686
738
|
console.log(`Resetting failed events for ${env}...\n`);
|
|
687
739
|
try {
|
|
@@ -756,65 +808,91 @@ function validateProjectConfig(config, configPath) {
|
|
|
756
808
|
* makefx spaces --id <space_id> Show details for a specific space
|
|
757
809
|
* makefx spaces create <name> Create a new space
|
|
758
810
|
*/
|
|
811
|
+
var defaultDeps$9 = {
|
|
812
|
+
loadConfig: loadStoredConfig,
|
|
813
|
+
resolveBaseUrl,
|
|
814
|
+
saveProjectConfig,
|
|
815
|
+
fetch,
|
|
816
|
+
print: console.log
|
|
817
|
+
};
|
|
759
818
|
async function handleSpaces(parsed) {
|
|
819
|
+
try {
|
|
820
|
+
await executeSpaces(parsed);
|
|
821
|
+
} catch (error) {
|
|
822
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
823
|
+
process$1.exitCode = 1;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
async function executeSpaces(parsed, deps = defaultDeps$9) {
|
|
760
827
|
const env = resolveCommandEnvironment(parsed);
|
|
761
828
|
const showDetails = parsed.options.details === "true";
|
|
762
829
|
const spaceId = parsed.options.id;
|
|
763
830
|
const subcommand = parsed.positionals[0];
|
|
764
831
|
const jsonOutput = parsed.options.json === "true";
|
|
765
|
-
const config = await
|
|
766
|
-
if (!config) {
|
|
767
|
-
|
|
768
|
-
console.error(`Run: ${loginCommandForEnvironment(env)}`);
|
|
769
|
-
process$1.exitCode = 1;
|
|
770
|
-
return;
|
|
771
|
-
}
|
|
772
|
-
if (config.token.expiresAt < Date.now()) {
|
|
773
|
-
console.error(`Token expired for ${env} environment.`);
|
|
774
|
-
console.error(`Run: ${loginCommandForEnvironment(env)}`);
|
|
775
|
-
process$1.exitCode = 1;
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
778
|
-
const baseUrl = resolveBaseUrl(env);
|
|
779
|
-
const accessToken = config.token.accessToken;
|
|
832
|
+
const config = await deps.loadConfig(env);
|
|
833
|
+
if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
|
|
834
|
+
if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
|
|
780
835
|
if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
const project = parsed.options.init === "true" ? {
|
|
793
|
-
configPath: await saveProjectConfig({
|
|
794
|
-
environment: env,
|
|
795
|
-
spaceId: space.id
|
|
796
|
-
}),
|
|
836
|
+
const ctx = {
|
|
837
|
+
env,
|
|
838
|
+
baseUrl: deps.resolveBaseUrl(env),
|
|
839
|
+
accessToken: config.token.accessToken
|
|
840
|
+
};
|
|
841
|
+
if (subcommand === "create") {
|
|
842
|
+
const spaceName = parsed.positionals.slice(1).join(" ") || parsed.options.name;
|
|
843
|
+
if (!spaceName) throw new Error("Space name is required. Usage: makefx spaces create <name>");
|
|
844
|
+
const space = await createSpace(ctx, deps, spaceName);
|
|
845
|
+
const project = parsed.options.init === "true" ? {
|
|
846
|
+
configPath: await deps.saveProjectConfig({
|
|
797
847
|
environment: env,
|
|
798
848
|
spaceId: space.id
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
else
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
849
|
+
}),
|
|
850
|
+
environment: env,
|
|
851
|
+
spaceId: space.id
|
|
852
|
+
} : void 0;
|
|
853
|
+
if (jsonOutput) deps.print(JSON.stringify({
|
|
854
|
+
space,
|
|
855
|
+
project
|
|
856
|
+
}, null, 2));
|
|
857
|
+
else printCreatedSpace(space, ctx.env, project?.configPath, deps.print);
|
|
858
|
+
return {
|
|
859
|
+
type: "create",
|
|
860
|
+
space,
|
|
861
|
+
project
|
|
862
|
+
};
|
|
811
863
|
}
|
|
864
|
+
if (spaceId) {
|
|
865
|
+
const details = await getSpaceDetails(ctx, deps, spaceId);
|
|
866
|
+
if (jsonOutput) deps.print(JSON.stringify(details, null, 2));
|
|
867
|
+
else printSpaceDetails(details, deps.print);
|
|
868
|
+
return {
|
|
869
|
+
type: "show",
|
|
870
|
+
space: details.space,
|
|
871
|
+
assets: details.assets
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
if (showDetails) {
|
|
875
|
+
const spaces = await listSpaceSummaries(ctx, deps);
|
|
876
|
+
if (jsonOutput) deps.print(JSON.stringify(spaces, null, 2));
|
|
877
|
+
else printSpaceSummaries(spaces, deps.print);
|
|
878
|
+
return {
|
|
879
|
+
type: "details",
|
|
880
|
+
spaces
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
const spaces = await fetchSpaces(ctx, deps);
|
|
884
|
+
if (jsonOutput) deps.print(JSON.stringify(spaces, null, 2));
|
|
885
|
+
else printSpaces(spaces, deps.print);
|
|
886
|
+
return {
|
|
887
|
+
type: "list",
|
|
888
|
+
spaces
|
|
889
|
+
};
|
|
812
890
|
}
|
|
813
|
-
async function createSpace(
|
|
814
|
-
const response = await fetch(`${baseUrl}/api/spaces`, {
|
|
891
|
+
async function createSpace(ctx, deps, name) {
|
|
892
|
+
const response = await deps.fetch(`${ctx.baseUrl}/api/spaces`, {
|
|
815
893
|
method: "POST",
|
|
816
894
|
headers: {
|
|
817
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
895
|
+
"Authorization": `Bearer ${ctx.accessToken}`,
|
|
818
896
|
"Content-Type": "application/json"
|
|
819
897
|
},
|
|
820
898
|
body: JSON.stringify({ name })
|
|
@@ -825,83 +903,82 @@ async function createSpace(baseUrl, accessToken, name) {
|
|
|
825
903
|
}
|
|
826
904
|
return (await response.json()).space;
|
|
827
905
|
}
|
|
828
|
-
function printCreatedSpace(space, env, configPath) {
|
|
906
|
+
function printCreatedSpace(space, env, configPath, print) {
|
|
829
907
|
const envFlag = env === "production" ? "" : env === "local" ? " --local" : ` --env ${env}`;
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
if (configPath)
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
}
|
|
840
|
-
async function
|
|
841
|
-
const response = await fetch(`${baseUrl}/api/spaces`, { headers: {
|
|
842
|
-
"Authorization": `Bearer ${accessToken}`,
|
|
908
|
+
print(`\nSpace created successfully!\n`);
|
|
909
|
+
print(` ID: ${space.id}`);
|
|
910
|
+
print(` Name: ${space.name}`);
|
|
911
|
+
print(` Role: ${space.role}`);
|
|
912
|
+
if (configPath) print(` Config: ${configPath}`);
|
|
913
|
+
print(`\nTo bind this directory:`);
|
|
914
|
+
print(` makefx init --space ${space.id}${envFlag}`);
|
|
915
|
+
print(`\nTo listen for events:`);
|
|
916
|
+
print(` makefx listen --space ${space.id}${envFlag}`);
|
|
917
|
+
}
|
|
918
|
+
async function fetchSpaces(ctx, deps) {
|
|
919
|
+
const response = await deps.fetch(`${ctx.baseUrl}/api/spaces`, { headers: {
|
|
920
|
+
"Authorization": `Bearer ${ctx.accessToken}`,
|
|
843
921
|
"Content-Type": "application/json"
|
|
844
922
|
} });
|
|
845
923
|
if (!response.ok) throw new Error(`Failed to fetch spaces: ${response.status}`);
|
|
846
|
-
|
|
924
|
+
return (await response.json()).spaces;
|
|
925
|
+
}
|
|
926
|
+
function printSpaces(spaces, print) {
|
|
847
927
|
if (spaces.length === 0) {
|
|
848
|
-
|
|
928
|
+
print("No spaces found.");
|
|
849
929
|
return;
|
|
850
930
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
for (const space of spaces)
|
|
855
|
-
|
|
856
|
-
|
|
931
|
+
print(`\nFound ${spaces.length} space(s):\n`);
|
|
932
|
+
print("ID".padEnd(38) + "Name".padEnd(30) + "Role");
|
|
933
|
+
print("-".repeat(80));
|
|
934
|
+
for (const space of spaces) print(space.id.padEnd(38) + truncatePad(space.name, 30) + space.role);
|
|
935
|
+
print(`\nFor details: makefx spaces --details`);
|
|
936
|
+
print(`For a specific space: makefx spaces --id <space_id>`);
|
|
857
937
|
}
|
|
858
|
-
async function
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
938
|
+
async function listSpaceSummaries(ctx, deps) {
|
|
939
|
+
const spaces = await fetchSpaces(ctx, deps);
|
|
940
|
+
const summaries = [];
|
|
941
|
+
for (const space of spaces) {
|
|
942
|
+
const assets = await fetchSpaceAssets(ctx, deps, space.id);
|
|
943
|
+
summaries.push({
|
|
944
|
+
space,
|
|
945
|
+
assetCount: assets.length,
|
|
946
|
+
assetSummary: summarizeAssets(assets)
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
return summaries;
|
|
950
|
+
}
|
|
951
|
+
function printSpaceSummaries(summaries, print) {
|
|
952
|
+
if (summaries.length === 0) {
|
|
953
|
+
print("No spaces found.");
|
|
867
954
|
return;
|
|
868
955
|
}
|
|
869
|
-
|
|
870
|
-
for (const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
if (assetsResponse.ok) {
|
|
878
|
-
const assets = (await assetsResponse.json()).assets;
|
|
879
|
-
assetCount = assets.length;
|
|
880
|
-
if (assets.length > 0) {
|
|
881
|
-
const byType = /* @__PURE__ */ new Map();
|
|
882
|
-
for (const asset of assets) {
|
|
883
|
-
const type = asset.type || "unknown";
|
|
884
|
-
byType.set(type, (byType.get(type) || 0) + 1);
|
|
885
|
-
}
|
|
886
|
-
const typeParts = [];
|
|
887
|
-
for (const [type, count] of byType) typeParts.push(`${count} ${type}`);
|
|
888
|
-
assetSummary = typeParts.join(", ");
|
|
889
|
-
const firstNames = assets.slice(0, 3).map((a) => a.name);
|
|
890
|
-
if (assets.length > 3) firstNames.push(`+${assets.length - 3} more`);
|
|
891
|
-
assetSummary += ` (${firstNames.join(", ")})`;
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
console.log(`━━━ ${space.name} ━━━`);
|
|
895
|
-
console.log(` ID: ${space.id}`);
|
|
896
|
-
console.log(` Role: ${space.role}`);
|
|
897
|
-
console.log(` Assets: ${assetCount}`);
|
|
898
|
-
if (assetSummary) console.log(` Content: ${assetSummary}`);
|
|
899
|
-
console.log("");
|
|
956
|
+
print(`\nFetching details for ${summaries.length} space(s)...\n`);
|
|
957
|
+
for (const summary of summaries) {
|
|
958
|
+
print(`━━━ ${summary.space.name} ━━━`);
|
|
959
|
+
print(` ID: ${summary.space.id}`);
|
|
960
|
+
print(` Role: ${summary.space.role}`);
|
|
961
|
+
print(` Assets: ${summary.assetCount}`);
|
|
962
|
+
if (summary.assetSummary) print(` Content: ${summary.assetSummary}`);
|
|
963
|
+
print("");
|
|
900
964
|
}
|
|
901
965
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
966
|
+
function summarizeAssets(assets) {
|
|
967
|
+
if (assets.length === 0) return "";
|
|
968
|
+
const byType = /* @__PURE__ */ new Map();
|
|
969
|
+
for (const asset of assets) {
|
|
970
|
+
const type = asset.type || "unknown";
|
|
971
|
+
byType.set(type, (byType.get(type) || 0) + 1);
|
|
972
|
+
}
|
|
973
|
+
const typeParts = [];
|
|
974
|
+
for (const [type, count] of byType) typeParts.push(`${count} ${type}`);
|
|
975
|
+
const firstNames = assets.slice(0, 3).map((a) => a.name);
|
|
976
|
+
if (assets.length > 3) firstNames.push(`+${assets.length - 3} more`);
|
|
977
|
+
return `${typeParts.join(", ")} (${firstNames.join(", ")})`;
|
|
978
|
+
}
|
|
979
|
+
async function getSpaceDetails(ctx, deps, spaceId) {
|
|
980
|
+
const spaceResponse = await deps.fetch(`${ctx.baseUrl}/api/spaces/${spaceId}`, { headers: {
|
|
981
|
+
"Authorization": `Bearer ${ctx.accessToken}`,
|
|
905
982
|
"Content-Type": "application/json"
|
|
906
983
|
} });
|
|
907
984
|
if (!spaceResponse.ok) {
|
|
@@ -909,18 +986,28 @@ async function showSpaceDetails(baseUrl, accessToken, spaceId) {
|
|
|
909
986
|
if (spaceResponse.status === 404) throw new Error(`Space not found: ${spaceId}`);
|
|
910
987
|
throw new Error(`Failed to fetch space: ${spaceResponse.status}`);
|
|
911
988
|
}
|
|
912
|
-
const
|
|
913
|
-
const
|
|
914
|
-
|
|
989
|
+
const spaceData = await spaceResponse.json();
|
|
990
|
+
const assets = await fetchSpaceAssets(ctx, deps, spaceId);
|
|
991
|
+
return {
|
|
992
|
+
space: spaceData.space,
|
|
993
|
+
assets
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
async function fetchSpaceAssets(ctx, deps, spaceId) {
|
|
997
|
+
const assetsResponse = await deps.fetch(`${ctx.baseUrl}/api/spaces/${spaceId}/assets`, { headers: {
|
|
998
|
+
"Authorization": `Bearer ${ctx.accessToken}`,
|
|
915
999
|
"Content-Type": "application/json"
|
|
916
1000
|
} });
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1001
|
+
if (assetsResponse.ok) return (await assetsResponse.json()).assets;
|
|
1002
|
+
throw new Error(`Failed to fetch assets for space ${spaceId}: ${assetsResponse.status}`);
|
|
1003
|
+
}
|
|
1004
|
+
function printSpaceDetails(details, print) {
|
|
1005
|
+
const { space, assets } = details;
|
|
1006
|
+
print(`\n━━━ ${space.name} ━━━`);
|
|
1007
|
+
print(`ID: ${space.id}`);
|
|
1008
|
+
print(`Assets: ${assets.length}\n`);
|
|
922
1009
|
if (assets.length === 0) {
|
|
923
|
-
|
|
1010
|
+
print("(No assets in this space)");
|
|
924
1011
|
return;
|
|
925
1012
|
}
|
|
926
1013
|
const byType = /* @__PURE__ */ new Map();
|
|
@@ -930,16 +1017,15 @@ async function showSpaceDetails(baseUrl, accessToken, spaceId) {
|
|
|
930
1017
|
byType.get(type).push(asset);
|
|
931
1018
|
}
|
|
932
1019
|
for (const [type, typeAssets] of byType) {
|
|
933
|
-
|
|
1020
|
+
print(`${type.charAt(0).toUpperCase() + type.slice(1)}s (${typeAssets.length}):`);
|
|
934
1021
|
for (const asset of typeAssets) {
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
console.log(` ID: ${asset.id}`);
|
|
1022
|
+
print(` ${asset.active_variant_id ? "✓" : "○"} ${asset.name}`);
|
|
1023
|
+
print(` ID: ${asset.id}`);
|
|
938
1024
|
}
|
|
939
|
-
|
|
1025
|
+
print("");
|
|
940
1026
|
}
|
|
941
|
-
|
|
942
|
-
|
|
1027
|
+
print(`\nTo start a chat session with this space:`);
|
|
1028
|
+
print(` makefx chat send "What's in this space?" --space ${space.id} --state ./test/${space.name.toLowerCase().replace(/\s+/g, "-")}.json`);
|
|
943
1029
|
}
|
|
944
1030
|
function truncatePad(str, width) {
|
|
945
1031
|
if (str.length > width - 2) return str.slice(0, width - 3) + ".. ";
|
|
@@ -21542,9 +21628,9 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$6, option
|
|
|
21542
21628
|
try {
|
|
21543
21629
|
await client.connect();
|
|
21544
21630
|
switch (command) {
|
|
21545
|
-
case "generate": return await executeGenerate(parsed, ctx, client, deps, mediaKind);
|
|
21631
|
+
case "generate": return await executeGenerate(parsed, ctx, client, deps, mediaKind, { audioMode: options.audioMode });
|
|
21546
21632
|
case "refine": return await executeRefine(parsed, ctx, client, deps, mediaKind);
|
|
21547
|
-
case "derive": return await executeDerive(parsed, ctx, client, deps, mediaKind);
|
|
21633
|
+
case "derive": return await executeDerive(parsed, ctx, client, deps, mediaKind, { audioMode: options.audioMode });
|
|
21548
21634
|
case "batch": return await executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManifest);
|
|
21549
21635
|
}
|
|
21550
21636
|
} finally {
|
|
@@ -21560,7 +21646,8 @@ async function executeAudioCommand(command, parsed, deps = defaultDeps$6, option
|
|
|
21560
21646
|
if (parsed.options.input && command !== "generate") throw new Error("Audio --input is only supported with generate");
|
|
21561
21647
|
return executeForgeCommand(command, await prepareAudioParsedArgs(parsed, options.mode), deps, {
|
|
21562
21648
|
mediaKind: audioProfile.mediaKind,
|
|
21563
|
-
saveBatchManifest: audioProfile.savesBatchManifest
|
|
21649
|
+
saveBatchManifest: audioProfile.savesBatchManifest,
|
|
21650
|
+
audioMode: options.mode
|
|
21564
21651
|
});
|
|
21565
21652
|
}
|
|
21566
21653
|
async function executeVideoCommand(command, parsed, deps = defaultDeps$6) {
|
|
@@ -21583,12 +21670,17 @@ async function prepareAudioParsedArgs(parsed, mode) {
|
|
|
21583
21670
|
const input = await readFile(options.input, "utf8");
|
|
21584
21671
|
positionals.push(input);
|
|
21585
21672
|
}
|
|
21673
|
+
if (!options.follow) validateAudioModeRequiredVoiceOptions(options, effectiveMode);
|
|
21586
21674
|
return {
|
|
21587
21675
|
options,
|
|
21588
21676
|
positionals
|
|
21589
21677
|
};
|
|
21590
21678
|
}
|
|
21591
|
-
|
|
21679
|
+
function validateAudioModeRequiredVoiceOptions(options, mode) {
|
|
21680
|
+
if (mode === "speech" && !normalizeCliOption(options.voice)) throw new Error("Speech generation requires --voice <voice_id>. Run: makefx audio voices");
|
|
21681
|
+
if (mode === "dialogue" && !normalizeCliOption(options["dialogue-voices"] ?? options.dialogueVoices)) throw new Error("Dialogue generation requires --dialogue-voices <voice_id,voice_id>. Run: makefx audio voices");
|
|
21682
|
+
}
|
|
21683
|
+
async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptions = {}) {
|
|
21592
21684
|
const prompt = getPrompt(parsed, "generate");
|
|
21593
21685
|
const outputPath = getOutputPath$1(parsed);
|
|
21594
21686
|
const name = requireOption(parsed, "name");
|
|
@@ -21619,7 +21711,7 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind) {
|
|
|
21619
21711
|
...musicProvider ? { musicProvider } : {},
|
|
21620
21712
|
...videoAudioOptions,
|
|
21621
21713
|
...videoOptions,
|
|
21622
|
-
onStarted: (started) => printFollowHint(started, ctx, outputPath, "generate", mediaKind)
|
|
21714
|
+
onStarted: (started) => printFollowHint(started, ctx, outputPath, "generate", mediaKind, followOptions)
|
|
21623
21715
|
});
|
|
21624
21716
|
const productionRecord = await placeProductionRecordFromScene({
|
|
21625
21717
|
command: "generate",
|
|
@@ -21721,7 +21813,7 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
|
|
|
21721
21813
|
printResult(result, outputPath, ctx, manifestPath, productionRecord);
|
|
21722
21814
|
return result;
|
|
21723
21815
|
}
|
|
21724
|
-
async function executeDerive(parsed, ctx, client, deps, mediaKind) {
|
|
21816
|
+
async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions = {}) {
|
|
21725
21817
|
const prompt = getPrompt(parsed, "derive");
|
|
21726
21818
|
const outputPath = getOutputPath$1(parsed);
|
|
21727
21819
|
const name = requireOption(parsed, "name");
|
|
@@ -21752,7 +21844,7 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind) {
|
|
|
21752
21844
|
mediaKind,
|
|
21753
21845
|
...videoAudioOptions,
|
|
21754
21846
|
...videoOptions,
|
|
21755
|
-
onStarted: (started) => printFollowHint(started, ctx, outputPath, "derive", mediaKind)
|
|
21847
|
+
onStarted: (started) => printFollowHint(started, ctx, outputPath, "derive", mediaKind, followOptions)
|
|
21756
21848
|
});
|
|
21757
21849
|
const productionRecord = await placeProductionRecordFromScene({
|
|
21758
21850
|
command: "derive",
|
|
@@ -22175,16 +22267,17 @@ function printResult(result, outputPath, ctx, manifestPath, productionRecord) {
|
|
|
22175
22267
|
if (productionRecord) console.log(` Production: ${productionRecord.production_id} (${productionRecord.id})`);
|
|
22176
22268
|
console.log(` Web: ${ctx.baseUrl}/spaces/${ctx.spaceId}/assets/${variant.asset_id}`);
|
|
22177
22269
|
}
|
|
22178
|
-
function printFollowHint(started, ctx, outputPath, command, mediaKind) {
|
|
22270
|
+
function printFollowHint(started, ctx, outputPath, command, mediaKind, options = {}) {
|
|
22179
22271
|
console.log(` Started variant: ${started.jobId}`);
|
|
22180
|
-
console.log(` Follow: ${formatFollowCommand(started.jobId, outputPath, ctx, command, mediaKind)}`);
|
|
22272
|
+
console.log(` Follow: ${formatFollowCommand(started.jobId, outputPath, ctx, command, mediaKind, options)}`);
|
|
22181
22273
|
}
|
|
22182
|
-
function formatFollowCommand(variantId, outputPath, ctx, command, mediaKind) {
|
|
22274
|
+
function formatFollowCommand(variantId, outputPath, ctx, command, mediaKind, options = {}) {
|
|
22183
22275
|
const baseCommand = mediaKind === "audio" ? [
|
|
22184
22276
|
"makefx",
|
|
22185
22277
|
"audio",
|
|
22278
|
+
options.audioMode,
|
|
22186
22279
|
"generate"
|
|
22187
|
-
] : mediaKind === "video" ? [
|
|
22280
|
+
].filter((part) => Boolean(part)) : mediaKind === "video" ? [
|
|
22188
22281
|
"makefx",
|
|
22189
22282
|
"video",
|
|
22190
22283
|
command
|
|
@@ -22250,10 +22343,11 @@ function validateVideoAudioOptions(parsed, mediaKind) {
|
|
|
22250
22343
|
if (parsed.options.audio !== void 0 && (parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0)) throw new Error("Pass either --audio or --no-audio, not both");
|
|
22251
22344
|
}
|
|
22252
22345
|
function parseVideoAudioOptions(parsed, mediaKind) {
|
|
22253
|
-
if (mediaKind
|
|
22254
|
-
|
|
22255
|
-
|
|
22256
|
-
|
|
22346
|
+
if (mediaKind === "video") {
|
|
22347
|
+
if (parsed.options.audio !== void 0) return { generateAudio: true };
|
|
22348
|
+
if (parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0) return { generateAudio: false };
|
|
22349
|
+
}
|
|
22350
|
+
return {};
|
|
22257
22351
|
}
|
|
22258
22352
|
function parseVideoGenerationOptions(parsed, mediaKind) {
|
|
22259
22353
|
const resolutionValue = readOptionalOption(parsed, "resolution", "resolution") ?? readOptionalOption(parsed, "video-resolution", "videoResolution");
|
|
@@ -22568,9 +22662,9 @@ Usage:
|
|
|
22568
22662
|
makefx audio <${modes}> batch "prompt" --name <name> --count <2-8> --output-dir <dir> [--space <id>]
|
|
22569
22663
|
makefx audio music generate "prompt" --provider lyria --name <name> -o <file> [--space <id>]
|
|
22570
22664
|
|
|
22571
|
-
Voice selection:
|
|
22665
|
+
Voice selection (run 'makefx audio voices' to list voice IDs):
|
|
22572
22666
|
makefx audio speech generate "text" --voice <voice_id> --name <name> -o <file>
|
|
22573
|
-
makefx audio dialogue generate --input script.txt --
|
|
22667
|
+
makefx audio dialogue generate --input script.txt --dialogue-voices <voice_id,voice_id> --name <name> -o <file>
|
|
22574
22668
|
|
|
22575
22669
|
Low-level compatibility:
|
|
22576
22670
|
makefx audio generate "prompt" --name <name> --type <type> -o <file> [--space <id>]
|
|
@@ -22618,8 +22712,8 @@ Video:
|
|
|
22618
22712
|
--tier <tier> Veo model tier: ${tierValues}
|
|
22619
22713
|
|
|
22620
22714
|
Audio:
|
|
22621
|
-
--audio Request native synchronized Veo audio
|
|
22622
|
-
--no-audio Request a silent video
|
|
22715
|
+
--audio Request native synchronized Veo audio (default)
|
|
22716
|
+
--no-audio Request a silent video; MakeFX records this and adds a silent-video instruction.
|
|
22623
22717
|
|
|
22624
22718
|
Production metadata:
|
|
22625
22719
|
--scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
|
|
@@ -23513,9 +23607,11 @@ Options:
|
|
|
23513
23607
|
}
|
|
23514
23608
|
//#endregion
|
|
23515
23609
|
//#region src/cli/index.ts
|
|
23516
|
-
var CLI_VERSION = "0.1.
|
|
23610
|
+
var CLI_VERSION = "0.1.2+2907a84228d9";
|
|
23517
23611
|
async function main() {
|
|
23518
|
-
const
|
|
23612
|
+
const argv = process$1.argv.slice(2);
|
|
23613
|
+
if (argv[0] === "--") argv.shift();
|
|
23614
|
+
const [command, ...args] = argv;
|
|
23519
23615
|
if (command === "--version" || command === "version") {
|
|
23520
23616
|
console.log(CLI_VERSION);
|
|
23521
23617
|
return;
|
|
@@ -23702,12 +23798,15 @@ Project:
|
|
|
23702
23798
|
Billing (Polar.sh):
|
|
23703
23799
|
billing status Show sync status (pending, failed, synced events)
|
|
23704
23800
|
billing check Run operational checks for workers, meters, and sync health
|
|
23801
|
+
billing reconcile --user-id <id>
|
|
23802
|
+
Compare local billable usage with Polar usage
|
|
23705
23803
|
billing retry-failed Retry all failed events
|
|
23706
23804
|
|
|
23707
23805
|
Spaces:
|
|
23708
23806
|
spaces List all spaces
|
|
23709
|
-
spaces --
|
|
23710
|
-
spaces --
|
|
23807
|
+
spaces --json List all spaces as JSON
|
|
23808
|
+
spaces --details [--json] List spaces with asset summaries
|
|
23809
|
+
spaces --id <id> [--json] Show details for a specific space
|
|
23711
23810
|
spaces create <name> Create a new space
|
|
23712
23811
|
|
|
23713
23812
|
Listen:
|
|
@@ -23800,6 +23899,7 @@ Usage:
|
|
|
23800
23899
|
Subcommands:
|
|
23801
23900
|
status Show sync status (pending, failed, synced events)
|
|
23802
23901
|
check Run operational checks for workers, Polar meters, and sync health
|
|
23902
|
+
reconcile Compare local billable usage with Polar usage for one user
|
|
23803
23903
|
retry-failed Reset failed events for retry (next cron will sync them)
|
|
23804
23904
|
|
|
23805
23905
|
Options:
|
|
@@ -23811,8 +23911,9 @@ function printSpacesHelp() {
|
|
|
23811
23911
|
console.log(`
|
|
23812
23912
|
Usage:
|
|
23813
23913
|
makefx spaces
|
|
23814
|
-
makefx spaces --
|
|
23815
|
-
makefx spaces --
|
|
23914
|
+
makefx spaces --json
|
|
23915
|
+
makefx spaces --details [--json]
|
|
23916
|
+
makefx spaces --id <space_id> [--json]
|
|
23816
23917
|
makefx spaces create <name>
|
|
23817
23918
|
makefx spaces create --name "My Space" [--init] [--json]
|
|
23818
23919
|
`);
|
|
@@ -23989,8 +24090,7 @@ Usage:
|
|
|
23989
24090
|
${videoCapabilityHelp()}
|
|
23990
24091
|
|
|
23991
24092
|
Audio:
|
|
23992
|
-
--audio
|
|
23993
|
-
--no-audio Request a silent video (default)
|
|
24093
|
+
Video defaults to generated audio. Use --no-audio to record a silent-video request and add a silent-video instruction.
|
|
23994
24094
|
|
|
23995
24095
|
Production metadata:
|
|
23996
24096
|
--scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
|
|
@@ -24007,8 +24107,7 @@ Usage:
|
|
|
24007
24107
|
${videoCapabilityHelp()}
|
|
24008
24108
|
|
|
24009
24109
|
Audio:
|
|
24010
|
-
--audio
|
|
24011
|
-
--no-audio Request a silent video (default)
|
|
24110
|
+
Video defaults to generated audio. Use --no-audio to record a silent-video request and add a silent-video instruction.
|
|
24012
24111
|
|
|
24013
24112
|
Production metadata:
|
|
24014
24113
|
--scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
|
|
@@ -24025,8 +24124,7 @@ Usage:
|
|
|
24025
24124
|
${videoCapabilityHelp()}
|
|
24026
24125
|
|
|
24027
24126
|
Audio:
|
|
24028
|
-
--audio
|
|
24029
|
-
--no-audio Request a silent video (default)
|
|
24127
|
+
Video defaults to generated audio. Use --no-audio to record a silent-video request and add a silent-video instruction.
|
|
24030
24128
|
|
|
24031
24129
|
Production metadata:
|
|
24032
24130
|
--scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
|
|
@@ -24044,8 +24142,7 @@ Usage:
|
|
|
24044
24142
|
${videoCapabilityHelp()}
|
|
24045
24143
|
|
|
24046
24144
|
Audio:
|
|
24047
|
-
--audio
|
|
24048
|
-
--no-audio Request a silent video (default)
|
|
24145
|
+
Video defaults to generated audio. Use --no-audio to record a silent-video request and add a silent-video instruction.
|
|
24049
24146
|
|
|
24050
24147
|
Production metadata:
|
|
24051
24148
|
--scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
|
package/package.json
CHANGED
|
@@ -1,111 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makefx",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Command-line interface for AI-assisted game asset production with Make Effects.",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/krasnoperov/inventory.git"
|
|
10
|
+
},
|
|
6
11
|
"bin": {
|
|
7
|
-
"makefx": "
|
|
12
|
+
"makefx": "makefx.mjs"
|
|
8
13
|
},
|
|
9
14
|
"files": [
|
|
10
|
-
"
|
|
15
|
+
"makefx.mjs",
|
|
11
16
|
"README.md"
|
|
12
17
|
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {},
|
|
13
22
|
"publishConfig": {
|
|
14
23
|
"access": "public"
|
|
15
|
-
},
|
|
16
|
-
"packageManager": "pnpm@11.1.1",
|
|
17
|
-
"scripts": {
|
|
18
|
-
"bootstrap:worktree": "node ./scripts/bootstrap-worktree.mjs",
|
|
19
|
-
"dev": "CLOUDFLARE_VITE_CONFIG_PATH=wrangler.dev.toml vite",
|
|
20
|
-
"build": "vite build && pnpm run package:frontend-start && pnpm run build:cli",
|
|
21
|
-
"package:frontend-start": "node scripts/package-frontend-start.mjs",
|
|
22
|
-
"build:cli": "node scripts/build-cli.mjs",
|
|
23
|
-
"deploy": "pnpm run build && pnpm exec wrangler deploy",
|
|
24
|
-
"deploy:production": "CLOUDFLARE_ENV=production pnpm run build && pnpm exec wrangler deploy --env production",
|
|
25
|
-
"deploy:stage": "pnpm run build && pnpm exec wrangler deploy",
|
|
26
|
-
"test": "node ./scripts/run-node-tests.mjs",
|
|
27
|
-
"test:components": "playwright test --config playwright.component.config.ts",
|
|
28
|
-
"test:components:ci": "node ./scripts/run-component-ci.mjs",
|
|
29
|
-
"test:e2e:media-foundation": "pnpm run build && node scripts/e2e-media-foundation.mjs",
|
|
30
|
-
"test:e2e:cli-forge": "pnpm run build && node scripts/e2e-cli-forge.mjs",
|
|
31
|
-
"auth:session-state": "node scripts/auth/mint-session.mjs",
|
|
32
|
-
"lint": "oxlint --config .oxlintrc.json src scripts && pnpm d1:guard && pnpm lint:tokens",
|
|
33
|
-
"lint:tokens": "pnpm tokens:guard && pnpm tokens:snapshot:check && pnpm tokens:roundtrip",
|
|
34
|
-
"tokens:guard": "node scripts/check-design-tokens.mjs",
|
|
35
|
-
"tokens:snapshot": "node scripts/snapshot-design-tokens.mjs",
|
|
36
|
-
"tokens:snapshot:check": "node scripts/snapshot-design-tokens.mjs --check",
|
|
37
|
-
"tokens:roundtrip": "node scripts/generate-css-from-tokens.mjs --check",
|
|
38
|
-
"d1:guard": "node scripts/check-no-d1-transactions.mjs",
|
|
39
|
-
"typecheck": "tsc --noEmit",
|
|
40
|
-
"ci:pre-push": "pnpm run typecheck && pnpm run lint && pnpm run build && pnpm test --test-reporter=dot && pnpm run test:components:ci",
|
|
41
|
-
"db:migrate": "node --import @swc-node/register/esm-register scripts/db-migrate.ts",
|
|
42
|
-
"db:migrate:stage": "node --import @swc-node/register/esm-register scripts/db-migrate.ts stage remote",
|
|
43
|
-
"db:migrate:production": "node --import @swc-node/register/esm-register scripts/db-migrate.ts production remote",
|
|
44
|
-
"cli": "node dist/cli/makefx.mjs",
|
|
45
|
-
"cli:dev": "node --import @swc-node/register/esm-register src/cli/index.ts",
|
|
46
|
-
"stories": "LADLE=true ladle serve",
|
|
47
|
-
"stories:build": "LADLE=true ladle build",
|
|
48
|
-
"style-reference": "node scripts/export-style-reference.mjs",
|
|
49
|
-
"style-reference:rebuild": "node scripts/export-style-reference.mjs --rebuild"
|
|
50
|
-
},
|
|
51
|
-
"dependencies": {
|
|
52
|
-
"@anthropic-ai/sdk": "^0.71.0",
|
|
53
|
-
"@google/genai": "^1.30.0",
|
|
54
|
-
"@hono/zod-openapi": "^1.4.0",
|
|
55
|
-
"@openai/agents": "^0.3.3",
|
|
56
|
-
"@polar-sh/sdk": "^0.41.5",
|
|
57
|
-
"@react-oauth/google": "^0.12.2",
|
|
58
|
-
"@tanstack/react-query": "^5.90.11",
|
|
59
|
-
"@tanstack/react-router": "^1.170.15",
|
|
60
|
-
"@tanstack/react-start": "^1.168.25",
|
|
61
|
-
"@types/d3-force": "^3.0.10",
|
|
62
|
-
"@types/dagre": "^0.7.53",
|
|
63
|
-
"@xyflow/react": "^12.9.3",
|
|
64
|
-
"better-sqlite3": "^12.4.6",
|
|
65
|
-
"d3-force": "^3.0.0",
|
|
66
|
-
"dagre": "^0.8.5",
|
|
67
|
-
"dotenv": "^17.2.3",
|
|
68
|
-
"fflate": "^0.8.2",
|
|
69
|
-
"hono": "^4.10.6",
|
|
70
|
-
"inversify": "^7.10.4",
|
|
71
|
-
"jose": "^6.1.2",
|
|
72
|
-
"kysely": "^0.28.8",
|
|
73
|
-
"kysely-d1": "^0.4.0",
|
|
74
|
-
"nanoid": "^5.1.11",
|
|
75
|
-
"react": "^19.2.0",
|
|
76
|
-
"react-dom": "^19.2.0",
|
|
77
|
-
"react-markdown": "^10.1.0",
|
|
78
|
-
"reflect-metadata": "^0.2.2",
|
|
79
|
-
"remark-gfm": "^4.0.1",
|
|
80
|
-
"standardwebhooks": "1.0.0",
|
|
81
|
-
"uuid": "^13.0.0",
|
|
82
|
-
"ws": "^8.21.0",
|
|
83
|
-
"zod": "^4.4.3",
|
|
84
|
-
"zustand": "^5.0.8"
|
|
85
|
-
},
|
|
86
|
-
"devDependencies": {
|
|
87
|
-
"@cloudflare/ai": "^1.2.2",
|
|
88
|
-
"@cloudflare/vite-plugin": "^1.39.0",
|
|
89
|
-
"@cloudflare/workers-types": "4.20260317.1",
|
|
90
|
-
"@csstools/postcss-light-dark-function": "^3.0.0",
|
|
91
|
-
"@ladle/react": "^5.1.1",
|
|
92
|
-
"@playwright/test": "^1.59.1",
|
|
93
|
-
"@swc-node/register": "^1.11.1",
|
|
94
|
-
"@tanstack/router-plugin": "^1.168.18",
|
|
95
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
96
|
-
"@types/node": "^24.10.1",
|
|
97
|
-
"@types/react": "^19.2.7",
|
|
98
|
-
"@types/react-dom": "^19.2.3",
|
|
99
|
-
"@types/ws": "^8.18.1",
|
|
100
|
-
"@vitejs/plugin-react": "^5.1.1",
|
|
101
|
-
"express": "^5.1.0",
|
|
102
|
-
"oxlint": "1.67.0",
|
|
103
|
-
"postcss": "^8.5.6",
|
|
104
|
-
"postcss-preset-env": "^10.4.0",
|
|
105
|
-
"prettier": "^3.6.2",
|
|
106
|
-
"rollup-plugin-visualizer": "^6.0.5",
|
|
107
|
-
"typescript": "^5.9.3",
|
|
108
|
-
"vite": "^8.0.14",
|
|
109
|
-
"wrangler": "4.95.0"
|
|
110
24
|
}
|
|
111
25
|
}
|