From c347c4ab8f05d64a4b83979aadf2ab9e19dd08c4 Mon Sep 17 00:00:00 2001 From: shushushu <45039815+shushushv@users.noreply.github.com> Date: Fri, 7 Aug 2026 17:36:21 +0800 Subject: [PATCH] feat: improve public onboarding and release reliability --- .github/workflows/publish-release.yml | 11 +- README.en.md | 114 ++++++++ README.md | 256 +++++------------- README.zh-CN.md | 198 -------------- RELEASING.md | 5 +- cmd/root.go | 19 +- cmd/root_test.go | 42 +++ docs/automation.md | 12 +- .../byted_interactai_guide_content_test.go | 23 +- internal/update/update_test.go | 39 +++ scripts/build-release-artifacts_test.sh | 14 +- scripts/publish-release-assets_test.sh | 49 ++-- skills/byted-interactai-guide/SKILL.md | 11 +- 13 files changed, 363 insertions(+), 430 deletions(-) create mode 100644 README.en.md delete mode 100644 README.zh-CN.md diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index f65d248..01ad6f1 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -38,10 +38,12 @@ jobs: stability=stable prerelease=false latest=true + npm_tag=latest if [[ "$version" == *-* ]]; then stability=prerelease prerelease=true latest=false + npm_tag=next fi notes_file="$RUNNER_TEMP/release-notes.md" git for-each-ref --format='%(contents)' "refs/tags/$GITHUB_REF_NAME" > "$notes_file" @@ -50,6 +52,7 @@ jobs: echo "VERTC_STABILITY=$stability" >> "$GITHUB_ENV" echo "VERTC_PRERELEASE=$prerelease" >> "$GITHUB_ENV" echo "VERTC_LATEST=$latest" >> "$GITHUB_ENV" + echo "VERTC_NPM_TAG=$npm_tag" >> "$GITHUB_ENV" echo "VERTC_NOTES_FILE=$notes_file" >> "$GITHUB_ENV" - name: Install pinned release tools run: make tools release-tools @@ -77,14 +80,14 @@ jobs: run: | npm_root="$RUNNER_TEMP/vertc-npm-package" mkdir -p "$npm_root/artifacts" "$npm_root/scripts" - cp package.json CHANGELOG.md LICENSE README.md README.zh-CN.md "$npm_root/" + cp package.json CHANGELOG.md LICENSE README.md README.en.md "$npm_root/" cp scripts/install.js scripts/run.js "$npm_root/scripts/" cp "$VERTC_VERIFIED_DIST"/vertc_"${VERTC_VERSION}"_*.tar.gz "$npm_root/artifacts/" cp "$VERTC_VERIFIED_DIST"/vertc_"${VERTC_VERSION}"_*.zip "$npm_root/artifacts/" cp "$VERTC_VERIFIED_DIST/checksums.txt" "$npm_root/checksums.txt" npm --prefix "$npm_root" version "$VERTC_VERSION" --no-git-tag-version --allow-same-version echo "VERTC_NPM_ROOT=$npm_root" >> "$GITHUB_ENV" - - name: Stage draft, publish npm latest, then finalize GitHub release + - name: Stage draft, publish npm package, then finalize GitHub release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -97,7 +100,7 @@ jobs: --notes-file "$VERTC_NOTES_FILE" \ --prerelease "$VERTC_PRERELEASE" \ --latest "$VERTC_LATEST" \ - --npm-tag latest + --npm-tag "$VERTC_NPM_TAG" - name: Verify GitHub and npm publication env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -109,4 +112,4 @@ jobs: --notes-file "$VERTC_NOTES_FILE" \ --prerelease "$VERTC_PRERELEASE" \ --latest "$VERTC_LATEST" \ - --npm-tag latest + --npm-tag "$VERTC_NPM_TAG" diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..ff9fba8 --- /dev/null +++ b/README.en.md @@ -0,0 +1,114 @@ +# vertc + +[![CI](https://github.com/volcengine/VolcEngineRTC_CLI/actions/workflows/ci.yml/badge.svg)](https://github.com/volcengine/VolcEngineRTC_CLI/actions/workflows/ci.yml) +[![Release](https://img.shields.io/github/v/release/volcengine/VolcEngineRTC_CLI?label=release)](https://github.com/volcengine/VolcEngineRTC_CLI/releases) +[![npm](https://img.shields.io/npm/v/@volcengine/rtc-cli?label=npm)](https://www.npmjs.com/package/@volcengine/rtc-cli) +[![Go Version](https://img.shields.io/badge/Go-%3E%3D1.25.12-00ADD8?logo=go)](./go.mod) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) + +[简体中文](./README.md) | English + +`vertc` is a developer-workflow CLI for building, configuring, running, and diagnosing Volcengine RTC AI audio/video projects. It works for both developers and coding agents. + +> **Current scope:** `voice-agent × web`. More scenes and platforms will be added as their end-to-end workflows become ready. + +[Install](#install) · [Quick start](#quick-start) · [Core capabilities](#core-capabilities) · [Agent and CI](#agent-and-ci) · [Security](#configuration-and-security) · [Documentation](#documentation) + +## Install + +Prebuilt binaries are available for macOS, Linux, and Windows on amd64 and arm64. Install with Node.js 16 or later: + +```bash +npm install -g @volcengine/rtc-cli +vertc version +``` + +The installer downloads the binary for the package version and current platform from GitHub Releases, then verifies it against `checksums.txt`. Building from source requires Go 1.25.12 or later: + +```bash +git clone https://github.com/volcengine/VolcEngineRTC_CLI.git +cd VolcEngineRTC_CLI +make build +./bin/vertc version +``` + +## Quick start + +Your Volcengine account must have an RTC application. A conversational-AI agent is optional; if the account has none, `dev` uses the built-in default scene. + +```bash +# 1. Create a project +vertc init ./my-agent --scene voice-agent --platform web +cd my-agent + +# 2. Sign in to Volcengine +vertc auth login + +# 3. Configure RTC resources and start the web app and local server +vertc dev +``` + +Open the URL printed in the terminal and click **Start** to join the room and talk. On the first run, `vertc` finds the RTC applications and conversational-AI agents in the account, prompting only when there is more than one choice. If setup or runtime fails, use `vertc doctor` to inspect the problem without changing the project. + +See [Voice-agent projects](./docs/voice-agent.md) for the generated layout, runtime options, and identity management. + +## Core capabilities + +- **Create and run projects** — `init` scaffolds a pinned official template. `dev` configures Console resources and starts the web app and local server. +- **Diagnose problems** — `doctor` reports PASS/WARN/SKIP/UNKNOWN/FAIL checks; `explain-error` looks up SDK and conversational-AI errors offline. +- **Use it from agents and scripts** — pipes and redirected output default to JSON, stdout contains data only, and failures return a stable `error.code`. Side-effecting commands support `--dry-run`. +- **Keep configuration and credentials separate** — project metadata, runtime secrets, scene data, and Signin credentials use separate storage. + +### Common commands + +| Command | Purpose | +| --- | --- | +| `init [dir] --scene --platform ` | List or scaffold supported project templates | +| `auth login` / `auth status` / `auth logout` | Manage the Volcengine Signin session | +| `dev [--reconfigure]` | Configure RTC resources and run the project | +| `doctor [cli\|project]` | Check CLI and project readiness without changing the project | +| `explain-error ` | Look up SDK and conversational-AI errors offline | +| `skills list/read/sync` | Inspect or synchronize the official Skill embedded in the current release | +| `update [--check\|--force]` | Check or update an npm-managed installation | + +Run `vertc --help` for prerequisites, complete options, and examples. + +## Agent and CI + +The official workflow Skill identifier is `byted-interactai-guide`: + +```bash +vertc skills sync +# or +npx skills add volcengine/VolcEngineRTC_CLI -g -y +``` + +Agents and automation scripts should pass `--format json` explicitly so their output does not depend on the terminal environment. stdout contains data only, while progress and warnings go to stderr. Failed commands return a non-zero exit code and a stable `error.code`. See [Automation and structured output](./docs/automation.md) for headless authorization, non-interactive resource selection, error handling, and notification settings. + +## Configuration and security + +- `vertc.config.yaml` contains only non-secret project metadata and `${ENV}` references. +- `.env.local` contains local runtime values. It is Gitignored and written with restricted permissions; never commit it. +- Signin credentials are stored in the protected `$VERTC_HOME/auth.json` file by default. You can opt in to the operating-system keyring. +- `RTC_APP_KEY` is never written to project configuration, `VITE_*` frontend variables, logs, command arguments, or structured output; never provide AppKey in chat. + +See [Automation and structured output](./docs/automation.md) for authentication modes, credential storage, and automation safety boundaries. See [SECURITY.md](./SECURITY.md) for vulnerability reporting. + +## Documentation + +- [Voice-agent projects](./docs/voice-agent.md) — generated layout, first-run configuration, runtime modes, and identity behavior +- [Automation and structured output](./docs/automation.md) — authentication, JSON envelopes, error routing, dry runs, notices, and Skills +- [Troubleshooting](./docs/troubleshooting.md) — installation, authentication, templates, credentials, and runtime recovery +- [CHANGELOG.md](./CHANGELOG.md) — release changes +- [SUPPORT.md](./SUPPORT.md) — where to ask questions or report bugs +- [CONTRIBUTING.md](./CONTRIBUTING.md) — development setup and contribution workflow + +## Development and contributing + +```bash +make build +make test +make ci +``` + +Read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a pull request. This project is licensed under the [MIT License](./LICENSE). diff --git a/README.md b/README.md index 2427c6c..d584820 100644 --- a/README.md +++ b/README.md @@ -1,242 +1,114 @@ # vertc [![CI](https://github.com/volcengine/VolcEngineRTC_CLI/actions/workflows/ci.yml/badge.svg)](https://github.com/volcengine/VolcEngineRTC_CLI/actions/workflows/ci.yml) +[![Release](https://img.shields.io/github/v/release/volcengine/VolcEngineRTC_CLI?label=release)](https://github.com/volcengine/VolcEngineRTC_CLI/releases) +[![npm](https://img.shields.io/npm/v/@volcengine/rtc-cli?label=npm)](https://www.npmjs.com/package/@volcengine/rtc-cli) [![Go Version](https://img.shields.io/badge/Go-%3E%3D1.25.12-00ADD8?logo=go)](./go.mod) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) -English | [简体中文](./README.zh-CN.md) +[English](./README.en.md) | 简体中文 -`vertc` is the Volcengine RTC developer-workflow CLI for creating, -configuring, diagnosing, and running AI audio/video projects. The current -release turns the official `rtc-aigc-demo` web voice-agent template into a -guided, runnable workflow for both developers and coding agents. +`vertc` 是火山引擎 RTC 的开发工作流 CLI,供开发者和 Coding Agent 创建、配置、运行和排查 AI 音视频项目。 -> **Current scope:** `voice-agent × web`. More scenes and platforms will be -> added only after their end-to-end workflows are ready. +> **当前范围:** `voice-agent × web`。其他场景和平台会在端到端工作流准备好后加入。 -[Quick start](#five-minute-quick-start) · [Agent & CI](#agent-and-ci-workflows) · -[Commands](#commands) · [Security](#configuration-and-security) · -[Documentation](#documentation) · [Contributing](#contributing) +[安装](#安装) · [快速开始](#快速开始) · [核心能力](#核心能力) · [Agent 与 CI](#agent-与-ci) · [安全](#配置与安全) · [文档](#文档) -## Why vertc? +## 安装 -- **One guided workflow** — scaffold a pinned official template, configure it - from the Console, check readiness, and start local development. -- **Console-aware setup** — Sign in once, then let the first `dev` run discover - your RTC applications and conversational-AI agents and configure the project. -- **Diagnostics first** — `doctor` reports evidence-based PASS/WARN/SKIP/UNKNOWN/FAIL checks; - `explain-error` provides an offline SDK and conversational-AI error catalog. -- **Agent-native output** — JSON is the default, stdout stays machine-readable, - errors have stable `error.code` values, and official Skills provide workflow - playbooks. - -## Requirements - -- macOS, Linux, or Windows on amd64 or arm64 -- Node.js 16 or later for the recommended npm installation -- Go 1.25.12 or later only when installing or building from source -- A Volcengine account with an RTC application; a conversational-AI agent is - optional because `dev` can use the built-in default scene -- Access to GitHub Releases for npm installation and GitHub codeload for the - first template download; later scaffolds can reuse the verified local cache - -## Install - -Install the prebuilt binary from npm: +预编译版本支持 macOS、Linux 和 Windows 的 amd64/arm64。使用 Node.js 16 或更高版本安装: ```bash npm install -g @volcengine/rtc-cli -vertc version --format pretty +vertc version ``` -The installer downloads the binary matching the package version and current -platform, then verifies it against the release `checksums.txt` before making it -available as `vertc`. - -You can also build from source: +安装器会从 GitHub Releases 下载对应版本和平台的二进制,并使用 `checksums.txt` 校验。从源码构建需要 Go 1.25.12 或更高版本: ```bash git clone https://github.com/volcengine/VolcEngineRTC_CLI.git cd VolcEngineRTC_CLI make build -./bin/vertc version --format pretty +./bin/vertc version ``` -Manually managed binaries are not overwritten by `vertc update`; the command -prints the appropriate upgrade guidance instead. - -## Five-minute quick start +## 快速开始 -You can start without creating a conversational-AI agent first. When the -signed-in account has no agent, `dev` uses the built-in default scene and links -to the Console for later customization. +开始前,账号下需要有一个 RTC 应用。对话式 AI 智能体不是必需的;如果没有,`dev` 会使用内置默认 Scene。 ```bash -# 1. Create the project from the verified rtc-aigc-demo template. -vertc init ./my-agent --scene voice-agent --platform web --format pretty +# 1. 创建项目 +vertc init ./my-agent --scene voice-agent --platform web cd my-agent -# 2. Sign in and store the refreshable Signin token. -vertc auth login --format pretty +# 2. 登录火山引擎 +vertc auth login -# 3. On first run, configure an RTC application and optionally select agents; -# vertc then writes the local runtime configuration and starts web + server. -vertc dev --format pretty +# 3. 配置 RTC 资源并启动 Web 应用和本地服务 +vertc dev ``` -The first positional argument to `init` is the target directory; here the -project is scaffolded into `./my-agent`. +打开终端给出的地址,点击 **Start** 即可进房对话。首次运行时,`vertc` 会查找账号下的 RTC 应用和智能体;有多个候选时再提示选择。配置或运行失败时,可以用 `vertc doctor` 检查问题;该命令不会修改项目。 -When authorization is needed, interactive `auth login` asks whether to open a -browser, use a manual link/code flow, or cancel. In an agent, remote, or -headless session, obtain user consent and run `vertc auth login --browser=open` -or use the resumable manual flow; no UI opens implicitly: +项目结构、运行方式和身份管理见[语音智能体项目](./docs/voice-agent.md)。 -```bash -# Agent turn 1: return data.authorization_url to the user, then exit. -vertc auth login --browser=manual --start +## 核心能力 -# Agent turn 2: send the code returned by that URL to the saved transaction. -printf '%s\n' '' | vertc auth login --resume -``` +- **创建和运行项目**:`init` 从固定版本的官方模板创建项目,`dev` 配置控制台资源并启动 Web 应用和本地服务。 +- **排查问题**:`doctor` 给出 PASS/WARN/SKIP/UNKNOWN/FAIL 检查结果;`explain-error` 可离线查询 SDK 与对话式 AI 错误码。 +- **用于 Agent 和脚本**:管道和重定向默认输出 JSON,stdout 只写数据,失败时返回稳定的 `error.code`。有副作用的命令支持 `--dry-run`。 +- **分开保存配置和凭据**:项目元数据、运行时密钥、场景数据和登录凭据各自存放。 -The second command must use `--resume`: starting `--browser=manual` again creates -a different OAuth state and invalidates the code from the first URL. A pending -manual authorization expires after `--timeout` (five minutes by default) and can -be consumed only once. The first interactive `dev` run automatically uses a -unique RTC application and prompts when a choice is required. If one or more -conversational-AI agents exist, the user chooses which to use; if none exist, -the built-in default scene is used. Run `vertc dev --reconfigure` to select -again later; existing bot scene files are preserved. - -When a usable Signin token is already stored, `auth login` reuses it (refreshing -it when near expiry) without prompting or opening a browser. Use -`vertc auth login --force` with an explicit browser mode to reauthorize or -switch accounts. - -Signin access and refresh tokens default to the protected -`$VERTC_HOME/auth.json` file (`~/.vertc/auth.json` when `VERTC_HOME` is unset). -Choose the operating-system credential store explicitly with -`vertc auth login --store=keyring`; later commands keep using the selected store. - -In an agent or another non-interactive terminal, run `vertc dev`. A -`vertc.dev.selection_required` error contains public candidates in -`error.details.apps` or `error.details.bots`; ask the user to choose, then retry -with `vertc dev --app-id ` or `vertc dev --bot-id `. -The signed-in CLI retrieves AppKey itself; never send AppKey to an agent or put -it in command arguments. - -The generated project contains the full `rtc-aigc-demo` web UI and local server. -After first-run configuration, `vertc dev` starts both processes; each browser -page session receives isolated room, user, token, task, and target-user -identities. Run `vertc doctor --format pretty` whenever setup or runtime fails; -it diagnoses without modifying the project. -See [Voice-agent projects](./docs/voice-agent.md) for the generated layout, -runtime modes, manual configuration, and advanced identity management. - -## Agent and CI workflows - -Register the official workflow Skill using either form: - -The published Skill identifier is `byted-interactai-guide`. +### 常用命令 -```bash -# From the installed CLI (no repository access required) -vertc skills sync +| 命令 | 用途 | +| --- | --- | +| `init [dir] --scene --platform ` | 列出或生成受支持的项目模板 | +| `auth login` / `auth status` / `auth logout` | 管理火山引擎登录状态 | +| `dev [--reconfigure]` | 配置 RTC 资源并运行项目 | +| `doctor [cli\|project]` | 检查 CLI 和项目是否就绪,不修改项目 | +| `explain-error ` | 离线查询 SDK 与对话式 AI 错误码 | +| `skills list/read/sync` | 查看或同步当前 Release 内嵌的官方 Skill | +| `update [--check\|--force]` | 检查或更新 npm 管理的安装 | -# Or directly from the public repository -npx skills add volcengine/VolcEngineRTC_CLI -g -y -``` +运行 `vertc --help` 查看前置条件、完整参数和示例。 + +## Agent 与 CI -Agent and automation runs should keep the default JSON format: +官方工作流 Skill 标识为 `byted-interactai-guide`: ```bash -vertc init ./my-agent --scene voice-agent --platform web -cd my-agent -vertc auth status -vertc dev -vertc doctor +vertc skills sync +# 或 +npx skills add volcengine/VolcEngineRTC_CLI -g -y ``` -- stdout contains one JSON envelope with `ok` plus `data` or `error`. -- progress, warnings, and recovery hints go to stderr. -- failures use non-zero exit codes and stable `error.code` values. -- side-effecting commands accept the global `--dry-run` flag. -- `VERTC_NO_UPDATE_NOTIFIER=1` and `VERTC_NO_SKILLS_NOTIFIER=1` suppress - additive lifecycle notices when required by a controlled environment. +Agent 和自动化脚本应显式传入 `--format json`,避免输出格式受终端环境影响。stdout 只写数据,进度和警告写入 stderr;命令失败时返回非零退出码和稳定的 `error.code`。无界面授权、非交互资源选择、错误处理和通知设置见[自动化与结构化输出](./docs/automation.md)。 -See [Automation and structured output](./docs/automation.md) for headless -authorization, non-interactive resource selection, JSON envelopes, failure -routing, and Skill contracts. +## 配置与安全 -## Commands +- `vertc.config.yaml` 只保存非敏感项目元数据和 `${ENV}` 引用。 +- `.env.local` 保存本地运行值。该文件已被 Git 忽略,并以受限权限写入;不要提交。 +- Signin 凭据默认保存在受保护的 `$VERTC_HOME/auth.json`。也可以主动选择系统 keyring。 +- `RTC_APP_KEY` 不会写入项目配置、`VITE_*` 前端变量、日志、命令参数或结构化输出;不要在聊天中提供 AppKey。 -| Command | Purpose | -| --- | --- | -| `init [dir] --scene --platform ` | List or scaffold supported project templates into `[dir]`; supports `--dry-run` | -| `auth login [--browser=ask\|open\|manual] [--start\|--resume] [--store=file\|keyring]` / `auth status/logout` | Manage Volcengine Signin credentials with explicit UI, resumable Agent login, and storage choices | -| `doctor [cli\|project]` | Diagnose CLI and project readiness without modifying the project | -| `dev [--reconfigure] [--app-id ] [--bot-id ]` | Configure RTC resources and run the template; unambiguous choices are automatic, selection errors return public candidates, and zero agents use the built-in default scene | -| `explain-error ` | Look up Web SDK and conversational-AI errors offline | -| `skills list/read/sync` | Inspect, install, or refresh the official Skill content embedded in this release | -| `update [--check\|--force] [--dry-run]` | Check, preview, or update npm-managed installs and synchronize official Skills | -| `version` | Print build version, commit, and date | - -Run `vertc --help` for prerequisites, examples, and advice about when -to use or avoid each command. Advanced manual/debugging commands remain hidden -from the main help so the supported onboarding path stays small. - -## Configuration and security - -`vertc` deliberately separates project metadata, runtime secrets, scene data, -and Signin credentials: - -| Location | Contains | Safety boundary | -| --- | --- | --- | -| `vertc.config.yaml` | Non-secret project metadata and CLI-managed RTC/agent identity references | Safe to review; secrets are referenced through `${ENV}` placeholders | -| `.env.local` | Local runtime values such as `RTC_APP_ID` and `RTC_APP_KEY` | Gitignored and written with restricted permissions; never commit it | -| `server/scenes/*.json` | VoiceChat ASR/LLM/TTS and agent configuration selected from the Console | Server-side scene configuration; review before sharing | -| `$VERTC_HOME/auth.json` (default `~/.vertc/auth.json`) | Selected store and, in `file` mode, Signin access/refresh tokens | Directory `0700`, file `0600`; treat it like a password and never commit it | -| OS credential store (optional `keyring` mode) | Signin access and refresh tokens | Used only after explicit `auth login --store=keyring` selection | - -`RTC_APP_KEY` is never written to `vertc.config.yaml`, a `VITE_*` frontend -variable, logs, or structured output. It may be stored in the gitignored -`.env.local` file so new shells and the companion server can use it. Exported -process environment variables take precedence over values in that file. Never -provide AppKey in chat or command arguments. - -For vulnerability reporting, see [SECURITY.md](./SECURITY.md). Do not include -credentials, tokens, private endpoints, or sensitive Console data in a public -issue. - -## Documentation - -- [Voice-agent projects](./docs/voice-agent.md) — generated layout, first-run - configuration, runtime modes, and identity behavior -- [Automation and structured output](./docs/automation.md) — JSON envelopes, - error routing, dry runs, notices, and Skills -- [Troubleshooting](./docs/troubleshooting.md) — installation, authentication, - template, credential, and runtime recovery -- [CONTRIBUTING.md](./CONTRIBUTING.md) — setup and contribution recipes -- [AGENTS.md](./AGENTS.md) — architecture and repository engineering contracts -- [SUPPORT.md](./SUPPORT.md) — where to ask questions or report bugs -- [CHANGELOG.md](./CHANGELOG.md) — release changes - -## Development +认证模式、凭据存储和自动化安全边界见[自动化与结构化输出](./docs/automation.md);漏洞报告方式见 [SECURITY.md](./SECURITY.md)。 -```bash -make build # build ./bin/vertc with version metadata -make test # unit and end-to-end tests -make check-error-codes # validate the stable error.code catalog -make ci # run the complete repository gate -``` +## 文档 -## Contributing +- [语音智能体项目](./docs/voice-agent.md):生成目录、首次配置、运行模式与身份行为 +- [自动化与结构化输出](./docs/automation.md):认证、JSON 信封、错误路由、dry-run、通知与 Skills +- [故障排查](./docs/troubleshooting.md):安装、登录、模板、凭据和运行时恢复 +- [CHANGELOG.md](./CHANGELOG.md):版本变更 +- [SUPPORT.md](./SUPPORT.md):问题咨询与 Bug 报告渠道 +- [CONTRIBUTING.md](./CONTRIBUTING.md):开发环境与贡献流程 -Contributions are welcome. Read [CONTRIBUTING.md](./CONTRIBUTING.md) before -opening a pull request, and use [SUPPORT.md](./SUPPORT.md) to choose the right -channel for questions, bugs, feature requests, and security reports. +## 开发与贡献 -## License +```bash +make build +make test +make ci +``` -This project is licensed under the [MIT License](./LICENSE). +提交 Pull Request 前请阅读 [CONTRIBUTING.md](./CONTRIBUTING.md)。本项目采用 [MIT License](./LICENSE)。 diff --git a/README.zh-CN.md b/README.zh-CN.md deleted file mode 100644 index 261408a..0000000 --- a/README.zh-CN.md +++ /dev/null @@ -1,198 +0,0 @@ -# vertc - -[![CI](https://github.com/volcengine/VolcEngineRTC_CLI/actions/workflows/ci.yml/badge.svg)](https://github.com/volcengine/VolcEngineRTC_CLI/actions/workflows/ci.yml) -[![Go Version](https://img.shields.io/badge/Go-%3E%3D1.25.12-00ADD8?logo=go)](./go.mod) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) - -[English](./README.md) | 简体中文 - -`vertc` 是面向火山引擎 RTC 开发工作流的 CLI,用于创建、配置、诊断和运行 -AI 音视频项目。当前版本将官方 `rtc-aigc-demo` Web 语音智能体模板整理为一套 -开发者和 Coding Agent 都可以执行的引导式工作流。 - -> **当前范围:** `voice-agent × web`。其他场景和平台会在端到端工作流准备好后 -> 再加入公开版本。 - -[快速开始](#五分钟快速开始) · [Agent 与 CI](#agent-与-ci-工作流) · -[命令](#命令) · [安全](#配置与安全) · [文档](#文档) · [参与贡献](#参与贡献) - -## 为什么选择 vertc? - -- **一套引导式工作流**:生成固定版本的官方模板,从控制台完成配置,检查就绪状态, - 然后启动本地开发环境。 -- **感知控制台配置**:登录一次,首次运行 `dev` 时发现账号下的 RTC 应用和对话式 - AI 智能体,并配置当前项目。 -- **诊断优先**:`doctor` 输出可执行的 PASS/WARN/FAIL 检查;`explain-error` 可离线 - 查询 SDK 与对话式 AI 错误码。 -- **Agent 原生输出**:默认输出 JSON,stdout 保持机器可读,错误提供稳定 - `error.code`,官方 Skills 提供完整工作流剧本。 - -## 环境要求 - -- macOS、Linux 或 Windows,支持 amd64 和 arm64 -- 推荐通过 npm 安装,需要 Node.js 16 或更高版本 -- 仅从源码安装或构建时需要 Go 1.25.12 或更高版本 -- 火山引擎账号下已有 RTC 应用;对话式 AI 智能体为可选,`dev` 可使用内置默认 Scene -- npm 安装需要访问 GitHub Releases;首次下载模板需要访问 GitHub codeload,之后可 - 复用已校验的本地缓存 - -## 安装 - -推荐通过 npm 安装预编译二进制: - -```bash -npm install -g @volcengine/rtc-cli -vertc version --format pretty -``` - -安装器会下载与 npm 包版本和当前平台匹配的二进制,并根据 Release 中的 -`checksums.txt` 完成校验后再将其暴露为 `vertc`。 - -也可以从源码构建: - -```bash -git clone https://github.com/volcengine/VolcEngineRTC_CLI.git -cd VolcEngineRTC_CLI -make build -./bin/vertc version --format pretty -``` - -`vertc update` 不会覆盖手工管理的二进制,而会输出对应安装方式的升级指引。 - -## 五分钟快速开始 - -无需预先创建对话式 AI 智能体。登录账号下没有智能体时,`dev` 会使用内置默认 Scene -快速启动,并提供控制台地址供后续定制。 - -```bash -# 1. 从经过校验的 rtc-aigc-demo 模板创建项目。 -vertc init ./my-agent --scene voice-agent --platform web --format pretty -cd my-agent - -# 2. 登录并保存可刷新的 Signin Token。 -vertc auth login --format pretty - -# 3. 首次运行时配置 RTC 应用,并按需选择智能体;vertc 写入本地运行配置后, -# 启动 Web 应用和配套服务端。 -vertc dev --format pretty -``` - -需要授权时,交互式 `auth login` 会先询问打开浏览器、使用手动链接/授权码或取消。 -在 Agent、远程或无图形界面的终端中,先获得用户同意,再显式运行 -`vertc auth login --browser=open` 或 `vertc auth login --browser=manual`;CLI 不会隐式弹出 UI。 -首次交互式 `dev` 会自动使用唯一 RTC 应用;存在一个或 -多个智能体时要求用户选择,确认没有智能体时使用内置默认 Scene。之后可运行 -`vertc dev --reconfigure` 重新选择;已有 Bot Scene 文件会保留。 - -当前 store 中已有可用 Signin Token 时,`auth login` 会直接复用(临近过期时先刷新), -不会询问或打开浏览器。如需重新授权或切换账号,组合使用 `--force` 和显式 browser 模式。 -Signin access/refresh token 默认保存在受保护的 `$VERTC_HOME/auth.json`(默认 -`~/.vertc/auth.json`);运行 `vertc auth login --store=keyring` 可显式改用系统凭据存储。 - -在 Agent 或其他非交互终端中直接运行 `vertc dev`。若返回 -`vertc.dev.selection_required`,从 `error.details.apps` 或 `error.details.bots` 读取公开 -候选,询问用户后用 `--app-id ` 或 `--bot-id ` 重试。 -CLI 会通过登录态自行获取 AppKey;不要把 AppKey 发给 Agent 或放入命令参数。 - -生成的项目包含完整 `rtc-aigc-demo` Web UI 和本地服务。首次配置完成后,`vertc dev` -会启动两个进程;每个浏览器页面 session 都拥有独立的房间、用户、Token、Task 和 -目标用户身份。配置或运行失败时可执行 `vertc doctor --format pretty`;它只做诊断, -不会修改项目。项目结构、运行模式、手动配置和高级身份管理详见 -[语音智能体项目](./docs/voice-agent.md)。 - -## Agent 与 CI 工作流 - -可用以下任一方式注册官方工作流 Skill: - -发布标识为 `byted-interactai-guide`。 - -```bash -# 通过已安装的 CLI(无需仓库权限) -vertc skills sync - -# 或直接从公开仓库注册 -npx skills add volcengine/VolcEngineRTC_CLI -g -y -``` - -Agent 和自动化运行应保留默认 JSON 格式: - -```bash -vertc init ./my-agent --scene voice-agent --platform web -cd my-agent -vertc auth status -vertc dev -vertc doctor -``` - -- stdout 输出一个 JSON 信封,包含 `ok` 以及 `data` 或 `error`。 -- 进度、警告和恢复提示写入 stderr。 -- 失败使用非零退出码和稳定 `error.code`。 -- 有副作用的命令支持全局 `--dry-run`。 -- 受控环境可设置 `VERTC_NO_UPDATE_NOTIFIER=1` 和 - `VERTC_NO_SKILLS_NOTIFIER=1`,关闭附加的生命周期通知。 - -无界面授权、非交互资源选择、JSON 信封、错误路由和 Skill 契约详见 -[自动化与结构化输出](./docs/automation.md)。 - -## 命令 - -| 命令 | 用途 | -| --- | --- | -| `init [dir] --scene --platform ` | 离线列出或生成受支持的项目模板到 `[dir]`;支持 `--dry-run` | -| `auth login [--browser=ask\|open\|manual] [--store=file\|keyring]` / `auth status/logout` | 以显式 UI 与存储选择管理火山引擎登录凭证 | -| `doctor [cli\|project]` | 只读诊断 CLI 与项目就绪状态 | -| `dev [--reconfigure] [--app-id ] [--bot-id ]` | 补全 RTC 配置并执行模板;无歧义时自动选择,有歧义时返回公开候选,零智能体时使用内置默认 Scene | -| `explain-error ` | 离线查询 Web SDK 与对话式 AI 错误码 | -| `skills list/read/sync` | 查看、安装或刷新当前 Release 内嵌的官方 Skill 内容 | -| `update [--check\|--force]` | 检查或更新 npm 管理的安装,并同步官方 Skills | -| `version` | 输出构建版本、commit 和日期 | - -运行 `vertc --help` 可查看前置条件、示例和适用/不适用场景。高级手动及调试 -命令不会出现在主帮助中,以保持公开接入路径精简。 - -## 配置与安全 - -`vertc` 将项目元数据、运行时密钥、场景数据和登录凭证分开管理: - -| 位置 | 内容 | 安全边界 | -| --- | --- | --- | -| `vertc.config.yaml` | 非敏感项目元数据及 CLI 管理的 RTC/Agent 身份引用 | 可审阅;敏感值通过 `${ENV}` 占位引用 | -| `.env.local` | `RTC_APP_ID`、`RTC_APP_KEY` 等本地运行值 | 已被 Git 忽略并以受限权限写入;禁止提交 | -| `server/scenes/*.json` | 从控制台选择的 VoiceChat ASR/LLM/TTS 与智能体配置 | 服务端场景配置;分享前应检查 | -| `$VERTC_HOME/auth.json`(默认 `~/.vertc/auth.json`) | store 选择;`file` 模式下还包含登录 access/refresh token | 目录 `0700`、文件 `0600`;应像密码一样保护且禁止提交 | -| 操作系统凭据存储(可选 `keyring` 模式) | 登录 access/refresh token | 仅在显式运行 `auth login --store=keyring` 后使用 | - -`RTC_APP_KEY` 不会写入 `vertc.config.yaml`、任何 `VITE_*` 前端变量、日志或结构化输出。 -为了让新 shell 和配套服务端可复用,它可能保存在已被 Git 忽略的 `.env.local` 中。 -进程中显式导出的环境变量优先于该文件中的值。禁止在聊天或命令参数中提供 AppKey。 - -漏洞报告方式见 [SECURITY.md](./SECURITY.md)。请勿在公开 Issue 中提交凭证、Token、 -私有 endpoint 或敏感控制台数据。 - -## 文档 - -- [语音智能体项目](./docs/voice-agent.md):生成目录、首次配置、运行模式与身份行为 -- [自动化与结构化输出](./docs/automation.md):JSON 信封、错误路由、dry-run、通知与 Skills -- [故障排查](./docs/troubleshooting.md):安装、登录、模板、凭证和运行时恢复 -- [CONTRIBUTING.md](./CONTRIBUTING.md):开发环境与贡献流程 -- [AGENTS.md](./AGENTS.md):架构和仓库工程契约 -- [SUPPORT.md](./SUPPORT.md):问题咨询与 Bug 报告渠道 -- [CHANGELOG.md](./CHANGELOG.md):版本变更 - -## 开发 - -```bash -make build # 构建 ./bin/vertc 并注入版本信息 -make test # 运行单元测试和端到端测试 -make check-error-codes # 校验稳定 error.code 目录 -make ci # 运行完整仓库门禁 -``` - -## 参与贡献 - -欢迎参与贡献。提交 Pull Request 前请阅读 [CONTRIBUTING.md](./CONTRIBUTING.md), -问题咨询、Bug、功能建议和安全报告的渠道选择见 [SUPPORT.md](./SUPPORT.md)。 - -## 许可证 - -本项目采用 [MIT License](./LICENSE)。 diff --git a/RELEASING.md b/RELEASING.md index 047eede..5a236d0 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -14,10 +14,11 @@ archived Skills, archive names, checksums, and npm metadata. | Tag | GitHub channel | npm channel | | --- | --- | --- | | `vX.Y.Z` | Latest release | `latest` | -| `vX.Y.Z-ID` | Pre-release, not Latest | `latest` | +| `vX.Y.Z-ID` | Pre-release, not Latest | `next` | For example, `v0.0.1-rc.1` produces a GitHub Pre-release that is not Latest, -while npm `latest` resolves to `@volcengine/rtc-cli@0.0.1-rc.1`. +while npm `next` resolves to `@volcengine/rtc-cli@0.0.1-rc.1` and npm +`latest` remains unchanged. ## Prerequisites diff --git a/cmd/root.go b/cmd/root.go index 3effe41..8acdf39 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -34,12 +34,23 @@ var ( // out builds an output.Writer from the current --format flag. func out() *output.Writer { - f, err := output.ParseFormat(flagFormat) + f := resolveOutputFormat(flagFormat, isTerminal(os.Stdout)) + return output.New(f) +} + +func resolveOutputFormat(requested string, stdoutTTY bool) output.Format { + if requested == "" { + if stdoutTTY { + return output.FormatPretty + } + return output.FormatJSON + } + f, err := output.ParseFormat(requested) if err != nil { // Fall back to JSON; the bad value is reported by the command itself. f = output.FormatJSON } - return output.New(f) + return f } // NewRootCmd builds the root command with all subcommands registered. @@ -79,8 +90,8 @@ func NewRootCmd() *cobra.Command { // runnable but is hidden (see TestRootCommandSurface). root.CompletionOptions.HiddenDefaultCmd = true - root.PersistentFlags().StringVar(&flagFormat, "format", "json", - "output format: json|pretty|table") + root.PersistentFlags().StringVar(&flagFormat, "format", "", + "output format: json|pretty|table (default: pretty in a terminal, json otherwise)") root.PersistentFlags().BoolVar(&flagDryRun, "dry-run", false, "preview side effects without applying them") diff --git a/cmd/root_test.go b/cmd/root_test.go index 4deeba2..a0b0b8a 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -8,8 +8,50 @@ import ( "os" "sort" "testing" + + "github.com/volcengine/VolcEngineRTC_CLI/internal/output" ) +func TestResolveOutputFormatDefaultsToPrettyInTerminal(t *testing.T) { + got := resolveOutputFormat("", true) + if got != output.FormatPretty { + t.Fatalf("terminal default = %q, want %q", got, output.FormatPretty) + } +} + +func TestResolveOutputFormatDefaultsToJSONOutsideTerminal(t *testing.T) { + got := resolveOutputFormat("", false) + if got != output.FormatJSON { + t.Fatalf("non-terminal default = %q, want %q", got, output.FormatJSON) + } +} + +func TestResolveOutputFormatHonorsExplicitFormat(t *testing.T) { + for _, tc := range []struct { + requested string + stdoutTTY bool + want output.Format + }{ + {requested: "json", stdoutTTY: true, want: output.FormatJSON}, + {requested: "pretty", stdoutTTY: false, want: output.FormatPretty}, + {requested: "table", stdoutTTY: false, want: output.FormatTable}, + } { + if got := resolveOutputFormat(tc.requested, tc.stdoutTTY); got != tc.want { + t.Errorf("resolveOutputFormat(%q, %t) = %q, want %q", tc.requested, tc.stdoutTTY, got, tc.want) + } + } +} + +func TestFormatFlagUsesTerminalAwareDefault(t *testing.T) { + format := NewRootCmd().PersistentFlags().Lookup("format") + if format == nil { + t.Fatal("--format flag is not registered") + } + if format.DefValue != "" { + t.Fatalf("--format default = %q, want terminal-aware default", format.DefValue) + } +} + // TestRootCommandSurface pins the public command surface. Visible // commands are what `vertc --help` lists; hidden commands stay registered and // runnable (advanced/manual/legacy fallbacks: env/config/token, the internal diff --git a/docs/automation.md b/docs/automation.md index 4496532..f1f4c6d 100644 --- a/docs/automation.md +++ b/docs/automation.md @@ -1,14 +1,14 @@ # Automation and structured output -`vertc` defaults to JSON because its command results are designed to be consumed -by coding agents, scripts, and CI. Human users can select `--format pretty` or -`--format table`. +`vertc` uses readable output when stdout is a terminal and JSON when stdout is +piped or redirected. Coding agents, scripts, and CI should pass `--format json` +explicitly so their output does not depend on the terminal environment. ## Stream contract - stdout contains command data only. - stderr contains progress, warnings, and recovery hints. -- a command writes one JSON envelope to stdout. +- in JSON mode, a command writes one envelope to stdout. - success exits with code 0; failure exits non-zero. A successful result has this shape: @@ -41,8 +41,8 @@ human-language messages. ## Output formats ```bash -vertc doctor # default JSON -vertc doctor --format json +vertc doctor # pretty in a terminal, JSON when redirected +vertc doctor --format json # stable choice for automation vertc doctor --format pretty vertc init --list --format table ``` diff --git a/internal/skillscan/byted_interactai_guide_content_test.go b/internal/skillscan/byted_interactai_guide_content_test.go index 97a254e..a08cc0f 100644 --- a/internal/skillscan/byted_interactai_guide_content_test.go +++ b/internal/skillscan/byted_interactai_guide_content_test.go @@ -303,7 +303,7 @@ func TestAgentFacingDocsNeverRecommendAppKeyArgument(t *testing.T) { root := moduleRoot(t) for _, rel := range []string{ "README.md", - "README.zh-CN.md", + "README.en.md", "docs/automation.md", "docs/troubleshooting.md", "docs/voice-agent.md", @@ -321,7 +321,26 @@ func TestAgentFacingDocsNeverRecommendAppKeyArgument(t *testing.T) { func TestSkillLifecycleNoticePolicy(t *testing.T) { skill := readSkillFile(t, "SKILL.md") - for _, marker := range []string{"先完成并验证当前任务", "不要擅自执行", "_notice.update", "vertc update", "_notice.skills", "vertc skills sync", "VERTC_NO_UPDATE_NOTIFIER", "VERTC_NO_SKILLS_NOTIFIER"} { + for _, marker := range []string{ + "每次读取 `vertc --format json`", + "成功或失败输出", + "不能只检查", + "不得静默", + "完成并验证当前用户任务后", + "必须向用户简短提示对应命令", + "两者同时出现就都提示", + "不要擅自执行", + "_notice.update", + "vertc update", + "_notice.skills", + "vertc skills sync", + "冷缓存首次调用可能没有 notice", + "不代表已是最新版", + "不要为了等待 notice", + "继续检查本任务后续每条 `vertc` JSON 输出", + "VERTC_NO_UPDATE_NOTIFIER", + "VERTC_NO_SKILLS_NOTIFIER", + } { if !strings.Contains(skill, marker) { t.Errorf("SKILL.md lifecycle policy missing %q", marker) } diff --git a/internal/update/update_test.go b/internal/update/update_test.go index 3464f6b..68fbeb2 100644 --- a/internal/update/update_test.go +++ b/internal/update/update_test.go @@ -74,6 +74,45 @@ func TestRefreshAndCheckCached(t *testing.T) { } } +func TestColdCacheBecomesVisibleOnlyAfterRefresh(t *testing.T) { + dir := t.TempDir() + t.Setenv("VERTC_STATE_DIR", dir) + clearAutomationEnvironment(t) + t.Setenv("VERTC_NO_UPDATE_NOTIFIER", "") + oldURL, oldClient, oldNow := registryURL, httpClient, now + requests := 0 + registryURL = "https://registry.npmjs.org/test" + httpClient = &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) { + requests++ + return &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(strings.NewReader(`{"version":"1.2.0"}`)), + }, nil + })} + now = func() time.Time { return time.Unix(1000, 0) } + t.Cleanup(func() { registryURL, httpClient, now = oldURL, oldClient, oldNow; SetPending(nil) }) + + if info := CheckCached("1.0.0"); info != nil { + t.Fatalf("cold cache unexpectedly returned notice: %+v", info) + } + if requests != 0 { + t.Fatalf("cache-only check made %d network requests", requests) + } + + if err := RefreshCache(context.Background(), "1.0.0"); err != nil { + t.Fatal(err) + } + if requests != 1 { + t.Fatalf("refresh made %d network requests, want 1", requests) + } + if info := CheckCached("1.0.0"); info == nil || info.Latest != "1.2.0" { + t.Fatalf("refreshed cache did not expose update: %+v", info) + } + if requests != 1 { + t.Fatalf("post-refresh cache check made a network request; total=%d", requests) + } +} + func TestNotifierGates(t *testing.T) { t.Setenv("VERTC_STATE_DIR", t.TempDir()) t.Setenv("VERTC_NO_UPDATE_NOTIFIER", "1") diff --git a/scripts/build-release-artifacts_test.sh b/scripts/build-release-artifacts_test.sh index aaefc20..f7c9f61 100755 --- a/scripts/build-release-artifacts_test.sh +++ b/scripts/build-release-artifacts_test.sh @@ -78,7 +78,7 @@ if ! grep -Fq 'queue: max' "$workflow"; then fi build_line="$(grep -n 'name: Build and verify all seven release assets' "$workflow" | cut -d: -f1)" npm_input_line="$(grep -n 'name: Prepare verified npm package input' "$workflow" | cut -d: -f1)" -publish_line="$(grep -n 'name: Stage draft, publish npm latest, then finalize GitHub release' "$workflow" | cut -d: -f1)" +publish_line="$(grep -n 'name: Stage draft, publish npm package, then finalize GitHub release' "$workflow" | cut -d: -f1)" verify_line="$(grep -n 'name: Verify GitHub and npm publication' "$workflow" | cut -d: -f1)" [[ "$build_line" -lt "$npm_input_line" && "$npm_input_line" -lt "$publish_line" && "$publish_line" -lt "$verify_line" ]] grep -Fq -- '--skip=publish' "$repo_root/scripts/build-release-artifacts.sh" @@ -97,7 +97,17 @@ grep -Fq './scripts/verify-release-publication.sh' "$workflow" grep -Fq 'git cat-file -t "refs/tags/$GITHUB_REF_NAME"' "$workflow" grep -Fq 'test "${#assets[@]}" -eq 7' "$workflow" grep -Fq -- '--publication public' "$workflow" -grep -Fq -- '--npm-tag latest' "$workflow" +grep -Fq 'npm_tag=latest' "$workflow" +grep -Fq 'npm_tag=next' "$workflow" +grep -Fq 'echo "VERTC_NPM_TAG=$npm_tag"' "$workflow" +if [[ "$(grep -Fc -- '--npm-tag "$VERTC_NPM_TAG"' "$workflow")" -ne 2 ]]; then + echo "build-release-artifacts-test: publication and verification must share the resolved npm dist-tag" >&2 + exit 1 +fi +if grep -Fq -- '--npm-tag latest' "$workflow"; then + echo "build-release-artifacts-test: workflow still hard-codes npm latest" >&2 + exit 1 +fi grep -Fq -- '--prerelease "$VERTC_PRERELEASE"' "$workflow" grep -Fq 'stability=prerelease' "$workflow" grep -Fq 'prerelease=true' "$workflow" diff --git a/scripts/publish-release-assets_test.sh b/scripts/publish-release-assets_test.sh index 5429672..3e9a915 100755 --- a/scripts/publish-release-assets_test.sh +++ b/scripts/publish-release-assets_test.sh @@ -119,9 +119,10 @@ case "$1" in [[ -f "$TEST_STATE/npm.shasum" ]] || exit 1 jq -Rn --arg value "$(cat "$TEST_STATE/npm.shasum")" '$value' ;; - dist-tags.latest) - [[ "${FAIL_NPM_LATEST_LOOKUP:-0}" == 0 ]] || exit 43 - jq -Rn --arg value "$(cat "$TEST_STATE/npm.latest" 2>/dev/null || true)" '$value' + dist-tags.*) + [[ "${FAIL_NPM_TAG_LOOKUP:-0}" == 0 ]] || exit 43 + npm_tag="${field#dist-tags.}" + jq -Rn --arg value "$(cat "$TEST_STATE/npm.$npm_tag" 2>/dev/null || true)" '$value' ;; *) echo "unexpected npm view: $*" >&2; exit 2 ;; esac @@ -129,12 +130,23 @@ case "$1" in publish) printf 'attempt\n' >> "$TEST_STATE/npm.attempts" [[ "${FAIL_NPM:-0}" == 0 ]] || exit 42 + shift + package_tarball="$1"; shift + npm_tag="" + while [[ $# -gt 0 ]]; do + case "$1" in + --tag) npm_tag="$2"; shift 2 ;; + *) shift ;; + esac + done + [[ -n "$npm_tag" ]] printf 'publish\n' >> "$TEST_STATE/npm.log" - shasum -a 1 "$2" | awk '{print $1}' > "$TEST_STATE/npm.shasum" - printf '%s\n' "$TEST_VERSION" > "$TEST_STATE/npm.latest" + shasum -a 1 "$package_tarball" | awk '{print $1}' > "$TEST_STATE/npm.shasum" + printf '%s\n' "$TEST_VERSION" > "$TEST_STATE/npm.$npm_tag" ;; dist-tag) - printf '%s\n' "$TEST_VERSION" > "$TEST_STATE/npm.latest" + [[ "$2" == add && -n "${4:-}" ]] + printf '%s\n' "$TEST_VERSION" > "$TEST_STATE/npm.$4" ;; *) echo "unexpected npm command: $*" >&2; exit 2 ;; esac @@ -149,9 +161,10 @@ if [[ -z "${REAL_NPM:-}" ]]; then # PATH now resolves the fake npm; locate the real executable explicitly. export REAL_NPM="$(PATH="${PATH#*:}" command -v npm)" fi -publish=("$repo_root/scripts/publish-release-assets.sh" --tag v0.0.1-rc.1 --target "$target" --artifacts "$artifacts" --npm-root "$npm_root" --notes-file "$notes" --prerelease true --latest false --npm-tag latest) +printf '0.0.0\n' > "$state/npm.latest" +publish=("$repo_root/scripts/publish-release-assets.sh" --tag v0.0.1-rc.1 --target "$target" --artifacts "$artifacts" --npm-root "$npm_root" --notes-file "$notes" --prerelease true --latest false --npm-tag next) -if (cd "$fixture" && "${publish[@]:0:${#publish[@]}-4}" --prerelease true --latest true --npm-tag latest) >/dev/null 2>&1; then +if (cd "$fixture" && "${publish[@]:0:${#publish[@]}-4}" --prerelease true --latest true --npm-tag next) >/dev/null 2>&1; then echo "publish-release-assets-test: impossible prerelease/latest combination was accepted" >&2 exit 1 fi @@ -168,12 +181,12 @@ if [[ "$(grep -c '^attempt$' "$state/npm.attempts")" -ne 1 ]]; then fi # Registry lookup failures must stop before any npm write is attempted. -if (cd "$fixture" && FAIL_NPM=1 FAIL_NPM_LATEST_LOOKUP=1 "${publish[@]}") >/dev/null 2>&1; then - echo "publish-release-assets-test: npm latest lookup failure was ignored" >&2 +if (cd "$fixture" && FAIL_NPM=1 FAIL_NPM_TAG_LOOKUP=1 "${publish[@]}") >/dev/null 2>&1; then + echo "publish-release-assets-test: npm dist-tag lookup failure was ignored" >&2 exit 1 fi if [[ "$(grep -c '^attempt$' "$state/npm.attempts")" -ne 1 ]]; then - echo "publish-release-assets-test: npm write was attempted after latest lookup failure" >&2 + echo "publish-release-assets-test: npm write was attempted after dist-tag lookup failure" >&2 exit 1 fi @@ -207,7 +220,8 @@ mv "$state/release.tmp" "$state/release.json" [[ "$(jq -r '.isDraft' "$state/release.json")" == false ]] [[ "$(jq -r '.isPrerelease' "$state/release.json")" == true ]] grep -Fq -- '--latest=false' "$state/gh.log" -[[ "$(cat "$state/npm.latest")" == 0.0.1-rc.1 ]] +[[ "$(cat "$state/npm.next")" == 0.0.1-rc.1 ]] +[[ "$(cat "$state/npm.latest")" == 0.0.0 ]] [[ "$(grep -c '^create$' "$state/gh.log")" -eq 1 ]] [[ "$(grep -c '^upload$' "$state/gh.log")" -eq 1 ]] @@ -216,14 +230,15 @@ grep -Fq -- '--latest=false' "$state/gh.log" [[ "$(grep -c '^create$' "$state/gh.log")" -eq 1 ]] [[ "$(grep -c '^publish$' "$state/npm.log")" -eq 1 ]] -# Rerunning an older workflow must never roll npm latest backward. -printf '0.0.2\n' > "$state/npm.latest" +# Rerunning an older workflow must never roll the selected npm channel backward. +printf '0.0.2\n' > "$state/npm.next" if (cd "$fixture" && "${publish[@]}") >/dev/null 2>&1; then - echo "publish-release-assets-test: older retry was allowed to move npm latest backward" >&2 + echo "publish-release-assets-test: older retry was allowed to move npm next backward" >&2 exit 1 fi -[[ "$(cat "$state/npm.latest")" == 0.0.2 ]] -printf '%s\n' "$TEST_VERSION" > "$state/npm.latest" +[[ "$(cat "$state/npm.next")" == 0.0.2 ]] +[[ "$(cat "$state/npm.latest")" == 0.0.0 ]] +printf '%s\n' "$TEST_VERSION" > "$state/npm.next" # Conflicting npm content leaves the GitHub Release safely in draft state. jq '.isDraft=true' "$state/release.json" > "$state/release.tmp" diff --git a/skills/byted-interactai-guide/SKILL.md b/skills/byted-interactai-guide/SKILL.md index 8274286..2a9a3e9 100644 --- a/skills/byted-interactai-guide/SKILL.md +++ b/skills/byted-interactai-guide/SKILL.md @@ -126,9 +126,14 @@ verification)给出结论。完整分阶段路由见 `references/integration-f 指向本地编辑器或密钥管理工作流。 - Voice Agent 错误知识已按火山官方「事件和错误码」「公共错误码」核验为 `verified`;无逐项 公开来源的登录凭证与签名排障条目标为 `curated-seed`,输出会显式提示以官方为准。 -- 生命周期 notice 不得打断当前用户任务:先完成并验证当前任务,再向用户说明。不要擅自执行 - 自动更新;仅在用户明确要求时运行命令。`_notice.update` 指向 `vertc update`, - `_notice.skills` 指向 `vertc skills sync`。受控自动化可分别设置 +- 每次读取 `vertc --format json` 的成功或失败输出时,都必须检查顶层 `_notice`,不能只检查 + 首次 `version` 输出。只要观察到 `_notice.update` 或 `_notice.skills`,先记住它,不得静默 + 丢弃;完成并验证当前用户任务后,必须向用户简短提示对应命令。两者同时出现就都提示: + `_notice.update` 指向 `vertc update`,`_notice.skills` 指向 `vertc skills sync`。不要擅自执行 + 更新;仅在用户明确要求时运行命令。 +- 生命周期 notice 来自 24 小时本地缓存,不得打断当前任务或给正常命令增加同步网络等待。 + 冷缓存首次调用可能没有 notice,只触发后台刷新;这不代表已是最新版。不要为了等待 notice + 轮询或重试,继续检查本任务后续每条 `vertc` JSON 输出即可。受控自动化可分别设置 `VERTC_NO_UPDATE_NOTIFIER=1`、`VERTC_NO_SKILLS_NOTIFIER=1`。 - `agent` / `env` / `token` 等为内部/legacy 命令(默认隐藏),非默认快速路径;优先用 公开命令 `init` / `auth login` / `dev` / `doctor` / `explain-error` / `skills`。