weaver-work-cli 0.1.32 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/chunks/{archive-UMGX72K6.js → archive-FVFY6GZN.js} +2 -2
- package/dist/chunks/{archive-oa-N2IYBLF3.js → archive-oa-NW3OD4UV.js} +2 -2
- package/dist/chunks/{asset-GLEGKFG5.js → asset-7QJKMIDV.js} +2 -2
- package/dist/chunks/{attachment-content-AQNX5N3S.js → attachment-content-OSAVA6K3.js} +3 -2
- package/dist/chunks/{blog-E44OTVDA.js → blog-I7SDPNW4.js} +2 -2
- package/dist/chunks/{caizhilian-DQUFZXZL.js → caizhilian-O37ZIQNY.js} +2 -2
- package/dist/chunks/{calendar-JKPIRKFD.js → calendar-7KXE4ED3.js} +2 -2
- package/dist/chunks/{chunk-4YC43QQ4.js → chunk-2FLWXFVS.js} +4 -4
- package/dist/chunks/{chunk-QWY6PGL6.js → chunk-2LV74IWP.js} +361 -56
- package/dist/chunks/chunk-3SO6QL6U.js +73 -0
- package/dist/chunks/{chunk-DW6AUUKS.js → chunk-6ATGWRZM.js} +6 -4
- package/dist/chunks/chunk-BYATLLEF.js +68 -0
- package/dist/chunks/chunk-BYBSCN4X.js +932 -0
- package/dist/chunks/{chunk-2GA5ZIQL.js → chunk-D223PTXU.js} +1 -0
- package/dist/chunks/{chunk-H7J4DC5R.js → chunk-EEWPQE3O.js} +2 -2
- package/dist/chunks/{chunk-6RKD4DRZ.js → chunk-GFPXQIY2.js} +2 -2
- package/dist/chunks/{chunk-C6R3B2ML.js → chunk-HEL5XTYI.js} +12 -6
- package/dist/chunks/{chunk-CVZ2JOSW.js → chunk-IHUYP6LO.js} +1 -1
- package/dist/chunks/{chunk-YRVDW4WN.js → chunk-ILMBNVSG.js} +2 -2
- package/dist/chunks/{chunk-G3QJULO2.js → chunk-KAS45KNR.js} +1 -1
- package/dist/chunks/{chunk-H6XSTSLM.js → chunk-MEEFGWTM.js} +54 -196
- package/dist/chunks/{chunk-GCG2NMWR.js → chunk-MQ2I5AA3.js} +4 -2
- package/dist/chunks/chunk-NHA62QD7.js +774 -0
- package/dist/chunks/{chunk-WKI2FBIQ.js → chunk-OCU4RLHC.js} +641 -309
- package/dist/chunks/{chunk-WSKBSQ2U.js → chunk-PRHJGPMA.js} +2 -2
- package/dist/chunks/{chunk-6EFWDL7Y.js → chunk-Q6LWB5HX.js} +2 -2
- package/dist/chunks/{chunk-IURUFGZK.js → chunk-RBGOMK4Y.js} +50 -33
- package/dist/chunks/chunk-VBCFFFGT.js +226 -0
- package/dist/chunks/{ebuilder-form-V5FG2EHC.js → chunk-WRRJ4GG2.js} +22 -1148
- package/dist/chunks/{chunk-E4Z23GHM.js → chunk-WY74UBJ6.js} +264 -750
- package/dist/chunks/conflict-SFNEVJY5.js +21 -0
- package/dist/chunks/continuation-RN6PZN2M.js +11 -0
- package/dist/chunks/cowork-CKWYHXYB.js +2508 -0
- package/dist/chunks/ebuilder-form-KOLJRVZD.js +121 -0
- package/dist/chunks/{ehr-HMFY6VIL.js → ehr-WFOC3B4D.js} +1174 -20
- package/dist/chunks/{esb-ZYSVB7SG.js → esb-LJZTN663.js} +4 -4
- package/dist/chunks/{fna-B7RKPAZD.js → fna-F7QRIIZC.js} +2 -2
- package/dist/chunks/{host-45WED2KK.js → host-BCGUVEWX.js} +3 -3
- package/dist/chunks/host-BQBRHVR3.js +23 -0
- package/dist/chunks/{host-I4Z6BFYX.js → host-DGE2TZD4.js} +3 -3
- package/dist/chunks/{host-KNZ52LJZ.js → host-KXPTEWFS.js} +3 -3
- package/dist/chunks/{host-OCH2BCCV.js → host-VQ6JJXGQ.js} +3 -3
- package/dist/chunks/{hrm-2KAZGUHI.js → hrm-NI6XAKW5.js} +3 -3
- package/dist/chunks/{im-ACJJWH4U.js → im-7TRTF3KT.js} +88 -12
- package/dist/chunks/{invoice-ZK3WCX2U.js → invoice-AOXWJKYT.js} +3 -3
- package/dist/chunks/{jiuchuanhui-5PQD3IL2.js → jiuchuanhui-7NQWEZAW.js} +2 -2
- package/dist/chunks/{lazy-dispatch-JQXBW3GM.js → lazy-dispatch-RNS4EE4S.js} +4 -4
- package/dist/chunks/{mail-S2HDDXO2.js → mail-VDHJAB4O.js} +3 -3
- package/dist/chunks/{meeting-QVN3I37L.js → meeting-GA7XCNNP.js} +214 -43
- package/dist/chunks/{okr-QNG4VC2Q.js → okr-TQIRERPQ.js} +2 -2
- package/dist/chunks/operations-5QL3AECO.js +11 -0
- package/dist/chunks/{plan-A25EMW6U.js → plan-4RY4LN2P.js} +2 -2
- package/dist/chunks/{project-G6XV66DZ.js → project-D6XT2OC5.js} +2 -2
- package/dist/chunks/{registry-DC6KR3NH.js → registry-JHRIDQ3A.js} +4 -4
- package/dist/chunks/{registry-2VLUAESA.js → registry-OZSMDVPP.js} +2 -2
- package/dist/chunks/{registry-TI3CIUXF.js → registry-QKMI43Q6.js} +8 -6
- package/dist/chunks/{registry-7C5UMIPL.js → registry-VOGKFFTR.js} +2 -2
- package/dist/chunks/{room-recommend-WRTHO6Y2.js → room-recommend-D4EUOOWY.js} +4 -3
- package/dist/chunks/{schedule-KFIITGSK.js → schedule-XPFBHPCV.js} +4 -3
- package/dist/chunks/{workflow-DJ7SYWAF.js → workflow-HLBZRWIY.js} +172 -6
- package/dist/index.js +30 -25
- package/dist/internal/e10/auth-recovery.js +14 -4
- package/dist/shortcuts/contract/host.js +34 -59
- package/dist/shortcuts/cowork/continuation.js +70 -0
- package/dist/shortcuts/cowork/errors.js +59 -0
- package/dist/shortcuts/cowork/host.js +172 -0
- package/dist/shortcuts/cowork/index.js +166 -0
- package/dist/shortcuts/cowork/manifest.js +65 -0
- package/dist/shortcuts/cowork/operations/discuss-write.js +277 -0
- package/dist/shortcuts/cowork/operations/item-write.js +380 -0
- package/dist/shortcuts/cowork/operations/member-write.js +283 -0
- package/dist/shortcuts/cowork/operations/permission-write.js +286 -0
- package/dist/shortcuts/cowork/operations/read.js +423 -0
- package/dist/shortcuts/cowork/operations/registry.js +39 -0
- package/dist/shortcuts/cowork/operations/review-write.js +157 -0
- package/dist/shortcuts/cowork/operations/shared.js +215 -0
- package/dist/shortcuts/cowork/operations/types.js +24 -0
- package/dist/shortcuts/cowork/operations.js +19 -0
- package/dist/shortcuts/ehr/host.js +4 -1
- package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +757 -0
- package/dist/shortcuts/ehr/operations/recruit-position.js +367 -0
- package/dist/shortcuts/ehr/operations/recruit-stats.js +133 -0
- package/dist/shortcuts/ehr/operations/recruit-write.js +8 -16
- package/dist/shortcuts/ehr/operations/recruit.js +35 -10
- package/dist/shortcuts/ehr/operations/registry.js +6 -0
- package/dist/shortcuts/im/diagnostics.js +97 -0
- package/dist/shortcuts/im/host.js +58 -31
- package/dist/shortcuts/im/index.js +7 -2
- package/dist/shortcuts/im/operations/at-mention.js +127 -0
- package/dist/shortcuts/im/operations/file-user.js +10 -2
- package/dist/shortcuts/im/operations/group-read.js +26 -5
- package/dist/shortcuts/im/operations/group-write.js +35 -28
- package/dist/shortcuts/im/operations/msg-sync.js +7 -2
- package/dist/shortcuts/im/operations/msg-write.js +76 -10
- package/dist/shortcuts/im/operations/quote-mention.js +119 -0
- package/dist/shortcuts/im/operations/session.js +1 -1
- package/dist/shortcuts/im/operations/shared.js +10 -0
- package/dist/shortcuts/im/operations/types.js +13 -0
- package/dist/shortcuts/index.js +5 -0
- package/dist/shortcuts/mail/host.js +4 -1
- package/dist/shortcuts/meeting/host.js +27 -34
- package/dist/shortcuts/meeting/operations/create.js +4 -1
- package/dist/shortcuts/meeting/operations/eb/catalog.js +5 -0
- package/dist/shortcuts/meeting/operations/eb/conflict.js +78 -7
- package/dist/shortcuts/meeting/operations/eb/create-flow.js +168 -26
- package/dist/shortcuts/meeting/operations/eb/factory.js +69 -1
- package/dist/shortcuts/meeting/operations/eb/index.js +16 -3
- package/dist/shortcuts/meeting/operations/eb/room-recommend.js +14 -3
- package/dist/shortcuts/meeting/operations/eb-fallback.js +159 -0
- package/dist/shortcuts/meeting/operations/env.js +93 -46
- package/dist/shortcuts/meeting/operations/form-fields.js +110 -0
- package/dist/shortcuts/meeting/operations/registry.js +2 -0
- package/dist/shortcuts/meeting/operations/standard-guard.js +71 -0
- package/dist/shortcuts/meeting/operations.js +16 -0
- package/dist/shortcuts/workflow/index.js +110 -1
- package/dist/shortcuts/workflow/operations/form.js +24 -3
- package/dist/shortcuts/workflow/operations/read.js +104 -23
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +448 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.js +106 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +47 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +30 -23
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +1 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +1 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +2 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +2 -4
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +138 -181
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +12 -7
- package/docs/e10-auth.md +1 -1
- package/docs/im.md +8 -1
- package/docs/todo-smart-convert/README.md +1 -1
- package/docs/todo-smart-convert/data-contract.md +2 -2
- package/docs/todo-smart-convert/subgroup-rules.md +6 -0
- package/package.json +1 -1
- package/skill-template/domains/yimiaoban.md +3 -3
- package/skill-template/skill-template.md +1 -1
- package/skills/weaver-e10-blog/SKILL.md +5 -5
- package/skills/weaver-e10-caizhilian/SKILL.md +5 -5
- package/skills/weaver-e10-calendar/SKILL.md +5 -5
- package/skills/weaver-e10-esb/SKILL.md +5 -5
- package/skills/weaver-e10-hrm/SKILL.md +5 -5
- package/skills/weaver-e10-jinchengda/SKILL.md +2 -2
- package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -5
- package/skills/weaver-e10-jucailin/SKILL.md +18 -12
- package/skills/weaver-e10-jucailin/references/recruit-create.md +104 -0
- package/skills/weaver-e10-mail/SKILL.md +5 -5
- package/skills/weaver-e10-meeting/SKILL.md +171 -25
- package/skills/weaver-e10-meeting/references/meeting-eb.md +4 -3
- package/skills/weaver-e10-meeting/references/meeting-queries.md +9 -6
- package/skills/weaver-e10-meeting/references/meeting-verification.md +8 -6
- package/skills/weaver-e10-meeting.zip +0 -0
- package/skills/weaver-e10-okr/SKILL.md +5 -5
- package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
- package/skills/weaver-e10-plan/SKILL.md +5 -5
- package/skills/weaver-e10-shared/SKILL.md +12 -12
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -4
- package/skills/weaver-e10-wenshuding/SKILL.md +5 -5
- package/skills/weaver-e10-workflow/SKILL.md +29 -5
- package/skills/weaver-e10-workflow/aigroup/default.json +88 -0
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +66 -14
- package/skills/weaver-e10-workflow/references/workflow-agent-entry.md +1 -1
- package/skills/weaver-e10-workflow/references/workflow-memory.md +1 -1
- package/skills/weaver-e10-workflow/references/workflow-query.md +12 -10
- package/skills/weaver-e10-workflow/references/workflow-view.md +2 -2
- package/skills/weaver-e10-workflow/tools/todo-serve.cjs +239 -0
- package/skills/weaver-e10-workflow/{scripts → tools}/todo-summary.cjs +218 -28
- package/skills/weaver-e10-yepiaotong/SKILL.md +10 -8
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +7 -7
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +10 -10
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +40 -37
- package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +4 -4
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +27 -38
- package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +4 -4
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +37 -29
- package/skills/weaver-e10-yimiaoban/SKILL.md +156 -33
- package/skills/weaver-e10-yimiaoban/references/ding-write.md +1 -1
- package/skills/weaver-e10-yimiaoban/references/error-codes.md +5 -1
- package/skills/weaver-e10-yimiaoban/references/group-read.md +5 -1
- package/skills/weaver-e10-yimiaoban/references/group-write.md +6 -4
- package/skills/weaver-e10-yimiaoban/references/msg-read.md +1 -0
- package/skills/weaver-e10-yimiaoban/references/msg-write.md +34 -2
- package/skills/weaver-e10-yimiaoban/references/safety-boundaries.md +5 -2
- package/skills/weaver-e10-yimiaoban/references/source-manifest.json +79 -58
- package/skills/weaver-e10-yimiaoban/references/user-remind.md +2 -2
- package/skills/weaver-e10-ziguanjia/SKILL.md +5 -5
|
@@ -2,15 +2,22 @@ import { createRequire as __esbuildCreateRequire } from 'node:module';
|
|
|
2
2
|
const require = __esbuildCreateRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
createWorkflowHost
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-PRHJGPMA.js";
|
|
6
6
|
import {
|
|
7
|
+
USER_INTENT_RULE_FILE,
|
|
8
|
+
aigroupUserDir,
|
|
7
9
|
asObject,
|
|
8
10
|
assertNoForbiddenKeys,
|
|
9
11
|
compactStdoutPaths,
|
|
12
|
+
emptyRuleFile,
|
|
10
13
|
getWorkflowOperation,
|
|
14
|
+
loadRuleFile,
|
|
15
|
+
loadRules,
|
|
16
|
+
resetActiveRules,
|
|
17
|
+
validateRuleFile,
|
|
11
18
|
workflowOperationDefinitions,
|
|
12
19
|
workflowSuccess
|
|
13
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-OCU4RLHC.js";
|
|
14
21
|
import {
|
|
15
22
|
createWorkflowContinuationSigner
|
|
16
23
|
} from "./chunk-EZALDOQH.js";
|
|
@@ -21,8 +28,8 @@ import {
|
|
|
21
28
|
} from "./chunk-FMPJJYYI.js";
|
|
22
29
|
import "./chunk-EG6ZU444.js";
|
|
23
30
|
import "./chunk-AJ62BGAW.js";
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
31
|
+
import "./chunk-6ATGWRZM.js";
|
|
32
|
+
import "./chunk-D223PTXU.js";
|
|
26
33
|
import {
|
|
27
34
|
isCliError,
|
|
28
35
|
toErrorEnvelope
|
|
@@ -129,6 +136,86 @@ async function executeWorkflowOperation(operation, rawInput, context) {
|
|
|
129
136
|
return result;
|
|
130
137
|
}
|
|
131
138
|
|
|
139
|
+
// src/shortcuts/workflow/index.ts
|
|
140
|
+
import { join as join2 } from "node:path";
|
|
141
|
+
|
|
142
|
+
// src/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.ts
|
|
143
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
144
|
+
import { join } from "node:path";
|
|
145
|
+
function normalizeIntentPayload(payload) {
|
|
146
|
+
if (Array.isArray(payload)) return payload;
|
|
147
|
+
if (payload && typeof payload === "object") {
|
|
148
|
+
const record = payload;
|
|
149
|
+
if (Array.isArray(record.rules)) return record.rules;
|
|
150
|
+
if (record.workflowName !== void 0) return [record];
|
|
151
|
+
}
|
|
152
|
+
throw workflowValidationError("aigroup_invalid", "\u5165\u53C2\u5FC5\u987B\u662F\u89C4\u5219\u5BF9\u8C61\u3001\u89C4\u5219\u6570\u7EC4\uFF0C\u6216 { rules: [...] }");
|
|
153
|
+
}
|
|
154
|
+
function namesOf(rule) {
|
|
155
|
+
const raw = rule?.workflowName;
|
|
156
|
+
if (typeof raw === "string") return [raw.trim()].filter(Boolean);
|
|
157
|
+
if (Array.isArray(raw)) return raw.map((item) => String(item ?? "").trim()).filter(Boolean);
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
function saveUserIntents(payload, options = {}) {
|
|
161
|
+
const dir = options.dir ?? aigroupUserDir(options.ctx);
|
|
162
|
+
const warnings = [];
|
|
163
|
+
const entries = normalizeIntentPayload(payload);
|
|
164
|
+
if (entries.length === 0) throw workflowValidationError("aigroup_invalid", "\u5165\u53C2\u91CC\u6CA1\u6709\u89C4\u5219\u6761\u76EE");
|
|
165
|
+
const starred = entries.filter((rule) => namesOf(rule).includes("*"));
|
|
166
|
+
if (starred.length > 0) {
|
|
167
|
+
throw workflowValidationError(
|
|
168
|
+
"aigroup_wildcard_unsupported",
|
|
169
|
+
"\u7528\u6237\u610F\u56FE\u4E0D\u80FD\u4F7F\u7528\u901A\u914D workflowName\u300C*\u300D\uFF1A\u515C\u5E95\u89C4\u5219\u7531 aigroup/default.json \u51B3\u5B9A"
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const check = validateRuleFile({ schemaVersion: 2, defaults: {}, rules: entries });
|
|
173
|
+
if (check.length > 0) {
|
|
174
|
+
throw workflowValidationError("aigroup_invalid", `\u89C4\u5219\u6821\u9A8C\u5931\u8D25\uFF1A${check.join("\uFF1B")}`);
|
|
175
|
+
}
|
|
176
|
+
const file = join(dir, USER_INTENT_RULE_FILE);
|
|
177
|
+
const existing = existsSync(file) ? loadRuleFile(file) : emptyRuleFile();
|
|
178
|
+
if (existing.error) {
|
|
179
|
+
warnings.push(`${existing.error}\uFF1B\u672C\u6B21\u5C06\u91CD\u5EFA\u8BE5\u6587\u4EF6`);
|
|
180
|
+
}
|
|
181
|
+
const byName = /* @__PURE__ */ new Map();
|
|
182
|
+
const replaced = [];
|
|
183
|
+
for (const rule of existing.file.rules) {
|
|
184
|
+
for (const name of namesOf(rule)) byName.set(name, rule);
|
|
185
|
+
}
|
|
186
|
+
for (const rule of entries) {
|
|
187
|
+
const names = namesOf(rule);
|
|
188
|
+
for (const name of names) {
|
|
189
|
+
if (byName.has(name)) replaced.push(name);
|
|
190
|
+
byName.set(name, rule);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const merged = [...new Set(byName.values())];
|
|
194
|
+
const text = `${JSON.stringify({ schemaVersion: 2, rules: merged }, null, 2)}
|
|
195
|
+
`;
|
|
196
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
197
|
+
writeFileSync(file, text, { mode: 384 });
|
|
198
|
+
return { file, saved: entries.length, total: merged.length, replaced: [...new Set(replaced)], warnings };
|
|
199
|
+
}
|
|
200
|
+
function readUserIntents(options = {}) {
|
|
201
|
+
const dir = options.dir ?? aigroupUserDir(options.ctx);
|
|
202
|
+
const file = join(dir, USER_INTENT_RULE_FILE);
|
|
203
|
+
if (!existsSync(file)) return { dir, file, exists: false, error: null, rules: [] };
|
|
204
|
+
const loaded = loadRuleFile(file);
|
|
205
|
+
return { dir, file, exists: true, error: loaded.error, rules: loaded.file.rules };
|
|
206
|
+
}
|
|
207
|
+
function clearUserIntents(options = {}) {
|
|
208
|
+
const dir = options.dir ?? aigroupUserDir(options.ctx);
|
|
209
|
+
const file = join(dir, USER_INTENT_RULE_FILE);
|
|
210
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
211
|
+
writeFileSync(file, `${JSON.stringify({ schemaVersion: 2, rules: [] }, null, 2)}
|
|
212
|
+
`, { mode: 384 });
|
|
213
|
+
return file;
|
|
214
|
+
}
|
|
215
|
+
function readRawUserIntents(file) {
|
|
216
|
+
return readFileSync(file, "utf8");
|
|
217
|
+
}
|
|
218
|
+
|
|
132
219
|
// src/shortcuts/workflow/index.ts
|
|
133
220
|
function asOptions(value) {
|
|
134
221
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
@@ -218,6 +305,43 @@ async function executeAndPrint(ctx, operation, input) {
|
|
|
218
305
|
process.exitCode = isCliError(error) ? error.exitCode : 1 /* GeneralError */;
|
|
219
306
|
}
|
|
220
307
|
}
|
|
308
|
+
function fieldNamesOf(inputSchema) {
|
|
309
|
+
const properties = inputSchema.properties;
|
|
310
|
+
if (!properties || typeof properties !== "object" || Array.isArray(properties)) return [];
|
|
311
|
+
return Object.keys(properties);
|
|
312
|
+
}
|
|
313
|
+
function manifestIndex() {
|
|
314
|
+
return {
|
|
315
|
+
schemaVersion: workflowManifest.schemaVersion,
|
|
316
|
+
name: workflowManifest.name,
|
|
317
|
+
title: workflowManifest.title,
|
|
318
|
+
version: workflowManifest.version,
|
|
319
|
+
host: workflowManifest.host,
|
|
320
|
+
status: workflowManifest.status,
|
|
321
|
+
sourceSkill: workflowManifest.sourceSkill,
|
|
322
|
+
capabilities: workflowManifest.capabilities,
|
|
323
|
+
operationCount: workflowManifest.operations.length,
|
|
324
|
+
operations: workflowManifest.operations.map((definition) => ({
|
|
325
|
+
name: definition.name,
|
|
326
|
+
resource: definition.resource,
|
|
327
|
+
summary: definition.summary,
|
|
328
|
+
...definition.capability ? { capability: definition.capability } : {},
|
|
329
|
+
risk: definition.risk,
|
|
330
|
+
...definition.requiresConfirmation ? { requiresConfirmation: true } : {},
|
|
331
|
+
fields: fieldNamesOf(definition.inputSchema)
|
|
332
|
+
})),
|
|
333
|
+
withheldOperations: workflowManifest.withheldOperations,
|
|
334
|
+
operationsHint: "\u9ED8\u8BA4\u53EA\u5217 operation \u4E0E\u5B57\u6BB5\u540D\uFF1B\u5B57\u6BB5\u7C7B\u578B\u3001\u679A\u4E3E\u548C\u586B\u5199\u53E3\u5F84\u7528 `workflow schema --operation <name>` \u5355\u53D6\uFF0C\u6574\u4EFD\u5B8C\u6574 manifest \u7528 `workflow schema --full`\u3002"
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function findOperationContract(name) {
|
|
338
|
+
const full = name.startsWith("workflow.") ? name : `workflow.${name}`;
|
|
339
|
+
const matched = workflowManifest.operations.find((definition) => definition.name === full);
|
|
340
|
+
if (!matched) {
|
|
341
|
+
throw workflowValidationError("operation_unknown", `\u6D41\u7A0B\u6A21\u5757\u4E0D\u652F\u6301\u64CD\u4F5C\uFF1A${name}`);
|
|
342
|
+
}
|
|
343
|
+
return matched;
|
|
344
|
+
}
|
|
221
345
|
function withJsonInputOptions(command) {
|
|
222
346
|
command.option("--input <path>", "JSON input file, or - for stdin").option("--input-json <json>", "inline JSON input object");
|
|
223
347
|
return command;
|
|
@@ -228,8 +352,50 @@ var workflowShortcut = {
|
|
|
228
352
|
category: "shortcut",
|
|
229
353
|
register({ program, action }) {
|
|
230
354
|
const workflow = program.command("workflow").description("\u6CDB\u5FAEE10\u6D41\u7A0B\u667A\u80FD\u52A9\u624B\uFF08\u5F85\u529E/\u5DF2\u529E/\u6211\u53D1\u8D77/\u5168\u90E8\u3001\u8BE6\u60C5\u3001\u64CD\u4F5C\u3001\u6279\u91CF\u3001\u53D1\u8D77\u3001\u4FEE\u6539\uFF09");
|
|
231
|
-
workflow.command("schema").description("Print workflow operation manifest for agents").action(action((ctx) => {
|
|
232
|
-
|
|
355
|
+
workflow.command("schema").description("Print workflow operation manifest for agents").option("--operation <name>", "print one operation with its full inputSchema").option("--full", "print the whole manifest (about 65 KB; stdout may be trimmed)").action(action((ctx, options) => {
|
|
356
|
+
const opts = asOptions(options);
|
|
357
|
+
const requested = String(opts.operation ?? "").trim();
|
|
358
|
+
if (requested && opts.full === true) {
|
|
359
|
+
throw workflowValidationError("option_conflict", "\u4E0D\u80FD\u540C\u65F6\u4F20 --operation \u548C --full");
|
|
360
|
+
}
|
|
361
|
+
if (opts.full === true) {
|
|
362
|
+
ctx.output.write(workflowManifest, { json: true });
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (requested) {
|
|
366
|
+
ctx.output.write(findOperationContract(requested), { json: true });
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
ctx.output.write(manifestIndex(), { json: true });
|
|
370
|
+
}));
|
|
371
|
+
const aigroup = workflow.command("aigroup").description("ai\u4E8C\u6B21\u5206\u7EC4\u89C4\u5219\u5E93\uFF08\u9ED8\u8BA4\u89C4\u5219 + \u7528\u6237\u610F\u56FE\uFF09");
|
|
372
|
+
aigroup.command("show").description("Print effective ai-group rules (default merged with user intents)").option("--raw", "also print user-intents.json as stored on disk").action(action((ctx, options) => {
|
|
373
|
+
const opts = asOptions(options);
|
|
374
|
+
const loaded = loadRules({ ctx });
|
|
375
|
+
const user = readUserIntents({ ctx });
|
|
376
|
+
ctx.output.write({
|
|
377
|
+
dir: loaded.dir,
|
|
378
|
+
defaultFile: join2(loaded.dir, "default.json"),
|
|
379
|
+
userIntentFile: user.file,
|
|
380
|
+
userIntentExists: user.exists,
|
|
381
|
+
userIntentError: user.error,
|
|
382
|
+
defaults: loaded.file.defaults,
|
|
383
|
+
rules: loaded.file.rules,
|
|
384
|
+
userRules: user.rules,
|
|
385
|
+
warnings: loaded.warnings,
|
|
386
|
+
...opts.raw === true && user.exists ? { rawUserIntents: readRawUserIntents(user.file) } : {}
|
|
387
|
+
}, { json: true });
|
|
388
|
+
}));
|
|
389
|
+
withJsonInputOptions(aigroup.command("set").description("Save user-intent rules: validated, whole-entry replace by workflowName").action(action(async (ctx, options) => {
|
|
390
|
+
const payload = await inputFrom(options);
|
|
391
|
+
const result = saveUserIntents(payload, { ctx });
|
|
392
|
+
resetActiveRules();
|
|
393
|
+
ctx.output.write(result, { json: true });
|
|
394
|
+
})));
|
|
395
|
+
aigroup.command("clear").description("Empty user-intent rules (default.json is never touched)").action(action((ctx) => {
|
|
396
|
+
const file = clearUserIntents({ ctx });
|
|
397
|
+
resetActiveRules();
|
|
398
|
+
ctx.output.write({ cleared: true, file }, { json: true });
|
|
233
399
|
}));
|
|
234
400
|
withJsonInputOptions(workflow.command("run").description("Run a workflow operation with JSON input").argument("<operation>", "operation name, e.g. workflow.search")).action(action(async (ctx, operation, options) => {
|
|
235
401
|
await executeAndPrint(ctx, String(operation), await inputFrom(options));
|
package/dist/index.js
CHANGED
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
firstPositionalToken,
|
|
8
8
|
registerCommands,
|
|
9
9
|
toCommandMetadata
|
|
10
|
-
} from "./chunks/chunk-
|
|
10
|
+
} from "./chunks/chunk-GFPXQIY2.js";
|
|
11
11
|
import "./chunks/chunk-EG6ZU444.js";
|
|
12
12
|
import "./chunks/chunk-AJ62BGAW.js";
|
|
13
|
-
import "./chunks/chunk-
|
|
14
|
-
import "./chunks/chunk-
|
|
15
|
-
import "./chunks/chunk-
|
|
13
|
+
import "./chunks/chunk-EEWPQE3O.js";
|
|
14
|
+
import "./chunks/chunk-6ATGWRZM.js";
|
|
15
|
+
import "./chunks/chunk-D223PTXU.js";
|
|
16
16
|
import "./chunks/chunk-LUSPKZKY.js";
|
|
17
17
|
import "./chunks/chunk-BUSC6UAE.js";
|
|
18
18
|
|
|
@@ -29,7 +29,7 @@ function lazyShortcut(definition) {
|
|
|
29
29
|
placeholder.allowExcessArguments(true);
|
|
30
30
|
placeholder.helpOption(false);
|
|
31
31
|
placeholder.action(async () => {
|
|
32
|
-
const { dispatchLazyShortcut } = await import("./chunks/lazy-dispatch-
|
|
32
|
+
const { dispatchLazyShortcut } = await import("./chunks/lazy-dispatch-RNS4EE4S.js");
|
|
33
33
|
await dispatchLazyShortcut(definition, shortcutMetadata());
|
|
34
34
|
});
|
|
35
35
|
}
|
|
@@ -39,102 +39,107 @@ var builtinShortcuts = [
|
|
|
39
39
|
lazyShortcut({
|
|
40
40
|
name: "invoice",
|
|
41
41
|
description: "E10 \u4E1A\u7968\u901A\u53D1\u7968\u7BA1\u7406 CLI",
|
|
42
|
-
load: async () => (await import("./chunks/invoice-
|
|
42
|
+
load: async () => (await import("./chunks/invoice-AOXWJKYT.js")).invoiceShortcut
|
|
43
43
|
}),
|
|
44
44
|
lazyShortcut({
|
|
45
45
|
name: "ehr",
|
|
46
46
|
description: "\u6CDB\u5FAEE10\u805A\u624D\u6797\uFF08\u4EBA\u4E8B/\u51FA\u52E4/\u85AA\u916C\uFF09CLI",
|
|
47
|
-
load: async () => (await import("./chunks/ehr-
|
|
47
|
+
load: async () => (await import("./chunks/ehr-WFOC3B4D.js")).ehrShortcut
|
|
48
|
+
}),
|
|
49
|
+
lazyShortcut({
|
|
50
|
+
name: "cowork",
|
|
51
|
+
description: "\u6CDB\u5FAEE10\u534F\u4F5C\u533A\uFF08\u534F\u4F5C\u4E8B\u9879/\u8BA8\u8BBA/\u5BA1\u6279/\u5171\u4EAB\u6743\u9650\uFF09CLI",
|
|
52
|
+
load: async () => (await import("./chunks/cowork-CKWYHXYB.js")).coworkShortcut
|
|
48
53
|
}),
|
|
49
54
|
lazyShortcut({
|
|
50
55
|
name: "archive",
|
|
51
56
|
description: "E10 \u6587\u4E66\u5B9A\u6863\u6848\u7BA1\u7406 CLI",
|
|
52
|
-
load: async () => (await import("./chunks/archive-
|
|
57
|
+
load: async () => (await import("./chunks/archive-FVFY6GZN.js")).archiveShortcut
|
|
53
58
|
}),
|
|
54
59
|
lazyShortcut({
|
|
55
60
|
name: "archive-oa",
|
|
56
61
|
description: "E10 \u6863\u6848\u5B9A\u4F4D\u4E0E OA \u5546\u52A1\u5408\u540C\u501F\u9605 CLI",
|
|
57
|
-
load: async () => (await import("./chunks/archive-oa-
|
|
62
|
+
load: async () => (await import("./chunks/archive-oa-NW3OD4UV.js")).archiveOaShortcut
|
|
58
63
|
}),
|
|
59
64
|
lazyShortcut({
|
|
60
65
|
name: "calendar",
|
|
61
66
|
description: "\u6CDB\u5FAEE10\u65E5\u7A0B\u7BA1\u7406 CLI\uFF08\u521B\u5EFA/\u67E5\u8BE2/\u66F4\u65B0/\u5220\u9664/\u5B57\u5178\uFF09",
|
|
62
|
-
load: async () => (await import("./chunks/calendar-
|
|
67
|
+
load: async () => (await import("./chunks/calendar-7KXE4ED3.js")).calendarShortcut
|
|
63
68
|
}),
|
|
64
69
|
lazyShortcut({
|
|
65
70
|
name: "fna",
|
|
66
71
|
description: "\u6CDB\u5FAEE10\u9F50\u4E1A\u6210\u8D39\u63A7\u4E2D\u5FC3\uFF08\u9884\u7B97/\u8D39\u7528\u4E2D\u5FC3/\u501F\u6B3E\u7BA1\u7406/\u53D1\u7968\u6838\u9500\uFF09CLI",
|
|
67
|
-
load: async () => (await import("./chunks/fna-
|
|
72
|
+
load: async () => (await import("./chunks/fna-F7QRIIZC.js")).fnaShortcut
|
|
68
73
|
}),
|
|
69
74
|
lazyShortcut({
|
|
70
75
|
name: "hrm",
|
|
71
76
|
description: "\u6CDB\u5FAEE10\u7EC4\u7EC7\u7BA1\u7406\uFF08\u5458\u5DE5/\u7EC4\u7EC7/\u5C97\u4F4D\u67E5\u8BE2\uFF09CLI",
|
|
72
|
-
load: async () => (await import("./chunks/hrm-
|
|
77
|
+
load: async () => (await import("./chunks/hrm-NI6XAKW5.js")).hrmShortcut
|
|
73
78
|
}),
|
|
74
79
|
lazyShortcut({
|
|
75
80
|
name: "mail",
|
|
76
81
|
description: "\u6CDB\u5FAEE10\u90AE\u4EF6\u7BA1\u7406 CLI",
|
|
77
|
-
load: async () => (await import("./chunks/mail-
|
|
82
|
+
load: async () => (await import("./chunks/mail-VDHJAB4O.js")).mailShortcut
|
|
78
83
|
}),
|
|
79
84
|
lazyShortcut({
|
|
80
85
|
name: "meeting",
|
|
81
86
|
description: "\u6CDB\u5FAEE10\u4F1A\u8BAE\u7BA1\u7406 CLI\uFF08\u6807\u51C6\u7248\uFF1A\u67E5\u8BE2/\u51B2\u7A81/\u9884\u7EA6/\u56DE\u6267/\u7B7E\u5230\uFF09",
|
|
82
|
-
load: async () => (await import("./chunks/meeting-
|
|
87
|
+
load: async () => (await import("./chunks/meeting-GA7XCNNP.js")).meetingShortcut
|
|
83
88
|
}),
|
|
84
89
|
lazyShortcut({
|
|
85
90
|
name: "okr",
|
|
86
91
|
description: "\u6CDB\u5FAEE10 OKR \u76EE\u6807\u7BA1\u7406 CLI\uFF08\u76EE\u6807\u67E5\u8BE2/\u65B0\u5EFA/\u7F16\u8F91\u3001\u5173\u952E\u6210\u679C\u3001\u76EE\u6807\u5BF9\u9F50\u3001\u8BC4\u8BBA\uFF09",
|
|
87
|
-
load: async () => (await import("./chunks/okr-
|
|
92
|
+
load: async () => (await import("./chunks/okr-TQIRERPQ.js")).okrShortcut
|
|
88
93
|
}),
|
|
89
94
|
lazyShortcut({
|
|
90
95
|
name: "plan",
|
|
91
96
|
description: "\u6CDB\u5FAEE10\u8BA1\u5212\u62A5\u544A CLI\uFF08\u67E5\u8BE2/\u65B0\u5EFA/\u4FEE\u6539/\u53D1\u5E03/\u64A4\u56DE/\u63D0\u4EA4\u63D0\u9192/\u8BC4\u8BBA\uFF09",
|
|
92
|
-
load: async () => (await import("./chunks/plan-
|
|
97
|
+
load: async () => (await import("./chunks/plan-4RY4LN2P.js")).planShortcut
|
|
93
98
|
}),
|
|
94
99
|
lazyShortcut({
|
|
95
100
|
name: "esb",
|
|
96
101
|
description: "\u6CDB\u5FAEE10 ESB \u4E2D\u5FC3\u81EA\u5B9A\u4E49\u89E6\u53D1\u52A8\u4F5C\u6D41 CLI",
|
|
97
|
-
load: async () => (await import("./chunks/esb-
|
|
102
|
+
load: async () => (await import("./chunks/esb-LJZTN663.js")).esbShortcut
|
|
98
103
|
}),
|
|
99
104
|
lazyShortcut({
|
|
100
105
|
name: "ebuilder-form",
|
|
101
106
|
description: "\u6CDB\u5FAEE10 eBuilder \u8868\u5355\u83DC\u5355\u3001\u5217\u8868\u548C\u8868\u5355\u6570\u636E CLI",
|
|
102
|
-
load: async () => (await import("./chunks/ebuilder-form-
|
|
107
|
+
load: async () => (await import("./chunks/ebuilder-form-KOLJRVZD.js")).ebuilderFormShortcut
|
|
103
108
|
}),
|
|
104
109
|
lazyShortcut({
|
|
105
110
|
name: "jiuchuanhui",
|
|
106
111
|
description: "\u6CDB\u5FAEE10\u4E5D\u6C1A\u6C47\u8425\u9500\u7BA1\u7406 CLI\uFF08\u5BA2\u6237/\u8054\u7CFB\u4EBA/\u5546\u673A/\u7EBF\u7D22/\u8054\u7CFB\u8BA1\u5212/\u516C\u6D77\uFF09",
|
|
107
|
-
load: async () => (await import("./chunks/jiuchuanhui-
|
|
112
|
+
load: async () => (await import("./chunks/jiuchuanhui-7NQWEZAW.js")).jiuchuanhuiShortcut
|
|
108
113
|
}),
|
|
109
114
|
lazyShortcut({
|
|
110
115
|
name: "asset",
|
|
111
116
|
description: "E10 \u8D44\u4EA7\u7BA1\u7406\uFF08\u8D44\u7BA1\u5BB6\uFF09CLI",
|
|
112
|
-
load: async () => (await import("./chunks/asset-
|
|
117
|
+
load: async () => (await import("./chunks/asset-7QJKMIDV.js")).assetShortcut
|
|
113
118
|
}),
|
|
114
119
|
lazyShortcut({
|
|
115
120
|
name: "im",
|
|
116
121
|
description: "\u6CDB\u5FAEE10\u6613\u79D2\u529E\uFF08\u5373\u65F6\u901A\u8BAF\uFF09CLI",
|
|
117
|
-
load: async () => (await import("./chunks/im-
|
|
122
|
+
load: async () => (await import("./chunks/im-7TRTF3KT.js")).imShortcut
|
|
118
123
|
}),
|
|
119
124
|
lazyShortcut({
|
|
120
125
|
name: "project",
|
|
121
126
|
description: "\u6CDB\u5FAEE10\u4E8B\u4E95\u7136\u9879\u76EE\u7BA1\u7406 CLI\uFF08\u9879\u76EE/\u4EFB\u52A1\u67E5\u8BE2\u4E0E\u786E\u8BA4\u5199\u5165\uFF09",
|
|
122
|
-
load: async () => (await import("./chunks/project-
|
|
127
|
+
load: async () => (await import("./chunks/project-D6XT2OC5.js")).projectShortcut
|
|
123
128
|
}),
|
|
124
129
|
lazyShortcut({
|
|
125
130
|
name: "workflow",
|
|
126
131
|
description: "\u6CDB\u5FAEE10\u6D41\u7A0B\u667A\u80FD\u52A9\u624B CLI\uFF08\u67E5\u8BE2/\u67E5\u770B/\u64CD\u4F5C/\u6279\u91CF/\u53D1\u8D77/\u4FEE\u6539\uFF09",
|
|
127
|
-
load: async () => (await import("./chunks/workflow-
|
|
132
|
+
load: async () => (await import("./chunks/workflow-HLBZRWIY.js")).workflowShortcut
|
|
128
133
|
}),
|
|
129
134
|
lazyShortcut({
|
|
130
135
|
name: "blog",
|
|
131
136
|
description: "\u6CDB\u5FAEE10\u5DE5\u4F5C\u65E5\u62A5 CLI\uFF08\u67E5\u8BE2/\u53D1\u5E03/\u7F16\u8F91/\u8BC4\u8BBA/\u70B9\u8D5E/\u63D0\u9192/\u5BFC\u51FA\uFF09",
|
|
132
|
-
load: async () => (await import("./chunks/blog-
|
|
137
|
+
load: async () => (await import("./chunks/blog-I7SDPNW4.js")).blogShortcut
|
|
133
138
|
}),
|
|
134
139
|
lazyShortcut({
|
|
135
140
|
name: "caizhilian",
|
|
136
141
|
description: "\u6CDB\u5FAEE10\u91C7\u77E5\u8FDE\uFF08\u6587\u6863\u4E2D\u5FC3\uFF09CLI",
|
|
137
|
-
load: async () => (await import("./chunks/caizhilian-
|
|
142
|
+
load: async () => (await import("./chunks/caizhilian-O37ZIQNY.js")).caizhilianShortcut
|
|
138
143
|
})
|
|
139
144
|
];
|
|
140
145
|
function shortcutMetadata() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isXiaoERuntimeAgent } from '../../core/runtime-agent.js';
|
|
1
2
|
import { getActiveProfile } from './auth/session.js';
|
|
2
3
|
import { hasXiaoEEnv, tryXiaoEUnifiedLogin } from './auth/xiaoe.js';
|
|
3
4
|
const AUTH_REQUIRED_CODES = new Set(['-2', '401']);
|
|
@@ -94,12 +95,21 @@ export function isE10AuthenticationRequired(response) {
|
|
|
94
95
|
function globalOptions(ctx) {
|
|
95
96
|
return typeof ctx.getGlobalOptions === 'function' ? ctx.getGlobalOptions() : {};
|
|
96
97
|
}
|
|
97
|
-
/**
|
|
98
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Decide whether an expired session can be recovered through XiaoE without
|
|
100
|
+
* involving the caller/Agent. Runtime evidence is preferred, but a persisted
|
|
101
|
+
* XiaoE login is also authoritative: business commands often run in a fresh
|
|
102
|
+
* process where the host no longer injects its original XIAOE_* markers.
|
|
103
|
+
*/
|
|
104
|
+
export function canAutomaticallyRecoverXiaoE(ctx, currentSession) {
|
|
99
105
|
const options = globalOptions(ctx);
|
|
100
106
|
// An explicitly supplied auth file is caller-owned and must not be replaced
|
|
101
107
|
// by a profile-backed XiaoE session behind the caller's back.
|
|
102
|
-
|
|
108
|
+
if (options.auth)
|
|
109
|
+
return false;
|
|
110
|
+
return hasXiaoEEnv(ctx.env || process.env, options)
|
|
111
|
+
|| currentSession?.loginSource === 'xiaoe-unified'
|
|
112
|
+
|| isXiaoERuntimeAgent(currentSession?.agentType);
|
|
103
113
|
}
|
|
104
114
|
/**
|
|
105
115
|
* Silently refresh a stale XiaoE session. Concurrent requests for the same
|
|
@@ -107,7 +117,7 @@ export function canAutomaticallyRecoverXiaoE(ctx) {
|
|
|
107
117
|
* does not start a burst of login attempts.
|
|
108
118
|
*/
|
|
109
119
|
export async function recoverXiaoEAuthSession(ctx, currentSession) {
|
|
110
|
-
if (!canAutomaticallyRecoverXiaoE(ctx))
|
|
120
|
+
if (!canAutomaticallyRecoverXiaoE(ctx, currentSession))
|
|
111
121
|
return null;
|
|
112
122
|
const options = globalOptions(ctx);
|
|
113
123
|
const profile = options.profile || getActiveProfile();
|
|
@@ -3,6 +3,7 @@ import { basename } from 'node:path';
|
|
|
3
3
|
import { E10_SESSION_EXPIRED_MESSAGE } from '../../internal/e10/auth/messages.js';
|
|
4
4
|
import { requireE10Session } from '../../internal/e10/context.js';
|
|
5
5
|
import { getActiveProfile } from '../../internal/e10/auth/session.js';
|
|
6
|
+
import { E10ApiError, createE10RequestRuntime, } from '../../internal/e10/request-runtime.js';
|
|
6
7
|
import { ContractCliError, contractAuthError, contractNetworkError, contractValidationError, } from './errors.js';
|
|
7
8
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
8
9
|
function assertPath(requestPath) {
|
|
@@ -16,38 +17,6 @@ function assertPath(requestPath) {
|
|
|
16
17
|
throw contractValidationError('path_not_allowed', '今承达合同管理只能调用 /api/ 路径');
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
|
-
function withQuery(baseUrl, requestPath, query = {}) {
|
|
20
|
-
const url = new URL(`${baseUrl}${requestPath}`);
|
|
21
|
-
for (const [key, value] of Object.entries(query)) {
|
|
22
|
-
if (value === undefined || value === null || value === '')
|
|
23
|
-
continue;
|
|
24
|
-
if (Array.isArray(value)) {
|
|
25
|
-
for (const item of value)
|
|
26
|
-
url.searchParams.append(key, String(item));
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
url.searchParams.set(key, String(value));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return url;
|
|
33
|
-
}
|
|
34
|
-
async function fetchWithTimeout(url, options, timeoutMs) {
|
|
35
|
-
const controller = new AbortController();
|
|
36
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
37
|
-
try {
|
|
38
|
-
return await fetch(url, { ...options, signal: controller.signal, redirect: 'manual' });
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
if (error instanceof Error && error.name === 'AbortError') {
|
|
42
|
-
throw contractNetworkError('timeout', `请求超时(${timeoutMs}ms)`, { retryable: false });
|
|
43
|
-
}
|
|
44
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
45
|
-
throw contractNetworkError('transport', `请求失败:${message}`, { retryable: true });
|
|
46
|
-
}
|
|
47
|
-
finally {
|
|
48
|
-
clearTimeout(timer);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
20
|
function textOf(value, keys) {
|
|
52
21
|
for (const key of keys) {
|
|
53
22
|
const candidate = value?.[key];
|
|
@@ -131,15 +100,6 @@ function inferProfile(ctx) {
|
|
|
131
100
|
const options = ctx.getGlobalOptions();
|
|
132
101
|
return options.profile || getActiveProfile();
|
|
133
102
|
}
|
|
134
|
-
function requestHeaders(session) {
|
|
135
|
-
return {
|
|
136
|
-
Accept: 'application/json, text/plain, */*',
|
|
137
|
-
Cookie: session.cookieHeader(),
|
|
138
|
-
eteamsid: session.eteamsId,
|
|
139
|
-
'User-Agent': session.uaHeader(),
|
|
140
|
-
Origin: session.getBaseUrl(),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
103
|
export function createContractHost(ctx, dependencies = {}) {
|
|
144
104
|
let e10Session = null;
|
|
145
105
|
let sessionContext = null;
|
|
@@ -164,10 +124,9 @@ export function createContractHost(ctx, dependencies = {}) {
|
|
|
164
124
|
assertPath(path);
|
|
165
125
|
const session = await ensureSession();
|
|
166
126
|
const context = await getSession();
|
|
167
|
-
const
|
|
168
|
-
const finalQuery = { ...query };
|
|
127
|
+
const finalQuery = Object.fromEntries(Object.entries(query).filter(([, value]) => value !== undefined && value !== null && value !== ''));
|
|
169
128
|
let finalBody = body;
|
|
170
|
-
|
|
129
|
+
let formData;
|
|
171
130
|
if (userIdField) {
|
|
172
131
|
if (!context.userId) {
|
|
173
132
|
throw contractAuthError('user_id_missing', '当前会话没有可用的用户 ID,请确认 E10 登录态');
|
|
@@ -178,9 +137,9 @@ export function createContractHost(ctx, dependencies = {}) {
|
|
|
178
137
|
finalBody = { ...finalBody, [userIdField]: context.userId };
|
|
179
138
|
}
|
|
180
139
|
if (form || file) {
|
|
181
|
-
|
|
140
|
+
formData = new FormData();
|
|
182
141
|
for (const [key, value] of Object.entries(form ?? {}))
|
|
183
|
-
|
|
142
|
+
formData.append(key, value);
|
|
184
143
|
if (file) {
|
|
185
144
|
let buffer;
|
|
186
145
|
try {
|
|
@@ -190,25 +149,41 @@ export function createContractHost(ctx, dependencies = {}) {
|
|
|
190
149
|
throw contractValidationError('file_unreadable', `无法读取文件:${file.path}`);
|
|
191
150
|
}
|
|
192
151
|
const filename = file.filename ?? basename(file.path);
|
|
193
|
-
|
|
152
|
+
formData.append(file.field ?? 'file', new Blob([new Uint8Array(buffer)], { type: file.contentType ?? 'application/octet-stream' }), filename);
|
|
194
153
|
}
|
|
195
|
-
init.body = data;
|
|
196
154
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
155
|
+
const runtime = createE10RequestRuntime(ctx, session, {
|
|
156
|
+
interceptors: dependencies.interceptors,
|
|
157
|
+
fetch: dependencies.fetch,
|
|
158
|
+
recoverAuthentication: dependencies.recoverAuthentication,
|
|
159
|
+
});
|
|
160
|
+
let response;
|
|
161
|
+
try {
|
|
162
|
+
response = await runtime.requestJson({
|
|
163
|
+
module: 'contract',
|
|
164
|
+
method,
|
|
165
|
+
path,
|
|
166
|
+
query: finalQuery,
|
|
167
|
+
body: formData ? undefined : finalBody,
|
|
168
|
+
formData,
|
|
169
|
+
headers: extraHeaders,
|
|
170
|
+
timeoutMs,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
if (error instanceof E10ApiError && error.type === 'network') {
|
|
175
|
+
throw contractNetworkError(error.subtype, error.message, {
|
|
176
|
+
retryable: error.retryable,
|
|
177
|
+
details: error.details,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
throw error;
|
|
200
181
|
}
|
|
201
|
-
const url = withQuery(context.baseUrl, path, finalQuery);
|
|
202
|
-
const response = await fetchWithTimeout(url, init, timeoutMs);
|
|
203
182
|
if (response.status === 401 || response.status === 302) {
|
|
204
183
|
throw contractAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status, path });
|
|
205
184
|
}
|
|
206
|
-
const text =
|
|
207
|
-
|
|
208
|
-
try {
|
|
209
|
-
value = text ? JSON.parse(text) : {};
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
185
|
+
const { text, value } = response;
|
|
186
|
+
if (response.parseError) {
|
|
212
187
|
throw contractNetworkError('protocol', `接口返回不是合法 JSON(HTTP ${response.status})`, {
|
|
213
188
|
retryable: false,
|
|
214
189
|
details: { path, status: response.status },
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { resolve } from 'node:path';
|
|
6
|
+
import { coworkValidationError } from './errors.js';
|
|
7
|
+
function stateRoot(ctx) {
|
|
8
|
+
const configured = ctx?.config?.path();
|
|
9
|
+
if (configured)
|
|
10
|
+
return resolve(configured, '..');
|
|
11
|
+
return process.env.WEAVER_WORK_CLI_HOME || process.env.WORK_CLI_HOME || resolve(homedir(), '.weaver-work-cli');
|
|
12
|
+
}
|
|
13
|
+
async function loadKey(ctx) {
|
|
14
|
+
const keysDir = resolve(stateRoot(ctx), 'keys');
|
|
15
|
+
const filename = resolve(keysDir, 'cowork-continuation.key');
|
|
16
|
+
await mkdir(keysDir, { recursive: true, mode: 0o700 });
|
|
17
|
+
if (existsSync(filename))
|
|
18
|
+
return readFile(filename);
|
|
19
|
+
const key = randomBytes(32);
|
|
20
|
+
try {
|
|
21
|
+
await writeFile(filename, key, { flag: 'wx', mode: 0o600 });
|
|
22
|
+
if (process.platform !== 'win32')
|
|
23
|
+
await chmod(filename, 0o600).catch(() => undefined);
|
|
24
|
+
return key;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return readFile(filename);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function encode(value) {
|
|
31
|
+
return Buffer.from(JSON.stringify(value)).toString('base64url');
|
|
32
|
+
}
|
|
33
|
+
function signature(payload, key) {
|
|
34
|
+
return createHmac('sha256', key).update(payload).digest('base64url');
|
|
35
|
+
}
|
|
36
|
+
export function createCoworkContinuationSigner(ctx) {
|
|
37
|
+
return {
|
|
38
|
+
async issue(payload, ttlMs = 10 * 60_000) {
|
|
39
|
+
const issuedAt = Date.now();
|
|
40
|
+
const body = encode({ ...payload, issuedAt, expiresAt: issuedAt + ttlMs });
|
|
41
|
+
const sig = signature(body, await loadKey(ctx));
|
|
42
|
+
return `${body}.${sig}`;
|
|
43
|
+
},
|
|
44
|
+
async verify(token, expectedOperation) {
|
|
45
|
+
if (typeof token !== 'string' || !token.includes('.')) {
|
|
46
|
+
throw coworkValidationError('continuation_invalid', 'continuation 无效');
|
|
47
|
+
}
|
|
48
|
+
const [body, provided] = token.split('.');
|
|
49
|
+
const expected = signature(body, await loadKey(ctx));
|
|
50
|
+
const valid = provided.length === expected.length
|
|
51
|
+
&& timingSafeEqual(Buffer.from(provided), Buffer.from(expected));
|
|
52
|
+
if (!valid)
|
|
53
|
+
throw coworkValidationError('continuation_invalid', 'continuation 签名校验失败');
|
|
54
|
+
let value;
|
|
55
|
+
try {
|
|
56
|
+
value = JSON.parse(Buffer.from(body, 'base64url').toString('utf8'));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw coworkValidationError('continuation_invalid', 'continuation 内容无法解析');
|
|
60
|
+
}
|
|
61
|
+
if (value.operation !== expectedOperation) {
|
|
62
|
+
throw coworkValidationError('continuation_mismatch', 'continuation 不属于当前操作');
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isSafeInteger(value.expiresAt) || value.expiresAt < Date.now()) {
|
|
65
|
+
throw coworkValidationError('continuation_expired', 'continuation 已过期');
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|