@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.
@@ -0,0 +1,10 @@
1
+ import {
2
+ buildProgram,
3
+ commandSchema,
4
+ definitions
5
+ } from "./chunk-YILIK7FE.js";
6
+ export {
7
+ buildProgram,
8
+ commandSchema,
9
+ definitions
10
+ };
@@ -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.