@oiioii/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,840 @@
1
+ # oiioii-cli
2
+
3
+ Agent-native CLI for Oiioii / Hogi GenAI capabilities.
4
+
5
+ `oiioii-cli` exposes Hogi workspace creation/selection, image/video/audio generation,
6
+ resource upload/download, and generation records through a scriptable
7
+ command-line interface. Authentication is persisted with `oiioii auth login`
8
+ or temporarily overridden through `OIIOII_API_KEY`. It supports both
9
+ human-readable output and a stable JSON envelope for AI agents and automation.
10
+
11
+ ## Current Status
12
+
13
+ | Command | Capability | Status |
14
+ |---|---|---|
15
+ | `auth login` | Persist API Key and backend configuration | Implemented |
16
+ | `workspace create/set/current` | Create, configure, and inspect workspaces | Implemented |
17
+ | `image text` | Text-to-image generation | Implemented |
18
+ | `image edit` | Image-to-image editing | Implemented |
19
+ | `video text` | Text-to-video generation | Implemented |
20
+ | `video image` | Image-to-video generation | Implemented |
21
+ | `video generate` | Model-validated mixed image/video/audio reference generation | Implemented |
22
+ | `audio generate` | Seed Audio and Suno audio/music generation | Implemented |
23
+ | `upload file` | Upload local image/video/audio resources | Implemented |
24
+ | `record get/open` | Query generation metadata and download resources | Implemented |
25
+ | `inspect capabilities/models` | Inspect declared capabilities and live backend models | Implemented |
26
+ | `preview latest/bundle` | Read local preview bundles created by generation commands | Implemented |
27
+ | `task list/status/wait` | Inspect and wait for local generation tasks | Implemented |
28
+ | `logs list/export/path` | Inspect and export structured local logs | Implemented |
29
+ | `points balance/quote/cost` | Inspect balance, estimate a request, and query actual charges | Implemented |
30
+
31
+ Important current limitations:
32
+
33
+ - API keys are stored in `~/.oiioii/config.json` after `oiioii auth login`; the file is owner-readable only (`0600`).
34
+ - Generation submits `submit_async_media_generation` and returns immediately with the authoritative backend `task_id` plus a `local_task_id`.
35
+ - The backend task ID, workspace, media type, asset ID, progress, and terminal outputs are cached in the owner-only local task store.
36
+ - `task status/wait` query `query_async_media_generation` for non-terminal cached tasks and accept either the backend or local task ID.
37
+ - Image, video, and audio generation create local preview bundles after a queried task reaches a terminal state.
38
+ - `inspect capabilities` is local metadata; `inspect models` requires authentication and queries the active backend.
39
+ - Asset-library browsing/search/update/delete and style-library commands are not available.
40
+
41
+ ## Requirements
42
+
43
+ - Node.js 18 or newer when running from source or the npm package.
44
+ - An existing Hogi MCP API Key.
45
+ - A workspace ID for image/video/audio generation and resource upload. It can be
46
+ created with `oiioii workspace create` or supplied from an existing project.
47
+ - `npm` is the repository package manager.
48
+
49
+ The hosted installer uses Node.js 18 or newer when available. If no compatible
50
+ Node.js/npm installation exists, it downloads an official Node.js runtime,
51
+ verifies its SHA256, and keeps it under the oiioii installation directory.
52
+
53
+ ## Quick Start
54
+
55
+ ```bash
56
+ npm install
57
+ npm run build
58
+
59
+ node dist/cli.js --help
60
+ node dist/cli.js --version
61
+ ```
62
+
63
+ Development mode does not require a build:
64
+
65
+ ```bash
66
+ npm run dev -- --help
67
+ ```
68
+
69
+ Install from the checkout:
70
+
71
+ ```bash
72
+ npm install -g .
73
+ oiioii --help
74
+ oiioii-cli --version
75
+ ```
76
+
77
+ Both `oiioii` and `oiioii-cli` point to the same CLI entry point.
78
+
79
+ ### Install from npm or the hosted bootstrap
80
+
81
+ The bootstrap scripts install the npm package into an application-owned prefix,
82
+ write `install.json`, and create stable `oiioii` / `oiioii-cli` wrappers. CLI
83
+ updates reuse the exact Node.js, npm, registry, package, and prefix recorded by
84
+ the installer.
85
+
86
+ macOS (Apple Silicon and Intel are detected automatically):
87
+
88
+ ```bash
89
+ curl -fsSL https://<public-host>/install.sh | bash
90
+ ```
91
+
92
+ Windows x64, from PowerShell:
93
+
94
+ ```powershell
95
+ $script = Join-Path $env:TEMP "install.ps1"; curl.exe -fsSL https://<public-host>/install.ps1 -o $script; powershell.exe -NoProfile -ExecutionPolicy Bypass -File $script; Remove-Item $script
96
+ ```
97
+
98
+ Production is the default and follows npm's `latest` dist-tag. For the HOE test
99
+ build, set `OIIOII_ENV=test`; it follows the `test` dist-tag and accepts only
100
+ prerelease versions. Set `OIIOII_CLI_VERSION` to install one exact version.
101
+
102
+ After bootstrap installation:
103
+
104
+ ```bash
105
+ oiioii update --check
106
+ oiioii update
107
+ oiioii install 0.2.0
108
+ oiioii versions
109
+ ```
110
+
111
+ Local builds are intentionally excluded from npm self-update and should be
112
+ rebuilt from the checkout.
113
+
114
+ ## Build Environments
115
+
116
+ The default backend URL is embedded into the generated bundle at build time.
117
+
118
+ | Build command | Environment | Embedded default backend |
119
+ |---|---|---|
120
+ | `npm run build:production` | production | `https://api.oiioii.ai` |
121
+ | `npm run build:test` | test (HOE) | `https://api-hoe.oiioii.tv` |
122
+ | `npm run build:local` | local | `http://localhost:4000` |
123
+
124
+ `npm run build` builds the test environment to preserve the existing default.
125
+
126
+ For a custom deployment, override the embedded URL during the build:
127
+
128
+ ```bash
129
+ OIIOII_BUILD_BASE_URL=https://custom.example.com npm run build:production
130
+ ```
131
+
132
+ Supported build environment names are exactly `production`, `test`, and
133
+ `local`. Unknown values fail the build instead of silently selecting a domain.
134
+
135
+ The embedded URL is a fallback. Existing runtime overrides remain available:
136
+
137
+ - Root option: `--base-url <url>` for commands that consume the root override.
138
+ - Environment variable: `OIIOII_BASE_URL`.
139
+ - Persisted `baseUrl` in `~/.oiioii/config.json`.
140
+
141
+ ## Authentication and Workspace
142
+
143
+ Persist an existing MCP API Key and the backend URL:
144
+
145
+ ```bash
146
+ oiioii auth login \
147
+ --api-key "oii_sk_..." \
148
+ --base-url "https://api-hoe.oiioii.tv"
149
+ ```
150
+
151
+ The CLI writes the API Key and Base URL to `~/.oiioii/config.json` with file
152
+ permissions `0600`. `OIIOII_API_KEY` remains available as a temporary process
153
+ override. A legacy `~/.oiioii/credentials.json` file, if present, is ignored.
154
+
155
+ Create a workspace using the injected API Key:
156
+
157
+ ```bash
158
+ oiioii workspace create \
159
+ --name "My video project" \
160
+ --language zh \
161
+ --set-current \
162
+ --json
163
+ ```
164
+
165
+ `--language` accepts `en`, `zh`, `zh-Hant`, or `ja`. `--set-current` is
166
+ explicit: without it, creating a workspace does not overwrite the current
167
+ workspace in local configuration.
168
+
169
+ Set and inspect the active workspace:
170
+
171
+ ```bash
172
+ oiioii workspace set <workspace_id> --json
173
+ oiioii workspace current --json
174
+ ```
175
+
176
+ Workspace resolution order is:
177
+
178
+ 1. Root `--workspace <id>` option.
179
+ 2. `OIIOII_WORKSPACE_ID` environment variable.
180
+ 3. `defaultWorkspaceId` in `~/.oiioii/config.json`.
181
+
182
+ ## Image Generation
183
+
184
+ Text-to-image:
185
+
186
+ ```bash
187
+ oiioii image text \
188
+ --prompt "a cinematic city in the rain" \
189
+ --model seedream45 \
190
+ --resolution 2K \
191
+ --json
192
+ ```
193
+
194
+ Image editing:
195
+
196
+ ```bash
197
+ oiioii image edit \
198
+ --image hogi://image/<id> \
199
+ --prompt "change the scene to watercolor" \
200
+ --model seedream45 \
201
+ --resolution 2K \
202
+ --json
203
+ ```
204
+
205
+ Current behavior:
206
+
207
+ - Accepts `--model-id <id>` from `inspect models` for exact backend model
208
+ selection, or `--model <key> --variant <variant>` as an alternative.
209
+ - Calls `POST /mcp/genai/sse` with JSON-RPC `tools/call` and `submit_async_media_generation`.
210
+ - Authenticates with `x-hogi-api-key`.
211
+ - Requires an active workspace.
212
+ - Returns after submission; use `task status` or `task wait` to query progress and terminal `hogi://image/...` output.
213
+ - Image editing adapts the source URI to the async service's `referenceImages` contract.
214
+ - When image shape options are omitted, the CLI uses the exact selected model
215
+ catalog row's first aspect ratio and resolution (falling back only when the
216
+ catalog leaves those fields empty).
217
+ - Prefer `--aspect-ratio` for image shape. Deprecated `--size WxH` remains
218
+ accepted for script compatibility but is hidden from help; GPT-4o receives
219
+ its nearest supported pixel-size enum.
220
+
221
+ ## Video Generation
222
+
223
+ Text-to-video:
224
+
225
+ ```bash
226
+ oiioii video text \
227
+ --prompt "slow camera push through neon rain" \
228
+ --model seedance20 \
229
+ --duration 5 \
230
+ --aspect-ratio 16:9 \
231
+ --resolution 720p \
232
+ --json
233
+ ```
234
+
235
+ Image-to-video:
236
+
237
+ ```bash
238
+ oiioii video image \
239
+ --image hogi://image/<id> \
240
+ --prompt "animate the clouds and move the camera forward" \
241
+ --model seedance20 \
242
+ --duration 5 \
243
+ --aspect-ratio 16:9 \
244
+ --resolution 720p \
245
+ --json
246
+ ```
247
+
248
+ Mixed model-supported references:
249
+
250
+ ```bash
251
+ oiioii video generate \
252
+ --prompt "combine the visual rhythm, motion, and soundtrack references" \
253
+ --image hogi://image/<id-1> hogi://image/<id-2> \
254
+ --video hogi://video/<id> \
255
+ --audio hogi://audio/<id> \
256
+ --model seedance25 \
257
+ --duration 8 \
258
+ --resolution 720p \
259
+ --json
260
+ ```
261
+
262
+ When video duration, aspect ratio, or resolution is omitted, the CLI resolves
263
+ the first supported value from the exact selected model/variant before dry-run
264
+ validation or submission. This avoids applying Seedance defaults to models
265
+ such as MiniMax, Veo, Sora, Kling, or Grok.
266
+
267
+ Current behavior:
268
+
269
+ - Accepts `--model-id <id>` from `inspect models` for exact backend model
270
+ selection, or `--model <key> --variant <variant>` as an alternative.
271
+ - Calls `submit_async_media_generation` through `/mcp/genai/sse` with `x-hogi-api-key` authentication.
272
+ - Returns after submission; terminal video URI validation happens during `task status/wait`.
273
+ - Text-to-video sends `prompt`, `duration`, `aspectRatio`, `resolution`, and
274
+ `workspace_id`.
275
+ - Model-specific `imageUrl`/`images` fields are validated locally, then adapted
276
+ to the async service's `referenceImages` field with `generateMode` preserved.
277
+ - `video generate` accepts zero or more `--image`, `--video`, and `--audio`
278
+ references in the same request. `--mode auto` derives `text2Video` or
279
+ `omni2Video`; frame semantics can be selected explicitly with `--mode`.
280
+ - Reference fields, combinations, and limits are validated against an exact
281
+ backend-tool contract before MCP submission. The current mixed-input matrix is:
282
+ Seedance 2.0/2.5 (image + video + audio), MiniMax H3
283
+ (image + video + optional audio), Wan 3.0 (image + video + audio), Wan 2.7
284
+ (image + video), Gemini Omni and Kling V3 Omni (image + video). Other verified
285
+ models accept image references only. Seedance 2.0 video references use the
286
+ same frontend asset-generation boundary as Hogi rather than the narrower
287
+ Agent-facing MCP schema.
288
+
289
+ ## Audio Generation
290
+
291
+ Seed Audio text generation:
292
+
293
+ ```bash
294
+ oiioii audio generate \
295
+ --prompt "温柔女声朗读一段雨夜旁白" \
296
+ --model seed-audio \
297
+ --format mp3 \
298
+ --subtitle \
299
+ --json
300
+ ```
301
+
302
+ Seed Audio reference generation accepts either up to three audio references or
303
+ one image reference; the two reference kinds cannot be mixed:
304
+
305
+ ```bash
306
+ oiioii audio generate --prompt "保持参考音色" --audio hogi://audio/<id> --json
307
+ oiioii audio generate --prompt "为画面生成氛围音" --image hogi://image/<id> --json
308
+ ```
309
+
310
+ Suno supports description mode, custom lyrics/style mode, and instrumental
311
+ music. The supported variants are `chirp-v4-5` and `chirp-v5`:
312
+
313
+ ```bash
314
+ oiioii audio generate --prompt "cinematic orchestral background music" --model suno --instrumental --json
315
+ oiioii audio generate --prompt "custom lyrics" --model suno --custom --tags "dream pop, female vocal" --json
316
+ ```
317
+
318
+ Current behavior:
319
+
320
+ - Accepts `--model-id <id>` from `inspect models`, or an exact
321
+ `--model <key> --variant <variant>` selection.
322
+ - Seed Audio supports `mp3`, `wav`, `pcm`, and `ogg_opus`, plus subtitle,
323
+ loudness, pitch, sample-rate, and speech-rate controls.
324
+ - Terminal queries accept only `hogi://audio/...` output for audio tasks.
325
+ - The backend async generation service owns the loading asset and final workspace update.
326
+ - Structured logs and telemetry record model/mode/reference counts/output
327
+ format/result metadata, but never prompts, request bodies, or API keys.
328
+
329
+ Generation consumes real credits. Do not run image/video/audio generation in
330
+ unbounded automated loops, and do not retry failures blindly.
331
+
332
+ ## Async Generation and Workspace Assets
333
+
334
+ Image, video, and audio commands submit through:
335
+
336
+ ```text
337
+ POST /mcp/genai/sse
338
+ method: tools/call
339
+ name: submit_async_media_generation
340
+ ```
341
+
342
+ The backend creates the loading workspace asset and returns its `assetId` and
343
+ authoritative `taskId`. The CLI caches both IDs. `task status/wait` calls
344
+ `query_async_media_generation`, reconciles progress/error/output into the local
345
+ record, and creates the terminal preview bundle. The CLI does not issue a second
346
+ `create_asset` call, which avoids duplicate workspace assets.
347
+
348
+ ## Local Resource Upload
349
+
350
+ Upload image, video, or audio bytes:
351
+
352
+ ```bash
353
+ oiioii upload file ./image.png --json
354
+ oiioii upload file ./clip.mp4 --json
355
+ oiioii upload file ./voice.mp3 --json
356
+
357
+ # Force VOD direct upload for any supported video
358
+ oiioii upload file ./clip.mp4 --vod --json
359
+ ```
360
+
361
+ Override the inferred extension or display name:
362
+
363
+ ```bash
364
+ oiioii upload file ./raw-file --type mp3 --name voice.mp3 --json
365
+ ```
366
+
367
+ Insert the new asset after an existing workspace asset when ordering matters:
368
+
369
+ ```bash
370
+ oiioii upload file ./voice.mp3 --after-asset-id <asset_id> --json
371
+ ```
372
+
373
+ Upload behavior:
374
+
375
+ - Images, audio, and videos smaller than 10 MB use raw `application/octet-stream` bytes at
376
+ `POST /v1/workspace/uploadAsset` with `workspace_id`, `file_type`, and optional
377
+ `file_name` / `after_asset_id` query parameters.
378
+ - MOV files and videos of 10 MB or larger automatically use the VOD flow:
379
+ `GET /media/vod/upload_token` -> direct upload to Volc VOD (multipart for large files) ->
380
+ `POST /media/vod/commit_upload` -> `GET /media/vod/transcode_status`.
381
+ `--vod` forces this flow for a smaller video.
382
+ - VOD uploads support videos up to 500 MB. File bytes bypass the Hogi backend;
383
+ only the short-lived token, Vid commit, and transcode polling use Hogi APIs.
384
+ - The command waits for VOD transcoding and returns the final `hogi://video/...`
385
+ URI together with `task_id` and `upload_mode: "vod"`.
386
+ - `--after-asset-id` applies only to the small-file endpoint and is rejected for VOD uploads.
387
+ - Requires an active workspace. The small-file request creates the asset directly;
388
+ VOD creates it during `commit_upload`.
389
+ - Returns `asset_id`, `asset_uri`, `file_uri`, `domain`, `workspace_id`, and
390
+ `upload_mode`; VOD also returns `task_id`. `uri`
391
+ remains an alias of `file_uri` for compatibility.
392
+ - `--attach` is retained as a no-op compatibility flag because uploads are now
393
+ always attached.
394
+ - A storage or workspace-write failure fails the upload command.
395
+ - Arbitrary documents and URL uploads are outside the current scope.
396
+
397
+ Supported extensions:
398
+
399
+ - Images: `jpg`, `jpeg`, `png`, `gif`, `svg`, `webp`, `heic`, `heif`, `bmp`, `ico`, `tiff`, `jfif`.
400
+ - Video: `mp4`, `webm`, `avi`, `mov`, `flv`, `mkv`.
401
+ - Audio: `mp3`, `wav`, `ogg`, `m4a`, `aac`, `flac`, `wma`, `ape`.
402
+
403
+ ## Records and Resource Download
404
+
405
+ Query generation metadata:
406
+
407
+ ```bash
408
+ oiioii record get hogi://image/<id> --json
409
+ oiioii record get hogi://video/<id> --json
410
+ ```
411
+
412
+ Download and open a resource:
413
+
414
+ ```bash
415
+ oiioii record open hogi://image/<id> --json
416
+ ```
417
+
418
+ Download without opening it:
419
+
420
+ ```bash
421
+ oiioii record open hogi://video/<id> \
422
+ --output ./downloads \
423
+ --no-open \
424
+ --json
425
+ ```
426
+
427
+ `record open` also supports `--filename <name>` and `--wm` for a watermarked
428
+ resource when supported by the backend.
429
+
430
+ Uploaded files are resources but not GenAI generation records. Use `record open`
431
+ for an uploaded URI; `record get` may not find it.
432
+
433
+ ## Capability and Model Inspection
434
+
435
+ ```bash
436
+ oiioii inspect capabilities --json
437
+ oiioii inspect models --json
438
+ oiioii inspect models --domain image --json
439
+ oiioii inspect models --domain video --json
440
+ oiioii inspect models --domain audio --json
441
+ ```
442
+
443
+ `inspect models` authenticates with `OIIOII_API_KEY` and calls the active
444
+ backend model catalog at `POST /points/mcp_model_pricings`. It returns actual
445
+ displayable image/video/audio model records, including the model name and key,
446
+ text-LLM input capabilities, reference-image bounds, points cost, supported
447
+ sizes/aspect ratios/durations, descriptions, tags, and membership restrictions.
448
+ MCP tool definitions are not returned.
449
+
450
+ Each model includes a unique, directly executable selector:
451
+
452
+ ```json
453
+ {
454
+ "id": 50,
455
+ "name": "Seedance2.0 fast",
456
+ "key": "seedance20",
457
+ "variant": "fast",
458
+ "selector": {
459
+ "model_id": 50,
460
+ "cli_args": ["--model-id", "50"]
461
+ }
462
+ }
463
+ ```
464
+
465
+ The top-level `selection` object is the machine-readable interpretation contract:
466
+
467
+ - `preferred: "model_id"` tells an Agent to copy `selector.cli_args` into a
468
+ generation command.
469
+ - `variant_mcp_argument: "version"` states that the selected catalog variant is
470
+ forwarded as the GenAI MCP `version` argument.
471
+ - `empty_input_capabilities: "unknown"` means an empty list must not be treated
472
+ as text-only or unsupported.
473
+ - `input_capabilities` describes text-LLM input modalities; it does not determine
474
+ whether an image/video/audio generation model belongs to that output domain.
475
+ - `reference_image_count_max` controls reference-image support for image models.
476
+ An explicit `0` disables image editing; a missing/null value follows the Hogi
477
+ frontend fallback and does not reject image references.
478
+ - `generation_input_contract` is the CLI's resolved per-model contract after
479
+ combining model-specific image/video/audio rules with catalog reference-image
480
+ bounds. Its `media` field lists accepted inputs, while
481
+ `prompt_only_supported` separately states whether references may be omitted.
482
+ - `points_cost_semantics: "base_cost"` means `points_cost` is not a final quote.
483
+ - Duration entries are either exact seconds (`"10"`) or inclusive ranges
484
+ (`"4-15"`).
485
+
486
+ Agents should prefer `--model-id` because a single key can have multiple
487
+ variants. Human callers can alternatively use `--model <key> --variant <value>`.
488
+ When `--variant` is omitted, the active catalog row with the lowest
489
+ `sort_order` is the deterministic default:
490
+
491
+ ```bash
492
+ oiioii video text --prompt "cinematic rain" --model-id 50 --duration 5 --resolution 720p --aspect-ratio 16:9 --json
493
+ oiioii video text --prompt "cinematic rain" --model seedance20 --variant fast --duration 5 --resolution 720p --aspect-ratio 16:9 --json
494
+ ```
495
+
496
+ When an exact catalog selection is used, generation validates its output domain,
497
+ reference-image bounds, aspect ratio, resolution, duration, and command-specific
498
+ reference contract before consuming credits. `input_capabilities` is not used as
499
+ a universal deny-list for image/video/audio generation models. The catalog
500
+ variant is sent to GenAI MCP as `version`. `--model <key>` resolves through the
501
+ same catalog selection and constraint validation path as `--model-id`.
502
+
503
+ ## Points and Generation Cost
504
+
505
+ ```bash
506
+ oiioii points balance --json
507
+ oiioii points quote --model-id 60 --duration 4 --resolution 480p --json
508
+ oiioii points quote --model seedance20 --variant mini --duration 4 --resolution 480p --json
509
+ oiioii points cost hogi://video/example.mp4 --json
510
+ ```
511
+
512
+ `points balance` calls MCP resource tool `get_user_info`. `points cost` calls
513
+ `query_generation_cost`; `chargedAmount` is authoritative when status is
514
+ `charged`. Because decrement ledgers commonly return a negative
515
+ `chargedAmount`, CLI also returns positive `consumed_points`. A successful generation can temporarily report `no_charge` while
516
+ the asynchronous backend settlement is still completing.
517
+
518
+ `points quote` combines the authenticated user's tier with the current backend
519
+ model catalog, including resolution prices, requested/reference duration and an
520
+ active promotional discount. Its result always contains `estimate: true` and a
521
+ `caveat`: backend feature flags, resolved media duration, promotion changes and
522
+ fallback pricing can make the final charge differ. Use `points cost` for the
523
+ settled amount.
524
+
525
+ Structured MCP errors `GENAI_POINTS_INSUFFICIENT` and
526
+ `GENAI_SUB_ACCOUNT_MONTHLY_POINTS_LIMIT_EXCEEDED` map to the stable CLI code
527
+ `QUOTA_EXCEEDED` instead of a generic generation failure.
528
+
529
+ ## Local Tasks and Preview Bundles
530
+
531
+ Generation commands create local task entries in:
532
+
533
+ ```text
534
+ ~/.oiioii/tasks.jsonl
535
+ ```
536
+
537
+ The current lifecycle is:
538
+
539
+ ```text
540
+ created -> submitting -> queued -> running -> succeeded | failed | cancelled
541
+ ```
542
+
543
+ The public commands accept the cached backend ID or local ID:
544
+
545
+ ```bash
546
+ oiioii task list
547
+ oiioii task status <task_id>
548
+ oiioii task wait <task_id> --timeout 300
549
+ ```
550
+
551
+ For non-terminal tasks, `status` makes one authenticated backend query and
552
+ `wait` polls the backend until a terminal state or `TASK_TIMEOUT`. Every query
553
+ uses the workspace cached with the original submission.
554
+
555
+ Existing preview bundles can be read with:
556
+
557
+ ```bash
558
+ oiioii preview latest --json
559
+ oiioii preview bundle <task_id> --json
560
+ ```
561
+
562
+ Bundle format:
563
+
564
+ ```text
565
+ ~/.oiioii/previews/<bundle_id>/
566
+ manifest.json
567
+ summary.json
568
+ artifacts/
569
+ ```
570
+
571
+ Image, video, and audio generation invoke `PreviewStore.createBundle` after the local
572
+ task reaches a terminal state. Preview persistence is best-effort: a local
573
+ preview write failure is reported as a warning and does not turn a successful
574
+ generation into a failure. When an older terminal task predates automatic
575
+ preview creation, `preview latest` and `preview bundle <task_id>` lazily create
576
+ the missing bundle from local task history.
577
+
578
+ ## JSON Output Protocol
579
+
580
+ Implemented commands support the global `--json` option.
581
+
582
+ Success envelope:
583
+
584
+ ```json
585
+ {
586
+ "ok": true,
587
+ "type": "generation_submitted",
588
+ "data": {
589
+ "task_id": "async_image_...",
590
+ "local_task_id": "task_...",
591
+ "status": "queued",
592
+ "artifacts": []
593
+ },
594
+ "next": [
595
+ { "command": "oiioii task status async_image_... --json" }
596
+ ]
597
+ }
598
+ ```
599
+
600
+ Error envelope:
601
+
602
+ ```json
603
+ {
604
+ "ok": false,
605
+ "type": "generation_failed",
606
+ "error": {
607
+ "code": "WORKSPACE_REQUIRED",
608
+ "message": "No workspace set."
609
+ }
610
+ }
611
+ ```
612
+
613
+ Stable error codes include:
614
+
615
+ | Code | Meaning |
616
+ |---|---|
617
+ | `AUTH_REQUIRED` | `OIIOII_API_KEY` is missing or empty |
618
+ | `AUTH_INVALID` | Credential rejected |
619
+ | `API_KEY_INVALID` | Invalid API Key |
620
+ | `WORKSPACE_REQUIRED` | No active workspace |
621
+ | `INVALID_ARGUMENT` | Unsupported or malformed input |
622
+ | `GENERATION_FAILED` | MCP/model generation failure |
623
+ | `GENERATION_TIMEOUT` | Long-running request timed out |
624
+ | `RECORD_NOT_FOUND` | Record/resource/bundle not found |
625
+ | `TASK_NOT_FOUND` | Local task ID not found |
626
+ | `TASK_TIMEOUT` | Local task did not become terminal before the wait deadline |
627
+ | `QUOTA_EXCEEDED` | Insufficient points, subgroup quota, or backend rate limit exceeded |
628
+ | `PAYLOAD_TOO_LARGE` | Upload exceeds the backend limit |
629
+ | `CONTENT_SAFETY_BLOCKED` | Prompt or reference rejected by the general content safety policy |
630
+ | `IP_CHARACTER_RESTRICTED` | Prompt or reference may contain a restricted IP or character |
631
+ | `SERVER_ERROR` | Invalid response or backend error |
632
+ | `NETWORK_ERROR` | Network request failed |
633
+ | `NOT_IMPLEMENTED` | Registered capability is not implemented |
634
+ | `CONFIG_ERROR` | Local configuration error category |
635
+
636
+ ## Structured Logs
637
+
638
+ Every CLI feature creates a client-side trace through the shared logging API.
639
+ The logging module owns the schema, redaction, local storage, filtering,
640
+ rotation, and export behavior; business modules never write log files directly.
641
+
642
+ A feature trace uses one `trace_id` from command entry to command completion:
643
+
644
+ ```text
645
+ feature.started
646
+ -> feature.step (configuration, task, validation, local storage)
647
+ -> api.request -> api.response | api.error
648
+ -> feature.completed | feature.failed
649
+ ```
650
+
651
+ This is CLI-side observability only. It does not collect or depend on logs from
652
+ inside the Hogi backend.
653
+
654
+ Recorded API events use the same `request_id` for correlation:
655
+
656
+ ```text
657
+ api.request -> api.response | api.error
658
+ ```
659
+
660
+ Feature traces cover workspace, image/video/audio generation, upload, records,
661
+ inspection, preview, task commands, and their local storage steps. API boundary
662
+ events cover:
663
+
664
+ - GenAI and Asset MCP calls.
665
+ - Resource upload and download.
666
+ - Generation-record lookup.
667
+
668
+ Logs contain safe operational fields such as source, operation, HTTP method,
669
+ path, status, duration, and selected non-sensitive metadata. They do not record
670
+ request headers, API Keys, bearer tokens, prompts, request bodies, or response
671
+ bodies. Sensitive key names and recognizable secret values are redacted again
672
+ inside the central logger before persistence.
673
+
674
+ Default storage:
675
+
676
+ ```text
677
+ ~/.oiioii/logs/events.jsonl
678
+ ```
679
+
680
+ The active file is limited to 5 MiB and rotated across at most five files. Log
681
+ directories use owner-only permissions and log/export files are written with
682
+ mode `0600`. Logging is best-effort: a storage failure does not change the
683
+ result of the API operation being logged.
684
+
685
+ List logs:
686
+
687
+ ```bash
688
+ oiioii logs list --json
689
+ oiioii logs list --category api --level error --limit 20 --json
690
+ oiioii logs list --source hogi_mcp_client --since 2026-08-14T00:00:00Z --json
691
+ oiioii logs list --feature image.text --json
692
+ oiioii logs list --trace trace_<id> --json
693
+ ```
694
+
695
+ Export logs as JSONL or JSON:
696
+
697
+ ```bash
698
+ oiioii logs export --output ./oiioii-logs.jsonl --json
699
+ oiioii logs export --output ./oiioii-logs.json --format json --json
700
+ ```
701
+
702
+ Exports do not overwrite an existing file unless `--force` is supplied.
703
+
704
+ Show the active log path:
705
+
706
+ ```bash
707
+ oiioii logs path --json
708
+ ```
709
+
710
+ `logs list`, `logs export`, and `logs path` do not create feature-trace entries
711
+ themselves, so inspecting or exporting logs does not change the result set.
712
+
713
+ ## DataFinder Telemetry
714
+
715
+ Remote product telemetry is centralized under `src/telemetry/`. Business code
716
+ only calls `recordTelemetryBusinessInfo`, `markTelemetryPartialSuccess`, or
717
+ `setTelemetryWorkspaceId` to provide safe business information. It does not
718
+ import the DataRangers SDK, define event names, construct common parameters, or
719
+ manage delivery.
720
+
721
+ Each executable command is mapped centrally to one business domain and emits at
722
+ most two events: `cli_biz_<domain>_called` and `cli_biz_<domain>_result`. The
723
+ result event records the command's total `duration_ms`, `result`
724
+ (`success`, `partial_success`, `failure`, or `timeout`), and a normalized
725
+ `error_code` on failure. There are no separate staged or technical events;
726
+ latency and outcome are measured on the business result event.
727
+
728
+ The telemetry manager adds `schema_version`, `app_env`, `app_name`,
729
+ `cli_version`, `command`, `trace_id`, `workspace_id`, `os`, `arch`, and
730
+ `node_major`. `workspace_id` is omitted for commands without an active
731
+ workspace. API Keys, tokens, prompts, file paths, and request/response bodies
732
+ are dropped centrally.
733
+
734
+ Telemetry requires an explicitly identified real Hogi user ID. There is no
735
+ installation-ID or anonymous fallback: until the authenticated backend UID is
736
+ provided through `identifyTelemetryUser`, events are not sent. SDK delivery is
737
+ best-effort, writes only delivery status to the local debug log, and waits for
738
+ the SDK queue for a bounded period at process exit.
739
+
740
+ ## Global Options
741
+
742
+ ```text
743
+ --json
744
+ --base-url <url>
745
+ --workspace <id>
746
+ --verbose
747
+ --no-color
748
+ ```
749
+
750
+ `--verbose` and `--no-color` are reserved global options; current
751
+ output does not yet vary based on them.
752
+
753
+ ## Local Files and Environment Variables
754
+
755
+ Default local directory: `~/.oiioii/`.
756
+
757
+ | Path | Purpose |
758
+ |---|---|
759
+ | `config.json` | API Key, backend URL, and default workspace |
760
+ | `tasks.jsonl` | Local generation task records |
761
+ | `previews/` | Preview bundles created by image, video, and audio generation |
762
+ | `logs/events.jsonl` | Active structured log file; older files use numeric suffixes |
763
+
764
+ Environment variables:
765
+
766
+ | Variable | Purpose |
767
+ |---|---|
768
+ | `OIIOII_CONFIG_DIR` | Override the local configuration directory |
769
+ | `OIIOII_BASE_URL` | Override the backend URL at runtime |
770
+ | `OIIOII_WORKSPACE_ID` | Override the active workspace |
771
+ | `OIIOII_BUILD_ENV` | Select `production`, `test`, or `local` while building |
772
+ | `OIIOII_BUILD_BASE_URL` | Override the URL embedded in a build |
773
+ | `OIIOII_API_KEY` | Temporarily override the persisted API Key for the current process |
774
+ | `OIIOII_E2E` | Explicit opt-in marker for credit-consuming E2E workflows |
775
+ | `OIIOII_LOG_DISABLED` | Set to `1` to disable local logging, primarily for isolated tests |
776
+ | `OIIOII_TELEMETRY_DISABLED` | Set to `1` to disable DataFinder telemetry |
777
+
778
+ Never commit or print real API Keys, tokens, or passwords.
779
+
780
+ ## Development and Verification
781
+
782
+ ```bash
783
+ npm install
784
+ npm run typecheck
785
+ npm test
786
+ npm run lint
787
+ npm run build
788
+ ```
789
+
790
+ The current local suite contains unit tests and CLI subprocess integration
791
+ tests with mocked HTTP servers. There are no checked-in real-backend E2E test
792
+ files at present; running the normal test command does not consume GenAI credits.
793
+
794
+ Most recent local verification for this README update:
795
+
796
+ - 45 test files passed.
797
+ - 333 tests passed.
798
+ - `npm run typecheck` passed.
799
+ - `npm run lint` passed.
800
+ - Production, HOE test, and local builds passed; their embedded backend
801
+ URLs were verified as `api.oiioii.ai`, `api-hoe.oiioii.tv`, and
802
+ `localhost:4000` respectively.
803
+
804
+ ## Project Structure
805
+
806
+ ```text
807
+ oiioii-cli/
808
+ src/
809
+ cli.ts Commander entry point
810
+ app/context.ts AppContext definition
811
+ commands/ CLI command wiring and workflows
812
+ clients/ Hogi HTTP/MCP adapters
813
+ config/
814
+ build_environment.ts Build environment/domain mapping
815
+ config_store.ts Local configuration storage
816
+ core/
817
+ model_map.ts Model-to-MCP-tool mapping
818
+ task_store.ts Local task persistence
819
+ preview_store.ts Preview bundle persistence
820
+ upload_file_types.ts Upload type/domain validation
821
+ output/ JSON envelopes, errors, human output
822
+ logging/ Log schema, redaction, storage, API spans
823
+ telemetry/ Event registry, common context, lifecycle, Volc transport
824
+ skills/SKILL.md Agent usage reference
825
+ tests/
826
+ unit/ Unit tests
827
+ cli/ CLI subprocess integration tests
828
+ .plan/release/ Standalone installer workflow/assets
829
+ tsup.config.ts Environment-aware ESM bundling
830
+ package.json
831
+ ```
832
+
833
+ ## Security Notes
834
+
835
+ - API keys are persisted by `oiioii auth login` in `~/.oiioii/config.json`.
836
+ - Config files containing credentials are written with owner-only permissions (`0600`).
837
+ - Generation and resource APIs use `x-hogi-api-key`.
838
+ - Generated artifacts must use the expected `hogi://image/...`,
839
+ `hogi://video/...`, or `hogi://audio/...` URI domain; public URLs and mismatched resource domains are
840
+ rejected by the generation workflow.