weaver-work-cli 0.1.25 → 0.1.26

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 (81) hide show
  1. package/README.md +30 -30
  2. package/dist/cmd/root.js +1 -0
  3. package/dist/core/runtime-agent.js +19 -0
  4. package/dist/internal/e10/auth/commands.js +47 -27
  5. package/dist/internal/e10/auth/xiaoe.js +62 -43
  6. package/dist/internal/e10/context.js +5 -27
  7. package/dist/shortcuts/archive-oa/constants.js +66 -0
  8. package/dist/shortcuts/archive-oa/continuation.js +70 -0
  9. package/dist/shortcuts/archive-oa/errors.js +53 -0
  10. package/dist/shortcuts/archive-oa/host.js +157 -0
  11. package/dist/shortcuts/archive-oa/index.js +225 -0
  12. package/dist/shortcuts/archive-oa/manifest.js +62 -0
  13. package/dist/shortcuts/archive-oa/operations/borrow-car.js +159 -0
  14. package/dist/shortcuts/archive-oa/operations/borrow-url.js +108 -0
  15. package/dist/shortcuts/archive-oa/operations/confirm.js +48 -0
  16. package/dist/shortcuts/archive-oa/operations/contract.js +120 -0
  17. package/dist/shortcuts/archive-oa/operations/locate.js +50 -0
  18. package/dist/shortcuts/archive-oa/operations/registry.js +40 -0
  19. package/dist/shortcuts/archive-oa/operations/shared.js +181 -0
  20. package/dist/shortcuts/archive-oa/operations/types.js +45 -0
  21. package/dist/shortcuts/archive-oa/operations.js +13 -0
  22. package/dist/shortcuts/index.js +2 -0
  23. package/dist/shortcuts/invoice/host.js +2 -1
  24. package/dist/shortcuts/invoice/manifest.js +111 -0
  25. package/dist/shortcuts/invoice/operations/issuing-qys.js +361 -0
  26. package/dist/shortcuts/invoice/operations/issuing.js +5 -5
  27. package/dist/shortcuts/invoice/operations/registry.js +4 -0
  28. package/dist/shortcuts/workflow/endpoints.js +11 -0
  29. package/dist/shortcuts/workflow/host.js +2 -2
  30. package/dist/shortcuts/workflow/index.js +6 -36
  31. package/dist/shortcuts/workflow/operations/chatscene.js +270 -0
  32. package/dist/shortcuts/workflow/operations/form.js +899 -158
  33. package/dist/shortcuts/workflow/operations/read.js +111 -6
  34. package/dist/shortcuts/workflow/operations/sign-input.js +106 -0
  35. package/dist/shortcuts/workflow/operations/write.js +9 -1
  36. package/dist/shortcuts/workflow/stdout-compact.js +9 -1
  37. package/docs/archive-oa.md +79 -0
  38. package/docs/e10-auth.md +7 -6
  39. package/package.json +1 -1
  40. package/skill-template/business-info.json +16 -0
  41. package/skill-template/domains/archive-oa.md +19 -0
  42. package/skill-template/domains/yepiaotong.md +2 -2
  43. package/skills/weaver-e10-archive-oa/SKILL.md +159 -0
  44. package/skills/weaver-e10-archive-oa/references/archive-locate.md +49 -0
  45. package/skills/weaver-e10-archive-oa/references/borrow-car.md +76 -0
  46. package/skills/weaver-e10-archive-oa/references/borrow-flow.md +53 -0
  47. package/skills/weaver-e10-archive-oa/references/contract-search.md +63 -0
  48. package/skills/weaver-e10-archive-oa/references/disabled-capabilities.md +29 -0
  49. package/skills/weaver-e10-archive-oa/references/qys-contract-search.md +47 -0
  50. package/skills/weaver-e10-archive-oa/references/source-manifest.json +400 -0
  51. package/skills/weaver-e10-builder/SKILL.md +22 -0
  52. package/skills/weaver-e10-caizhilian/SKILL.md +37 -15
  53. package/skills/weaver-e10-caizhilian/references/agent-entry.md +7 -3
  54. package/skills/weaver-e10-caizhilian/references/collaboration.md +5 -3
  55. package/skills/weaver-e10-caizhilian/references/document.md +33 -11
  56. package/skills/weaver-e10-caizhilian/references/file-collection.md +4 -3
  57. package/skills/weaver-e10-caizhilian/references/file-upload.md +2 -3
  58. package/skills/weaver-e10-caizhilian/references/files.md +9 -3
  59. package/skills/weaver-e10-caizhilian/references/folder.md +48 -16
  60. package/skills/weaver-e10-caizhilian/references/setting-attach.md +13 -39
  61. package/skills/weaver-e10-caizhilian/references/setting-backup.md +13 -51
  62. package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +20 -51
  63. package/skills/weaver-e10-caizhilian/references/setting-storage.md +82 -147
  64. package/skills/weaver-e10-caizhilian/references/withheld.md +20 -44
  65. package/skills/weaver-e10-shared/SKILL.md +22 -20
  66. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +14 -15
  67. package/skills/weaver-e10-shared/references/non-interactive-environment.md +10 -10
  68. package/skills/weaver-e10-workflow/references/source-manifest.json +32 -22
  69. package/skills/weaver-e10-workflow/references/workflow-create.md +68 -28
  70. package/skills/weaver-e10-yepiaotong/SKILL.md +10 -7
  71. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-examples.md +49 -1
  72. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-qys-ledger.md +66 -0
  73. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +59 -36
  74. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +54 -509
  75. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +182 -345
  76. package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +4 -5
  77. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +153 -345
  78. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +5 -5
  79. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +182 -154
  80. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +96 -0
  81. package/skills/weaver-e10-yepiaotong/references/reim-fast-path.md +0 -119
@@ -0,0 +1,270 @@
1
+ /**
2
+ * 智能填参:调 OA 的 `chatScene` 接口,让一个**独立智能体**把「用户意图 + 表单字段上下文」
3
+ * 映射成可直接喂给 `createRequest` 的 `data` 参数。
4
+ *
5
+ * ## 接口契约(来源:2026-10-19 真机 HAR,HTTP 200)
6
+ *
7
+ * ```
8
+ * POST {baseUrl}/api/ai/application/chat/chatScene
9
+ * aiappuniquekey: workflow_form_filler
10
+ * Content-Type: application/json;charset=UTF-8
11
+ * ```
12
+ *
13
+ * - body 里 `chatId`(19 位数字串)/ `taskId` / `userMessageId`(32 位无横线 hex)**每次随机**,
14
+ * 其余字段与值固定;
15
+ * - `messages[0].content` 是**字符串**(入参 JSON 序列化后的文本),**不是对象**;
16
+ * - 返回的 `data.chatMessage.content` 同样是**字符串**,要**二次 `JSON.parse`**;
17
+ * - **同步返回**(真机 `timeConsuming.all = 3592 ms`),不需要轮询 —— `pollingInterval` 在本场景不起作用。
18
+ *
19
+ * ## 失败口径
20
+ *
21
+ * 这个接口是**增强**而不是前置依赖:拿不到合法结果就返回 `ok:false`,由调用方原样退回旧口径
22
+ * (保留 `historyRequestData` / `systemFields`)。**任何异常都不向上抛**,绝不因为智能体故障
23
+ * 把整个发起流程打死。
24
+ */
25
+ import { randomUUID } from 'node:crypto';
26
+ /** 智能体应用标识。注意是**下划线**形态(不是早期的 `workflow-form-filler`)。 */
27
+ export const CHATSCENE_APP_UNIQUE_KEY = 'workflow_form_filler';
28
+ /** 接口路径(`/api/` 前缀是 host 的强制要求)。 */
29
+ export const CHATSCENE_PATH = '/api/ai/application/chat/chatScene';
30
+ /**
31
+ * 单独超时:真机 3.6 s,但这是**外部大模型**调用,可能排队。
32
+ *
33
+ * ★ 2026-10-20 用户裁定:**15 s**(此前 30 s)。实测该智能体真出状况时服务端自身也要挂到 30 s 才回
34
+ * `InterruptedIOException`,等它没有意义 —— 反正拿不到可用结果就会降级,早 15 s 放弃能让整条
35
+ * `createForm` 少等一半。失败口径不变(仍静默降级、不打断发起流程)。
36
+ */
37
+ const CHATSCENE_TIMEOUT_MS = 15_000;
38
+ /**
39
+ * 填写依据的后缀:智能体在每个字段值旁写 `<字段id>_reason`(实测还会写成 `_reason2`、`_reason3`),
40
+ * 这些键**必须**在进 `data` 之前剔掉。
41
+ *
42
+ * ★ 漏剔一个不是"多提交一个字段",而是**整张单被卡住**:`createRequest` 的 `bindInputFields`
43
+ * 会把 `main` / 明细行里的每个键拿去和字段 id / 名称匹配,匹配不到就记一条 `NOT_FOUND` 歧义,
44
+ * 而 `commandCreateRequest` 一见 `fieldAmbiguities.length` 就直接返回 `NEEDS_CONFIRMATION`。
45
+ *
46
+ * 依据本身**只用于调试参数是怎么生成出来的**,不进任何返回面(2026-10-20 用户裁定)。
47
+ */
48
+ const REASON_KEY = /_reason\d*$/;
49
+ /**
50
+ * 19 位数字串,形态对齐雪花 ID(真机 `1327983839164596324`)。
51
+ *
52
+ * 用 `Date.now() * 1e6 + 随机 6 位`:时间戳保证单调整体、尾 6 位保证同毫秒内不撞。
53
+ * 必须走 `BigInt` —— `1.79e12 × 1e6 = 1.79e18` 已远超 `Number.MAX_SAFE_INTEGER`(9.0e15),
54
+ * 用 number 会丢精度、末尾几位变成 0。
55
+ */
56
+ function randomChatId() {
57
+ const ts = BigInt(Date.now()) * 1000000n;
58
+ const seq = BigInt(Math.floor(Math.random() * 1_000_000));
59
+ return (ts + seq).toString();
60
+ }
61
+ /** 32 位无横线 hex(真机 `taskId` / `userMessageId` 的形态)。 */
62
+ function randomHex32() {
63
+ return randomUUID().replace(/-/g, '');
64
+ }
65
+ /** 本地时间 `YYYY-MM-DD HH:mm:ss`,供智能体把「今天 / 下周三 / 上个月」换算成绝对日期。 */
66
+ export function formatLocalNow(date = new Date()) {
67
+ const pad = (n) => String(n).padStart(2, '0');
68
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
69
+ + ` ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
70
+ }
71
+ /**
72
+ * 交给智能体的字段属性**白名单** —— 就是智能体入参契约里的那 12 个键,一个不多一个不少
73
+ * (2026-10-20 用户对齐真机入参)。为此要挡掉 `createForm` 侧那些**只给 CLI 自己用**的属性:
74
+ *
75
+ * | 属性 | 为什么不给智能体 |
76
+ * | --- | --- |
77
+ * | `fileUploadParams` | 文件夹 / 大小格式限制 / 一次性签名,是给调 caizhilian 上传的模型用的;带上它会让智能体误以为要自己判上传限制 |
78
+ * | `browserType` / `browserModule` | 浏览通道标识,由 CLI 在 `createRequest` 解析值时用,与「意图 → 值」无关 |
79
+ * | `readOnly` / `disableEdit` / `folderDependsOnOption` | 是否可写、附件文件夹是否随选项变,都是 CLI 侧的门禁/联动细节 |
80
+ *
81
+ * 键序与契约一致(`componentKey` → 布尔标记 → `format` → `initialValue` → `options`)。
82
+ */
83
+ const AGENT_FIELD_KEYS = [
84
+ 'id', 'name', 'subFormId', 'componentKey',
85
+ 'isBrowser', 'isSelect', 'isMultiple', 'isEmployeeScope', 'isEinvoice',
86
+ 'format', 'initialValue', 'options',
87
+ ];
88
+ function pickAgentFields(fields) {
89
+ const picked = [];
90
+ for (const field of fields) {
91
+ if (!field || typeof field !== 'object')
92
+ continue;
93
+ const item = {};
94
+ for (const key of AGENT_FIELD_KEYS) {
95
+ const value = field[key];
96
+ if (value === undefined || value === null)
97
+ continue;
98
+ item[key] = value;
99
+ }
100
+ picked.push(item);
101
+ }
102
+ return picked;
103
+ }
104
+ /**
105
+ * 交给智能体的 `systemFields` **只留三项**:`defaults` / `levelOptions` / `secLevelOptions`。
106
+ *
107
+ * `createForm` 内部那份 `systemFields` 还带 `permissions`(逐字段的 view/edit/mandatory 位图,
108
+ * 真机 278 字段的表单就是 278 条)—— 那是 CLI 自己判"字段看不看得见、能不能填"用的,
109
+ * 与「意图 → 字段值」这个映射无关,发给智能体纯属噪声(2026-10-20 用户对齐真机入参)。
110
+ */
111
+ function pickAgentSystemFields(raw) {
112
+ const source = (raw && typeof raw === 'object' && !Array.isArray(raw))
113
+ ? raw
114
+ : {};
115
+ const isPlainObject = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
116
+ return {
117
+ defaults: isPlainObject(source.defaults) ? source.defaults : {},
118
+ levelOptions: Array.isArray(source.levelOptions) ? source.levelOptions : [],
119
+ secLevelOptions: Array.isArray(source.secLevelOptions) ? source.secLevelOptions : [],
120
+ };
121
+ }
122
+ export function buildChatSceneInput(params) {
123
+ return {
124
+ userQuestion: params.userQuestion,
125
+ workflow: { id: String(params.workflow.id ?? ''), name: String(params.workflow.name ?? '') },
126
+ fields: pickAgentFields(params.fields || []),
127
+ historyRequestData: params.historyRequestData ?? null,
128
+ systemFields: pickAgentSystemFields(params.systemFields),
129
+ userMemory: String(params.userMemory ?? ''),
130
+ now: params.now || formatLocalNow(),
131
+ };
132
+ }
133
+ /** 摘掉一行里的所有依据键(`_reason` / `_reason2` …),只留真值;空值也不留。 */
134
+ function stripReasonKeys(source) {
135
+ const values = {};
136
+ for (const [key, value] of Object.entries(source)) {
137
+ if (REASON_KEY.test(key))
138
+ continue;
139
+ if (value === null || value === undefined)
140
+ continue;
141
+ values[key] = value;
142
+ }
143
+ return values;
144
+ }
145
+ /**
146
+ * 把智能体返回的 `formData` 收敛成 `{main, details}`,并**摘掉所有依据键**。
147
+ * 结构不对就返回 null(=降级)。
148
+ */
149
+ function normalizeFormData(raw) {
150
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
151
+ return null;
152
+ const mainRaw = raw.main;
153
+ const detailsRaw = raw.details;
154
+ const main = {};
155
+ if (mainRaw && typeof mainRaw === 'object' && !Array.isArray(mainRaw)) {
156
+ Object.assign(main, stripReasonKeys(mainRaw));
157
+ }
158
+ const details = {};
159
+ if (detailsRaw && typeof detailsRaw === 'object' && !Array.isArray(detailsRaw)) {
160
+ for (const [subFormId, rows] of Object.entries(detailsRaw)) {
161
+ if (!Array.isArray(rows))
162
+ continue;
163
+ const kept = [];
164
+ for (const row of rows) {
165
+ if (!row || typeof row !== 'object' || Array.isArray(row))
166
+ continue;
167
+ const values = stripReasonKeys(row);
168
+ // 整行只有依据键、一个值都没有 ⇒ 不产行(否则会多出一行空明细)
169
+ if (!Object.keys(values).length)
170
+ continue;
171
+ kept.push(values);
172
+ }
173
+ if (!kept.length)
174
+ continue;
175
+ details[subFormId] = kept;
176
+ }
177
+ }
178
+ // 一个字段都没有 ⇒ 视为没拿到结果(否则会把整张空表单当成"已填好"交出去)
179
+ if (!Object.keys(main).length && !Object.keys(details).length)
180
+ return null;
181
+ return { data: { main, details } };
182
+ }
183
+ /**
184
+ * `systemData` 只收四个已知键、统一成字符串;缺键 / 非字符串一律当空串。
185
+ * 四个键的 `_reason` 变体本来就不在白名单里,直接不收。
186
+ */
187
+ function normalizeSystemData(raw) {
188
+ const source = (raw && typeof raw === 'object' && !Array.isArray(raw)) ? raw : {};
189
+ const systemData = {};
190
+ for (const key of ['requestName', 'requestLevel', 'secLevel', 'remark']) {
191
+ const value = source[key];
192
+ systemData[key] = (value === null || value === undefined) ? '' : String(value).trim();
193
+ }
194
+ return systemData;
195
+ }
196
+ /**
197
+ * 调 `chatScene` 并解析结果。**永不抛异常**。
198
+ *
199
+ * 判成功的三个条件(缺一即降级,对应需求「返回值 data.chatMessage.content 不存在或者为空则走原逻辑」):
200
+ * 1. 外层 `code === 200 && status === true`;
201
+ * 2. `data.chatMessage.content` 是**非空字符串**;
202
+ * 3. 该字符串能 parse 成 JSON,且里面有非空的 `formData`。
203
+ */
204
+ export async function requestFormFill(env, input) {
205
+ const startedAt = Date.now();
206
+ const base = () => ({ ok: false, durationMs: Date.now() - startedAt });
207
+ try {
208
+ const body = {
209
+ appUniqueKey: CHATSCENE_APP_UNIQUE_KEY,
210
+ fromPersonalHome: false,
211
+ chatId: randomChatId(),
212
+ appConfigType: 3,
213
+ // ★ content 必须是**字符串**:整个入参 JSON 序列化一次
214
+ messages: [{ content: JSON.stringify(input), role: 'user' }],
215
+ isNeedContext: 1,
216
+ regenerate: false,
217
+ pollingInterval: 200,
218
+ globalParam: {},
219
+ sessionParam: {},
220
+ frontToolList: [],
221
+ searchType: 1,
222
+ userMessageId: randomHex32(),
223
+ assist: { fileList: [], quoteContent: '' },
224
+ taskId: randomHex32(),
225
+ clientType: 1,
226
+ };
227
+ const response = await env.host.workflowRequest({
228
+ method: 'POST',
229
+ path: CHATSCENE_PATH,
230
+ // 该接口靠这个头定位智能体应用;workflow 系列接口不需要它
231
+ headers: { aiappuniquekey: CHATSCENE_APP_UNIQUE_KEY },
232
+ body,
233
+ operation: 'workflow.createForm',
234
+ timeoutMs: CHATSCENE_TIMEOUT_MS,
235
+ // 失败要能自己读结论(也避免把 code/status 异常抛成业务错误中断 createForm)
236
+ tolerateBusinessError: true,
237
+ });
238
+ const root = (response && typeof response === 'object') ? response : {};
239
+ if (Number(root.code) !== 200 || root.status !== true) {
240
+ return { ...base(), reason: `chatScene 返回 code=${String(root.code)} status=${String(root.status)}` };
241
+ }
242
+ const content = root?.data?.chatMessage?.content;
243
+ if (typeof content !== 'string' || !content.trim()) {
244
+ return { ...base(), reason: 'chatScene 未返回 chatMessage.content' };
245
+ }
246
+ let parsed;
247
+ try {
248
+ parsed = JSON.parse(content);
249
+ }
250
+ catch {
251
+ return { ...base(), reason: 'chatMessage.content 不是合法 JSON' };
252
+ }
253
+ const normalized = normalizeFormData(parsed?.formData);
254
+ if (!normalized)
255
+ return { ...base(), reason: '返回值里没有可用的 formData' };
256
+ return {
257
+ ok: true,
258
+ data: normalized.data,
259
+ systemData: normalizeSystemData(parsed?.systemData),
260
+ durationMs: Date.now() - startedAt,
261
+ };
262
+ }
263
+ catch (error) {
264
+ // 超时 / 网络 / HTTP 5xx / 登录态以外的任何问题,一律降级,不打断 createForm。
265
+ const message = (error && typeof error === 'object' && 'message' in error)
266
+ ? String(error.message)
267
+ : String(error);
268
+ return { ...base(), reason: `chatScene 调用失败:${message}` };
269
+ }
270
+ }