@spatius/cli 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/THIRD_PARTY_NOTICES.md +26 -0
- package/dist/chunk-YILIK7FE.js +479 -0
- package/dist/cli.js +2523 -0
- package/dist/commands.js +10 -0
- package/docs/deployment.md +277 -0
- package/docs/staging-validation.md +46 -0
- package/docs/workflows.md +134 -0
- package/package.json +45 -0
- package/skills/spatius-avatar/SKILL.md +41 -0
- package/skills/spatius-shared/SKILL.md +50 -0
- package/skills/spatius-shared/references/recovery.md +24 -0
- package/skills/spatius-video/SKILL.md +44 -0
- package/skills/spatius-video/references/inputs-and-recovery.md +35 -0
package/dist/commands.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Deployment and releases
|
|
2
|
+
|
|
3
|
+
A published GitHub release deploys the production media Worker, then publishes
|
|
4
|
+
`@spatius/cli` with its matching skills and documentation. The executable remains
|
|
5
|
+
`spatius`. Keep the repository private while preparing this setup; perform the
|
|
6
|
+
first publication after it becomes public.
|
|
7
|
+
|
|
8
|
+
## Release contract
|
|
9
|
+
|
|
10
|
+
| Setting | Behavior |
|
|
11
|
+
| ----------- | ------------------------------------------------------------------------------------------------- |
|
|
12
|
+
| Trigger | GitHub `release.published`, including prereleases; pushing a tag alone does not publish |
|
|
13
|
+
| Source | Exact release commit, reachable from `main`; public repository required for provenance |
|
|
14
|
+
| Version | Canonical `vX.Y.Z[-prerelease]` tag without build metadata; GitHub prerelease checkbox must agree |
|
|
15
|
+
| npm channel | Any prerelease → `beta`; stable → `latest` |
|
|
16
|
+
| Worker | `spatius-cli-media` at `https://cli-media.spatius.ai` for **every** release |
|
|
17
|
+
| Runtime | GitHub-hosted Ubuntu, Node 24, compatible npm, and the workspace's pinned pnpm/Wrangler |
|
|
18
|
+
|
|
19
|
+
The workflow validates the release and npm version, runs `pnpm check`, installs
|
|
20
|
+
and tests the exact release tarball, deploys the Worker, checks HTTPS health and
|
|
21
|
+
unauthenticated upload rejection, and publishes that tarball with provenance.
|
|
22
|
+
Only a registry 404 permits a new version; duplicates and registry errors stop
|
|
23
|
+
before deployment. The release version is written in the runner only. There is
|
|
24
|
+
no version commit and no new tag created by CI.
|
|
25
|
+
|
|
26
|
+
Worker deployments record the release tag and commit SHA. Actions summarizes the
|
|
27
|
+
Worker deployment and npm publication. Keep Worker `/v1` compatible with older
|
|
28
|
+
CLI versions and inputs still in use. Prereleases also update production.
|
|
29
|
+
|
|
30
|
+
## One-time production setup
|
|
31
|
+
|
|
32
|
+
### 1. Cloudflare account, bucket, and domain
|
|
33
|
+
|
|
34
|
+
Use the Spatius Cloudflare account `5e47c9255b3c952c52f162ed53f6e14a`, with Workers
|
|
35
|
+
Paid and R2 enabled, and the active `spatius.ai` zone. In the dashboard, verify
|
|
36
|
+
that `cli-media.spatius.ai` is unused or already belongs to this Worker. Wrangler
|
|
37
|
+
can replace an existing custom-domain origin during noninteractive deployment.
|
|
38
|
+
|
|
39
|
+
Install dependencies from the repository root, then use the operator's Wrangler
|
|
40
|
+
login to provision storage:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
pnpm install --frozen-lockfile
|
|
44
|
+
export CLOUDFLARE_ACCOUNT_ID=5e47c9255b3c952c52f162ed53f6e14a
|
|
45
|
+
cd packages/media-worker
|
|
46
|
+
pnpm exec wrangler login
|
|
47
|
+
pnpm exec wrangler whoami
|
|
48
|
+
pnpm exec wrangler r2 bucket create spatius-cli-media-production
|
|
49
|
+
pnpm exec wrangler r2 bucket lifecycle add spatius-cli-media-production temporary-inputs media/ --expire-days 2 --abort-multipart-days 1 --force
|
|
50
|
+
pnpm exec wrangler r2 bucket lifecycle list spatius-cli-media-production
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Keep the R2 bucket private: no bucket custom domain and no `r2.dev` access. The
|
|
54
|
+
production Worker configuration attaches `cli-media.spatius.ai` to the Worker
|
|
55
|
+
and disables its `workers.dev` endpoint. Provisioning storage needs the
|
|
56
|
+
operator's R2 permissions; routine release credentials do not create buckets.
|
|
57
|
+
If the bucket or lifecycle rule already exists, inspect and retain it instead
|
|
58
|
+
of repeating creation; lifecycle additions append rules.
|
|
59
|
+
|
|
60
|
+
### 2. Signing secret and first Worker deployment
|
|
61
|
+
|
|
62
|
+
From `packages/media-worker`, generate the production key once and pipe it
|
|
63
|
+
directly into Wrangler. The JSON contains a `v1` key matching `SIGNING_KEY_ID`:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
node --input-type=module -e 'import { randomBytes } from "node:crypto"; process.stdout.write(JSON.stringify({ v1: randomBytes(32).toString("hex") }));' \
|
|
67
|
+
| pnpm exec wrangler secret put SIGNING_KEYS --env production
|
|
68
|
+
pnpm exec wrangler secret list --env production
|
|
69
|
+
pnpm exec wrangler deploy --env production --dry-run
|
|
70
|
+
pnpm exec wrangler deploy --env production
|
|
71
|
+
curl --fail --silent --show-error --max-time 15 https://cli-media.spatius.ai/health
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Wrangler may offer to create the Worker when storing its first secret. The first
|
|
75
|
+
full deployment applies its Durable Object migration and custom domain. Preserve
|
|
76
|
+
the Worker name, bucket, Durable Object binding, and migration history across
|
|
77
|
+
releases. `SIGNING_KEYS` is required; recurring deployments retain the saved
|
|
78
|
+
secret. Do not regenerate it when retrying deployment.
|
|
79
|
+
|
|
80
|
+
Before npm publication, run the authenticated upload/read check below. `/health`
|
|
81
|
+
checks process/routing only; it does not prove Studio auth, storage, or signing.
|
|
82
|
+
No Console signing secret, renderer token, app API key, or Studio refresh token
|
|
83
|
+
belongs in this Worker.
|
|
84
|
+
|
|
85
|
+
### 3. GitHub configuration
|
|
86
|
+
|
|
87
|
+
In `spatius-ai/spatius-cli`, configure:
|
|
88
|
+
|
|
89
|
+
| Setting | Type | Value/access |
|
|
90
|
+
| ----------------------- | --------------------------- | ------------------------------------------------------------------------------------- |
|
|
91
|
+
| `CLOUDFLARE_API_TOKEN` | Actions repository secret | **Workers Scripts: Edit** for the production account; **Zone: Read** for `spatius.ai` |
|
|
92
|
+
| `CLOUDFLARE_ACCOUNT_ID` | Actions repository variable | `5e47c9255b3c952c52f162ed53f6e14a` |
|
|
93
|
+
|
|
94
|
+
For example, the GitHub CLI prompts securely for the API token:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
gh secret set CLOUDFLARE_API_TOKEN --repo spatius-ai/spatius-cli
|
|
98
|
+
gh variable set CLOUDFLARE_ACCOUNT_ID --repo spatius-ai/spatius-cli --body 5e47c9255b3c952c52f162ed53f6e14a
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Only the deployment job receives Cloudflare credentials. Only the npm job gets
|
|
102
|
+
`id-token: write`; all jobs have `contents: read`. Leave `SIGNING_KEYS` in
|
|
103
|
+
Cloudflare. Do not configure `NPM_TOKEN`, Studio credentials, or renderer
|
|
104
|
+
credentials in GitHub. No approval environment or release enablement variable
|
|
105
|
+
is required.
|
|
106
|
+
|
|
107
|
+
### 4. Create the npm package
|
|
108
|
+
|
|
109
|
+
After the repository is public and production upload/read validation passes,
|
|
110
|
+
use an npm account with 2FA and permission to publish under `@spatius`.
|
|
111
|
+
The package must exist before configuring its trusted publisher, so create
|
|
112
|
+
`0.1.0-beta.0` once from the checked tarball. This initial manual publication has
|
|
113
|
+
no provenance; automated releases have provenance.
|
|
114
|
+
[npm trusted-publisher prerequisites](https://docs.npmjs.com/cli/v11/commands/npm-trust/#prerequisites)
|
|
115
|
+
|
|
116
|
+
From a clean repository root containing the merged release changes:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
pnpm install --frozen-lockfile
|
|
120
|
+
pnpm check
|
|
121
|
+
SPATIUS_RELEASE_DIR=$(mktemp -d)
|
|
122
|
+
pnpm package:check -- --artifact-dir "$SPATIUS_RELEASE_DIR"
|
|
123
|
+
npm login --registry=https://registry.npmjs.org
|
|
124
|
+
npm publish "$SPATIUS_RELEASE_DIR/spatius-cli-0.1.0-beta.0.tgz" --access public --tag beta --provenance=false --ignore-scripts
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`package:check` retains the validated tarball and `release-artifact.json`
|
|
128
|
+
(name, version, filename, and integrity) in the requested directory. Publish that
|
|
129
|
+
same tarball instead of rebuilding after validation. This bootstrap does not
|
|
130
|
+
need a published GitHub release; publishing `v0.1.0-beta.0` afterward would fail
|
|
131
|
+
the duplicate-version check. If the package already exists, inspect its versions
|
|
132
|
+
and configure the publisher instead of repeating bootstrap.
|
|
133
|
+
|
|
134
|
+
### 5. Configure npm trusted publishing
|
|
135
|
+
|
|
136
|
+
In the npm settings for `@spatius/cli`, add this trusted publisher:
|
|
137
|
+
|
|
138
|
+
| Field | Value |
|
|
139
|
+
| ----------------- | ------------------------------- |
|
|
140
|
+
| Provider | GitHub Actions |
|
|
141
|
+
| Organization | `spatius-ai` |
|
|
142
|
+
| Repository | `spatius-cli` |
|
|
143
|
+
| Workflow filename | `publish.yml` |
|
|
144
|
+
| Environment | Leave blank |
|
|
145
|
+
| Allowed action | Enable direct **`npm publish`** |
|
|
146
|
+
|
|
147
|
+
New publishers may default to staged publication; select direct publication so
|
|
148
|
+
GitHub releases complete automatically. npm uses the job's OIDC identity without
|
|
149
|
+
a long-lived token. See [npm trusted publishing](https://docs.npmjs.com/trusted-publishers/).
|
|
150
|
+
|
|
151
|
+
### 6. Publish releases
|
|
152
|
+
|
|
153
|
+
After merge and CI pass, select a commit on `main` and publish the first automated
|
|
154
|
+
release as `v0.1.0-beta.1`, with the GitHub prerelease checkbox selected. For
|
|
155
|
+
example, from the clean repository root:
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
git fetch origin main
|
|
159
|
+
SPATIUS_RELEASE_COMMIT=$(git rev-parse origin/main)
|
|
160
|
+
gh release create v0.1.0-beta.1 --repo spatius-ai/spatius-cli --target "$SPATIUS_RELEASE_COMMIT" --prerelease --generate-notes
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Wait for its Actions run, then verify:
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
npm install -g @spatius/cli@beta
|
|
167
|
+
spatius --version
|
|
168
|
+
spatius --help
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Stable releases use a tag such as `v0.1.0`, with the prerelease checkbox cleared,
|
|
172
|
+
and install with `npm install -g @spatius/cli` (`latest`). No release proceeds
|
|
173
|
+
while the repository is private. Ordinary pushes and pull requests run checks
|
|
174
|
+
without deployment or publication.
|
|
175
|
+
|
|
176
|
+
## Partial failure and retry
|
|
177
|
+
|
|
178
|
+
Publish one release at a time. A shared concurrency group with `queue: max`
|
|
179
|
+
keeps pending releases without cancelling a running release. Do not rely on the
|
|
180
|
+
queue to order releases for you.
|
|
181
|
+
|
|
182
|
+
| Failure | Recovery |
|
|
183
|
+
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
184
|
+
| Release validation, registry lookup, or tests | Fix the cause; Worker and npm remain unchanged |
|
|
185
|
+
| Worker deployment or post-deployment checks | npm is not published; inspect the actual Worker deployment before retrying |
|
|
186
|
+
| npm publication after Worker deployment | Keep the compatible Worker running; inspect npm before retrying. No automatic rollback or publish retry occurs |
|
|
187
|
+
| Version already exists in npm | Confirm its integrity/version and the Actions result; do not overwrite or republish it |
|
|
188
|
+
| Newer release has deployed since a failure | Fix forward with a new version; never rerun the older release and roll production backward |
|
|
189
|
+
|
|
190
|
+
Before rerunning a failed release, check its exact version with
|
|
191
|
+
`npm view @spatius/cli@<version> version dist.integrity --json`, and check the
|
|
192
|
+
Worker's release tag/commit in Cloudflare or `wrangler versions list --env production`.
|
|
193
|
+
For an npm-only failure, rerun all jobs only after confirming the version is
|
|
194
|
+
absent and no newer release has deployed. This repeats validation and deployment
|
|
195
|
+
before publication. A network error from npm is not evidence that the version is
|
|
196
|
+
absent.
|
|
197
|
+
|
|
198
|
+
## Configuration and storage
|
|
199
|
+
|
|
200
|
+
| Setting | Purpose |
|
|
201
|
+
| -------------------------------------- | --------------------------------------------------------------- |
|
|
202
|
+
| `STUDIO_API_URL` | Trusted Studio origin for online `GET /v1/auth/me` validation |
|
|
203
|
+
| `PUBLIC_URL` | Actual Worker HTTPS origin used to sign immutable input URLs |
|
|
204
|
+
| `SIGNING_KEY_ID` | Active key ID for new links |
|
|
205
|
+
| `SIGNING_KEYS` (secret) | JSON map of key IDs to random secrets of at least 32 characters |
|
|
206
|
+
| `MAX_STORED_BYTES` | Per-user reserved/retained byte limit; default 2 GiB |
|
|
207
|
+
| `MAX_UPLOADS_PER_DAY` | New uploads per rolling day; default 100 |
|
|
208
|
+
| `MAX_UNFINISHED_UPLOADS` | Unfinished uploads per user; default 10 |
|
|
209
|
+
| `REQUESTS_PER_SECOND`, `REQUEST_BURST` | Management-operation token bucket; default 10 and 20 |
|
|
210
|
+
|
|
211
|
+
The Worker streams exact-size 8 MiB parts to private R2, with a smaller final
|
|
212
|
+
part allowed. Each Studio user's SQLite Durable Object persists admission,
|
|
213
|
+
accepted parts, and the completion manifest. The whole-file digest is checked
|
|
214
|
+
before its URL is published. Completed files cannot be overwritten or deleted
|
|
215
|
+
through a public endpoint.
|
|
216
|
+
|
|
217
|
+
DO alarms abort incomplete uploads after one hour and delete completed inputs
|
|
218
|
+
after 24 hours. Failed cleanup retains quota reservations and retries. Signed
|
|
219
|
+
URLs expire on time even if physical deletion is delayed. R2 lifecycle rules
|
|
220
|
+
are fallback cleanup. For key rotation, add a key to `SIGNING_KEYS`, change
|
|
221
|
+
`SIGNING_KEY_ID`, and retain old keys until every link signed with them expires.
|
|
222
|
+
|
|
223
|
+
Monitor rejected admissions, authentication outages, upload completion failures,
|
|
224
|
+
and cleanup retries through controlled error codes. Keep invocation URL logging
|
|
225
|
+
disabled; request bodies, auth headers, and signed URLs must not enter logs.
|
|
226
|
+
Run `pnpm --filter @spatius/media-worker typegen` after configuration changes.
|
|
227
|
+
|
|
228
|
+
## Live smoke tests
|
|
229
|
+
|
|
230
|
+
Routine CI uses mocks/local bindings and performs no paid generation. Live tests
|
|
231
|
+
need the intended user's Studio login and approved Avatar/Video API access.
|
|
232
|
+
From an unpublished checkout, run `pnpm package:check`, then use
|
|
233
|
+
`node packages/cli/dist/cli.js` in place of `spatius` in these examples.
|
|
234
|
+
|
|
235
|
+
**Upload/read check:** supply a real `./speech.wav`, a private config directory,
|
|
236
|
+
and the intended media origin. This example needs Node.js. The signed URL stays
|
|
237
|
+
in the pipeline rather than being printed:
|
|
238
|
+
|
|
239
|
+
```sh
|
|
240
|
+
export SPATIUS_CONFIG_DIR=/absolute/path/to/private-test-config
|
|
241
|
+
export SPATIUS_MEDIA_URL=https://cli-media.spatius.ai
|
|
242
|
+
spatius auth login
|
|
243
|
+
spatius setup
|
|
244
|
+
spatius assets upload ./speech.wav --kind audio | node --input-type=module -e '
|
|
245
|
+
import { createHash } from "node:crypto";
|
|
246
|
+
let input = "";
|
|
247
|
+
for await (const chunk of process.stdin) input += chunk;
|
|
248
|
+
const { data } = JSON.parse(input);
|
|
249
|
+
if (data.status !== "completed") throw new Error("Upload not completed");
|
|
250
|
+
const response = await fetch(data.url, { redirect: "error", signal: AbortSignal.timeout(30000) });
|
|
251
|
+
if (!response.ok) throw new Error("Signed file read failed");
|
|
252
|
+
const bytes = Buffer.from(await response.arrayBuffer());
|
|
253
|
+
if (bytes.length !== data.size || createHash("sha256").update(bytes).digest("hex") !== data.sha256) throw new Error("File mismatch");
|
|
254
|
+
console.log("Authenticated upload and signed read passed");'
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Repeat setup and confirm the app ID is reused. Verify unsigned file reads and
|
|
258
|
+
unauthenticated upload-management calls fail, and that a second Studio user
|
|
259
|
+
cannot read/manage the first user's upload ID. The automated release probes
|
|
260
|
+
check only health and unauthenticated rejection, not this authenticated flow.
|
|
261
|
+
|
|
262
|
+
**Avatar → video → MP4:** follow the complete create/poll/download example in
|
|
263
|
+
[workflows](workflows.md) using a real portrait, speech, and optional background.
|
|
264
|
+
Save operation/job IDs, check progress, download the MP4 before expiry, and
|
|
265
|
+
verify audio/video playback. Avatar creation and video generation use existing
|
|
266
|
+
service allowances/accounting. Interrupted submissions should resume the saved
|
|
267
|
+
operation; confirm only one remote job exists. Keep private inputs, IDs, and
|
|
268
|
+
signed URLs out of public CI logs.
|
|
269
|
+
|
|
270
|
+
**Staging:** use the separate `spatius-cli-media-staging` Worker and bucket,
|
|
271
|
+
`--env staging`, and set `SPATIUS_MEDIA_URL` to
|
|
272
|
+
`https://spatius-cli-media-staging.472617147.workers.dev`. Provision the same
|
|
273
|
+
lifecycle rule on that bucket and its own signing key. If Studio uses staging
|
|
274
|
+
hosts, set API `SPATIUS_STUDIO_URL` and browser `SPATIUS_STUDIO_WEB_URL`
|
|
275
|
+
separately. The CLI requires completed upload links to match its configured
|
|
276
|
+
media origin. The existing [staging validation record](staging-validation.md)
|
|
277
|
+
is evidence for staging, not production readiness.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Staging validation
|
|
2
|
+
|
|
3
|
+
Validated on 2026-09-12 UTC. This is a staging record, not a production release.
|
|
4
|
+
|
|
5
|
+
Final `pnpm check` passed on Node.js 22.23.2: **58 CLI tests, 27 Worker tests**,
|
|
6
|
+
three packaged skills with 29 validated examples, type checks, lint, formatting,
|
|
7
|
+
npm artifact installation, and the Worker deployment dry run.
|
|
8
|
+
|
|
9
|
+
| Check | Result |
|
|
10
|
+
| ---------------------------------- | ------------------------------------------------------- |
|
|
11
|
+
| Studio browser login | Passed with the real API and browser approval origins |
|
|
12
|
+
| App bootstrap | Passed; two setup calls reused the same dedicated app |
|
|
13
|
+
| Authenticated temporary upload | Passed with a 649,644-byte real speech WAV |
|
|
14
|
+
| Signed input download | HTTP 200; byte count and SHA-256 matched the source |
|
|
15
|
+
| Missing login / tampered signature | Rejected with HTTP 401 / 403 |
|
|
16
|
+
| Avatar list | HTTP 200; the account currently has no owned avatars |
|
|
17
|
+
| Video creation | Passed by resuming the original saved request |
|
|
18
|
+
| Video list | HTTP 200; exactly one succeeded job |
|
|
19
|
+
| Video polling | Observed processing/rendering, then succeeded/completed |
|
|
20
|
+
| MP4 download and decoding | Passed; 1024×1024, 25 fps, H.264/AAC, 22.08 seconds |
|
|
21
|
+
| Live avatar creation | Not run; remains a separate release check |
|
|
22
|
+
|
|
23
|
+
The staging Worker is
|
|
24
|
+
`https://spatius-cli-media-staging.472617147.workers.dev`, backed by the private
|
|
25
|
+
`spatius-cli-media-staging` R2 bucket. Lifecycle fallback rules delete objects
|
|
26
|
+
after two days and abort multipart uploads after one day; the application
|
|
27
|
+
enforces its shorter upload and signed-link deadlines.
|
|
28
|
+
|
|
29
|
+
The original saved video operation was resumed after the Console deployment and
|
|
30
|
+
access updates. Console accepted the request and completed it in approximately
|
|
31
|
+
47 seconds. The CLI polled the job, refreshed its signed output link, and saved
|
|
32
|
+
a 2,285,695-byte MP4. `ffprobe` confirmed H.264 video at 1024×1024 and 25 fps,
|
|
33
|
+
with mono 16 kHz AAC audio; both streams are 22.08 seconds long. A full `ffmpeg`
|
|
34
|
+
decode completed without errors. The account's job list contained exactly one
|
|
35
|
+
succeeded job after the retry.
|
|
36
|
+
|
|
37
|
+
The operation, credentials, and input links remain in the private CLI
|
|
38
|
+
configuration directory. Do not put account identifiers, input URLs, keys, or
|
|
39
|
+
tokens in public validation reports. The authenticated upload-to-video workflow
|
|
40
|
+
has passed; live portrait-to-avatar creation remains a separate release check.
|
|
41
|
+
|
|
42
|
+
Automated checks cover login and app recovery, multipart limits and leases,
|
|
43
|
+
native Worker request construction, interrupted submission and resume, polling,
|
|
44
|
+
download, terminal failures, packaged skills, and npm installation. The Worker
|
|
45
|
+
suite also streams a complete 500 MiB upload through 63 local R2 parts. See
|
|
46
|
+
`pnpm check` and [the deployment guide](deployment.md) for repeatable checks.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Avatar and video workflows
|
|
2
|
+
|
|
3
|
+
## Authentication and output
|
|
4
|
+
|
|
5
|
+
Run `spatius auth login`, approve in a browser on the same machine, then run
|
|
6
|
+
`spatius setup`. Login is required for credential setup and temporary uploads;
|
|
7
|
+
Open API enablement still requires administrator approval. The CLI does not
|
|
8
|
+
grant access or alter creation allowances. API-key-only CLI use is not supported.
|
|
9
|
+
|
|
10
|
+
The Studio API and browser approval page have separate origins. Environment
|
|
11
|
+
settings are optional for production; configure both origins explicitly when
|
|
12
|
+
using a development or staging Studio deployment.
|
|
13
|
+
|
|
14
|
+
| Environment variable | Default | Purpose |
|
|
15
|
+
| ------------------------ | ------------------------------- | ----------------------------------------------- |
|
|
16
|
+
| `SPATIUS_STUDIO_URL` | `https://api.studio.spatius.ai` | Login/token, identity, and app/key API requests |
|
|
17
|
+
| `SPATIUS_STUDIO_WEB_URL` | `https://app.spatius.ai` | Expected browser approval origin |
|
|
18
|
+
| `SPATIUS_CONSOLE_URL` | `https://console.spatius.ai` | Avatar and Video Open APIs |
|
|
19
|
+
| `SPATIUS_MEDIA_URL` | `https://cli-media.spatius.ai` | Temporary uploads and input links |
|
|
20
|
+
|
|
21
|
+
The web origin must match the Studio backend's configured frontend URL.
|
|
22
|
+
Credential-bearing API requests reject redirects; the browser URL must match
|
|
23
|
+
the configured web origin and the exact authorization request path.
|
|
24
|
+
|
|
25
|
+
Commands return `{ "schemaVersion": 1, "ok": true, "data": ... }` on stdout.
|
|
26
|
+
Errors use `ok: false` and `error.code/message/retryable/recovery` on stderr.
|
|
27
|
+
Progress is also written to stderr. Help and version are plain text.
|
|
28
|
+
|
|
29
|
+
| Exit code | Meaning |
|
|
30
|
+
| --------- | ---------------------------------------------------- |
|
|
31
|
+
| 0 | Success |
|
|
32
|
+
| 1 | Operation failed; inspect the structured error |
|
|
33
|
+
| 2 | Invalid command arguments |
|
|
34
|
+
| 3 | Waiting reached its deadline; the job remains active |
|
|
35
|
+
| 130 | Interrupted locally; no remote job is cancelled |
|
|
36
|
+
|
|
37
|
+
## Create, poll, and download
|
|
38
|
+
|
|
39
|
+
This Bash example requires `jq`. Supply your own portrait and speech files.
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
set -euo pipefail
|
|
43
|
+
spatius auth login
|
|
44
|
+
spatius setup
|
|
45
|
+
AVATAR_CREATE=$(spatius avatars create --image ./portrait.png --name Presenter)
|
|
46
|
+
AVATAR_JOB_ID=$(printf '%s' "$AVATAR_CREATE" | jq -er '.data.jobId')
|
|
47
|
+
AVATAR_RESULT=$(spatius avatars jobs wait "$AVATAR_JOB_ID" --timeout 600)
|
|
48
|
+
AVATAR_ID=$(printf '%s' "$AVATAR_RESULT" | jq -er '.data.job.avatarId')
|
|
49
|
+
VIDEO_CREATE=$(spatius videos create --avatar-id "$AVATAR_ID" --audio ./speech.wav)
|
|
50
|
+
VIDEO_JOB_ID=$(printf '%s' "$VIDEO_CREATE" | jq -er '.data.jobId')
|
|
51
|
+
spatius videos wait "$VIDEO_JOB_ID" --timeout 600
|
|
52
|
+
spatius videos download "$VIDEO_JOB_ID" --output ./video.mp4
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If waiting exits 3, run the same wait command again. Creation accepts `--wait`
|
|
56
|
+
as a convenience, but submitting and waiting separately makes job IDs easier
|
|
57
|
+
to retain. Every creation exposes an operation ID in its result or recovery
|
|
58
|
+
error; progress reports the ID before external preparation begins.
|
|
59
|
+
|
|
60
|
+
## Inputs and presentation
|
|
61
|
+
|
|
62
|
+
| Input | Types | Maximum size |
|
|
63
|
+
| --------------- | ------------------------------------------------------------- | -----------: |
|
|
64
|
+
| Avatar portrait | JPEG, opaque PNG; shorter side ≥340 pixels and one clear face | 5 MiB |
|
|
65
|
+
| Audio | WAV, MP3, M4A/MP4 audio, AAC, Ogg | 500 MiB |
|
|
66
|
+
| Background | JPEG, PNG, WebP | 50 MiB |
|
|
67
|
+
|
|
68
|
+
The CLI and upload Worker check basic file signatures and sizes. Avatar content,
|
|
69
|
+
PNG opacity, image dimensions, audio decoding, and audio duration remain validated
|
|
70
|
+
by the existing services. Raw PCM and octet-stream sources are unsupported.
|
|
71
|
+
|
|
72
|
+
Use local paths or public HTTP(S) URLs, including signed URLs. Caller-supplied
|
|
73
|
+
URLs are not fetched by the CLI; existing Console download protections apply.
|
|
74
|
+
They cannot contain embedded credentials or point to private networks.
|
|
75
|
+
|
|
76
|
+
| Video option | Default | Allowed values |
|
|
77
|
+
| ----------------------------------------- | ------- | --------------------------------------------- |
|
|
78
|
+
| `--width`, `--height` | 1024 | Even integers 64–1920; area ≤2,073,600 pixels |
|
|
79
|
+
| `--fit` | crop | crop, contain |
|
|
80
|
+
| `--background-color` | #000000 | Six-digit RGB hex |
|
|
81
|
+
| `--background-fit` | cover | cover, contain, stretch |
|
|
82
|
+
| `--lead-in-seconds`, `--lead-out-seconds` | 0 | Finite values 0–60 |
|
|
83
|
+
|
|
84
|
+
Quote hex colors in shells. Encoding is service-controlled. Source URLs need to
|
|
85
|
+
cover the preparation window of up to 30 minutes. Temporary inputs are immutable
|
|
86
|
+
and expire 24 hours after upload completion. Anyone with a signed input URL can
|
|
87
|
+
read it until expiry; avoid sharing these URLs outside the intended workflow.
|
|
88
|
+
|
|
89
|
+
## Resume safely
|
|
90
|
+
|
|
91
|
+
| Situation | Action |
|
|
92
|
+
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
93
|
+
| Interrupted upload | Re-run `assets upload <same-file> --kind <kind> --resume <upload-or-operation-id>`; accepted parts are reused. An aborted multipart needs a fresh upload. |
|
|
94
|
+
| Video preparation or uncertain submission | `videos create --resume <operation-id>` reuses the saved request UUID and exact URLs. |
|
|
95
|
+
| Repeating a chosen video `--request-id` | The same original input resumes its operation; different input conflicts before uploading. |
|
|
96
|
+
| Avatar submission response lost | `SUBMISSION_UNCERTAIN`: inspect recent avatar jobs and reconcile. Automatic resubmission is unsafe because this API has no retry key. |
|
|
97
|
+
| Known job | Poll/wait by job ID; do not submit again. |
|
|
98
|
+
| Terminal failure | Fix its cause and intentionally start a new operation if wanted. `retryable` does not restart a job. |
|
|
99
|
+
| Output link expired | `videos download` requests a fresh link, while output retention remains unchanged. |
|
|
100
|
+
|
|
101
|
+
Downloads require direct HTTPS output links and use no Studio/app authentication
|
|
102
|
+
headers. Redirects are rejected with a retryable availability error; run download
|
|
103
|
+
again for a fresh link. Loopback HTTP is allowed only when the CLI Console origin
|
|
104
|
+
is explicitly configured for loopback development. Downloads stream into a temporary
|
|
105
|
+
file in the destination directory, then rename atomically. Existing files require
|
|
106
|
+
`--force`. Video output currently expires seven days after submission; use
|
|
107
|
+
`job.expiresAt` as authoritative. Expired output cannot be recovered by refreshing
|
|
108
|
+
a link.
|
|
109
|
+
|
|
110
|
+
## Account and storage limits
|
|
111
|
+
|
|
112
|
+
The existing APIs enforce user-level permissions, request rates, avatar concurrency,
|
|
113
|
+
and billing. The CLI does not add a video concurrency quota. All apps belonging
|
|
114
|
+
to one account share the server's Open API policies.
|
|
115
|
+
|
|
116
|
+
Temporary storage separately defaults to 2 GiB reserved/retained per user,
|
|
117
|
+
100 new uploads per rolling day, and 10 unfinished uploads. Management requests
|
|
118
|
+
are limited to 10/second with burst 20. Unfinished uploads expire after one hour.
|
|
119
|
+
Rejected requests return controlled errors; repeated upload admission with the
|
|
120
|
+
same retry UUID does not consume another reservation.
|
|
121
|
+
|
|
122
|
+
Credentials and saved input URLs are stored under private user configuration,
|
|
123
|
+
outside repositories. On macOS/Linux use `$XDG_CONFIG_HOME/spatius` or
|
|
124
|
+
`~/.config/spatius`; Windows uses `%APPDATA%/Spatius`. Set `SPATIUS_CONFIG_DIR`
|
|
125
|
+
to an absolute private directory to isolate test accounts. macOS/Linux are the
|
|
126
|
+
validated v1 platforms; Windows storage relies on inherited user-directory ACLs.
|
|
127
|
+
|
|
128
|
+
If the cached CLI app was deleted, `spatius setup` reconciles existing apps and
|
|
129
|
+
creates a replacement when needed. An explicit `--app-id` is never silently replaced.
|
|
130
|
+
|
|
131
|
+
Logout clears local tokens and cached API keys and attempts refresh revocation.
|
|
132
|
+
The current Studio backend does not immediately revoke already issued access
|
|
133
|
+
tokens. It also does not provide cross-machine app-creation deduplication:
|
|
134
|
+
simultaneous first-time setup may require selecting among matching apps.
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spatius/cli",
|
|
3
|
+
"version": "0.1.0-beta.0",
|
|
4
|
+
"description": "Spatius avatar and video workflows for coding agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"bin": {
|
|
8
|
+
"spatius": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=22"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"skills",
|
|
16
|
+
"docs",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"THIRD_PARTY_NOTICES.md"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/spatius-ai/spatius-cli.git",
|
|
24
|
+
"directory": "packages/cli"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup && node ../../scripts/package-assets.mjs",
|
|
28
|
+
"dev": "tsx src/cli.ts",
|
|
29
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"prepack": "pnpm build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"commander": "^14.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@spatius/contracts": "workspace:*",
|
|
38
|
+
"tsup": "^8.5.0",
|
|
39
|
+
"tsx": "^4.20.0"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public",
|
|
43
|
+
"provenance": true
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spatius-avatar
|
|
3
|
+
description: Create Spatius avatars from portrait images, inspect account avatars, and poll avatar creation jobs with Spatius CLI. Use for avatar creation and recovery, including preparing local image inputs.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Create a Spatius avatar
|
|
8
|
+
|
|
9
|
+
Check `spatius auth status` and use the shared setup skill if login or app setup
|
|
10
|
+
is missing. Read `spatius schema avatars create` for installed command details.
|
|
11
|
+
|
|
12
|
+
Use an existing local portrait or the user's public URL. The image must be JPEG
|
|
13
|
+
or PNG, at most 5 MiB, with its shorter side at least 340 pixels. PNG must be
|
|
14
|
+
opaque; the portrait must contain one clearly visible face. These requirements
|
|
15
|
+
are finally checked by the service. Do not assume an accepted job has passed them.
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
spatius avatars create --image ./portrait.png --name Presenter --dry-run
|
|
19
|
+
spatius avatars create --image ./portrait.png --name Presenter
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Use the actual input path. Local files upload automatically; URL inputs are
|
|
23
|
+
passed to the service. Avatar creation consumes the user's existing Avatar
|
|
24
|
+
Creations allowance. Return promptly after acceptance, retaining `operationId`
|
|
25
|
+
and `jobId`, then wait or inspect:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
spatius avatars jobs wait 00000000-0000-4000-8000-000000000001 --timeout 600
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Replace the example UUID with the returned job ID. On success use `job.avatarId`
|
|
32
|
+
for a video request. A wait timeout preserves the job; run wait/get again.
|
|
33
|
+
|
|
34
|
+
On a preparation interruption, resume with
|
|
35
|
+
`spatius avatars create --resume <operation-id>`. An uncertain submission cannot
|
|
36
|
+
be repeated safely: this API has no creation retry key. If the CLI returns
|
|
37
|
+
`SUBMISSION_UNCERTAIN`, inspect recent jobs or ask the user to reconcile the
|
|
38
|
+
operation. Never automatically submit another avatar because the response was lost.
|
|
39
|
+
|
|
40
|
+
Fix a failed image or permission issue before proposing a replacement creation.
|
|
41
|
+
Do not retry terminal jobs in a loop, even when `job.error.retryable` is true.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spatius-shared
|
|
3
|
+
description: Set up Spatius CLI authentication and app credentials, inspect command schemas, and recover account access for avatar or video workflows. Use when preparing Spatius CLI or resolving its authentication and setup errors.
|
|
4
|
+
license: MIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Spatius setup and shared behavior
|
|
8
|
+
|
|
9
|
+
Use the installed `spatius` executable. If installation is needed, the prerelease
|
|
10
|
+
package is `@spatius/cli@beta` (`npm install -g @spatius/cli@beta`); stable releases
|
|
11
|
+
use `@spatius/cli`. The executable name remains `spatius`.
|
|
12
|
+
Read `spatius --version` and `spatius schema` to discover the installed contract.
|
|
13
|
+
The CLI requires Node.js 22+. The npm package includes matching skills under
|
|
14
|
+
`skills/`; prefer those over default-branch skills when versions differ.
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
spatius auth status
|
|
18
|
+
spatius auth login
|
|
19
|
+
spatius setup
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The production browser approval origin is `https://app.spatius.ai`; the Studio
|
|
23
|
+
API is `https://api.studio.spatius.ai`. For an explicitly configured development
|
|
24
|
+
environment, `SPATIUS_STUDIO_WEB_URL` selects the approved browser origin and
|
|
25
|
+
`SPATIUS_STUDIO_URL` selects the API. Do not change these to bypass an
|
|
26
|
+
`UNSAFE_AUTH_URL` error; check the intended environment first.
|
|
27
|
+
|
|
28
|
+
Run login only when needed. It opens a local browser approval page and waits up
|
|
29
|
+
to five minutes. Hand the approval URL to the user; keep the process alive until
|
|
30
|
+
approval or timeout. The browser must reach the CLI's localhost callback. A
|
|
31
|
+
remote agent without that connection needs the user to run login on the machine
|
|
32
|
+
where subsequent CLI commands run. Do not request tokens or passwords in chat.
|
|
33
|
+
|
|
34
|
+
Setup reuses an owned `Spatius CLI` app and key. If selection is required, use
|
|
35
|
+
`spatius apps list` and `spatius setup --app-id <id>`. Never read credential files
|
|
36
|
+
to obtain keys. Login does not grant Avatar or Video API approval; report a 403
|
|
37
|
+
as an account/permission issue instead of repeatedly logging in.
|
|
38
|
+
|
|
39
|
+
Success is one JSON object on stdout with `schemaVersion`, `ok`, and `data`.
|
|
40
|
+
Progress and structured failures go to stderr. Inspect the exit code and error
|
|
41
|
+
`code`, `retryable`, and `recovery`; avoid parsing decorative human text. Exit 3
|
|
42
|
+
means a wait deadline, and does not cancel the remote job.
|
|
43
|
+
|
|
44
|
+
Save returned operation and job IDs. After interrupted creation, use the saved
|
|
45
|
+
operation's resume command; after admission, poll its job. An error marked
|
|
46
|
+
retryable is not authorization to create another paid job indefinitely.
|
|
47
|
+
|
|
48
|
+
For ambiguous setup, rotating-token failures, or source-link privacy, read
|
|
49
|
+
[recovery](references/recovery.md). Do not use `setup --retry-uncertain` until the
|
|
50
|
+
uncertain creation has been reconciled and another creation is intended.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Recovery and credential boundaries
|
|
2
|
+
|
|
3
|
+
| Condition | Next action |
|
|
4
|
+
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
5
|
+
| No login or `AUTH_RELOGIN_REQUIRED` | Have the user approve `spatius auth login` locally. A lost refresh response cannot safely reuse the old rotating token. |
|
|
6
|
+
| `UNSAFE_AUTH_URL` | Verify `SPATIUS_STUDIO_WEB_URL` matches the intended Studio frontend; `SPATIUS_STUDIO_URL` is the separate API origin. Do not approve an unexpected host. |
|
|
7
|
+
| App selection required | Choose an owned app from sanitized candidates and run `spatius setup --app-id <id>`. |
|
|
8
|
+
| `BOOTSTRAP_UNCERTAIN` | Run setup again to reconcile through reads. If unresolved, explain that the prior app/key creation may have succeeded; only use `--retry-uncertain` when a new attempt is intended. |
|
|
9
|
+
| HTTP 402 | Ask the user to check the Avatar Creations balance in Studio. |
|
|
10
|
+
| HTTP 403 | Check API enablement or avatar permission with the administrator. Login does not change the allowlist. |
|
|
11
|
+
| HTTP 429 | Respect the retry hint. Stop after bounded retries and report the limiting condition. |
|
|
12
|
+
|
|
13
|
+
If a cached app was deleted, run `spatius setup` to select or create its replacement.
|
|
14
|
+
If an explicitly supplied `--app-id` is unavailable, choose an owned app instead;
|
|
15
|
+
the CLI does not silently replace an explicit selection.
|
|
16
|
+
|
|
17
|
+
Do not echo credentials, refresh tokens, or credential-file contents. Download
|
|
18
|
+
URLs and temporary input URLs are bearer links: anyone possessing them can read
|
|
19
|
+
the file until expiry. Use them only for the intended workflow; avoid putting
|
|
20
|
+
them in commits, issue bodies, or diagnostics.
|
|
21
|
+
|
|
22
|
+
Logout clears local credentials and attempts refresh-token revocation. The
|
|
23
|
+
existing Studio backend does not immediately invalidate already issued access
|
|
24
|
+
tokens. Never claim that logout has remotely revoked every credential.
|