@xbongbong/xbbcli 2.0.0 → 2.2.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.
Files changed (258) hide show
  1. package/README.md +101 -2
  2. package/ai-call-add-task.js +3 -6
  3. package/ai-word-list.js +3 -6
  4. package/bin/xbbcli.js +20 -2
  5. package/buyer-inquiry-detail.js +2 -5
  6. package/buyer-inquiry-list.js +2 -5
  7. package/clue-add-couser.js +2 -5
  8. package/clue-add.js +2 -5
  9. package/clue-back.js +2 -5
  10. package/clue-del.js +2 -5
  11. package/clue-delete-couser.js +2 -5
  12. package/clue-delete-mainuser.js +2 -5
  13. package/clue-detail.js +2 -5
  14. package/clue-distribution.js +2 -5
  15. package/clue-edit.js +2 -5
  16. package/clue-handover.js +3 -6
  17. package/clue-list.js +2 -5
  18. package/clue-thorough-delete.js +2 -5
  19. package/communicate-add.js +2 -5
  20. package/communicate-del.js +2 -5
  21. package/communicate-detail.js +2 -5
  22. package/communicate-edit.js +2 -5
  23. package/communicate-list.js +2 -5
  24. package/communicate-plan-add.js +2 -5
  25. package/communicate-plan-cancel.js +2 -5
  26. package/communicate-plan-del.js +2 -5
  27. package/communicate-plan-detail.js +2 -5
  28. package/communicate-plan-list.js +2 -5
  29. package/communicate-plan-single-operate.js +2 -5
  30. package/contact-add-couser.js +2 -5
  31. package/contact-add-mainuser.js +2 -5
  32. package/contact-add.js +2 -5
  33. package/contact-del.js +2 -1
  34. package/contact-delete-couser.js +2 -5
  35. package/contact-delete-mainuser.js +2 -5
  36. package/contact-detail.js +2 -1
  37. package/contact-edit.js +2 -5
  38. package/contact-handover.js +2 -5
  39. package/contact-list.js +2 -5
  40. package/contract-add-couser.js +2 -5
  41. package/contract-add-mainuser.js +2 -5
  42. package/contract-add.js +2 -5
  43. package/contract-del.js +2 -5
  44. package/contract-delete-couser.js +2 -5
  45. package/contract-delete-mainuser.js +2 -5
  46. package/contract-detail.js +2 -5
  47. package/contract-edit.js +2 -5
  48. package/contract-handover.js +2 -5
  49. package/contract-list.js +2 -5
  50. package/contract-outstock-add.js +2 -5
  51. package/contract-outstock-del.js +2 -5
  52. package/contract-outstock-detail.js +2 -5
  53. package/contract-outstock-edit.js +2 -5
  54. package/contract-outstock-list.js +2 -5
  55. package/customer-add-couser.js +2 -5
  56. package/customer-add.js +2 -5
  57. package/customer-back.js +2 -5
  58. package/customer-del.js +2 -5
  59. package/customer-delete-couser.js +2 -5
  60. package/customer-delete-mainuser.js +2 -5
  61. package/customer-detail.js +2 -5
  62. package/customer-distribution.js +2 -5
  63. package/customer-edit.js +2 -5
  64. package/customer-handover.js +2 -5
  65. package/customer-invoice-address-add.js +2 -5
  66. package/customer-invoice-address-edit.js +2 -5
  67. package/customer-invoice-address.js +2 -5
  68. package/customer-invoice-info-add.js +2 -5
  69. package/customer-invoice-info-edit.js +2 -5
  70. package/customer-invoice-info.js +2 -5
  71. package/customer-list.js +2 -5
  72. package/department-add.js +2 -5
  73. package/department-del.js +2 -5
  74. package/department-edit.js +2 -5
  75. package/department-list.js +2 -5
  76. package/form-data-add-couser.js +2 -5
  77. package/form-data-add-mainuser.js +2 -5
  78. package/form-data-add.js +2 -5
  79. package/form-data-del.js +2 -5
  80. package/form-data-delete-couser.js +2 -5
  81. package/form-data-delete-mainuser.js +2 -5
  82. package/form-data-detail.js +2 -5
  83. package/form-data-edit.js +2 -5
  84. package/form-data-handover.js +2 -5
  85. package/form-data-list.js +2 -5
  86. package/form-get.js +2 -5
  87. package/form-list.js +2 -5
  88. package/invoice-add.js +3 -6
  89. package/invoice-cancel.js +3 -6
  90. package/invoice-del.js +3 -6
  91. package/invoice-detail.js +3 -6
  92. package/invoice-edit.js +3 -6
  93. package/invoice-get-amount-detail.js +3 -6
  94. package/invoice-list.js +3 -6
  95. package/invoice-red.js +3 -6
  96. package/label-add.js +3 -6
  97. package/label-all-list.js +3 -6
  98. package/label-batch-add.js +3 -6
  99. package/label-batch-remove.js +3 -6
  100. package/label-del-completely.js +3 -6
  101. package/label-del.js +3 -6
  102. package/label-edit.js +3 -6
  103. package/label-group-add.js +3 -6
  104. package/label-group-del.js +3 -6
  105. package/label-group-list.js +3 -6
  106. package/label-group-update.js +3 -6
  107. package/label-list.js +3 -6
  108. package/label-reduction.js +3 -6
  109. package/label-repeat.js +3 -6
  110. package/market-activity-add.js +2 -5
  111. package/market-activity-del.js +2 -5
  112. package/market-activity-detail.js +2 -5
  113. package/market-activity-edit.js +2 -5
  114. package/market-activity-handover.js +2 -5
  115. package/market-activity-list.js +2 -5
  116. package/opportunity-add-couser.js +2 -5
  117. package/opportunity-add-mainuser.js +2 -5
  118. package/opportunity-add.js +2 -5
  119. package/opportunity-del.js +2 -5
  120. package/opportunity-delete-couser.js +2 -5
  121. package/opportunity-delete-mainuser.js +2 -5
  122. package/opportunity-detail.js +2 -5
  123. package/opportunity-edit.js +2 -5
  124. package/opportunity-handover.js +2 -5
  125. package/opportunity-list.js +2 -5
  126. package/package.json +1 -1
  127. package/pay-plan-add-couser.js +2 -5
  128. package/pay-plan-add-mainuser.js +2 -5
  129. package/pay-plan-add.js +2 -5
  130. package/pay-plan-delete-couser.js +2 -5
  131. package/pay-plan-delete-mainuser.js +2 -5
  132. package/pay-plan-handover.js +2 -5
  133. package/pay-sheet-add-bad.js +2 -5
  134. package/pay-sheet-add-couser.js +2 -5
  135. package/pay-sheet-add-mainuser.js +2 -5
  136. package/pay-sheet-add-red.js +2 -5
  137. package/pay-sheet-add-write-off.js +2 -5
  138. package/pay-sheet-del.js +2 -5
  139. package/pay-sheet-delete-couser.js +2 -5
  140. package/pay-sheet-delete-mainuser.js +2 -5
  141. package/pay-sheet-detail.js +2 -5
  142. package/pay-sheet-edit-bad.js +2 -5
  143. package/pay-sheet-edit-red.js +2 -5
  144. package/pay-sheet-edit-write-off.js +2 -5
  145. package/pay-sheet-get-amount-detail.js +2 -5
  146. package/pay-sheet-list.js +2 -5
  147. package/payment-add-couser.js +2 -5
  148. package/payment-add-mainuser.js +2 -5
  149. package/payment-add.js +2 -5
  150. package/payment-del.js +2 -5
  151. package/payment-delete-couser.js +2 -5
  152. package/payment-delete-mainuser.js +2 -5
  153. package/payment-detail.js +2 -5
  154. package/payment-edit.js +2 -5
  155. package/payment-handover.js +2 -5
  156. package/payment-list.js +2 -5
  157. package/payment-sheet-add-bad-debt.js +2 -5
  158. package/payment-sheet-add-pre.js +2 -5
  159. package/payment-sheet-add-red.js +2 -5
  160. package/payment-sheet-add-write-off.js +2 -5
  161. package/payment-sheet-del.js +2 -5
  162. package/payment-sheet-detail.js +2 -5
  163. package/payment-sheet-edit-bad-debt.js +2 -5
  164. package/payment-sheet-edit-red.js +2 -5
  165. package/payment-sheet-edit-write-off.js +2 -5
  166. package/payment-sheet-get-amount-detail.js +2 -5
  167. package/payment-sheet-handover.js +2 -5
  168. package/payment-sheet-list.js +2 -5
  169. package/product-add.js +2 -5
  170. package/product-category-add.js +2 -5
  171. package/product-category-del.js +2 -5
  172. package/product-category-list.js +2 -5
  173. package/product-category-update.js +2 -5
  174. package/product-del.js +2 -5
  175. package/product-detail.js +2 -5
  176. package/product-edit.js +2 -5
  177. package/product-list.js +2 -5
  178. package/product-online.js +2 -5
  179. package/quotation-add-couser.js +3 -6
  180. package/quotation-add-mainuser.js +3 -6
  181. package/quotation-add.js +3 -6
  182. package/quotation-del.js +3 -6
  183. package/quotation-delete-couser.js +3 -6
  184. package/quotation-delete-mainuser.js +3 -6
  185. package/quotation-detail.js +3 -6
  186. package/quotation-edit.js +3 -6
  187. package/quotation-handover.js +2 -5
  188. package/quotation-list.js +3 -6
  189. package/refund-add.js +4 -1
  190. package/refund-del.js +4 -1
  191. package/refund-detail.js +4 -1
  192. package/refund-edit.js +4 -1
  193. package/refund-list.js +2 -5
  194. package/role-list.js +2 -5
  195. package/sign-in-list.js +2 -5
  196. package/stage-get.js +2 -5
  197. package/stage-jump.js +2 -5
  198. package/supplier-add.js +2 -5
  199. package/token-del.js +106 -0
  200. package/token-generate.js +2 -5
  201. package/token-list.js +119 -0
  202. package/token-set.js +191 -10
  203. package/token-use.js +102 -0
  204. package/user-add.js +2 -5
  205. package/user-del.js +2 -5
  206. package/user-edit.js +2 -5
  207. package/user-handover.js +2 -5
  208. package/user-list.js +5 -8
  209. package/work-order-add.js +2 -5
  210. package/work-order-asset-add-couser.js +3 -6
  211. package/work-order-asset-add-mainuser.js +3 -6
  212. package/work-order-asset-add.js +3 -6
  213. package/work-order-asset-del-couser.js +3 -6
  214. package/work-order-asset-del-mainuser.js +3 -6
  215. package/work-order-asset-del.js +3 -6
  216. package/work-order-asset-detail.js +3 -6
  217. package/work-order-asset-edit.js +3 -6
  218. package/work-order-asset-handover.js +3 -6
  219. package/work-order-asset-list.js +3 -6
  220. package/work-order-del.js +2 -5
  221. package/work-order-detail.js +2 -5
  222. package/work-order-dynamic-list.js +2 -5
  223. package/work-order-edit.js +2 -5
  224. package/work-order-list.js +2 -5
  225. package/work-order-operate.js +2 -5
  226. package/work-order-template-detail.js +2 -5
  227. package/work-order-template-list.js +2 -5
  228. package/work-report-daily-add.js +2 -5
  229. package/work-report-daily-del.js +2 -5
  230. package/work-report-daily-detail.js +2 -5
  231. package/work-report-daily-edit.js +2 -5
  232. package/work-report-daily-get-work-plan.js +2 -5
  233. package/work-report-daily-list.js +2 -5
  234. package/work-report-monthly-add.js +2 -5
  235. package/work-report-monthly-del.js +2 -5
  236. package/work-report-monthly-detail.js +2 -5
  237. package/work-report-monthly-edit.js +2 -5
  238. package/work-report-monthly-list.js +2 -5
  239. package/work-report-weekly-add.js +2 -5
  240. package/work-report-weekly-del.js +2 -5
  241. package/work-report-weekly-detail.js +2 -5
  242. package/work-report-weekly-edit.js +2 -5
  243. package/work-report-weekly-list.js +2 -5
  244. package/work-task-add-couser.js +2 -5
  245. package/work-task-add.js +2 -5
  246. package/work-task-delete-couser.js +2 -5
  247. package/work-task-detail.js +2 -5
  248. package/work-task-edit.js +2 -5
  249. package/work-task-handover.js +2 -5
  250. package/workorder-add-couser.js +2 -5
  251. package/workorder-delete-couser.js +2 -5
  252. package/workorder-handover.js +2 -5
  253. package/workorderlist.js +2 -5
  254. package/workorderproductlist.js +2 -5
  255. package/worktimerecorddetail.js +2 -5
  256. package/worktimerecordlist.js +2 -5
  257. package/xbb-config.js +113 -0
  258. package/version.js +0 -18
package/README.md CHANGED
@@ -13,6 +13,21 @@ xbbcli --help
13
13
 
14
14
  需要升级时运行 `npm update -g @xbongbong/xbbcli`。
15
15
 
16
+
17
+
18
+ 首次使用时配置销帮帮凭证:
19
+
20
+ ```bash
21
+ xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>
22
+ ```
23
+
24
+ 配置完成后即可运行各业务命令,例如:
25
+
26
+ ```bash
27
+ xbbcli user-list
28
+ xbbcli form-list --saasMark 1 -f json
29
+ ```
30
+
16
31
  ## 初始化配置
17
32
 
18
33
  首次使用先保存 `corpid`、`token` 和 `userId`:
@@ -27,12 +42,40 @@ xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>
27
42
  ~/.xbbcli/config.env
28
43
  ```
29
44
 
30
- 文件内容包含:
45
+ `config.env` 是一个 JSON 文件,可同时保存多家公司,每个公司包含:
31
46
 
32
47
  - `corpid`
33
48
  - `token`
34
49
  - `baseurl`
35
50
  - `userId`
51
+ - `enable`:是否启用;任何时刻**仅且只有一个**公司的 `enable` 为 `true`
52
+ - `corpName`:公司名称,取部门列表中 `id` 为 `1` 的部门名称(`token-set` 自动写入)
53
+ - `userName`:当前 `userId` 对应的员工姓名,从员工列表中按 `userId` 匹配(`token-set` 自动写入)
54
+
55
+ 示例:
56
+
57
+ ```json
58
+ [
59
+ {
60
+ "corpid": "<CORPID_A>",
61
+ "token": "<TOKEN_A>",
62
+ "baseurl": "https://proapi.xbongbong.com",
63
+ "userId": "<USERID_A>",
64
+ "corpName": "<CORP_NAME_A>",
65
+ "userName": "<USER_NAME_A>",
66
+ "enable": true
67
+ },
68
+ {
69
+ "corpid": "<CORPID_B>",
70
+ "token": "<TOKEN_B>",
71
+ "baseurl": "https://appapi.xbongbong.com",
72
+ "userId": "<USERID_B>",
73
+ "enable": false
74
+ }
75
+ ]
76
+ ```
77
+
78
+ `token-set` 会按 `corpid` 新增或覆盖一家公司,并把该公司置为 `enable=true`(其余公司自动置为 `false`),同时写入公司名称 `corpName`(取部门 `id` 为 `1` 的部门名称)和操作人姓名 `userName`(从员工列表中按 `userId` 匹配)。除 `token-set`、`token-list`、`token-use`、`token-del` 外,其余命令都使用 `enable` 为 `true` 的公司配置。
36
79
 
37
80
  同时会自动拉取两份表单清单并合并缓存到:
38
81
 
@@ -47,16 +90,68 @@ xbbcli form-list --saasMark 2 -f json
47
90
  xbbcli form-list --saasMark 1 -f json
48
91
  ```
49
92
 
93
+ 同时会自动分页拉取所有部门与员工并缓存到:
94
+
95
+ ```text
96
+ ~/.xbbcli/<corpid>.department-user.json
97
+ ```
98
+
99
+ 初始化过程调用:
100
+
101
+ ```bash
102
+ xbbcli department-list --pageSize 200 -f json
103
+ xbbcli user-list --pageSize 200 -f json
104
+ ```
105
+
106
+ 缓存文件内容:
107
+
108
+ - `departments`:部门清单(`id`、`name`、`parentId`、`depIdRouter`)
109
+ - `users`:员工清单(`userId`、`name`、`position`、`jobnumber`、`departmentList`)
110
+ - `departmentCount`、`userCount`、`pageSize`、`updatedAt`
111
+
112
+ 以后需要查询部门或员工信息时,可以先查这个文件,避免重复调用接口。
113
+
50
114
  `baseurl` 路由规则:
51
115
 
52
116
  - `corpid` 以 `ding` 开头,或包含 `$$ding` 时,使用 `https://proapi.xbongbong.com`
53
117
  - 其他 `corpid` 使用 `https://appapi.xbongbong.com`
54
118
 
119
+ ## 环境变量模式(单公司)
120
+
121
+ 除 `config.env` 外,命令也支持从环境变量读取一家公司的凭证,便于 CI、容器与其他工具集成:
122
+
123
+ | 环境变量 | 对应字段 |
124
+ | --- | --- |
125
+ | `XBB_CORPID` | `corpid` |
126
+ | `XBB_TOKEN` | `token` |
127
+ | `XBB_BASEURL` | `baseurl` |
128
+ | `XBB_USERID` | `userId` |
129
+ | `XBB_CORPNAME` | `corpName` |
130
+ | `XBB_USERNAME` | `userName` |
131
+
132
+ 读取优先级:
133
+
134
+ 1. `config.env` 中存在 `enable=true` 的公司时,使用该配置(多公司切换行为不变)
135
+ 2. `config.env` 缺失、解析失败或没有启用公司时,回落到上述环境变量
136
+ 3. 设置 `XBB_ENV_ONLY=1` 可强制只使用环境变量(完全忽略 `config.env`)
137
+
138
+ `token-set` 成功后会自动把这 6 个值写入环境变量(加 `--noEnv` 可跳过):
139
+
140
+ - Windows:用 `setx` 写入用户级环境变量,**只对新开的终端生效**
141
+ - macOS/Linux:写入 `~/.xbbcli/env.sh`(`export` 形式,权限 600),需要 `source ~/.xbbcli/env.sh` 才在当前 shell 生效
142
+
143
+ 环境变量模式只支持一家公司:此时 `token-list` 以 `source=env` 单行显示,`token-use` / `token-del` 会返回不支持多公司的错误行,并提示改用 `config.env`。
144
+
145
+ > 注意:`token-del` 不会清理已经写入的环境变量。如需移除环境变量模式,Windows 下执行 `setx XBB_TOKEN ""`(其余 `XBB_*` 同理)并重开终端;macOS/Linux 下删除 `~/.xbbcli/env.sh`,再 `unset` 当前 shell 中已导出的变量。
146
+
55
147
  ## 当前支持的命令
56
148
 
57
149
  ### 配置
58
150
 
59
- - `token-set`:保存个人 token、`corpid`、`userId`、`baseurl`,并刷新本地表单缓存;传入的 token 不以 `user_` 开头时,会先为该 `userId` 刷新并保存个人 token
151
+ - `token-set`:保存个人 token、`corpid`、`userId`、`baseurl`,并刷新本地表单缓存、命令映射文件与部门/员工缓存;传入的 token 不以 `user_` 开头时,会先为该 `userId` 刷新并保存个人 token;成功后同步写入 `XBB_*` 环境变量(Windows 用 `setx`,其他平台写 `~/.xbbcli/env.sh`),`--noEnv` 可跳过;返回 `envStored` / `envFile` 两列
152
+ - `token-list`:列出本地保存的所有公司配置和唯一启用的公司(含 `corpName` 公司名称与 `userName` 操作人姓名,`source` 列标记来源 `config`/`env`);`--showToken` 显示完整 token(默认脱敏);环境变量模式下单行显示
153
+ - `token-use`:切换当前启用的公司(`xbbcli token-use --corpid <CORPID>`),保证仅且只有一个公司被启用
154
+ - `token-del`:删除指定公司的本地配置(`xbbcli token-del --corpid <CORPID>`),并保证剩余配置中仅且只有一个公司被启用
60
155
  - `token-generate`:生成/获取个人 token,`--resetToken 0` 获取(默认)、`1` 刷新;`--checkUserId` 未传则用配置中的 `userId`
61
156
 
62
157
  ### 组织与人员
@@ -302,8 +397,11 @@ xbbcli form-list --saasMark 1 -f json
302
397
  - 先执行一次 `token-set` 保存有效的 `corpid`、`token`、`userId`
303
398
  - 除 `token-set` 外,其余命令都会从 `~/.xbbcli/config.env` 读取 `corpid`
304
399
  - 大部分命令会从 `~/.xbbcli/config.env` 读取 `token`
400
+ - 未配置 `config.env`(或其中没有启用公司)时,命令会回落到 `XBB_CORPID` / `XBB_TOKEN` / `XBB_BASEURL` / `XBB_USERID` / `XBB_CORPNAME` / `XBB_USERNAME` 环境变量;`XBB_ENV_ONLY=1` 可强制只用环境变量
305
401
  - 所有命令会从配置中读取 `userId` 并附加到请求 header 中
306
402
  - 大部分命令需要 formId 参数,可以根据业务名称或 businessType 从 `~/.xbbcli/<corpid>.formlist.json` 中获取 formId
403
+ - 需要查询部门 id/名称,或员工 userId/所属部门时,可以先查 `~/.xbbcli/<corpid>.department-user.json`(由 `token-set` 分页抓取并缓存全部部门与员工)
404
+ - 当前公司名称存在 `~/.xbbcli/config.env` 的 `corpName` 字段(取部门 `id` 为 `1` 的部门名称),操作人姓名存在 `userName` 字段(按 `userId` 匹配员工列表)
307
405
  - 未传入的可选参数不会进入请求体
308
406
  - `--attr` 和 `--value` 只有同时提供时才会拼入查询条件
309
407
  - `--limit` 是在响应映射之后截断结果
@@ -311,6 +409,7 @@ xbbcli form-list --saasMark 1 -f json
311
409
  - 加 `--debug` 可以输出 `requestBody` 和 `responseBody`
312
410
  - 加 `--raw` 可以输出接口返回的原始 JSON 字符串(所有 list 命令均支持)
313
411
  - 在填充参数时不清楚参数含义/下拉框可选项值,调用 `form-get` 命令获取 form 解释
412
+ - `xbbcli -v` / `xbbcli --version` 查看版本号(读取 `package.json` 的 `version`)
314
413
 
315
414
  ## 常用示例
316
415
 
@@ -2,7 +2,8 @@ import crypto from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
- import { cli, Strategy } from './xbb-registry.js';
5
+ import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.opencli', 'xbb', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/hkh/call/addTask';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 opencli xbb token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/ai-word-list.js CHANGED
@@ -2,7 +2,8 @@ import crypto from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
- import { cli, Strategy } from './xbb-registry.js';
5
+ import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.opencli', 'xbb', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/hkh/call/aiWords';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 opencli xbb token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/bin/xbbcli.js CHANGED
@@ -21,12 +21,22 @@ async function loadCommands() {
21
21
  }
22
22
  }
23
23
 
24
+ function readVersion() {
25
+ try {
26
+ const parsed = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
27
+ return String(parsed.version || '').trim() || 'unknown';
28
+ } catch {
29
+ return 'unknown';
30
+ }
31
+ }
32
+
24
33
  function printHelp() {
25
34
  const commands = [...getRegistry().values()].sort((a, b) => a.name.localeCompare(b.name));
26
- process.stdout.write('Usage: xbbcli <command> [options]\n\nCommands:\n');
35
+ process.stdout.write('Usage: xbbcli <command> [options]\n xbbcli -v | --version\n\nCommands:\n');
27
36
  for (const command of commands) {
28
37
  process.stdout.write(` ${command.name.padEnd(34)} ${command.description || ''}\n`);
29
38
  }
39
+ process.stdout.write(`\n ${'-v, --version'.padEnd(34)} show version\n`);
30
40
  }
31
41
 
32
42
  function printCommandHelp(command) {
@@ -91,11 +101,19 @@ function outputRows(rows, command, format) {
91
101
  }
92
102
  process.stdout.write(`${columns.join('\t')}\n`);
93
103
  for (const row of rows) process.stdout.write(`${columns.map((column) => String(row[column] ?? '')).join('\t')}\n`);
104
+
105
+ const footer = typeof command.footerExtra === "function"
106
+ ? command.footerExtra()
107
+ : command.footerExtra;
108
+ if (footer) process.stdout.write(`${footer}\n`);
94
109
  }
95
110
 
96
111
  await loadCommands();
97
112
  const [commandName, ...argv] = process.argv.slice(2);
98
- if (!commandName || commandName === '--help' || commandName === '-h') {
113
+ if (commandName === '--version' || commandName === '-v') {
114
+ process.stdout.write(`${readVersion()}\n`);
115
+ process.exitCode = 0;
116
+ } else if (!commandName || commandName === '--help' || commandName === '-h') {
99
117
  printHelp();
100
118
  process.exitCode = 0;
101
119
  } else {
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const BUYER_INQUIRY_DETAIL_API_URL = 'https://proapi.xbongbong.com/pro/v2/api/buyerInquiry/detail';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const BUYER_INQUIRY_LIST_API_URL = 'https://proapi.xbongbong.com/pro/v2/api/buyerInquiry/list';
@@ -11,11 +12,7 @@ const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --co
11
12
  let lastPagination = null;
12
13
 
13
14
  function readConfig() {
14
- try {
15
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
16
- } catch {
17
- return {};
18
- }
15
+ return readActiveConfig();
19
16
  }
20
17
 
21
18
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/addCoUser';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/clue-add.js CHANGED
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/add';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/clue-back.js CHANGED
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/back';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/clue-del.js CHANGED
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/del';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/deleteCoUser';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/deleteMainUser';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/clue-detail.js CHANGED
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/detail';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/distribution';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/clue-edit.js CHANGED
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/edit';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/clue-handover.js CHANGED
@@ -2,7 +2,8 @@ import crypto from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
- import { cli, Strategy } from './xbb-registry.js';
5
+ import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.opencli', 'xbb', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/handover';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 opencli xbb token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
package/clue-list.js CHANGED
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const CLUE_LIST_API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/list';
@@ -11,11 +12,7 @@ const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --co
11
12
  let lastPagination = null;
12
13
 
13
14
  function readConfig() {
14
- try {
15
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
16
- } catch {
17
- return {};
18
- }
15
+ return readActiveConfig();
19
16
  }
20
17
 
21
18
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/clue/thorough/delete';
@@ -10,11 +11,7 @@ const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
10
11
  const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --corpid <CORPID> --token <TOKEN> --userId <USERID>';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_DIR = path.join(os.homedir(), '.xbbcli');
8
9
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
@@ -10,11 +11,7 @@ const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/communicate/add';
10
11
  const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_DIR = path.join(os.homedir(), '.xbbcli');
8
9
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
@@ -10,11 +11,7 @@ const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/communicate/del';
10
11
  const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_DIR = path.join(os.homedir(), '.xbbcli');
8
9
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
@@ -10,11 +11,7 @@ const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/communicate/detail';
10
11
  const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import crypto from 'node:crypto';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_DIR = path.join(os.homedir(), '.xbbcli');
8
9
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.env');
@@ -10,11 +11,7 @@ const API_URL = 'https://proapi.xbongbong.com/pro/v2/api/communicate/edit';
10
11
  const DEFAULT_BASE_URL = 'https://proapi.xbongbong.com';
11
12
 
12
13
  function readConfig() {
13
- try {
14
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
15
- } catch {
16
- return {};
17
- }
14
+ return readActiveConfig();
18
15
  }
19
16
 
20
17
  function getRuntimeConfig() {
@@ -3,6 +3,7 @@ import fs from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { cli, Strategy } from './xbb-registry.js';
6
+ import { readActiveConfig } from './xbb-config.js';
6
7
 
7
8
  const CONFIG_FILE = path.join(os.homedir(), '.xbbcli', 'config.env');
8
9
  const COMMUNICATE_LIST_API_URL = 'https://proapi.xbongbong.com/pro/v2/api/communicate/list';
@@ -11,11 +12,7 @@ const MISSING_TOKEN_MESSAGE = '缺少 token;请先执行 xbbcli token-set --co
11
12
  let lastPagination = null;
12
13
 
13
14
  function readConfig() {
14
- try {
15
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
16
- } catch {
17
- return {};
18
- }
15
+ return readActiveConfig();
19
16
  }
20
17
 
21
18
  function getRuntimeConfig() {