tirtc-devtools-cli 0.0.9 → 0.0.11

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.
Files changed (115) hide show
  1. package/README.md +17 -11
  2. package/USAGE.md +72 -33
  3. package/bin/tirtc-devtools-cli.js +1 -1
  4. package/dist/cli/src/bootstrap_flows.d.ts +46 -0
  5. package/dist/cli/src/bootstrap_flows.js +249 -0
  6. package/dist/{devtools/cli → cli}/src/config.d.ts +4 -15
  7. package/dist/{devtools/cli → cli}/src/config.js +7 -31
  8. package/dist/cli/src/default_paths.d.ts +3 -0
  9. package/dist/cli/src/default_paths.js +23 -0
  10. package/dist/{devtools/cli → cli}/src/embedded_paths.d.ts +1 -0
  11. package/dist/{devtools/cli → cli}/src/embedded_paths.js +18 -1
  12. package/dist/{devtools/cli → cli}/src/facade.d.ts +41 -235
  13. package/dist/{devtools/cli → cli}/src/facade.js +8 -27
  14. package/dist/cli/src/guide.js +47 -0
  15. package/dist/{devtools/cli → cli}/src/index.js +55 -141
  16. package/dist/{devtools/cli → cli}/src/session_manager.js +9 -11
  17. package/dist/{devtools/cli → cli}/src/token_command.js +69 -0
  18. package/dist/{devtools/cli → cli}/src/token_tool.d.ts +26 -0
  19. package/dist/{devtools/cli → cli}/src/token_tool.js +123 -22
  20. package/dist/{devtools/cli → cli}/src/transport.d.ts +1 -1
  21. package/package.json +6 -2
  22. package/script/ensure_ffmpeg.sh +1 -1
  23. package/vendor/app-server/bin/native/linux-x64/credential_napi.node +0 -0
  24. package/vendor/app-server/bin/native/macos-arm64/credential_napi.node +0 -0
  25. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/credential.h +34 -0
  26. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/error.h +13 -0
  27. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/foundation/build_info.h +27 -0
  28. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/http.h +57 -0
  29. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/logging.h +3 -1
  30. package/vendor/app-server/bin/runtime/linux-x64/lib/libcrypto.a +0 -0
  31. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_credential.a +0 -0
  32. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_foundation_http.a +0 -0
  33. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_foundation_logging.a +0 -0
  34. package/vendor/app-server/bin/runtime/linux-x64/lib/libssl.a +0 -0
  35. package/vendor/app-server/bin/runtime/linux-x64/manifest.txt +2 -32
  36. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/audio.h +176 -133
  37. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/av.h +223 -182
  38. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/error.h +2 -0
  39. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/media_downlink.h +6 -0
  40. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/transport.h +58 -133
  41. package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/trp.h +47 -224
  42. package/vendor/app-server/bin/runtime/macos-arm64/lib/libTGTRP.a +0 -0
  43. package/vendor/app-server/bin/runtime/macos-arm64/lib/libTiRTC.a +0 -0
  44. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_audio.a +0 -0
  45. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_credential.a +0 -0
  46. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_facade.a +0 -0
  47. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_http.a +0 -0
  48. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a +0 -0
  49. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_media.a +0 -0
  50. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_transport.a +0 -0
  51. package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_video.a +0 -0
  52. package/vendor/app-server/bin/runtime/macos-arm64/manifest.txt +19 -15
  53. package/vendor/app-server/dist/host/HostCommandCoordinator.d.ts +19 -0
  54. package/vendor/app-server/dist/host/HostCommandCoordinator.js +196 -0
  55. package/vendor/app-server/dist/host/HostProtocol.d.ts +1 -11
  56. package/vendor/app-server/dist/host/HostProtocol.js +3 -37
  57. package/vendor/app-server/dist/host/HostServer.d.ts +1 -4
  58. package/vendor/app-server/dist/host/HostServer.js +16 -152
  59. package/vendor/app-server/dist/host/RuntimeAdapter.js +2 -2
  60. package/vendor/app-server/dist/host/native/RuntimeCredentialTokenIssuer.js +3 -3
  61. package/vendor/app-server/dist/host/native/RuntimeHostBridge.js +4 -4
  62. package/vendor/app-server/dist/host/runtime_backed_preflight.js +2 -2
  63. package/vendor/app-server/dist/host/tests/helpers/runtime_e2e_local_config.js +1 -1
  64. package/vendor/app-server/dist/protocol/contract.d.ts +5 -64
  65. package/vendor/app-server/dist/protocol/contract.js +3 -12
  66. package/dist/devtools/cli/src/guide.js +0 -50
  67. package/dist/dummy.d.ts +0 -0
  68. package/dist/dummy.js +0 -1
  69. package/dist/index.d.ts +0 -1
  70. package/dist/index.js +0 -48
  71. package/vendor/app-server/bin/native/macos-arm64/libcrypto.dylib +0 -0
  72. package/vendor/app-server/bin/native/macos-arm64/libssl.dylib +0 -0
  73. package/vendor/app-server/bin/native/macos-arm64/runtime_host_napi.node +0 -0
  74. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_codec.h +0 -23
  75. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_frame.h +0 -36
  76. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io.h +0 -56
  77. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_android.h +0 -19
  78. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_apple.h +0 -19
  79. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_harmony.h +0 -19
  80. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_io_windows.h +0 -19
  81. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_processing.h +0 -56
  82. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/audio_sample_rate.h +0 -18
  83. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_codec.h +0 -21
  84. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_downlink.h +0 -89
  85. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/media_uplink.h +0 -115
  86. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/runtime.h +0 -236
  87. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_codec.h +0 -57
  88. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_frame.h +0 -55
  89. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io.h +0 -46
  90. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_android.h +0 -32
  91. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_apple.h +0 -34
  92. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_harmony.h +0 -32
  93. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_io_windows.h +0 -26
  94. package/vendor/app-server/bin/runtime/linux-x64/include/tirtc/video_processing.h +0 -34
  95. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_audio.a +0 -0
  96. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_facade.a +0 -0
  97. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_media.a +0 -0
  98. package/vendor/app-server/bin/runtime/linux-x64/lib/libmatrix_runtime_video.a +0 -0
  99. package/vendor/app-server/bin/runtime/linux-x64/lib/libwebrtc_apm.a +0 -0
  100. package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.d.ts +0 -30
  101. package/vendor/app-server/dist/host/RuntimeCredentialTokenIssuer.js +0 -224
  102. /package/dist/{devtools/cli → cli}/src/dummy.d.ts +0 -0
  103. /package/dist/{devtools/cli → cli}/src/dummy.js +0 -0
  104. /package/dist/{devtools/cli → cli}/src/ffmpeg_tool.d.ts +0 -0
  105. /package/dist/{devtools/cli → cli}/src/ffmpeg_tool.js +0 -0
  106. /package/dist/{devtools/cli → cli}/src/guide.d.ts +0 -0
  107. /package/dist/{devtools/cli → cli}/src/index.d.ts +0 -0
  108. /package/dist/{devtools/cli → cli}/src/media_assets.d.ts +0 -0
  109. /package/dist/{devtools/cli → cli}/src/media_assets.js +0 -0
  110. /package/dist/{devtools/cli → cli}/src/progress.d.ts +0 -0
  111. /package/dist/{devtools/cli → cli}/src/progress.js +0 -0
  112. /package/dist/{devtools/cli → cli}/src/session_manager.d.ts +0 -0
  113. /package/dist/{devtools/cli → cli}/src/token_command.d.ts +0 -0
  114. /package/dist/{devtools/cli → cli}/src/transport.js +0 -0
  115. /package/vendor/app-server/bin/{native/macos-arm64 → runtime/macos-arm64/lib}/libtgrtc.dylib +0 -0
package/README.md CHANGED
@@ -1,12 +1,17 @@
1
1
  # TiRTC DevTools CLI
2
2
 
3
- `devtools/cli/` 承接 `TiRTC DevTools CLI`。它是当前唯一用户界面的产品门面 (command client),为用户提供了一套操作 `Matrix Host` 控制面的终端工具。
3
+ `products/cli/` 承接 `TiRTC DevTools CLI`。它是当前唯一用户界面的产品门面 (command client),为用户提供了一套操作 `Matrix Host` 控制面的终端工具。
4
4
 
5
5
  ## 使用说明 (C-Lite)
6
6
 
7
7
  关于 `tirtc-devtools-cli` 命令的详细使用方法、参数说明与示例,请参考 [USAGE.md](./USAGE.md)。
8
8
 
9
- 如果要先快速确认当前 binary 暴露了哪些命令面,直接运行:`node devtools/cli/bin/tirtc-devtools-cli.js --help`。
9
+ 如果要先快速确认当前 binary 暴露了哪些命令面,直接运行:`node products/cli/bin/tirtc-devtools-cli.js --help`。
10
+
11
+ 当前正式入口补充:
12
+
13
+ - server 侧最小入口:`service start`
14
+ - client 本地预览正式入口:`client start --token <token>` + `[client]` TOML
10
15
 
11
16
  ## 负责什么
12
17
 
@@ -15,6 +20,7 @@
15
20
  - **产品级 Observability**:将底层的运行时事件和状态翻译为结构化输出 (JSON) 或友好的终端日志输出;对长耗时命令补轻量进度提示。
16
21
  - **调试期工具内聚**:承接调试期必要工具(如 token bootstrap、二维码与媒体预处理)的产品化入口,避免把调试流程散落在 runtime 或外部手工步骤中。
17
22
  - **本地 token 工具**:提供直接签发 token、打印组合 JSON、单独 token 与本地二维码 PNG 路径的公开 CLI 能力,服务本地联调与体验验证。
23
+ - **本地 license 二维码工具**:提供 server 扫码用的 license JSON 二维码生成能力,支持可选 `service_entry`。
18
24
 
19
25
  ## 不负责什么
20
26
 
@@ -24,7 +30,7 @@
24
30
 
25
31
  ## 依赖方向
26
32
 
27
- - **依赖 `app-server/protocol-client/`**:通过可复用的第一方协议客户端与 `Matrix Host` 进程通信。
33
+ - **依赖 `products/app-server/protocol-client/`**:通过可复用的第一方协议客户端与 `Matrix Host` 进程通信。
28
34
  - **绝不依赖 `runtime/` 代码实现**:CLI 不直接链接 runtime 模块,只消费 app-server 打包好的运行时产物与 Host 协议。
29
35
 
30
36
  ## 这里应该放什么
@@ -36,7 +42,7 @@
36
42
 
37
43
  ## 代码规范与 lint
38
44
 
39
- - TypeScript 代码规范通过 `eslint` 承接,配置文件位于 `devtools/cli/.eslintrc.cjs`。
45
+ - TypeScript 代码规范通过 `eslint` 承接,配置文件位于 `products/cli/.eslintrc.cjs`。
40
46
  - 本目录作者侧收口命令:`npm run lint`、`npm test`、`npm run build`。
41
47
  - 仓库级 gate 会通过 `./script/lint_node_products.sh` 在 `pre-commit` 与 `./script/check.sh` 中统一执行 Node 产品 lint。
42
48
 
@@ -44,18 +50,18 @@
44
50
 
45
51
  - `npm run build`:执行 TypeScript 编译。
46
52
  - `npm test`:运行 CLI 门面与 Smoke 测试。
47
- - `npm run package`:执行 `./script/package.sh`,构建 CLI 本体并同步 npm 发布所需的 app-server/runtime vendor 资产。
53
+ - `npm run package`:执行 `./script/package.sh`,构建 CLI 本体并同步 npm 发布所需的 products/app-server/runtime vendor 资产。
48
54
  - 运行 `media assets prepare` 时,CLI 会优先复用系统 `ffmpeg/ffprobe`;若本机不存在,则首次使用时自动下载到用户缓存目录。
49
55
 
50
56
  ## Runtime E2E Tester Config
51
57
 
52
- - 本地测试配置文件路径:`devtools/cli/tests/.local/runtime-backed.e2e.local.json`(必需,已在 `.gitignore` 忽略)。
53
- - 示例模板:`devtools/cli/tests/runtime-backed.e2e.config.example.json`。
54
- - CLI server-only 正式 E2E 现在直接读取 `mp4Path`,由 `service start` 内部自动 prepare;不再要求先手工 prepare 再维护 `assetsDir`。
58
+ - CLI server/client E2E 本地配置路径:`products/cli/config/.local/server.local.toml` + `products/cli/config/.local/client.local.toml`。
59
+ - `products/cli/config/.local/` 默认整体忽略;本地 gate 直接读取这两份 TOML,不再依赖 `tests/.local/*.json`。
60
+ - `server.local.toml` 负责 `service start` `debug.connect_bootstrap` 真相;`client.local.toml` 负责 `client start` `token issue` 所需的本地 truth。`license qrcode` 为纯命令行输入,不依赖 TOML。
55
61
 
56
62
  ## Command Loop E2E Harness
57
63
 
58
- - 长驻人工验收脚本:`devtools/cli/script/command_loop_e2e.sh`
59
- - 示例配置:`devtools/cli/config/command_loop_e2e.example.toml`
60
- - 本地配置路径:`devtools/cli/config/.local/command_loop_e2e.local.toml`(已在 `.gitignore` 忽略)
64
+ - 长驻人工验收脚本:`products/cli/script/command_loop_e2e.sh`
65
+ - 示例配置:`products/cli/config/command_loop_e2e.example.toml`
66
+ - 本地配置路径:`products/cli/config/.local/command_loop_e2e.local.toml`(已在 `.gitignore` 忽略)
61
67
  - 该脚本会先打包最新 `runtime + app-server + cli`,再清场、`service start`、周期性发送 `stream message` / time command,并轮询 `command pending list` 后自动做 CLI 侧显式 reply;启动成功后保持常驻,等待人工去操作 Android example。
package/USAGE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TiRTC DevTools CLI(用户手册)
2
2
 
3
- `tirtc-devtools-cli` 是基于 `app-server/host` 的命令行门面,用来控制会话、服务、连接、流、命令通道与调试工具。
3
+ `tirtc-devtools-cli` 是基于 `products/app-server/host` 的命令行门面,用来控制会话、服务、连接、流、命令通道与调试工具。
4
4
 
5
5
  ## 一、关系
6
6
 
@@ -11,16 +11,16 @@
11
11
  ## 二、开发态构建
12
12
 
13
13
  ```bash
14
- npm --prefix app-server ci
15
- npm --prefix devtools/cli ci
16
- npm --prefix app-server run build
17
- npm --prefix devtools/cli run build
14
+ npm --prefix products/app-server ci
15
+ npm --prefix products/cli ci
16
+ npm --prefix products/app-server run build
17
+ npm --prefix products/cli run build
18
18
  ```
19
19
 
20
20
  运行入口:
21
21
 
22
22
  ```bash
23
- node devtools/cli/bin/tirtc-devtools-cli.js --help
23
+ node products/cli/bin/tirtc-devtools-cli.js --help
24
24
  ```
25
25
 
26
26
  ## 三、Help 菜单速览
@@ -28,7 +28,7 @@ node devtools/cli/bin/tirtc-devtools-cli.js --help
28
28
  安装或构建完成后,先用 help 菜单确认当前 binary 暴露的命令面:
29
29
 
30
30
  ```bash
31
- node devtools/cli/bin/tirtc-devtools-cli.js --help
31
+ node products/cli/bin/tirtc-devtools-cli.js --help
32
32
  ```
33
33
 
34
34
  当前顶层 help 快照:
@@ -41,7 +41,7 @@ TiRTC DevTools CLI
41
41
  Options:
42
42
  --config <path> 配置文件路径(TOML)
43
43
  --json 以机器可读 JSON 输出(便于脚本集成)
44
- --session <sessionId> 指定会话 ID;除 service start/connect 外必须传
44
+ --session <sessionId> 指定会话 ID;除 service start / client start / connection connect 外必须传
45
45
  -h, --help display help for command
46
46
 
47
47
  Commands:
@@ -49,8 +49,10 @@ Commands:
49
49
  init 新手第一步:生成 CLI 配置模板
50
50
  media 媒体素材辅助:prepare local assets
51
51
  service 服务端能力:启动/停止服务,等待远端接入
52
+ client 客户端正式入口:连接远端并自动挂载本地 web preview
52
53
  connection 客户端能力:主动连接远端 peer
53
54
  token Token 工具:签发 token,并输出可直接使用的 JSON 与本地二维码 PNG
55
+ license License 工具:生成 server 扫码 JSON 与本地二维码 PNG
54
56
  stream 流控制:发送/接收/消息
55
57
  output 输出挂载:文件等消费者 attach/detach
56
58
  command 命令通道:发送命令与事件跟踪
@@ -64,10 +66,10 @@ Commands:
64
66
  常用子菜单 help:
65
67
 
66
68
  ```bash
67
- node devtools/cli/bin/tirtc-devtools-cli.js service --help
68
- node devtools/cli/bin/tirtc-devtools-cli.js stream --help
69
- node devtools/cli/bin/tirtc-devtools-cli.js command --help
70
- node devtools/cli/bin/tirtc-devtools-cli.js token issue --help
69
+ node products/cli/bin/tirtc-devtools-cli.js service --help
70
+ node products/cli/bin/tirtc-devtools-cli.js stream --help
71
+ node products/cli/bin/tirtc-devtools-cli.js command --help
72
+ node products/cli/bin/tirtc-devtools-cli.js token issue --help
71
73
  ```
72
74
 
73
75
  当前关键子菜单快照:
@@ -104,13 +106,19 @@ Options:
104
106
  --channel-ttl-seconds <seconds>
105
107
  --qr-error-correction-level <level>
106
108
  --ascii-max-columns <columns>
109
+
110
+ $ node ... license qrcode --help
111
+ Options:
112
+ --service-entry <entry>
113
+ --qr-error-correction-level <level>
114
+ --ascii-max-columns <columns>
107
115
  ```
108
116
 
109
117
  ## 四、全局参数
110
118
 
111
119
  - `--config <path>`:TOML 配置文件路径。
112
120
  - `--json`:结构化 JSON 输出。
113
- - `--session <sessionId>`:除 `service start` / `connection connect` 外,其余业务命令必须显式提供。
121
+ - `--session <sessionId>`:除 `service start` / `client start` / `connection connect` 外,其余业务命令必须显式提供。
114
122
 
115
123
  ## 五、会话模型
116
124
 
@@ -120,13 +128,13 @@ Options:
120
128
  - `host session list`:查看会话。
121
129
  - `host session stop <sessionId>`:停止会话。
122
130
  - `service start`:默认创建 `service` 会话;可通过 `--session` 绑定已有空闲会话。
123
- - `connection connect`:总是创建新的 `client` 会话,不允许复用 `--session`。
131
+ - `client start` / `connection connect`:总是创建新的 `client` 会话,不允许复用 `--session`。
124
132
 
125
133
  ## 六、server-only 正式入口
126
134
 
127
135
  ### 1. 配置真相
128
136
 
129
- server-only 正式路径只认 `[server] + [logging]`:
137
+ server-only 正式路径只认 `[server]`:
130
138
 
131
139
  ```toml
132
140
  [server]
@@ -136,10 +144,6 @@ mp4_path = "/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.
136
144
  video_stream_id = 11
137
145
  audio_stream_id = 10
138
146
 
139
- [logging]
140
- root_dir = "./.tmp/tirtc-devtools-cli/logging"
141
- console_mirror = true
142
- level = "info"
143
147
  ```
144
148
 
145
149
  说明:
@@ -147,11 +151,12 @@ level = "info"
147
151
  - `license`、`mp4_path`、`video_stream_id`、`audio_stream_id` 必填。
148
152
  - `service_entry` 可留空,回退到底层默认值。
149
153
  - 旧 `[service]`、`[stream.request_policy]`、`[streams.send]` 不再属于正式合同。
154
+ - 正式命令默认开启 console mirror,并把日志固定落到 `~/.tirtc-devtools-cli/logging/`。
150
155
 
151
156
  ### 2. 启动命令
152
157
 
153
158
  ```bash
154
- node devtools/cli/bin/tirtc-devtools-cli.js --config ./server.toml --json service start
159
+ node products/cli/bin/tirtc-devtools-cli.js --config ./server.toml --json service start
155
160
  ```
156
161
 
157
162
  `service start` 固定流程:
@@ -170,18 +175,49 @@ node devtools/cli/bin/tirtc-devtools-cli.js --config ./server.toml --json servic
170
175
  - CLI 不再暴露 request-policy 配置或命令。
171
176
  - 一旦远端请求对应 media,已绑定的发送流会自动转为 `active`。
172
177
 
173
- ## 七、connection connect
178
+ ## 七、client start
179
+
180
+ ```bash
181
+ node products/cli/bin/tirtc-devtools-cli.js --config ./client.toml --json client start --token <TOKEN>
182
+ ```
183
+
184
+ client 正式路径只认 `[client]`:
185
+
186
+ ```toml
187
+ [client]
188
+ service_entry = ""
189
+ peer_id = "peer-123"
190
+ audio_stream_id = 10
191
+ video_stream_id = 11
192
+ consumer = "web_preview"
193
+ ```
194
+
195
+ 说明:
196
+
197
+ - `peer_id`、`audio_stream_id`、`video_stream_id`、`consumer` 必填。
198
+ - `consumer` 当前固定为 `web_preview`。
199
+ - token 必须通过命令行 `--token` 显式提供,不进入配置文件。
200
+
201
+ `client start` 固定流程:
202
+
203
+ 1. 读取并校验 `[client]`。
204
+ 2. 调用 `connection/connect`。
205
+ 3. 自动调用两次 `stream/receiveStart`:一次音频、一次视频。
206
+ 4. 自动调用两次 `output/attach`,consumer 固定为 `web_preview`。
207
+ 5. 返回 `autoApplied` 摘要,其中 `preview.url` 是正式浏览器入口。
208
+
209
+ ## 八、connection connect
174
210
 
175
211
  ```bash
176
- node devtools/cli/bin/tirtc-devtools-cli.js --config ./server.toml --json connection connect <serviceEntry> <peerId> [token]
212
+ node products/cli/bin/tirtc-devtools-cli.js --config ./client.toml --json connection connect <serviceEntry> <peerId> <token>
177
213
  ```
178
214
 
179
215
  说明:
180
216
 
181
- - 若未显式传 `token`,CLI 会尝试使用 `[connection.auto_token]` 触发 App Server 自动签发。
182
- - 若命令行、省略 token、且配置也缺自动签发凭据,则命令失败。
217
+ - 该命令保留为 expert/atomic 路径。
218
+ - token 必须显式提供;CLI 不再提供 auto token 回退。
183
219
 
184
- ## 八、stream / output / command
220
+ ## 九、stream / output / command
185
221
 
186
222
  ### Stream
187
223
 
@@ -214,18 +250,21 @@ CLI 仍会在本地收紧最小组合矩阵:
214
250
 
215
251
  `command request` 是 canonical 主语,`command send` 只保留为兼容别名。若要发 JSON,请把 JSON 文本作为 `payload` 传入。`command pending list` 用于恢复或轮询当前积压,`command reply` 基于 `remoteRequestId` 显式回复待处理请求。
216
252
 
217
- ## 九、token / debug / report
253
+ ## 十、token / debug / report
218
254
 
219
255
  - `token issue <peerId>`:本地签发 token。
256
+ - `license qrcode <license>`:本地生成 server 扫码二维码。
220
257
  - `debug bootstrap qrcode ...` / `debug bootstrap qrcode-from-config`:生成联调用二维码。
221
258
  - `events tail`:实时查看事件流。
222
259
  - `logs export <outputPath>`:导出日志。
223
260
  - `report show` / `report export <outputPath>`:查看或导出报告。
224
261
 
225
- ## 十、本地 E2E 配置
262
+ ## 十一、本地 E2E 配置
226
263
 
227
- - CLI server/client E2E 本地配置文件:`devtools/cli/tests/.local/runtime-backed.e2e.local.json`
228
- - 推荐字段:`mp4Path`、`serviceEntry`、`license`、`peerId`、`accessId`、`secretKey`、可选 `e2eToken`
264
+ - CLI server/client E2E 本地配置文件:`products/cli/config/.local/server.local.toml` + `products/cli/config/.local/client.local.toml`
265
+ - `products/cli/config/.local/` 默认整体忽略,由本地联调环境自行维护
266
+ - `server.local.toml` 字段:`[server]` + `[debug.connect_bootstrap]`
267
+ - `client.local.toml` 字段:`[client]` + `[debug.token_issue]`
229
268
  - CLI server-only E2E 不再要求先手工 `media assets prepare` 再回填 `assetsDir`
230
269
 
231
270
  ## 十一、Android 人工闭环脚本
@@ -233,16 +272,16 @@ CLI 仍会在本地收紧最小组合矩阵:
233
272
  如果需要把 CLI 侧闭环常驻起来,再手工去操作 Android example,使用:
234
273
 
235
274
  ```bash
236
- ./devtools/cli/script/command_loop_e2e.sh
275
+ ./products/cli/script/command_loop_e2e.sh
237
276
  ```
238
277
 
239
- 默认读取:`devtools/cli/config/.local/command_loop_e2e.local.toml`
278
+ 默认读取:`products/cli/config/.local/command_loop_e2e.local.toml`
240
279
 
241
280
  建议先从模板复制:
242
281
 
243
282
  ```bash
244
- mkdir -p devtools/cli/config/.local
245
- cp devtools/cli/config/command_loop_e2e.example.toml devtools/cli/config/.local/command_loop_e2e.local.toml
283
+ mkdir -p products/cli/config/.local
284
+ cp products/cli/config/command_loop_e2e.example.toml products/cli/config/.local/command_loop_e2e.local.toml
246
285
  ```
247
286
 
248
287
  该脚本会:
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- require('../dist/devtools/cli/src/index.js');
2
+ require('../dist/cli/src/index.js');
@@ -0,0 +1,46 @@
1
+ import { AppServerClient } from '../../app-server/protocol-client';
2
+ import type { CliConfig } from './config';
3
+ import { ProgressIndicator } from './progress';
4
+ type ClientPreview = {
5
+ url: string;
6
+ token?: string;
7
+ endpoint?: string;
8
+ };
9
+ export type ServerBootstrapConfig = {
10
+ serviceEntry?: string;
11
+ license: string;
12
+ mp4Path: string;
13
+ audioStreamId: number;
14
+ videoStreamId: number;
15
+ };
16
+ export type ClientBootstrapConfig = {
17
+ serviceEntry?: string;
18
+ peerId: string;
19
+ audioStreamId: number;
20
+ videoStreamId: number;
21
+ consumer: 'web_preview';
22
+ };
23
+ export declare class BootstrapStepError extends Error {
24
+ readonly reasonCode: string;
25
+ readonly data: Record<string, unknown>;
26
+ constructor(reasonCode: string, message: string, data: Record<string, unknown>);
27
+ }
28
+ export declare function validateServerConfig(config: CliConfig): ServerBootstrapConfig;
29
+ export declare function validateClientConfig(config: CliConfig): ClientBootstrapConfig;
30
+ export declare function applyConfiguredServerBootstrap(client: AppServerClient, config: CliConfig, progress?: ProgressIndicator): Promise<{
31
+ preparedAssetsDir: string;
32
+ mediaSendPolicy: 'AUTO_ON_CONNECTED';
33
+ bootstrapSendStreams: Array<Record<string, unknown>>;
34
+ }>;
35
+ export declare function applyClientStartBootstrap(client: AppServerClient, config: CliConfig, token: string, progress?: ProgressIndicator): Promise<{
36
+ connection: unknown;
37
+ autoApplied: {
38
+ consumer: 'web_preview';
39
+ audioStream: unknown;
40
+ videoStream: unknown;
41
+ audioOutput: unknown;
42
+ videoOutput: unknown;
43
+ preview: ClientPreview;
44
+ };
45
+ }>;
46
+ export {};
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BootstrapStepError = void 0;
7
+ exports.validateServerConfig = validateServerConfig;
8
+ exports.validateClientConfig = validateClientConfig;
9
+ exports.applyConfiguredServerBootstrap = applyConfiguredServerBootstrap;
10
+ exports.applyClientStartBootstrap = applyClientStartBootstrap;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const os_1 = __importDefault(require("os"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const default_paths_1 = require("./default_paths");
15
+ const media_assets_1 = require("./media_assets");
16
+ class BootstrapStepError extends Error {
17
+ reasonCode;
18
+ data;
19
+ constructor(reasonCode, message, data) {
20
+ super(message);
21
+ this.name = 'BootstrapStepError';
22
+ this.reasonCode = reasonCode;
23
+ this.data = data;
24
+ }
25
+ }
26
+ exports.BootstrapStepError = BootstrapStepError;
27
+ function resolveProtocolError(error) {
28
+ if (typeof error === 'object' && error !== null) {
29
+ const typed = error;
30
+ if (typed.data?.reasonCode && typed.data.reasonCode.trim().length > 0) {
31
+ return {
32
+ reasonCode: typed.data.reasonCode,
33
+ message: typed.data.message ?? typed.message ?? 'Request failed',
34
+ };
35
+ }
36
+ if (typed.message && typed.message.trim().length > 0) {
37
+ return {
38
+ reasonCode: 'internal_error',
39
+ message: typed.message,
40
+ };
41
+ }
42
+ }
43
+ if (error instanceof Error) {
44
+ return {
45
+ reasonCode: 'internal_error',
46
+ message: error.message,
47
+ };
48
+ }
49
+ return {
50
+ reasonCode: 'internal_error',
51
+ message: 'Request failed',
52
+ };
53
+ }
54
+ function ensureNonNegativeInteger(value, field) {
55
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {
56
+ throw new Error(field + ' must be a non-negative integer');
57
+ }
58
+ return value;
59
+ }
60
+ function ensureNonEmptyString(value, field) {
61
+ if (typeof value !== 'string' || value.trim().length === 0) {
62
+ throw new Error(field + ' must be a non-empty string');
63
+ }
64
+ return value.trim();
65
+ }
66
+ function extractPreview(result, step) {
67
+ if (typeof result !== 'object' || result === null) {
68
+ throw new Error(step + ' did not return an object result');
69
+ }
70
+ const previewRaw = result.preview;
71
+ if (typeof previewRaw !== 'object' || previewRaw === null) {
72
+ throw new Error(step + ' did not return preview metadata');
73
+ }
74
+ const preview = previewRaw;
75
+ const url = ensureNonEmptyString(preview.url, step + ' preview.url');
76
+ return {
77
+ url,
78
+ token: typeof preview.token === 'string' && preview.token.trim().length > 0 ? preview.token.trim() : undefined,
79
+ endpoint: typeof preview.endpoint === 'string' && preview.endpoint.trim().length > 0 ? preview.endpoint.trim() : undefined,
80
+ };
81
+ }
82
+ async function runBootstrapStep(client, method, params, step, completed) {
83
+ try {
84
+ return await client.sendRequest(method, params);
85
+ }
86
+ catch (error) {
87
+ const resolved = resolveProtocolError(error);
88
+ throw new BootstrapStepError(resolved.reasonCode, resolved.message, {
89
+ failedStep: step,
90
+ completedSteps: completed,
91
+ });
92
+ }
93
+ }
94
+ function validateServerConfig(config) {
95
+ const server = config.server;
96
+ const license = server?.license?.trim() ?? '';
97
+ const mp4Path = server?.mp4_path?.trim() ?? '';
98
+ const audioStreamId = ensureNonNegativeInteger(server?.audio_stream_id, '[server].audio_stream_id');
99
+ const videoStreamId = ensureNonNegativeInteger(server?.video_stream_id, '[server].video_stream_id');
100
+ if (license.length === 0) {
101
+ throw new Error('server-only config requires [server].license');
102
+ }
103
+ if (mp4Path.length === 0) {
104
+ throw new Error('server-only config requires [server].mp4_path');
105
+ }
106
+ if (audioStreamId === videoStreamId) {
107
+ throw new Error('server-only config requires distinct audio_stream_id and video_stream_id');
108
+ }
109
+ const resolvedMp4Path = path_1.default.resolve(mp4Path);
110
+ let stats;
111
+ try {
112
+ stats = fs_1.default.statSync(resolvedMp4Path);
113
+ }
114
+ catch {
115
+ throw new Error('server-only config mp4_path does not exist: ' + resolvedMp4Path);
116
+ }
117
+ if (!stats.isFile()) {
118
+ throw new Error('server-only config mp4_path must be a readable file: ' + resolvedMp4Path);
119
+ }
120
+ const serviceEntry = server?.service_entry?.trim();
121
+ return {
122
+ serviceEntry: serviceEntry && serviceEntry.length > 0 ? serviceEntry : undefined,
123
+ license,
124
+ mp4Path: resolvedMp4Path,
125
+ audioStreamId,
126
+ videoStreamId,
127
+ };
128
+ }
129
+ function validateClientConfig(config) {
130
+ const client = config.client;
131
+ if (!client) {
132
+ throw new Error('client start requires [client] config');
133
+ }
134
+ const peerId = ensureNonEmptyString(client.peer_id, '[client].peer_id');
135
+ const audioStreamId = ensureNonNegativeInteger(client.audio_stream_id, '[client].audio_stream_id');
136
+ const videoStreamId = ensureNonNegativeInteger(client.video_stream_id, '[client].video_stream_id');
137
+ if (audioStreamId === videoStreamId) {
138
+ throw new Error('client config requires distinct audio_stream_id and video_stream_id');
139
+ }
140
+ if (client.consumer !== 'web_preview') {
141
+ throw new Error('client config requires [client].consumer = "web_preview"');
142
+ }
143
+ const serviceEntry = client.service_entry?.trim();
144
+ return {
145
+ serviceEntry: serviceEntry && serviceEntry.length > 0 ? serviceEntry : undefined,
146
+ peerId,
147
+ audioStreamId,
148
+ videoStreamId,
149
+ consumer: 'web_preview',
150
+ };
151
+ }
152
+ async function applyConfiguredServerBootstrap(client, config, progress) {
153
+ const server = validateServerConfig(config);
154
+ progress?.start('Preparing MP4 assets');
155
+ const prepared = await (0, media_assets_1.prepareMediaAssets)({
156
+ source: server.mp4Path,
157
+ outputRoot: (0, default_paths_1.resolveCliPreparedAssetsRoot)(),
158
+ });
159
+ progress?.update('Prepared MP4 assets');
160
+ const bootstrapSendStreams = [
161
+ { streamId: server.audioStreamId, media: 'audio' },
162
+ { streamId: server.videoStreamId, media: 'video' },
163
+ ].map(({ streamId, media }) => ({
164
+ streamId,
165
+ media,
166
+ source: {
167
+ mode: 'local_assets',
168
+ local_assets: {
169
+ assets_dir: prepared.assets_dir,
170
+ },
171
+ },
172
+ }));
173
+ return {
174
+ preparedAssetsDir: prepared.assets_dir,
175
+ mediaSendPolicy: 'AUTO_ON_CONNECTED',
176
+ bootstrapSendStreams,
177
+ };
178
+ }
179
+ async function applyClientStartBootstrap(client, config, token, progress) {
180
+ const normalizedToken = ensureNonEmptyString(token, '--token');
181
+ const clientConfig = validateClientConfig(config);
182
+ const audioArtifactPath = path_1.default.join(os_1.default.tmpdir(), `tirtc-client-preview-audio-${Date.now()}-${process.pid}.pcm`);
183
+ const videoArtifactPath = path_1.default.join(os_1.default.tmpdir(), `tirtc-client-preview-video-${Date.now()}-${process.pid}.jpeg`);
184
+ const completed = {
185
+ consumer: clientConfig.consumer,
186
+ };
187
+ progress?.start('Connecting client session');
188
+ const connection = await runBootstrapStep(client, 'connection/connect', {
189
+ serviceEntry: clientConfig.serviceEntry,
190
+ peerId: clientConfig.peerId,
191
+ token: normalizedToken,
192
+ timeoutMs: 5000,
193
+ }, 'connect', completed);
194
+ completed.connection = connection;
195
+ progress?.update('Connected client session');
196
+ const audioStream = await runBootstrapStep(client, 'stream/receiveStart', {
197
+ streamId: clientConfig.audioStreamId,
198
+ media: 'audio',
199
+ }, 'receive audio', completed);
200
+ completed.audioStream = audioStream;
201
+ progress?.update('Attached audio receive stream');
202
+ const videoStream = await runBootstrapStep(client, 'stream/receiveStart', {
203
+ streamId: clientConfig.videoStreamId,
204
+ media: 'video',
205
+ }, 'receive video', completed);
206
+ completed.videoStream = videoStream;
207
+ progress?.update('Attached video receive stream');
208
+ const audioOutput = await runBootstrapStep(client, 'output/attach', {
209
+ streamId: clientConfig.audioStreamId,
210
+ consumer: clientConfig.consumer,
211
+ mediaView: 'encoded_packet',
212
+ format: 'pcm',
213
+ delivery: 'artifact_path',
214
+ targetPath: audioArtifactPath,
215
+ }, 'attach audio preview', completed);
216
+ completed.audioOutput = audioOutput;
217
+ progress?.update('Attached audio preview output');
218
+ const videoOutput = await runBootstrapStep(client, 'output/attach', {
219
+ streamId: clientConfig.videoStreamId,
220
+ consumer: clientConfig.consumer,
221
+ mediaView: 'encoded_packet',
222
+ format: 'jpeg',
223
+ delivery: 'artifact_path',
224
+ targetPath: videoArtifactPath,
225
+ }, 'attach video preview', completed);
226
+ completed.videoOutput = videoOutput;
227
+ progress?.succeed('Client preview session is ready');
228
+ const audioPreview = extractPreview(audioOutput, 'attach audio preview');
229
+ const videoPreview = extractPreview(videoOutput, 'attach video preview');
230
+ if (audioPreview.url !== videoPreview.url) {
231
+ throw new BootstrapStepError('internal_error', 'web_preview outputs returned different preview URLs', {
232
+ failedStep: 'preview aggregation',
233
+ completedSteps: completed,
234
+ audioPreview,
235
+ videoPreview,
236
+ });
237
+ }
238
+ return {
239
+ connection,
240
+ autoApplied: {
241
+ consumer: clientConfig.consumer,
242
+ audioStream,
243
+ videoStream,
244
+ audioOutput,
245
+ videoOutput,
246
+ preview: audioPreview,
247
+ },
248
+ };
249
+ }
@@ -6,23 +6,12 @@ export type CliConfig = {
6
6
  video_stream_id?: number;
7
7
  audio_stream_id?: number;
8
8
  };
9
- connection?: {
9
+ client?: {
10
10
  service_entry?: string;
11
11
  peer_id?: string;
12
- token?: string;
13
- auto_token?: {
14
- openapi_entry?: string;
15
- access_id?: string;
16
- secret_key?: string;
17
- local_id?: string;
18
- user_ttl_seconds?: number;
19
- channel_ttl_seconds?: number;
20
- };
21
- };
22
- logging?: {
23
- root_dir?: string;
24
- console_mirror?: boolean;
25
- level?: 'verbose' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
12
+ audio_stream_id?: number;
13
+ video_stream_id?: number;
14
+ consumer?: 'web_preview';
26
15
  };
27
16
  debug?: {
28
17
  connect_bootstrap?: {