weaver-work-cli 0.1.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 (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +422 -0
  3. package/dist/cmd/action.js +35 -0
  4. package/dist/cmd/commands/index.js +15 -0
  5. package/dist/cmd/config/index.js +64 -0
  6. package/dist/cmd/docs/index.js +56 -0
  7. package/dist/cmd/doctor/index.js +45 -0
  8. package/dist/cmd/e10/index.js +25 -0
  9. package/dist/cmd/index.js +18 -0
  10. package/dist/cmd/register.js +19 -0
  11. package/dist/cmd/root.js +36 -0
  12. package/dist/cmd/run/index.js +38 -0
  13. package/dist/cmd/setup/index.js +77 -0
  14. package/dist/cmd/skills/index.js +72 -0
  15. package/dist/core/config-store.js +43 -0
  16. package/dist/core/context.js +31 -0
  17. package/dist/core/errors.js +60 -0
  18. package/dist/core/hooks.js +41 -0
  19. package/dist/core/logger.js +27 -0
  20. package/dist/core/output.js +25 -0
  21. package/dist/core/write-with-retry.js +21 -0
  22. package/dist/index.js +11 -0
  23. package/dist/internal/e10/auth/commands.js +594 -0
  24. package/dist/internal/e10/auth/crypto.js +126 -0
  25. package/dist/internal/e10/auth/paths.js +12 -0
  26. package/dist/internal/e10/auth/session.js +449 -0
  27. package/dist/internal/e10/client.js +104 -0
  28. package/dist/internal/e10/context.js +20 -0
  29. package/dist/internal/e10/index.js +2 -0
  30. package/dist/internal/e10/types.js +1 -0
  31. package/dist/internal/skills/install.js +99 -0
  32. package/dist/internal/skills/reader.js +119 -0
  33. package/dist/services/command-runner.js +44 -0
  34. package/dist/shortcuts/index.js +4 -0
  35. package/dist/shortcuts/invoice/continuation.js +70 -0
  36. package/dist/shortcuts/invoice/errors.js +59 -0
  37. package/dist/shortcuts/invoice/host.js +337 -0
  38. package/dist/shortcuts/invoice/index.js +301 -0
  39. package/dist/shortcuts/invoice/manifest.js +288 -0
  40. package/dist/shortcuts/invoice/operations/add.js +106 -0
  41. package/dist/shortcuts/invoice/operations/delete.js +92 -0
  42. package/dist/shortcuts/invoice/operations/download.js +16 -0
  43. package/dist/shortcuts/invoice/operations/get.js +7 -0
  44. package/dist/shortcuts/invoice/operations/import.js +128 -0
  45. package/dist/shortcuts/invoice/operations/list.js +12 -0
  46. package/dist/shortcuts/invoice/operations/ocr-preview.js +40 -0
  47. package/dist/shortcuts/invoice/operations/registry.js +50 -0
  48. package/dist/shortcuts/invoice/operations/shared.js +640 -0
  49. package/dist/shortcuts/invoice/operations/types.js +1 -0
  50. package/dist/shortcuts/invoice/operations/update.js +109 -0
  51. package/dist/shortcuts/invoice/operations/upload.js +8 -0
  52. package/dist/shortcuts/invoice/operations/validate-preview.js +39 -0
  53. package/dist/shortcuts/invoice/operations.js +8 -0
  54. package/dist/types.js +1 -0
  55. package/docs/SKILL.md +36 -0
  56. package/docs/_catalog.md +12 -0
  57. package/docs/agent-invoice.md +53 -0
  58. package/docs/e10-auth.md +51 -0
  59. package/docs/invoice.md +99 -0
  60. package/package.json +51 -0
  61. package/scripts/clean.mjs +4 -0
  62. package/scripts/package-skill.mjs +164 -0
  63. package/scripts/sync-docs.mjs +17 -0
  64. package/skill-template/business-info.json +4 -0
  65. package/skill-template/domains/invoice.md +23 -0
  66. package/skill-template/domains/shared.md +8 -0
  67. package/skill-template/master-skill-template.md +29 -0
  68. package/skill-template/skill-template.md +60 -0
  69. package/skills/weaver-work-cli-invoice/SKILL.md +103 -0
  70. package/skills/weaver-work-cli-invoice/product.json +8 -0
  71. package/skills/weaver-work-cli-invoice/references/invoice-add.md +18 -0
  72. package/skills/weaver-work-cli-invoice/references/invoice-agent-entry.md +38 -0
  73. package/skills/weaver-work-cli-invoice/references/invoice-delete.md +20 -0
  74. package/skills/weaver-work-cli-invoice/references/invoice-detail.md +29 -0
  75. package/skills/weaver-work-cli-invoice/references/invoice-disabled-capabilities.md +26 -0
  76. package/skills/weaver-work-cli-invoice/references/invoice-download.md +22 -0
  77. package/skills/weaver-work-cli-invoice/references/invoice-enterprise-list.md +35 -0
  78. package/skills/weaver-work-cli-invoice/references/invoice-file-upload.md +28 -0
  79. package/skills/weaver-work-cli-invoice/references/invoice-import.md +28 -0
  80. package/skills/weaver-work-cli-invoice/references/invoice-ocr-preview.md +33 -0
  81. package/skills/weaver-work-cli-invoice/references/invoice-personal-list.md +47 -0
  82. package/skills/weaver-work-cli-invoice/references/invoice-update.md +38 -0
  83. package/skills/weaver-work-cli-invoice/references/invoice-validation-preview.md +26 -0
  84. package/skills/weaver-work-cli-shared/SKILL.md +53 -0
  85. package/skills/weaver-work-cli-shared/references/e10-auth-and-session.md +83 -0
  86. package/skills/weaver-work-cli-shared/references/high-risk-write.md +36 -0
  87. package/skills/weaver-work-cli-shared/references/json-output-contract.md +61 -0
  88. package/skills/weaver-work-cli-shared/references/weaver-work-cli-installation.md +61 -0
  89. package/templates/shortcut/index.ts.tpl +19 -0
  90. package/templates/shortcut/operations/ping.ts.tpl +7 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 weaver-work-cli contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,422 @@
1
+ # weaver-work-cli
2
+
3
+ 面向泛微工作工具链的可扩展 TypeScript CLI 基础框架。
4
+
5
+ 核心框架保持业务无关;E10 共享能力通过 `src/internal/e10` 隔离提供。新增具体业务 CLI 时,优先放在 `src/shortcuts/<name>` 下,并复用 E10 鉴权、profile、HTTP client 和命令钩子。
6
+
7
+ ## 环境要求
8
+
9
+ - Node.js >= 18
10
+ - npm
11
+
12
+ ## 下载后快速运行
13
+
14
+ 从代码仓库获取项目:
15
+
16
+ ```bash
17
+ git clone <git-repo-url> weaver-work-cli
18
+ cd weaver-work-cli
19
+ npm install
20
+ npm run build
21
+ node dist/index.js --help
22
+ ```
23
+
24
+ 开发阶段可以直接从源码运行:
25
+
26
+ ```bash
27
+ npm run dev -- --help
28
+ npm run dev -- commands list
29
+ ```
30
+
31
+ 构建后的本地验证:
32
+
33
+ ```bash
34
+ npm run build
35
+ node dist/index.js --version
36
+ node dist/index.js commands list
37
+ node dist/index.js doctor --e10
38
+ ```
39
+
40
+ ## 全局安装
41
+
42
+ 从当前源码目录安装到全局命令:
43
+
44
+ ```bash
45
+ # 在克隆到本地的仓库根目录执行(将 <repo-root> 替换为实际路径)
46
+ cd <repo-root>
47
+ npm install
48
+ npm run build
49
+ npm link
50
+ weaver-work-cli --help
51
+ ```
52
+
53
+ 打包后全局安装:
54
+
55
+ ```bash
56
+ # 在克隆到本地的仓库根目录执行(将 <repo-root> 替换为实际路径)
57
+ cd <repo-root>
58
+ npm run build
59
+ npm pack
60
+ npm install -g ./weaver-work-cli-0.1.0.tgz
61
+ weaver-work-cli --version
62
+ ```
63
+
64
+ 发布到 npm 或公司私有 registry 后,可以直接安装:
65
+
66
+ ```bash
67
+ npm install -g weaver-work-cli
68
+ weaver-work-cli setup invoice
69
+ ```
70
+
71
+ 推荐把 `weaver-work-cli` 作为唯一必须安装的运行时包。发票业务命令和随包
72
+ Agent Skill 文档都包含在这个 npm 包中;普通 CLI 用户不需要再单独安装
73
+ 发票 zip 包。
74
+
75
+ 首次启用发票业务时:
76
+
77
+ ```bash
78
+ weaver-work-cli setup invoice
79
+ weaver-work-cli auth login --base-url "https://weapp.xxx.cn"
80
+ weaver-work-cli invoice schema
81
+ ```
82
+
83
+ 如果要让 Codex/Agent 一键识别发票业务,把随包 Skill 安装到 Codex skills 目录:
84
+
85
+ ```bash
86
+ weaver-work-cli setup invoice --install-skill
87
+ # 或只安装 Skill
88
+ weaver-work-cli skills install invoice
89
+ ```
90
+
91
+ `skills install invoice` 会同时安装 `weaver-work-cli-shared` 和
92
+ `weaver-work-cli-invoice`。默认目标目录是 `$CODEX_HOME/skills`,未设置
93
+ `CODEX_HOME` 时使用 `~/.codex/skills`;需要自定义时可加
94
+ `--target-dir <path>`。
95
+
96
+ 卸载全局命令:
97
+
98
+ ```bash
99
+ npm unlink -g weaver-work-cli
100
+ # 或
101
+ npm uninstall -g weaver-work-cli
102
+ ```
103
+
104
+ ## 常用命令
105
+
106
+ ```bash
107
+ weaver-work-cli --help
108
+ weaver-work-cli --version
109
+ weaver-work-cli commands list
110
+ weaver-work-cli config list
111
+ weaver-work-cli docs root
112
+ weaver-work-cli docs copy
113
+ weaver-work-cli doctor --e10
114
+ weaver-work-cli setup invoice
115
+ weaver-work-cli skills list
116
+ weaver-work-cli skills read weaver-work-cli-invoice
117
+ weaver-work-cli skills install invoice
118
+ weaver-work-cli invoice schema
119
+ weaver-work-cli --json invoice run invoice.list --input -
120
+ ```
121
+
122
+ 为了兼容 E10 使用习惯,`auth` 命令保留在顶层;同时也支持 `e10 auth` 命名空间:
123
+
124
+ ```bash
125
+ weaver-work-cli auth status
126
+ weaver-work-cli e10 auth status
127
+ ```
128
+
129
+ ## E10 鉴权方式
130
+
131
+ 方式一:浏览器 OAuth2.0 登录,推荐优先使用。
132
+
133
+ ```bash
134
+ weaver-work-cli auth login --base-url "https://weapp.xxx.cn"
135
+ ```
136
+
137
+ 等价命令:
138
+
139
+ ```bash
140
+ weaver-work-cli auth oidc --base-url "https://weapp.xxx.cn"
141
+ ```
142
+
143
+ 默认本地回调地址为 `http://127.0.0.1:19800/callback`。如果端口被占用:
144
+
145
+ ```bash
146
+ weaver-work-cli auth login --base-url "https://weapp.xxx.cn" --port 19801
147
+ ```
148
+
149
+ 需要区分客户端来源时,可以指定 `agent_type`,默认值为 `weaver-work-cli`:
150
+
151
+ ```bash
152
+ weaver-work-cli auth login --base-url "https://weapp.xxx.cn" --agent_type weaver-work-cli
153
+ ```
154
+
155
+ 方式二:手动写入浏览器中的 `ETEAMSID`。
156
+
157
+ ```bash
158
+ weaver-work-cli auth set --eteamsid "PCACCOUNT_xxx" --base-url "https://weapp.xxx.cn"
159
+ ```
160
+
161
+ 如果 E10 环境需要区分 agent:
162
+
163
+ ```bash
164
+ weaver-work-cli auth set --eteamsid "PCACCOUNT_xxx" --base-url "https://weapp.xxx.cn" --agent_type weaver-work-cli
165
+ ```
166
+
167
+ 查看登录状态:
168
+
169
+ ```bash
170
+ weaver-work-cli auth status
171
+ weaver-work-cli auth status --no-check
172
+ weaver-work-cli --json auth status --no-check
173
+ ```
174
+
175
+ 查看当前用户:
176
+
177
+ ```bash
178
+ weaver-work-cli auth whoami
179
+ weaver-work-cli auth whoami --live
180
+ weaver-work-cli auth whoami --json
181
+ ```
182
+
183
+ 清理当前 profile 的登录状态:
184
+
185
+ ```bash
186
+ weaver-work-cli auth logout
187
+ weaver-work-cli --profile <name> auth logout
188
+ ```
189
+
190
+ `auth logout` 只删除本地 auth 文件,不删除 profile 配置和 keychain 密钥。
191
+
192
+ 导出 E10 登录态到当前 shell:
193
+
194
+ ```bash
195
+ eval "$(weaver-work-cli auth export-weaver-env)"
196
+ ```
197
+
198
+ 导出的环境变量包括:
199
+
200
+ - `WEAVER_BASE_URL`
201
+ - `WEAVER_ETEAMSID`
202
+ - `WEAVER_COOKIE`
203
+ - `WEAVER_USER_AGENT`
204
+ - `WEAVER_AGENT_TYPE`
205
+
206
+ 通过 `weaver-work-cli run` 执行外部命令时,CLI 会在前置钩子中自动注入上述 `WEAVER_*` 变量:
207
+
208
+ ```bash
209
+ weaver-work-cli run node -e "console.log(process.env.WEAVER_BASE_URL || 'no e10 auth')"
210
+ ```
211
+
212
+ ## Profile 管理
213
+
214
+ 鉴权文件默认由 `weaver-work-cli` 独立管理:
215
+
216
+ - 鉴权根目录:`~/.weaver-work-cli/e10`
217
+ - Profile 目录:`~/.weaver-work-cli/e10/profiles/<profile>`
218
+ - 当前激活 profile:`~/.weaver-work-cli/e10/profile`
219
+ - Keychain service/account:`weaver-work-cli` / `auth-key`
220
+
221
+ CLI 默认不读取、不迁移 `e10-login` / `e10-cli` 的 `~/.e10-cli` 登录态;
222
+ 打包给用户后,用户必须通过 `weaver-work-cli auth login` 或
223
+ `weaver-work-cli auth set` 建立本插件自己的登录状态。确需复用外部 auth 文件时,
224
+ 可以显式使用 `--auth <path>` 或 `E10_AUTH_PATH`。
225
+
226
+ 常用 profile 命令:
227
+
228
+ ```bash
229
+ weaver-work-cli auth profile list
230
+ weaver-work-cli auth profile current
231
+ weaver-work-cli auth profile use <name>
232
+ weaver-work-cli --profile <name> auth status
233
+ ```
234
+
235
+ 支持的鉴权相关环境变量:
236
+
237
+ - `E10_AUTH_PATH`:指定 auth 文件路径
238
+ - `WEAVER_WORK_CLI_AUTH_ROOT`:覆盖 `weaver-work-cli` 的独立鉴权根目录
239
+ - `E10_ACCOUNT` / `E10_PASSWORD`:session 过期且需要 RSA 自动重登时使用
240
+
241
+ ## 目录结构
242
+
243
+ ```text
244
+ src/
245
+ index.ts CLI bin 入口。
246
+ cmd/ Commander root、注册协议和顶层命令。
247
+ index.ts 汇总内置 cmd。
248
+ root.ts 程序创建、全局 flags 和版本信息。
249
+ register.ts 命令注册、hooks 注册和 action 包装。
250
+ action.ts 统一错误处理和命令生命周期。
251
+ config/ 通用本地配置命令。
252
+ docs/ 包内文档和模板复制命令。
253
+ doctor/ 环境检查命令。
254
+ commands/ 已注册命令查看命令,兼容 module 别名。
255
+ run/ 带前置/后置钩子的外部命令执行器。
256
+ e10/ E10 auth/profile 命令和 run-hook 环境注入。
257
+ skills/ 包内 Agent Skill 读取命令。
258
+ core/ 业务无关的上下文、钩子、配置、输出和错误处理。
259
+ internal/ 只供本包复用的实现细节。
260
+ e10/ E10 session、auth 文件、API client。
261
+ skills/ Skill 内容读取和路径保护。
262
+ shortcuts/ 面向人和 Agent 的高层业务命令。
263
+ index.ts 汇总内置 shortcuts。
264
+ invoice/ E10 业票通发票 shortcut、operation manifest 和业务执行器。
265
+ operations/ 按业务执行逻辑拆分的 operation class。
266
+ services/ 可复用的非业务服务。
267
+ docs/ 随包发布的 CLI 文档。
268
+ skills/ 随包发布的 Agent Skills;入口 SKILL.md 做路由,细节放 references/。
269
+ weaver-work-cli-shared/ 所有业务 Skill 共享的安装、认证、JSON 和写入规则。
270
+ weaver-work-cli-invoice/ 业票通业务 Skill。
271
+ skill-template/ 新增或重写业务 Skill 时使用的模板来源,参考 lark-cli 的 skill-template。
272
+ templates/ 后续 shortcut 脚手架模板。
273
+ scripts/ 维护脚本。
274
+ test/ Node 内置测试运行器测试。
275
+ ```
276
+
277
+ ## 命令分层
278
+
279
+ `weaver-work-cli` 采用与 `lark-cli` 接近的三层组织:
280
+
281
+ - `cmd`:稳定的系统/平台命令,例如 `config`、`doctor`、`run`、`e10 auth`、`skills list/read`。
282
+ - `shortcuts`:业务友好的高层命令,例如 `invoice list`、`invoice import prepare`;按 `src/shortcuts/<business-module>` 分模块维护,模块内每个业务 operation 用相对独立的 class 封装。
283
+ - `skills`:Agent 可读的使用说明和引用文件;按 `skills/weaver-work-cli-<business-module>` 分模块维护。业务入口 `SKILL.md` 只放路由、前置要求和执行原则,具体 operation、工作流、错误处理放到 `references/*.md`;公共规则只放在 `weaver-work-cli-shared`。
284
+ - `skill-template`:维护者新增业务 Skill 时的模板来源,作用类似飞书 CLI 的 `skill-template`。`master-skill-template.md` 用于未来聚合入口,`skill-template.md` 用于单业务 Skill,`business-info.json` 记录路由关键词,`domains/*.md` 记录当前业务域应拆出的 reference 与 Agent 调优重点。
285
+
286
+ ## 新增业务 Shortcut
287
+
288
+ 业务 shortcut 统一创建在 `src/shortcuts/<name>` 下,不和框架内置命令、E10 共享适配混放。
289
+ 配套 Agent Skill 统一创建在 `skills/weaver-work-cli-<name>`:
290
+
291
+ ```text
292
+ skills/weaver-work-cli-<name>/
293
+ SKILL.md 入口路由:共享 Skill、schema、reference 索引、禁用边界。
294
+ product.json 可选:业务 Skill 包元信息。
295
+ references/
296
+ <name>-agent-entry.md CLI 入口、schema、stdin JSON、输出约定。
297
+ <name>-read.md 查询/详情类只读 operation。
298
+ <name>-write.md prepare/apply 写入协议、确认和回查。
299
+ ```
300
+
301
+ 新增 Skill 时先参考 `skill-template/skill-template.md` 和 `skill-template/domains/<name>.md`。入口文件不要复制大段接口细节;让 Agent 按用户意图读取最小必要 reference。
302
+
303
+ 当前已内置 `invoice` shortcut,用于 E10 业票通发票管理。典型调用:
304
+
305
+ ```bash
306
+ weaver-work-cli --json invoice list --input -
307
+ weaver-work-cli --json invoice enterprise list --input -
308
+ weaver-work-cli --json invoice get --fid <fid>
309
+ weaver-work-cli --json invoice upload --file ./invoice.pdf
310
+ weaver-work-cli --json invoice ocr preview --file ./invoice.pdf
311
+ weaver-work-cli --json invoice validate preview --fid <fid> --scope personal
312
+ weaver-work-cli --json invoice download --fid <fid> --file-id <fileId> --output ./invoice.pdf
313
+ ```
314
+
315
+ 写操作固定使用 `prepare -> apply`:
316
+
317
+ ```bash
318
+ echo '{"file":"./invoice.pdf","validate":false,"syncToOa":false}' \
319
+ | weaver-work-cli --json invoice import prepare --input -
320
+
321
+ echo '{"file":"./invoice.pdf","continuation":"<prepare返回值>","confirm":true}' \
322
+ | weaver-work-cli --json invoice import apply --input -
323
+ ```
324
+
325
+ Agent 应优先调用 `weaver-work-cli --json invoice run <operation> --input -`,并读取 `weaver-work-cli invoice schema` 获取 operation 契约。共享、转让和标签接口因缺少稳定 ID 来源和写后回查契约,当前不暴露给 Agent。
326
+
327
+ 如需交付通用 Agent Skill 包:
328
+
329
+ ```bash
330
+ npm run build:skill -- invoice
331
+ # 或保留的 invoice 便捷命令
332
+ npm run build:invoice-skill
333
+ ```
334
+
335
+ 输出文件默认在 `dist/weaver-work-cli-invoice-skill.zip`。该 zip 主要用于
336
+ Codex/Agent 平台导入、离线分发或版本归档;日常推荐直接通过 npm 包内置内容
337
+ 执行 `weaver-work-cli skills install invoice`。zip 包包含
338
+ `weaver-work-cli-invoice` 和共享的 `weaver-work-cli-shared`,要求用户本机已安装
339
+ 可用的 `weaver-work-cli`。
340
+ 如需打包全部 Skill:
341
+
342
+ ```bash
343
+ npm run build:skill
344
+ ```
345
+
346
+ 示例:新增 `workflow` shortcut。
347
+
348
+ ```text
349
+ src/shortcuts/workflow/
350
+ index.ts
351
+ operations/
352
+ list.ts
353
+ ```
354
+
355
+ `src/shortcuts/workflow/index.ts`:
356
+
357
+ ```ts
358
+ import { WorkflowListOperation } from './operations/list.js';
359
+ import type { CliCommand } from '../../types.js';
360
+
361
+ const listOperation = new WorkflowListOperation();
362
+
363
+ export const workflowShortcut: CliCommand = {
364
+ name: 'workflow',
365
+ description: '流程业务命令',
366
+ category: 'shortcut',
367
+ register({ program, action }) {
368
+ const workflow = program.command('workflow').description('流程业务命令');
369
+
370
+ workflow.command('list')
371
+ .description('查询流程列表')
372
+ .action(action(async (ctx) => {
373
+ ctx.output.write(await listOperation.execute(ctx));
374
+ }));
375
+ },
376
+ };
377
+ ```
378
+
379
+ `src/shortcuts/workflow/operations/list.ts`:
380
+
381
+ ```ts
382
+ import { requireE10Client } from '../../../internal/e10/context.js';
383
+ import type { CliContext } from '../../../core/context.js';
384
+
385
+ export class WorkflowListOperation {
386
+ async execute(ctx: CliContext): Promise<unknown> {
387
+ const client = await requireE10Client(ctx);
388
+ return client.post('/api/xxx/workflow/list', {});
389
+ }
390
+ }
391
+ ```
392
+
393
+ 然后在 `src/shortcuts/index.ts` 中注册:
394
+
395
+ ```ts
396
+ import { invoiceShortcut } from './invoice/index.js';
397
+ import { workflowShortcut } from './workflow/index.js';
398
+ import type { CliCommand } from '../types.js';
399
+
400
+ export const builtinShortcuts: CliCommand[] = [
401
+ invoiceShortcut,
402
+ workflowShortcut,
403
+ ];
404
+ ```
405
+
406
+ 验证命令是否注册成功:
407
+
408
+ ```bash
409
+ npm run build
410
+ node dist/index.js commands list
411
+ node dist/index.js workflow --help
412
+ ```
413
+
414
+ 如果业务 shortcut 不依赖 E10,只使用 `ctx.output`、`ctx.config`、`ctx.hooks` 等通用能力即可;如果依赖 E10,优先复用 `requireE10Client(ctx)` 或 `requireE10Session(ctx)`,不要在 shortcut 里重复实现登录态读取、cookie 拼接或 HTTP header 注入。
415
+
416
+ ## 发布前验证
417
+
418
+ ```bash
419
+ npm run build
420
+ npm test
421
+ npm pack --dry-run
422
+ ```
@@ -0,0 +1,35 @@
1
+ import { ExitCode, isCliError, toErrorEnvelope } from '../core/errors.js';
2
+ function commandFromArgs(args) {
3
+ const last = args[args.length - 1];
4
+ return last && typeof last === 'object' && 'name' in last && 'opts' in last ? last : undefined;
5
+ }
6
+ export function createAction(ctx) {
7
+ return (handler) => async (...args) => {
8
+ const commandCtx = ctx.forCommand(commandFromArgs(args));
9
+ try {
10
+ await commandCtx.hooks.beforeCommand(commandCtx);
11
+ const result = await handler(commandCtx, ...args);
12
+ await commandCtx.hooks.afterCommand(commandCtx, result);
13
+ }
14
+ catch (error) {
15
+ await commandCtx.hooks.onError(commandCtx, error);
16
+ if (commandCtx.getGlobalOptions().json) {
17
+ console.error(JSON.stringify({
18
+ schemaVersion: 1,
19
+ ok: false,
20
+ error: toErrorEnvelope(error),
21
+ }, null, 2));
22
+ process.exitCode = isCliError(error) ? error.exitCode : ExitCode.GeneralError;
23
+ return;
24
+ }
25
+ if (isCliError(error)) {
26
+ commandCtx.logger.error(error.message);
27
+ process.exitCode = error.exitCode;
28
+ return;
29
+ }
30
+ const message = error instanceof Error ? error.message : String(error);
31
+ commandCtx.logger.error(message);
32
+ process.exitCode = ExitCode.GeneralError;
33
+ }
34
+ };
35
+ }
@@ -0,0 +1,15 @@
1
+ export const commandsCommand = {
2
+ name: 'commands',
3
+ description: 'Registered command discovery',
4
+ category: 'system',
5
+ register({ program, action }) {
6
+ const commands = program.command('commands')
7
+ .alias('module')
8
+ .description('Inspect registered commands');
9
+ commands.command('list')
10
+ .description('List registered commands')
11
+ .action(action((ctx) => {
12
+ ctx.output.write({ commands: ctx.commands, modules: ctx.modules });
13
+ }));
14
+ },
15
+ };
@@ -0,0 +1,64 @@
1
+ import { CliError, ExitCode } from '../../core/errors.js';
2
+ function parseValue(value) {
3
+ if (value === 'true')
4
+ return true;
5
+ if (value === 'false')
6
+ return false;
7
+ if (value === 'null')
8
+ return null;
9
+ if (/^-?\d+(\.\d+)?$/.test(value))
10
+ return Number(value);
11
+ try {
12
+ return JSON.parse(value);
13
+ }
14
+ catch {
15
+ return value;
16
+ }
17
+ }
18
+ export const configCommand = {
19
+ name: 'config',
20
+ description: 'Generic local configuration commands',
21
+ category: 'system',
22
+ register({ program, action }) {
23
+ const config = program.command('config').description('Manage weaver-work-cli config');
24
+ config.command('path')
25
+ .description('Print the active config file path')
26
+ .action(action((ctx) => {
27
+ ctx.output.write({ path: ctx.config.path() }, { text: ctx.config.path() });
28
+ }));
29
+ config.command('list')
30
+ .description('Print all config values')
31
+ .action(action((ctx) => {
32
+ ctx.output.write(ctx.config.all());
33
+ }));
34
+ config.command('get')
35
+ .description('Print one config value')
36
+ .argument('<key>', 'config key')
37
+ .action(action((ctx, key) => {
38
+ if (typeof key !== 'string')
39
+ throw new CliError('key must be a string', ExitCode.UsageError);
40
+ ctx.output.write({ key, value: ctx.config.get(key) });
41
+ }));
42
+ config.command('set')
43
+ .description('Set one config value')
44
+ .argument('<key>', 'config key')
45
+ .argument('<value>', 'config value')
46
+ .action(action((ctx, key, value) => {
47
+ if (typeof key !== 'string' || typeof value !== 'string') {
48
+ throw new CliError('key and value must be strings', ExitCode.UsageError);
49
+ }
50
+ const parsed = parseValue(value);
51
+ ctx.config.set(key, parsed);
52
+ ctx.output.write({ key, value: parsed, path: ctx.config.path() }, { text: 'Saved ' + key });
53
+ }));
54
+ config.command('delete')
55
+ .description('Delete one config value')
56
+ .argument('<key>', 'config key')
57
+ .action(action((ctx, key) => {
58
+ if (typeof key !== 'string')
59
+ throw new CliError('key must be a string', ExitCode.UsageError);
60
+ const deleted = ctx.config.delete(key);
61
+ ctx.output.write({ key, deleted, path: ctx.config.path() }, { text: deleted ? 'Deleted ' + key : 'No value for ' + key });
62
+ }));
63
+ },
64
+ };
@@ -0,0 +1,56 @@
1
+ import { cpSync, existsSync, readdirSync, readFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { CliError } from '../../core/errors.js';
5
+ const DOCS_DIR = fileURLToPath(new URL('../../../docs/', import.meta.url));
6
+ const PKG_JSON_URL = new URL('../../../package.json', import.meta.url);
7
+ function packageVersion() {
8
+ try {
9
+ return JSON.parse(readFileSync(PKG_JSON_URL, 'utf-8')).version;
10
+ }
11
+ catch {
12
+ return 'unknown';
13
+ }
14
+ }
15
+ function countFiles(dir) {
16
+ let count = 0;
17
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
18
+ const entryPath = resolve(dir, entry.name);
19
+ count += entry.isDirectory() ? countFiles(entryPath) : 1;
20
+ }
21
+ return count;
22
+ }
23
+ function ensureDocs() {
24
+ if (!existsSync(DOCS_DIR)) {
25
+ throw new CliError('docs directory does not exist: ' + DOCS_DIR);
26
+ }
27
+ }
28
+ export const docsCommand = {
29
+ name: 'docs',
30
+ description: 'Packaged docs and template copy commands',
31
+ category: 'system',
32
+ register({ program, action }) {
33
+ const docs = program.command('docs').description('Read or copy packaged docs');
34
+ docs.command('root')
35
+ .description('Print packaged docs root path')
36
+ .action(action((ctx) => {
37
+ ensureDocs();
38
+ const root = DOCS_DIR.replace(/[\\/]+$/, '');
39
+ ctx.output.write({ root, version: packageVersion() }, { text: root + '\nversion: ' + packageVersion() });
40
+ }));
41
+ docs.command('copy')
42
+ .description('Copy packaged docs to <target>/weaver-work-cli-docs')
43
+ .argument('[target]', 'target directory', process.cwd())
44
+ .action(action((ctx, target) => {
45
+ ensureDocs();
46
+ const dest = resolve(String(target || process.cwd()), 'weaver-work-cli-docs');
47
+ const sourceRoot = DOCS_DIR.replace(/[\\/]+$/, '');
48
+ if (dest === sourceRoot || dest.startsWith(sourceRoot + '/') || dest.startsWith(sourceRoot + '\\')) {
49
+ throw new CliError('target directory is inside docs source: ' + dest);
50
+ }
51
+ cpSync(DOCS_DIR, dest, { recursive: true });
52
+ const files = countFiles(dest);
53
+ ctx.output.write({ files, dest, version: packageVersion() }, { text: 'Copied ' + files + ' files to ' + dest });
54
+ }));
55
+ },
56
+ };
@@ -0,0 +1,45 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { findAuthFile } from '../../internal/e10/auth/session.js';
3
+ function versionMajor(version) {
4
+ return Number(version.replace(/^v/, '').split('.')[0] || 0);
5
+ }
6
+ export const doctorCommand = {
7
+ name: 'doctor',
8
+ description: 'Environment diagnostics',
9
+ category: 'system',
10
+ register({ program, action }) {
11
+ program.command('doctor')
12
+ .description('Check local CLI environment')
13
+ .option('--e10', 'also check E10 auth file discovery')
14
+ .action(action((ctx, options) => {
15
+ const opts = options && typeof options === 'object' ? options : {};
16
+ const checks = [
17
+ {
18
+ name: 'node',
19
+ ok: versionMajor(process.version) >= 18,
20
+ detail: process.version,
21
+ },
22
+ {
23
+ name: 'package',
24
+ ok: Boolean(ctx.packageInfo.version),
25
+ detail: ctx.packageInfo.name + '@' + ctx.packageInfo.version,
26
+ },
27
+ {
28
+ name: 'configPath',
29
+ ok: true,
30
+ detail: ctx.config.path(),
31
+ },
32
+ ];
33
+ if (opts.e10) {
34
+ const authFile = findAuthFile(ctx.cwd);
35
+ checks.push({
36
+ name: 'e10AuthFile',
37
+ ok: Boolean(authFile && existsSync(authFile)),
38
+ detail: authFile || 'not found',
39
+ });
40
+ }
41
+ const ok = checks.every((check) => check.ok);
42
+ ctx.output.write({ ok, checks });
43
+ }));
44
+ },
45
+ };
@@ -0,0 +1,25 @@
1
+ import { registerE10AuthCommands } from '../../internal/e10/auth/commands.js';
2
+ import { E10AuthSession, findAuthFile } from '../../internal/e10/auth/session.js';
3
+ export const e10Command = {
4
+ name: 'e10',
5
+ description: 'E10 platform adapter: auth, profiles, and shared API client',
6
+ category: 'platform',
7
+ register({ program, ctx, action }) {
8
+ registerE10AuthCommands(program, action);
9
+ const e10 = program.command('e10').description('E10 platform commands');
10
+ registerE10AuthCommands(e10, action);
11
+ ctx.hooks.register({
12
+ beforeRun(runCtx) {
13
+ const authFile = findAuthFile(runCtx.cwd);
14
+ const session = authFile ? E10AuthSession.fromFile(authFile) : null;
15
+ if (!session)
16
+ return;
17
+ runCtx.env.WEAVER_BASE_URL ||= session.getBaseUrl();
18
+ runCtx.env.WEAVER_ETEAMSID ||= session.eteamsId;
19
+ runCtx.env.WEAVER_COOKIE ||= session.cookieHeader();
20
+ runCtx.env.WEAVER_USER_AGENT ||= session.uaHeader();
21
+ runCtx.env.WEAVER_AGENT_TYPE ||= session.agentType;
22
+ },
23
+ });
24
+ },
25
+ };