@302ai/media-studio-cli

中文文档
0.1.6发布于 2026/11/06Apache-2.0ES Module零依赖近 30 天下载 1985

CLI for AI Media Studio — let external agents drive the core media-studio features

原始使用文档
文档目录19 节
  1. Install
  2. Usage
  3. CLI compatibility and updates
  4. Multi-turn conversation
  5. Configuration and storage
  6. Skills
  7. Agent Skill ( 302ai/msc-skill )
  8. Attachments
  9. Staging server (expired TLS certificate)
  10. TLS-intercepting proxies
  11. Proxies
  12. Development
  13. Testing (before shipping any change)
  14. 1. Dev iteration (fastest)
  15. 2. Automated external-consumer check (required)
  16. 3. Manual user-install simulation
  17. 4. End-to-end against a real server
  18. Notes learned the hard way
  19. License

@302ai/media-studio-cli

CLI for AI Media Studio — drive media-studio chat from any terminal or external agent.

Install

npm install -g @302ai/media-studio-cli
# requires Node.js >= 22

Staging and Local are available only in prerelease versions. Region visibility follows the package version, not the npm dist-tag: a published prerelease exposes them, while a stable version installed from @beta does not.

If you installed via bun and get command not found: bun's global bin dir is not on PATH by default. Run once:

echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc

Usage

msc login                   # authenticate in a browser
msc guide                   # the full agent-facing manual
msc whoami                  # show current auth status
msc chat "hi"               # one chat turn (multi-turn by default)
msc sessions                # list sessions from the server
msc skills                  # list the skill catalog you can reference
msc logout                  # clear stored credentials

media-studio-cli is the long alias for msc — the same program, both installed. The docs, the help output, and every error message use the short name:

msc chat "画一只猫" -r        # -r/--show-reasoning = 展示模型推理过程
msc chat "hi" --json          # machine-readable output
msc chat "hi" --session <id>  # 切换到已有会话(先校验存在)并设为默认
msc chat "hi" --new           # 新建会话并设为默认(id 不复用)
msc sessions                  # 列出所有会话(标记当前默认 `(current)`)
msc sessions --json           # 机器可读的原始 JSON 数组
msc sessions use <id>         # 校验存在后切换默认会话
msc sessions use --new        # 新建会话并设为默认
msc skills                    # 列出技能库(--plaza 浏览技能广场)
msc skills add <slug>          # 从广场安装技能(如 brainstorming,见 --plaza --json 的 slug)
msc skills rm <command>       # 从技能库移除(-y/--yes 跳过确认)
msc skills enable <command>   # 启用 / disable 停用
msc --help                    # all flags

Session deletion is not available in the CLI. To delete a session, open the corresponding session page in the Media Studio web app and delete it manually.

msc --help carries an agent-oriented quickstart — the auth prerequisite, the three canonical calls, and the --json contract. msc guide prints the full manual: every command, both JSON schemas, the nextStep values, exit codes, stream discipline, and skill semantics. Point an agent at those two instead of duplicating them here.

CLI compatibility and updates

Online CLI requests carry X-Agent-Cli-Version: <package version>. The BFF applies CMS CliVersionPolicy (cli-version-policy) to whoami, chat, sessions, skills and attachments. enabled defaults true; enabled=false is the emergency disable. Blank minSupportedVersion uses the CLI package version bundled in the BFF build (0.1.4 for this release); a custom stable SemVer can raise or lower the floor. Clearing the minimum restores the release baseline rather than disabling enforcement. Headerless Bearer requests are legacy CLI and normally receive 426 (prewarm exception below); headerless browser-cookie/anonymous requests are unaffected. This is not an authentication boundary. Local help, version, guide, logout and browser login remain available.

A below-floor request receives HTTP 426, CLI_UPGRADE_REQUIRED (10010) and nextStep: "upgrade_cli" before its upstream work or stream begins. This is an application convention, not an HTTP transport upgrade. CMS read failure uses a valid available cached policy or returns 503, not an upgrade refusal; do not interpret every whoami exit 1 as expired credentials. Policy caching uses save-triggered tag invalidation and periodic revalidation, not simultaneous cross-instance activation.

Older clients may not decode upgrade_cli; the server message still supplies both installation commands and requires permission first. Publishing a CLI does not deploy the BFF or change its bundled baseline: publish 0.1.4 and sync the matching public Agent Skill before deploying/activating the BFF build containing that manifest. See the operator activation procedure below.

The sole transport exception is an upgrade refusal for headerless Bearer POST /api/sessions/prewarm: HTTP 200 SSE event:error carries flat { err_code: 10010, message: <full permission-first commands> }, with no session_ready or upstream work. The old CLI exits 1 and exposes errCode: 10010 and the message, but no httpStatus. Stamped clients and all other interfaces retain 426; CMS failure remains 503 and is not converted to SSE.

Optional npm discovery uses a best-effort 24-hour cache and short timeout; discovery failures never fail a media task or change its exit status. Chat success/incomplete JSON may contain a stable updateAvailable: { current, latest, upgradeCommand, skillUpgradeCommand }; successful whoami may append a stable notice. Stable emissions are deduplicated per target version across both commands after output, not acknowledgment. Interactive terminal commands can also report beta updates for prerelease builds; beta notices are not deduplicated. A stable version installed via @beta cannot be identified as beta and receives no beta notice. Skills/sessions arrays and single-document JSON stdout stay unchanged. Agents finish the task before telling the user about an optional update and never silently install it.

Local notification deduplication is best-effort, not exactly-once: simultaneous processes or an unwritable cache can repeat notices.

Required upgrade recovery needs permission for both global installs, in order:

npm install -g @302ai/media-studio-cli@latest
npx -y skills add 302ai/msc-skill --skill msc-skill -g -y
msc --version
msc guide

Stop if either install fails and report completed steps; do not claim success or automatically roll back the other installation. Skill installation may not reload a running Agent's cached context, so read the guide before resuming. Retry only definitely unaccepted generation. A refusal covers only that request: earlier stages may already have effects. Reuse an error's sessionId with --session, not --new; inspect the existing session/artifacts when acceptance is uncertain. Policy changes must not terminate accepted work or established SSE streams.

Operators: see CLI minimum-version activation before changing the floor.

Headless environments cannot complete browser sign-in, so msc login refuses immediately instead of waiting out the callback deadline: CI (CI set), and Linux with neither DISPLAY nor WAYLAND_DISPLAY. Sign in from a machine whose browser can reach the loopback callback.

Multi-turn conversation

chat is multi-turn by default — no flag needed. The CLI keeps a single lastSessionId pointer in config.json (under the config dir):

  • First-ever chat provisions a session via the same prewarm flow the web app uses (source cli), printing stage progress (creating / sandbox / skills / finishing), then chats. The pointer is written the moment the session is durably persisted upstream — an interrupted provision never loses a live session.
  • Later chats continue that session — upstream remembers the conversation by session id, so no history is resent.
  • If the current session is gone before a turn produces any output, the CLI transparently provisions a fresh one and re-runs the turn — a first-turn failure never strands you.
  • Once a turn has started producing output, a session failure is reported instead: the partial result stands, nothing is re-run, and no replacement session is created (a retry would replay output and re-dispatch tool calls or generation tasks the first attempt may already have started).
  • --session <id> switches to an existing session (including web-created ones) and makes it the default. The id is verified upstream first: a missing id fails with a hint, it never provisions a different session behind your back.
  • --new creates a fresh session with a newly generated id and makes it the default for later runs. Ids are never reused or adopted: the CLI either uses the id it generated or reports the refusal.

Manual proof of continuity:

msc chat "记住数字42"
msc chat "刚才的数字是几?"   # answers 42

Point at a different server via msc login --region default|cn|local (the server you log into is saved and reused; local — like staging — is a prerelease-only region, see the note at the top).

Configuration and storage

The CLI stores credentials and local settings in:

  • Default: ~/.config/media-studio-cli/
  • XDG standard: $XDG_CONFIG_HOME/media-studio-cli/
  • Override: MEDIA_STUDIO_CONFIG_DIR=/path/to/dir

Key files:

  • auth.json: stores active platform credentials and user session metadata (permissions 0600 on POSIX)
  • config.json: stores CLI client settings, including lastSessionId pointer

auth.json's apiUrl is only accepted when its host is on the CLI allowlist: the official hosts (which the rejection message lists) plus the local-dev hosts localhost / 127.0.0.1 / ::1. A hand-edited URL outside that list is refused before any request is sent, and the CLI reports it as a rejected credential naming the URL — not as "not logged in", since the token itself may be fine. msc login rewrites the file with a server-supplied URL and is the fix; the refused URL is never used, and base-URL resolution falls back to the official default host.

In --json mode the two auth states are distinguishable without reading the message: a rejected credential carries "nextStep": "relogin" (and its guidance), while no credential at all reports status and message only.

Skills

Discover what your account can reference, then reference it — the reference must name a skill that exists in your catalog:

msc skills                     # list your library
msc skills --json              # raw catalog array (see fields below)
msc skills --plaza             # browse the Skill Plaza with your library
                               # state merged in (built-ins excluded)
msc skills --plaza --json

msc skills add <slug>           # install a plaza entry by slug
msc skills rm <command>        # remove a library skill by command
msc skills enable <command>    # flip a library skill's enabled flag
msc skills disable <command>

add takes the entry's plaza slug (brainstorming, shown in msc skills --plaza --json as slug); the library mutations take the command string (brainstorming and /brainstorming are the same entry) — the same string the prompt uses to reference the skill.

--json is the intended output for agents: the catalog is the input to a decision the calling program makes itself. Both descriptionEn/descriptionZh are passed through untouched — upstream does not guarantee the En slot is English, so the CLI picks nothing. The human rendering lists names only (the command string is available in --json) with the full descriptionEn on a second line, and marks [on] enabled / [off] disabled / [-] not installed in the plaza view.

Shared API endpoints: mutations use the exact same endpoints as the web app (POST /api/skills for installs, DELETE /api/skills?skillId= for removal, POST /api/skills/enabled for enable/disable). The CLI resolves the slug/command to the entry/id before calling the endpoint. rm requires --yes outside a terminal. Built-in entries are rejected (422): they sync into your library from the backend. Managing skills (upload, cover) stays in the Media Studio web app.

Then reference a skill in the prompt and the CLI installs it into the session sandbox on demand:

msc chat "/always-hello 不管我说什么"      # leading slash command
msc chat "%%/always-hello%%不管我说什么"    # web composer marker, paste-compatible

Both spellings resolve to the same thing. The upstream installs a skill only from the turn's skill_urls field, so the CLI looks the reference up in your catalog (GET /api/skills) and sends the matching package URL — prompt text alone triggers nothing.

  • A bare /command counts only at the start of the prompt, so mid-sentence slashes stay prose (check /etc/hosts is not a skill reference). The %%…%% marker is also recognized anywhere — a web prompt pasted verbatim keeps its token — but the skill activates upstream only when the marker leads the message, so lead the prompt with it. The leading token can be any bare slug, single-segment included — /tmp what is this resolves /tmp — and a reference that matches nothing fails the turn with the catalog listed, so a typo never silently degrades to a skill-less answer.
  • The catalog is fetched only when the prompt references a skill; skill-free turns cost no extra request.
  • Unknown skills fail the turn with a non-zero exit before any session is provisioned. A disabled skill is auto-enabled first — the same ADR-0001 behavior as the web's "Use in Chat" — because the upstream treats enabled as a hard precondition for invocation and would otherwise download the package and silently never run it. The enable flips the skill's enabled flag on your account (a persistent change), is reported as Auto-enabled for this turn: …, and a failed enable aborts the turn.

Agent Skill (302ai/msc-skill)

To teach an external AI agent (Claude Code, Cursor, Codex, OpenCode, Gemini CLI, etc.) how and when to invoke msc, install the public Agent Skill:

npx -y skills add 302ai/msc-skill --skill msc-skill -g -y

For opt-in beta, pair the @beta CLI with the beta Skill installation. Installing another channel replaces the same global CLI or Skill; ask permission before switching. The public beta branch is created by the first successful beta sync.

  • Source of truth: The canonical skill source lives in this repository under msc-skill/. A verified CLI Release synchronizes its matching channel to 302ai/msc-skill; compatible Skill-only changes and retries use manual dispatch.
  • Contract co-evolution: When modifying CLI commands, --json payloads, exit codes, error structures (nextStep), authentication behavior, or file attachment syntax in media-studio-cli, always update msc-skill/skills/msc-skill/SKILL.md in the same commit.

Attachments

Attach local files to a chat turn using @path anywhere in the prompt:

msc chat "看看 @cover.png 这张图"             # bare path (ends at whitespace)
msc chat "总结 @/abs/path/notes.pdf"          # absolute path
msc chat '对比 @"my docs/report.docx" 内容'   # quoted path with spaces

The CLI mirrors the web composer's upload flow:

  1. Validates each referenced file locally (exists, readable, supported extension, under 50 MB) before any network call.
  2. Uploads each file via the web app's POST /api/chat/attachments endpoint with a terminal spinner (Uploading attachment 1/2: cover.png).
  3. Rewrites the prompt to inline the remote URL using the web's &&<url>&& marker, which the upstream model and web session history natively understand.
  4. Up to 10 unique attachments per turn (same as the web composer); referencing the same file twice uploads it once.
  5. An unattachable reference (missing file, unsupported format) fails the turn before any session is provisioned.
  6. Prose mentions (@team 辛苦了, email addresses) stay literal text — only tokens with a file extension or path slash are treated as attachments.
  7. @path is local-filesystem-only: @https://example.com/a.png fails with no such file. There is no @url form — remote URLs are not attachments.

In --json mode the uploaded attachments are surfaced under the attachments array: [{ name, type, size, remoteUrl }].

Staging server (expired TLS certificate)

The staging server's certificate is expired (ops declines renewal), so the CLI skips TLS certificate verification only while pointed at the staging host; the server choice itself is the opt-in, and the default / CN hosts always verify. The interactive msc login region list shows each server's URL and marks Staging with the auto-off behavior; msc login --region staging opts in.

Stable (production) builds hide Staging and Local from the msc login region menu and --region, but a persisted auth.json from a prerelease login keeps pointing at that server — and a staging one still auto-bypasses TLS verification. This is intentional (the login persists across upgrades), not an oversight.

The whitelist is the only way the bypass turns on — no environment variable can extend it to another server, so production can never skip verification. To force verification back on while pointed at staging (once ops renews the certificate, or to debug its chain):

MEDIA_STUDIO_INSECURE_TLS=0 msc chat "hi"   # also accepts "false"

Plain-http:// servers skip the bypass entirely (nothing to verify). The bypass prints nothing: the staging choice is already stated in the msc login menu and here, so no warning repeats on every command (--help and --version included, whose output scripts and agents parse).

TLS-intercepting proxies

If browser SSO login works but every API call fails with fetch failed, a TLS-intercepting proxy (Clash/FlClash TUN mode, corporate MITM) is breaking certificate verification (unable to verify the first certificate). Node/Bun do not use the OS keychain, so a proxy CA trusted by your browser is not trusted by the CLI. Either trust the proxy CA explicitly:

export NODE_EXTRA_CA_CERTS=/path/to/proxy-ca.crt

or skip verification for the CLI only (no certificate checks). The staging host already does this automatically, so this is only needed for other servers — and it is now the only way to bypass a non-staging host, since no msc flag or env var does so. Note it is process-global: every host the CLI talks to stops being verified.

NODE_TLS_REJECT_UNAUTHORIZED=0 msc sessions

Proxies

msc follows the usual CLI convention (git, gh, curl): the environment owns the proxy, the CLI only reads it. No OS-level "system proxy" detection, no --proxy flag, and nothing printed.

export HTTPS_PROXY=http://127.0.0.1:7890
export NO_PROXY=localhost,127.0.0.1,::1    # appended automatically when absent

HTTP_PROXY / HTTPS_PROXY / NO_PROXY and their lowercase spellings are accepted. ALL_PROXY is not, matching gh. Loopback is never proxied, so the msc login callback and any future local helper keep working even when the proxy list is empty.

Node reads proxy settings only while it builds the global dispatcher, before any CLI code runs, so a set proxy variable makes msc re-run itself once with --use-env-proxy (one extra process start; nothing at all when no proxy variable is set). Setting NODE_USE_ENV_PROXY=1 in the environment skips that restart. NO_PROXY entries are host names, .suffix or host:port; CIDR ranges are not matched. The Bun dev run (bun run dev) and the standalone binary ignore the proxy variables — Node's flag does not exist there.

A proxied browser is not evidence that the CLI can reach the host: if SSO login works but every command fails with fetch failed, check what the hostname resolves to before blaming certificates.

Development

bun run dev                   # run from TS source (bun), no build step
bun run build                 # bundled JS entry -> dist/ (the npm artifact)
bun run build:binary          # standalone single-file binary -> bin/

Testing (before shipping any change)

Test layers from fast to faithful. Minimum bar: layer 2 passes; before an actual publish also run layer 4.

1. Dev iteration (fastest)

bun run dev -- chat "hi"      # runs TS source directly, no packaging

2. Automated external-consumer check (required)

# from repo root
bun run package:cli:check

Builds, type-checks, packs the real tarball, installs it into a temp directory outside the repo, and executes the installed binaries (--version / --help assertions). Catches packaging-only breakage (missing shebang, lost exec bit, stale bin target) that in-repo runs never see.

3. Manual user-install simulation

cd packages/media-studio-cli
bun pm pack --destination /tmp/cli-test

# option A: clean local consumer
mkdir /tmp/cli-consumer && cd /tmp/cli-consumer
bun add /tmp/cli-test/302ai-media-studio-cli-0.1.0.tgz
./node_modules/.bin/msc --version

# option B: global install (also verifies the short name doesn't collide)
bun add -g /tmp/cli-test/302ai-media-studio-cli-0.1.0.tgz
msc --version

# cleanup afterwards — one command removes BOTH bin names
bun remove -g @302ai/media-studio-cli

4. End-to-end against a real server

# terminal 1: local gateway (CLI defaults to localhost:3000)
bun run dev

# terminal 2:
msc login                     # browser sign-in
msc whoami                    # verify auth state
msc chat "画一只猫" -r        # real streaming turn
msc chat "hi" --json

# Multi-turn continuity acceptance recipe:
msc chat "记住数字42"
msc chat "刚才的数字是几?"     # answers 42

# Session management verification:
msc sessions                  # shows session list with (current) marker
msc chat "hi" --session <id>  # switch to an existing session
msc chat "hi" --new           # start a new session
msc sessions use <id>         # switch default pointer to an existing session
msc sessions use --new        # create a new session and switch to it

Without the local server, point at production with msc login --region default.

Notes learned the hard way

  • bun pm pack does NOT run publish lifecycle scripts; the smoke script builds explicitly first. Don't assume pack produces a fresh dist.
  • Two bin entries pointing at the SAME file make bun pm pack emit duplicate tarball entries — that's why msc targets the tiny dist/msc.js shim instead of dist/index.js. Keep bin targets unique.
  • bun publish requires a modern bun (lifecycle scripts); the repo standard publish gate is bun run package:cli:check first.

License

Apache-2.0

版本与发布记录

@302ai/media-studio-cli 共发布 24 个版本,首次发布于 2026/09/04;过去 12 个月发布了 24 个版本。

版本发布日期距今
0.1.6latest2026/11/061 天前
0.1.6-beta.1beta2026/11/061 天前
0.1.6-beta.02026/11/061 天前
0.1.52026/10/308 天前
0.1.5-beta.02026/10/308 天前
0.1.42026/10/308 天前

关于 @302ai/media-studio-cli 的常见问题

@302ai/media-studio-cli 是什么?

CLI for AI Media Studio — let external agents drive the core media-studio features

如何安装 @302ai/media-studio-cli?

在项目目录运行 npm install @302ai/media-studio-cli,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 msc、media-studio-cli,可以用 npx msc 直接运行。

@302ai/media-studio-cli 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/302ai__media-studio-cli 是否存在。

@302ai/media-studio-cli 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@302ai/media-studio-cli 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@302ai/media-studio-cli 可以商用吗?

@302ai/media-studio-cli 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@302ai/media-studio-cli 的下载量有多少?

根据 npm 官方下载统计,@302ai/media-studio-cli 在 2026/10/05 – 2026/11/03 这 30 天内被下载 1,985 次,日均约 66 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@302ai/media-studio-cli 还在维护吗?

最新版本 0.1.6 发布于 2026/11/06(1 天前);至今共发布 24 个版本,其中过去 12 个月发布了 24 个;首次发布于 2026/09/04。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。