@sokeai/cli 1.2.2 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sokeai/cli",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "授客AI官方CLI工具 - 支持AI Agent Skills",
5
5
  "bin": {
6
6
  "soke-cli": "scripts/run.js"
@@ -15,6 +15,32 @@ NC='\033[0m' # No Color
15
15
  VERSION=$(node -p "require('./package.json').version")
16
16
  echo -e "${GREEN}开始编译 soke-cli v${VERSION}${NC}"
17
17
 
18
+ # task 11.2 — OAuth 凭证通过 env 注入(替代原 sed 改 Go 源的方式)。
19
+ #
20
+ # 重要:vendor.yaml 的 ${SOKE_CLIENT_ID} / ${SOKE_CLIENT_SECRET} 由
21
+ # sokeai/provider.go 在 init() 阶段 Interpolate,**取的是产物运行时的 env**,
22
+ # 而不是 build 期。因此:
23
+ #
24
+ # * 本地开发:用户在 shell 里 export SOKE_CLIENT_ID / SOKE_CLIENT_SECRET,
25
+ # 然后 go run / 已 build 的 ./bin/soke-cli 启动时 init() 取到。
26
+ # * Release 二进制:client_id / client_secret 不在 build 阶段嵌入产物。
27
+ # 发版 CI 应当在制作 NPM 包时附带一个 wrapper(scripts/run.js)在启动
28
+ # soke-cli 前 setenv 注入(具体方式由 release-lead 在发版 CI 里定),
29
+ # 或要求最终用户自己 export(仅适用于内部分发场景)。
30
+ #
31
+ # 本脚本只做 sanity check + 把当前 shell env 透传到 go build(用于自动化
32
+ # 测试场景中,build 后立即跑 ./bin/soke-cli auth login 走流程)。
33
+ if [ -z "${SOKE_CLIENT_ID:-}" ] || [ -z "${SOKE_CLIENT_SECRET:-}" ]; then
34
+ if [ "${SOKE_CLI_RELEASE:-}" = "1" ]; then
35
+ echo -e "${RED}[FATAL] release 模式必须设置 SOKE_CLIENT_ID / SOKE_CLIENT_SECRET${NC}"
36
+ echo -e "${RED} 二进制本身不嵌入凭证,run.js wrapper 也需要相应的注入逻辑${NC}"
37
+ exit 1
38
+ fi
39
+ echo -e "${YELLOW}[警告] SOKE_CLIENT_ID / SOKE_CLIENT_SECRET 未设置;${NC}"
40
+ echo -e "${YELLOW} 本地 build 后直接 ./bin/soke-cli auth login 会 fail-fast。${NC}"
41
+ fi
42
+ export SOKE_CLIENT_ID SOKE_CLIENT_SECRET
43
+
18
44
  # 编译参数
19
45
  LDFLAGS="-s -w -X main.Version=${VERSION}"
20
46
 
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bash
2
+ # task 9.1 — 拦截误引入的 dws-cli upstream 旧常量。
3
+ #
4
+ # 故意提一个引入旧常量的 bad PR 时,CI 该步骤应当失败。
5
+ # 允许出现在 openspec/ 历史 doc 与 docs/dead-code-audit-*.md。
6
+ #
7
+ # 用法:bash scripts/ci/check-legacy-constants.sh
8
+
9
+ set -euo pipefail
10
+
11
+ PATTERN='OpenDevURL\|AuthorizeURL\|DefaultMCPBaseURL\|DefaultClientID\|DefaultClientSecret\|<YOUR_CLIENT_'
12
+
13
+ # 只扫源码目录;openspec/docs/scripts 历史档案允许出现。
14
+ hits=$(grep -rn -E "$PATTERN" cmd/ internal/ extension/ 2>/dev/null \
15
+ | grep -v vendorplugin/ \
16
+ | grep -v "_test.go" \
17
+ || true)
18
+
19
+ if [ -n "$hits" ]; then
20
+ echo "[FAIL] 检测到 dws-cli 旧常量残留:"
21
+ echo "$hits"
22
+ echo
23
+ echo "请改用 vendor.Active().Endpoints() / OAuth() 读取(见 cmd/user_auth/vendor.go)。"
24
+ exit 1
25
+ fi
26
+
27
+ echo "[OK] 无 dws-cli 旧常量残留。"
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+ # task 9.2 — 校验 extension/vendorplugin/builtin/**/vendor.yaml 内 ${VAR}
3
+ # 占位符全部符合白名单(^SOKE_[A-Z0-9_]+$)。
4
+ #
5
+ # 故意写一个 ${HOME} 进 vendor.yaml 时,本步骤应当 FAIL。
6
+ #
7
+ # 用法:bash scripts/ci/check-yaml-env-whitelist.sh
8
+
9
+ set -euo pipefail
10
+
11
+ WHITELIST_RE='^SOKE_[A-Z0-9_]+$'
12
+ fail=0
13
+
14
+ for yaml in $(find extension/vendorplugin/builtin -name vendor.yaml 2>/dev/null); do
15
+ # 抽出所有 ${...} 占位符内层内容(去掉默认值部分)
16
+ vars=$(grep -oE '\$\{[^{}]+\}' "$yaml" \
17
+ | sed -E 's/^\$\{([^:}]+)(:-[^}]*)?\}$/\1/' \
18
+ | sort -u)
19
+ for v in $vars; do
20
+ if ! echo "$v" | grep -qE "$WHITELIST_RE"; then
21
+ echo "[FAIL] $yaml 引用了非白名单 env: $v"
22
+ fail=1
23
+ fi
24
+ done
25
+ done
26
+
27
+ if [ "$fail" -ne 0 ]; then
28
+ echo
29
+ echo "白名单规则:^SOKE_[A-Z0-9_]+\$(见 extension/vendorplugin/env_whitelist.go)"
30
+ exit 1
31
+ fi
32
+
33
+ echo "[OK] 所有 vendor.yaml 内 \${VAR} 占位符均符合 SOKE_* 白名单。"
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+ # mcp-stdout-scan.sh — openspec change make-soke-cli-mcp-first §10.3
3
+ #
4
+ # 静态扫描 internal/mcp/ / extension/vendor/builtin/ / internal/courseimport/ 三个
5
+ # 与 mcp stdio 帧纯净性相关的代码树,拦下任何会污染 stdout JSON-RPC 帧的调用:
6
+ # - fmt.Println / fmt.Printf / fmt.Print
7
+ # - fmt.Fprintln / Fprintf / Fprint to os.Stdout
8
+ # - os.Stdout.Write*
9
+ # - 顶层 print( / println( 内建函数
10
+ #
11
+ # 排除 _test.go (测试代码允许写 stdout);
12
+ # 通过 sed 把 `// ...` 注释剥掉再 grep,避免文档/注释里提到 fmt.Println 触发 false positive。
13
+ #
14
+ # 用法: bash scripts/mcp-stdout-scan.sh
15
+ # 退出码: 0 = 干净;1 = 有命中(并打到 stderr)。
16
+
17
+ set -e
18
+
19
+ ROOTS="internal/mcp extension/vendor/builtin internal/courseimport"
20
+ PATTERN='fmt\.(Println|Printf|Print\()|fmt\.(Fprintln|Fprintf|Fprint)\(os\.Stdout|os\.Stdout\.Write|^[[:space:]]*(print|println)\('
21
+
22
+ have_hits=0
23
+ for d in $ROOTS; do
24
+ if [ ! -d "$d" ]; then
25
+ echo "skip 不存在的目录 $d"
26
+ continue
27
+ fi
28
+ files=$(find "$d" -name '*.go' ! -name '*_test.go' 2>/dev/null)
29
+ for f in $files; do
30
+ # 把行号前缀附在文件内容上, 再用 sed 剥 // 注释 (单行注释一律剥), 再 grep
31
+ hits=$(awk '{ printf "%s:%d:%s\n", FILENAME, NR, $0 }' "$f" \
32
+ | sed 's_//.*$__' \
33
+ | grep -E "$PATTERN" \
34
+ || true)
35
+ if [ -n "$hits" ]; then
36
+ echo "❌ $f 检测到 stdout-write 调用 (会破坏 mcp stdio JSON-RPC 帧):" >&2
37
+ echo "$hits" >&2
38
+ have_hits=1
39
+ fi
40
+ done
41
+ done
42
+
43
+ if [ "$have_hits" -eq 1 ]; then
44
+ exit 1
45
+ fi
46
+ echo "✓ stdout 纯净性扫描通过"
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env bash
2
+ # 回归 auth 命令体感 — task 8.1
3
+ #
4
+ # 串行跑:
5
+ # 1. auth status --json (预期未登录)
6
+ # 2. auth login (人工:浏览器跳转 + 真账号授权)
7
+ # 3. auth status --json (预期已登录)
8
+ # 4. auth logout
9
+ # 5. auth status --json (预期未登录)
10
+ #
11
+ # 用法:
12
+ # SOKE_CLIENT_ID=... SOKE_CLIENT_SECRET=... bash scripts/regress-auth.sh
13
+ # 首次运行前 build:make install 或 go build -o bin/soke-cli main.go
14
+ #
15
+ # 输出建议用 tee 保存,事后人工对比 baseline:
16
+ # bash scripts/regress-auth.sh 2>&1 | tee /tmp/regress-after.txt
17
+ # diff /tmp/regress-before.txt /tmp/regress-after.txt
18
+
19
+ set -u
20
+
21
+ BIN="${SOKE_CLI_BIN:-./bin/soke-cli}"
22
+ if [ ! -x "$BIN" ]; then
23
+ BIN="$(command -v soke-cli 2>/dev/null || echo "$BIN")"
24
+ fi
25
+
26
+ if [ ! -x "$BIN" ]; then
27
+ echo "[FATAL] 找不到 soke-cli 二进制(尝试 SOKE_CLI_BIN env 指定路径)" >&2
28
+ exit 2
29
+ fi
30
+
31
+ run_step() {
32
+ local label="$1"; shift
33
+ echo
34
+ echo "==== [$label] $* ===="
35
+ "$@"
36
+ local rc=$?
37
+ echo "==== [$label] exit=$rc ===="
38
+ return $rc
39
+ }
40
+
41
+ # baseline 时间戳 mask:让 diff 忽略 expires_at / iat / nbf / exp 等时间字段。
42
+ mask_timestamps() {
43
+ sed -E 's/("(expires_at|iat|nbf|exp|access_token|refresh_token)":\s*)"[^"]*"/\1"<masked>"/g'
44
+ }
45
+
46
+ run_step "1.before-status" "$BIN" auth status --json | mask_timestamps
47
+ echo
48
+ echo "请在浏览器完成授权后按回车继续…"
49
+ run_step "2.login" "$BIN" auth login
50
+ read -r _
51
+ run_step "3.after-login-status" "$BIN" auth status --json | mask_timestamps
52
+ run_step "4.logout" "$BIN" auth logout
53
+ run_step "5.final-status" "$BIN" auth status --json | mask_timestamps
54
+
55
+ echo
56
+ echo "[done] 完成。请人工对比 baseline diff(/tmp/regress-before.txt)。"
@@ -0,0 +1,84 @@
1
+ # auth 回归 baseline 流程(task 8.2)
2
+
3
+ > 配套脚本:`scripts/regress-auth.sh`
4
+ > 用途:在本 change 引入前后两次跑同一脚本,diff 验证零回归。
5
+
6
+ ## 1. baseline 采样(本 change 引入**前**)
7
+
8
+ 在 master 或上一个 release tag 下:
9
+
10
+ ```bash
11
+ git checkout <last-release-tag>
12
+ make install # 或:go build -o bin/soke-cli main.go
13
+ SOKE_CLIENT_ID=... SOKE_CLIENT_SECRET=... \
14
+ bash scripts/regress-auth.sh 2>&1 | tee /tmp/regress-before.txt
15
+ ```
16
+
17
+ `/tmp/regress-before.txt` 即 baseline,包含:
18
+ - 各步 stdout/stderr
19
+ - 各步 exit code(脚本内 `==== [label] exit=N ====` 行)
20
+ - timestamps 已 mask,仅保留结构性差异
21
+
22
+ ## 2. 引入后采样
23
+
24
+ 切到本 change 分支,重新 build 跑一次:
25
+
26
+ ```bash
27
+ git checkout worktree-generalize-vendor-plugin
28
+ make install
29
+ SOKE_CLIENT_ID=... SOKE_CLIENT_SECRET=... \
30
+ bash scripts/regress-auth.sh 2>&1 | tee /tmp/regress-after.txt
31
+ ```
32
+
33
+ ## 3. diff
34
+
35
+ ```bash
36
+ diff /tmp/regress-before.txt /tmp/regress-after.txt
37
+ ```
38
+
39
+ 期望:**无差异**(允许时间戳 mask 后的剩余 token 字段差异,因每次实际签发的
40
+ token bytes 不同 —— 但 mask 应已覆盖)。
41
+
42
+ 若 diff 显示行为变化,本 change 视为引入回归,**禁止 merge**,
43
+ 回到代码层检查 ClientID() / Endpoints() / CallbackPath 取值路径。
44
+
45
+ ## 4. keychain 字段验证(任选其一,平台相关)
46
+
47
+ macOS:
48
+ ```bash
49
+ security find-generic-password -s "soke-cli" -g 2>&1 | grep -E "acct|cdat"
50
+ ```
51
+
52
+ Linux(libsecret):
53
+ ```bash
54
+ secret-tool search service soke-cli
55
+ ```
56
+
57
+ 字段名(`access_token` / `refresh_token` 等)与 baseline 完全一致。
58
+
59
+ ## 5. 三平台 matrix(task 8.3)
60
+
61
+ 本 change 不接入 GH Actions yml(避免 PR 卡在未跑通的 CI 任务),由 ①
62
+ `make-soke-cli-mcp-first` 在 same release 时一并引入。matrix 草案:
63
+
64
+ ```yaml
65
+ # .github/workflows/regress-auth.yml(草案,在 ① 同 release 一起合)
66
+ strategy:
67
+ matrix:
68
+ os: [ubuntu-latest, macos-latest, windows-latest]
69
+ jobs:
70
+ regress:
71
+ runs-on: ${{ matrix.os }}
72
+ steps:
73
+ - uses: actions/checkout@v4
74
+ - uses: actions/setup-go@v5
75
+ with: { go-version: '1.25' }
76
+ - run: |
77
+ go build -o bin/soke-cli main.go
78
+ # auth login 需要真账号,CI 内只跑 status / logout 路径
79
+ ./bin/soke-cli auth status --json
80
+ ./bin/soke-cli auth logout
81
+ ./bin/soke-cli auth status --json
82
+ ```
83
+
84
+ 跑出 CI matrix 三个 job 全绿,本 change 才视为通过 task 8.3 AC。