diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index bd63c36..1fb48e9 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -27,94 +27,54 @@ jobs: echo "::notice::Release source branch(es):" echo "$CONTAINING_RELEASE_BRANCHES" - - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest - - uses: actions/setup-node@v4 with: node-version: 22 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + - name: Verify tag version run: | - PKG_VERSION="$(jq -r .version package.json)" + PKG_VERSION="$(node -p "require('./package.json').version")" TAG_VERSION="${GITHUB_REF_NAME#cli-v}" if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then echo "::error::tag $TAG_VERSION 与 package.json $PKG_VERSION 不一致" exit 1 fi - - name: Install dependencies - run: bun install --frozen-lockfile - - - name: Verify CLI source - run: | - bun run typecheck - bun run test - - - run: bun run build - env: - LIGHT_APP_KEY: ${{ secrets.LIGHT_APP_KEY }} - LIGHT_TEMPLATE_ID: ${{ secrets.LIGHT_TEMPLATE_ID }} - - - name: Smoke test npm CLI build + - name: Verify Go source run: | - test -s dist/bin.cjs - test -s dist/index.cjs - test -s dist/index.d.ts - - VERSION_OUT="$(node dist/bin.cjs --version)" - if [ "$VERSION_OUT" != "$(jq -r .version package.json)" ]; then - echo "::error::dist/bin.cjs --version 输出 $VERSION_OUT,与 package.json 不一致" - exit 1 - fi + go test ./... + go vet ./... - node dist/bin.cjs --help > /tmp/yoooclaw-help.txt - grep -q "Usage:" /tmp/yoooclaw-help.txt - grep -q "yoooclaw" /tmp/yoooclaw-help.txt - - build-native-linux: + build-release: needs: preflight - runs-on: ubuntu-latest + runs-on: macos-latest + environment: production steps: - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 + - uses: actions/setup-node@v4 with: - bun-version: latest - - - name: Install dependencies - run: bun install --frozen-lockfile - - - name: Build Linux native binaries - run: bun scripts/build-native.ts --target linux-x64,linux-arm64 - env: - LIGHT_APP_KEY: ${{ secrets.LIGHT_APP_KEY }} - LIGHT_TEMPLATE_ID: ${{ secrets.LIGHT_TEMPLATE_ID }} - - - name: Smoke test Linux native binary - run: ./dist-native/yoooclaw-linux-x64 --version + node-version: 22 - - name: Upload Linux native binaries - uses: actions/upload-artifact@v7 + - uses: actions/setup-go@v5 with: - name: cli-native-linux - path: | - dist-native/yoooclaw-linux-x64 - dist-native/yoooclaw-linux-arm64 - if-no-files-found: error - compression-level: 0 + go-version-file: go.mod + cache: true - build-native-darwin: - needs: preflight - runs-on: macos-latest - environment: production - steps: - - uses: actions/checkout@v4 - - - uses: oven-sh/setup-bun@v2 - with: - bun-version: latest + - name: Resolve version + run: | + VERSION="$(node -p "require('./package.json').version")" + TAG_VERSION="${GITHUB_REF_NAME#cli-v}" + if [ "$VERSION" != "$TAG_VERSION" ]; then + echo "::error::tag $TAG_VERSION 与 package.json $VERSION 不一致" + exit 1 + fi + echo "VERSION=$VERSION" >> "$GITHUB_ENV" - name: Validate Apple signing secrets env: @@ -141,14 +101,24 @@ jobs: exit 1 fi - - name: Install dependencies - run: bun install --frozen-lockfile + - name: Build Go npm distribution + run: scripts/build-go.sh "$VERSION" - - name: Build Darwin native binaries - run: bun scripts/build-native.ts --target darwin-arm64,darwin-x64 - env: - LIGHT_APP_KEY: ${{ secrets.LIGHT_APP_KEY }} - LIGHT_TEMPLATE_ID: ${{ secrets.LIGHT_TEMPLATE_ID }} + - name: Smoke test current macOS binary + run: | + case "$(uname -m)" in + arm64) bin="dist-native/yoooclaw-darwin-arm64" ;; + x86_64) bin="dist-native/yoooclaw-darwin-x64" ;; + *) + echo "::error::Unsupported macOS runner arch: $(uname -m)" + exit 1 + ;; + esac + VERSION_OUT="$("$bin" --version)" + if [ "$VERSION_OUT" != "$VERSION" ]; then + echo "::error::$bin --version 输出 $VERSION_OUT,期望 $VERSION" + exit 1 + fi - name: Import Developer ID certificate env: @@ -187,7 +157,7 @@ jobs: echo "SIGNING_IDENTITY=$SIGNING_IDENTITY" >> "$GITHUB_ENV" - - name: Sign Darwin native binaries + - name: Sign Darwin binaries run: | for file in \ dist-native/yoooclaw-darwin-arm64 \ @@ -203,7 +173,18 @@ jobs: codesign --verify --strict --verbose=2 "$file" done - - name: Notarize Darwin native binaries + cp dist-native/yoooclaw-darwin-arm64 dist-npm/cli-darwin-arm64/bin/yc + cp dist-native/yoooclaw-darwin-x64 dist-npm/cli-darwin-x64/bin/yc + chmod +x dist-npm/cli-darwin-arm64/bin/yc dist-npm/cli-darwin-x64/bin/yc + + for file in \ + dist-npm/cli-darwin-arm64/bin/yc \ + dist-npm/cli-darwin-x64/bin/yc + do + codesign --verify --strict --verbose=2 "$file" + done + + - name: Notarize Darwin binaries env: APPLE_NOTARY_APPLE_ID: ${{ secrets.APPLE_NOTARY_APPLE_ID }} APPLE_NOTARY_TEAM_ID: ${{ secrets.APPLE_NOTARY_TEAM_ID }} @@ -249,15 +230,54 @@ jobs: exit 1 fi - # Apple 会为 ZIP 内的独立二进制发布在线 ticket;独立二进制本身无法 staple。 + - name: Verify npm package layout + run: | + node <<'NODE' + const fs = require('node:fs'); + const path = require('node:path'); + const version = process.env.VERSION; + const root = 'dist-npm'; + const dirs = fs.readdirSync(root).sort(); + const expected = [ + 'cli', + 'cli-darwin-arm64', + 'cli-darwin-x64', + 'cli-linux-arm64', + 'cli-linux-x64', + 'cli-win32-x64', + ]; + for (const dir of expected) { + if (!dirs.includes(dir)) throw new Error(`missing ${dir}`); + const pkg = JSON.parse(fs.readFileSync(path.join(root, dir, 'package.json'), 'utf8')); + if (pkg.version !== version) throw new Error(`${pkg.name} version ${pkg.version} != ${version}`); + } + const main = JSON.parse(fs.readFileSync(path.join(root, 'cli', 'package.json'), 'utf8')); + for (const dep of [ + '@yoooclaw/cli-darwin-arm64', + '@yoooclaw/cli-darwin-x64', + '@yoooclaw/cli-linux-arm64', + '@yoooclaw/cli-linux-x64', + '@yoooclaw/cli-win32-x64', + ]) { + if (main.optionalDependencies?.[dep] !== version) { + throw new Error(`optional dependency ${dep} is not pinned to ${version}`); + } + } + NODE + + - name: Upload native binaries + uses: actions/upload-artifact@v4 + with: + name: cli-native + path: dist-native/ + if-no-files-found: error + compression-level: 0 - - name: Upload signed and notarized Darwin native binaries - uses: actions/upload-artifact@v7 + - name: Upload npm packages + uses: actions/upload-artifact@v4 with: - name: cli-native-darwin - path: | - dist-native/yoooclaw-darwin-arm64 - dist-native/yoooclaw-darwin-x64 + name: cli-npm + path: dist-npm/ if-no-files-found: error compression-level: 0 @@ -269,209 +289,144 @@ jobs: fi release: - needs: - - preflight - - build-native-linux - - build-native-darwin + needs: build-release runs-on: ubuntu-latest environment: production - # job 级注入:覆盖显式 build 与 `bun publish` 触发的 prepublishOnly 重建, - # 否则 publish 期间的重建会因缺 env 把灯效凭据烤成空串。 - env: - LIGHT_APP_KEY: ${{ secrets.LIGHT_APP_KEY }} - LIGHT_TEMPLATE_ID: ${{ secrets.LIGHT_TEMPLATE_ID }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Ensure tag commit is on release branch - run: | - git fetch --no-tags origin '+refs/heads/release/*:refs/remotes/origin/release/*' - CONTAINING_RELEASE_BRANCHES="$(git branch -r --contains "$GITHUB_SHA" --list 'origin/release/*')" - if [ -z "$CONTAINING_RELEASE_BRANCHES" ]; then - echo "::error::Release tag must point to a commit on origin/release/**" - exit 1 - fi - echo "::notice::Release source branch(es):" - echo "$CONTAINING_RELEASE_BRANCHES" + - uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: https://registry.npmjs.org - - uses: oven-sh/setup-bun@v2 + - name: Download native binaries + uses: actions/download-artifact@v4 with: - bun-version: latest + name: cli-native + path: dist-native - - uses: actions/setup-node@v4 + - name: Download npm packages + uses: actions/download-artifact@v4 with: - node-version: 22 + name: cli-npm + path: dist-npm - - name: Resolve version & channel + - name: Resolve version and channel run: | - PKG_VERSION="$(jq -r .version package.json)" + VERSION="$(node -p "require('./package.json').version")" TAG_VERSION="${GITHUB_REF_NAME#cli-v}" - if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then - echo "::error::tag $TAG_VERSION 与 package.json $PKG_VERSION 不一致" + if [ "$VERSION" != "$TAG_VERSION" ]; then + echo "::error::tag $TAG_VERSION 与 package.json $VERSION 不一致" exit 1 fi - echo "VERSION=$PKG_VERSION" >> "$GITHUB_ENV" - if [[ "$PKG_VERSION" == *-* ]]; then - echo "IS_BETA=1" >> "$GITHUB_ENV" - echo "::notice::预发布版本 cli-v$PKG_VERSION(仅 GitHub Release,跳过 npm publish)" + + echo "VERSION=$VERSION" >> "$GITHUB_ENV" + if [[ "$VERSION" == *-* ]]; then + echo "NPM_TAG=beta" >> "$GITHUB_ENV" + echo "PRERELEASE=1" >> "$GITHUB_ENV" else - echo "IS_BETA=0" >> "$GITHUB_ENV" - echo "::notice::稳定版本 cli-v$PKG_VERSION(GitHub Release + npm)" + echo "NPM_TAG=latest" >> "$GITHUB_ENV" + echo "PRERELEASE=0" >> "$GITHUB_ENV" fi - - name: Verify stable release prerequisites - if: env.IS_BETA == '0' + - name: Verify npm token env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - if [ -z "$NPM_CONFIG_TOKEN" ]; then - echo "::error::稳定版发布需要配置 NPM_TOKEN" + if [ -z "$NODE_AUTH_TOKEN" ]; then + echo "::error::发布 npm 需要配置 NPM_TOKEN" exit 1 fi - if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "::error::稳定版版本号必须是 x.y.z,当前为 $VERSION" - exit 1 - fi - - if NPM_VIEW_OUTPUT=$(npm view "@yoooclaw/cli@$VERSION" version 2>&1); then - echo "NPM_PACKAGE_EXISTS=1" >> "$GITHUB_ENV" - echo "::notice::@yoooclaw/cli@$VERSION 已存在于 npm,跳过重复发布" - elif ! grep -Eq '(^npm ERR! code E404|404)' <<< "$NPM_VIEW_OUTPUT"; then - echo "::error::无法确认 @yoooclaw/cli@$VERSION 是否已存在于 npm" - echo "$NPM_VIEW_OUTPUT" - exit 1 - else - echo "NPM_PACKAGE_EXISTS=0" >> "$GITHUB_ENV" - fi - - - name: Install dependencies - run: bun install --frozen-lockfile - - - run: bun run build - - - name: Smoke test npm CLI build + - name: Smoke test Linux binary run: | - test -s dist/bin.cjs - test -s dist/index.cjs - test -s dist/index.d.ts - - VERSION_OUT="$(node dist/bin.cjs --version)" + chmod +x dist-native/yoooclaw-* + VERSION_OUT="$(./dist-native/yoooclaw-linux-x64 --version)" if [ "$VERSION_OUT" != "$VERSION" ]; then - echo "::error::dist/bin.cjs --version 输出 $VERSION_OUT,期望 $VERSION" + echo "::error::linux native --version 输出 $VERSION_OUT,期望 $VERSION" exit 1 fi - node dist/bin.cjs --help > /tmp/yoooclaw-help.txt - grep -q "Usage:" /tmp/yoooclaw-help.txt - grep -q "yoooclaw" /tmp/yoooclaw-help.txt - - - name: Download native binaries - uses: actions/download-artifact@v8 - with: - pattern: cli-native-* - path: dist-native - merge-multiple: true + - name: Pack npm tarballs + run: | + mkdir -p release-tarballs + for dir in dist-npm/cli-* dist-npm/cli; do + npm pack "./$dir" --pack-destination release-tarballs --json + done - - name: Smoke test native binaries + - name: Publish npm packages + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - required=( - dist-native/yoooclaw-darwin-arm64 - dist-native/yoooclaw-darwin-x64 - dist-native/yoooclaw-linux-x64 - dist-native/yoooclaw-linux-arm64 - ) - for file in "${required[@]}"; do - if [ ! -s "$file" ]; then - echo "::error::缺少 native 产物: $file" - exit 1 + publish_pkg() { + local dir="$1" + local name + local version + name="$(node -p "require('./${dir}/package.json').name")" + version="$(node -p "require('./${dir}/package.json').version")" + + if npm view "$name@$version" version >/dev/null 2>&1; then + echo "::notice::$name@$version 已存在,跳过" + npm access set status=public "$name" + return fi + + echo "::notice::发布 $name@$version --tag $NPM_TAG" + npm publish "./$dir" --access public --tag "$NPM_TAG" + npm access set status=public "$name" + } + + for dir in dist-npm/cli-*; do + publish_pkg "$dir" done + publish_pkg dist-npm/cli - chmod +x dist-native/yoooclaw-* - VERSION_OUT="$(./dist-native/yoooclaw-linux-x64 --version)" - if [ "$VERSION_OUT" != "$VERSION" ]; then - echo "::error::native --version 输出 $VERSION_OUT,期望 $VERSION" - exit 1 - fi + - name: Deprecate broken beta.0 + if: env.VERSION == '0.2.0-beta.1' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + message="@yoooclaw/cli 0.2.0-beta.0 的平台二进制缺少 executable bit,请升级到 0.2.0-beta.1。" + npm deprecate "@yoooclaw/cli@0.2.0-beta.0" "$message" - - name: Compute checksums for native binaries + - name: Compute checksums run: | cd dist-native sha256sum yoooclaw-* > checksums.txt - if [ "$(wc -l < checksums.txt | tr -d ' ')" != "4" ]; then - echo "::error::checksums.txt 应包含 4 个 native 产物" + expected=5 + actual="$(wc -l < checksums.txt | tr -d ' ')" + if [ "$actual" != "$expected" ]; then + echo "::error::checksums.txt 应包含 $expected 个 native 产物,实际为 $actual" exit 1 fi cat checksums.txt - - run: | - rm -f ./*.tgz - bun pm pack - - - name: Verify npm package artifact - run: | - shopt -s nullglob - tarballs=(./*.tgz) - if [ "${#tarballs[@]}" -ne 1 ]; then - echo "::error::期望生成 1 个 npm tarball,实际为 ${#tarballs[@]}" - printf '%s\n' "${tarballs[@]}" - exit 1 - fi - - tar -tzf "${tarballs[0]}" > /tmp/yoooclaw-tarball.txt - required=( - package/package.json - package/dist/bin.cjs - package/dist/index.cjs - package/dist/index.d.ts - package/skills/yoooclaw-notification-query/SKILL.md - package/skills/yoooclaw-lightrule-create/SKILL.md - package/skills/yoooclaw-tunnel-debug/SKILL.md - ) - for path in "${required[@]}"; do - if ! grep -qx "$path" /tmp/yoooclaw-tarball.txt; then - echo "::error::npm tarball 缺少 $path" - exit 1 - fi - done - - - name: Publish to npm - if: env.IS_BETA == '0' && env.NPM_PACKAGE_EXISTS == '0' - run: bun publish --access public - env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Repack npm tarball for GitHub Release - run: | - rm -f ./*.tgz - bun pm pack - - name: Create GitHub Release env: GH_TOKEN: ${{ github.token }} run: | - shopt -s nullglob - tarballs=(./*.tgz) - if [ "${#tarballs[@]}" -ne 1 ]; then - echo "::error::GitHub Release 需要 1 个 npm tarball,实际为 ${#tarballs[@]}" - exit 1 - fi - - ARGS=(--generate-notes) - if [ "$IS_BETA" = "1" ]; then - ARGS+=(--prerelease) - fi - gh release create "cli-v$VERSION" \ - "${tarballs[0]}" \ + assets=( dist-native/yoooclaw-darwin-arm64 \ dist-native/yoooclaw-darwin-x64 \ - dist-native/yoooclaw-linux-x64 \ dist-native/yoooclaw-linux-arm64 \ + dist-native/yoooclaw-linux-x64 \ + dist-native/yoooclaw-win32-x64.exe \ dist-native/checksums.txt \ - "${ARGS[@]}" + release-tarballs/*.tgz + ) + + if gh release view "cli-v$VERSION" >/dev/null 2>&1; then + gh release upload "cli-v$VERSION" "${assets[@]}" --clobber + else + args=(--generate-notes) + if [ "$PRERELEASE" = "1" ]; then + args+=(--prerelease) + fi + gh release create "cli-v$VERSION" "${assets[@]}" "${args[@]}" + fi - name: Notify Feishu if: success() @@ -489,7 +444,6 @@ jobs: LOG_ARGS=(-20 "$CURRENT_TAG") fi - # 逐条输出:标题 + 缩进的提交正文(跳过 merge 与版本号提交) CHANGES=$(git log --no-merges --pretty=format:'%H' "${LOG_ARGS[@]}" | while read -r h; do subj=$(git log -1 --pretty=format:'%s' "$h") if grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([-.].*)?$' <<< "$subj"; then @@ -505,7 +459,7 @@ jobs: URL="https://github.com/${GITHUB_REPOSITORY}/releases/tag/${CURRENT_TAG}" CHANNEL="稳定版" - [ "$IS_BETA" = "1" ] && CHANNEL="预发布" + [ "$PRERELEASE" = "1" ] && CHANNEL="预发布" TEXT="🚀 @yoooclaw/cli ${CURRENT_TAG}(${CHANNEL})已发布 diff --git a/.gitignore b/.gitignore index 03577fc..a2e7544 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,14 @@ node_modules # 构建产物 dist dist-native +dist-npm *.tgz *.tsbuildinfo +# Go(本地散落的二进制;go vendor 用 /vendor 顶层,勿用裸 vendor 误伤 src/vendor) +/yc +/vendor/ + # 环境变量与密钥 .env .env.local diff --git a/assets.go b/assets.go new file mode 100644 index 0000000..cf4d4e9 --- /dev/null +++ b/assets.go @@ -0,0 +1,12 @@ +// Package assets 把随包发布的静态资源(SKILL.md 技能)通过 go:embed 编译进二进制。 +// +// Go 重写后 CLI 是单一二进制,没有 TS 版那种 /skills/ 同级目录可供解析与软链; +// 因此把 skills/ 整个嵌入二进制,由 `skills install` 解包(复制)到 agent 技能目录。 +package assets + +import "embed" + +// SkillsFS 内嵌 skills/ 目录(含各 yoooclaw-*/SKILL.md)。 +// +//go:embed all:skills +var SkillsFS embed.FS diff --git a/cmd/yc/main.go b/cmd/yc/main.go new file mode 100644 index 0000000..e51d654 --- /dev/null +++ b/cmd/yc/main.go @@ -0,0 +1,11 @@ +// Command yc 是 yoooclaw CLI 的 Go 实现入口。 +// +// 真实命令树与业务实现在 internal/cli 下逐步补齐(见 Go 重写计划 Phase 1+); +// 本文件只负责装配 root 命令并执行。 +package main + +import "github.com/YoooClaw/cli/internal/cli" + +func main() { + cli.Execute() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..18a7c52 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/YoooClaw/cli + +go 1.26.4 + +require github.com/spf13/cobra v1.10.2 + +require ( + github.com/gorilla/websocket v1.5.3 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/pflag v1.0.9 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..34e2208 --- /dev/null +++ b/go.sum @@ -0,0 +1,12 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/cli/cmd_auth.go b/internal/cli/cmd_auth.go new file mode 100644 index 0000000..85ae11f --- /dev/null +++ b/internal/cli/cmd_auth.go @@ -0,0 +1,227 @@ +package cli + +import ( + "strconv" + "strings" + + "github.com/YoooClaw/cli/internal/clictx" + "github.com/YoooClaw/cli/internal/config" + "github.com/YoooClaw/cli/internal/creds" + "github.com/YoooClaw/cli/internal/daemon" + "github.com/YoooClaw/cli/internal/errs" + "github.com/YoooClaw/cli/internal/prompt" + "github.com/spf13/cobra" +) + +func newAuthCmd() *cobra.Command { + c := &cobra.Command{Use: "auth", Short: "凭据与鉴权 🟢/🟡"} + + setKey := &cobra.Command{Use: "set-api-key ", Short: "设置/轮换 account 级 default api-key(- 从 stdin 读)🟢", Args: cobra.ExactArgs(1), RunE: run(authSetAPIKey)} + setKey.Flags().Bool("keychain", false, "写入 OS keychain 而非文件") + + addKey := &cobra.Command{Use: "add-api-key ", Short: "新增一条 multi-key api-key(- 从 stdin 读)🟢", Args: cobra.ExactArgs(1), RunE: run(authAddAPIKey)} + addKey.Flags().String("label", "", "api-key label([a-z0-9-]{1,32})") + addKey.Flags().Bool("default", false, "设为 default key") + addKey.Flags().Bool("force", false, "label 已存在时覆盖") + + listKeys := &cobra.Command{Use: "list-api-keys", Short: "列出 api-key 条目(key 自动遮罩)🟢", Args: cobra.NoArgs, RunE: run(authListAPIKeys)} + rmKey := &cobra.Command{Use: "remove-api-key