openyida 2026.5.20-beta.0 → 2026.5.20

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 CHANGED
@@ -297,6 +297,7 @@ For overseas apps, pass `--locale en_US` or `--locale ja_JP` on creation command
297
297
  | `openyida corp-efficiency [overview\|details\|detail\|groups\|notify] [options] [--open\|--no-open]` | Query enterprise efficiency metrics, detail report entries, and related notification actions |
298
298
  | `openyida create-app "<name>"\|--name <name> [options] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create an application and output `appType` |
299
299
  | `openyida update-app <appType> --name "..."` | Update application metadata |
300
+ | `openyida nav-group <list\|create\|rename\|delete\|move\|hide\|show> <appType> ...` | Manage sidebar navigation groups and move pages between groups |
300
301
  | `openyida app-permission <get\|set\|add\|remove\|search-user> ...` | Manage app primary admins, data admins, and developer members |
301
302
  | `openyida i18n <overview\|config\|languages\|list\|upsert\|delete\|translate\|translate-all\|upgrade> <appType> ...` | Manage app multilingual copy and language configuration |
302
303
  | `openyida export <appType> [output]` | Export an application migration package |
@@ -329,6 +330,7 @@ For overseas apps, pass `--locale en_US` or `--locale ja_JP` on creation command
329
330
  | `openyida data <action> <resource> [args]` | Unified data management for forms, processes, tasks, and subforms |
330
331
  | `openyida data check <appType> <formUuid> <rules.json>` | Detect anomalous process-form records |
331
332
  | `openyida task-center <type> [options]` | Query todo, created, processed, CC, or proxy-submitted tasks |
333
+ | `openyida agent-center <sub-command>` | Manage Yida process delegation and departure delegation |
332
334
  | `openyida basic-info <overview\|commodity\|grant\|capacity\|quota\|abs-path\|dataflow\|i18n\|domain>` | Query organization basic info, capacity, quotas, fixed-domain records, and domain settings |
333
335
  | `openyida get-permission <appType> <formUuid>` | Query form permission configuration |
334
336
  | `openyida save-permission <appType> <formUuid> [options]` | Save form permission configuration, including raw `--field-permission <json>` |
package/bin/yida.js CHANGED
@@ -705,6 +705,13 @@ async function main() {
705
705
  break;
706
706
  }
707
707
 
708
+ case 'nav-group':
709
+ case 'group': {
710
+ const { run: runNavGroup } = require('../lib/app/nav-group');
711
+ await runNavGroup(args);
712
+ break;
713
+ }
714
+
708
715
  case 'app-permission': {
709
716
  const { run: runAppPermission } = require('../lib/app-permission/app-permission');
710
717
  await runAppPermission(args);
@@ -919,6 +926,12 @@ async function main() {
919
926
  break;
920
927
  }
921
928
 
929
+ case 'agent-center': {
930
+ const { run: runAgentCenter } = require('../lib/agent-center/agent-center');
931
+ await runAgentCenter(args);
932
+ break;
933
+ }
934
+
922
935
  case 'flash-to-prd': {
923
936
  const { run: runFlashToPrd } = require('../lib/flash-note/flash-to-prd');
924
937
  await runFlashToPrd(args);
@@ -0,0 +1,261 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+
5
+ const {
6
+ listAgentTasks,
7
+ createAgentTask,
8
+ updateAgentTask,
9
+ cancelAgentTask,
10
+ isLeaderShip,
11
+ getLastDepartureAgent,
12
+ getAgentRange,
13
+ } = require('./api');
14
+ const { searchUsers } = require('../corp-manager/api');
15
+
16
+ const USAGE = `openyida agent-center - 代理中心
17
+
18
+ Usage:
19
+ openyida agent-center list [--status ALL|DIS|EFF|OUT|CANCEL] [--keyword TEXT] [--page N] [--size N]
20
+ openyida agent-center search-user <keyword> [--dept <text>] [--size N]
21
+ openyida agent-center create --source-user <userId> --target-user <userId> [--type normal|departure] [options]
22
+ openyida agent-center update <agentUuid> --target-user <userId> [--type normal|departure] [options]
23
+ openyida agent-center cancel <agentUuid> --type normal|departure
24
+ openyida agent-center range <agentUuid>
25
+ openyida agent-center is-leader
26
+ openyida agent-center last-departure
27
+
28
+ Create/update options for normal agents:
29
+ --start <time> 开始时间,例如 "2026-05-20 09:00" 或毫秒时间戳
30
+ --end <time> 结束时间,例如 "2026-05-21 18:00" 或毫秒时间戳
31
+ --category execute|start execute=代处理流程,start=代提交流程,默认 execute
32
+ --notify-source y|n 代理任务是否通知被代理人,默认 n
33
+ --range all|part 代理范围,默认 all
34
+ --range-form <appType:formUuid[,appType:formUuid]>
35
+ --range-json <json> 代理范围 JSON 数组,元素含 appType/formUuid
36
+ --range-file <file> 从 JSON 文件读取代理范围
37
+
38
+ Examples:
39
+ openyida agent-center list --status EFF --size 20
40
+ openyida agent-center search-user "余浩" --dept "宜搭,钉钉官方同学"
41
+ openyida agent-center create --source-user 111 --target-user 222 --start "2026-05-20 09:00" --end "2026-05-21 18:00"
42
+ openyida agent-center create --type departure --source-user 111 --target-user 222
43
+ openyida agent-center cancel Agent_xxx --type departure
44
+ `;
45
+
46
+ function fail(message) {
47
+ console.error(message);
48
+ console.error(USAGE);
49
+ process.exit(1);
50
+ }
51
+
52
+ function parseCliOptions(tokens) {
53
+ const positionals = [];
54
+ const options = {};
55
+
56
+ for (let i = 0; i < tokens.length; i += 1) {
57
+ const token = tokens[i];
58
+ if (token.startsWith('--')) {
59
+ const key = token.slice(2).replace(/-/g, '_');
60
+ const next = tokens[i + 1];
61
+ const value = next && !next.startsWith('--') ? next : true;
62
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
63
+ options[key] = Array.isArray(options[key]) ? options[key].concat(value) : [options[key], value];
64
+ } else {
65
+ options[key] = value;
66
+ }
67
+ if (value !== true) {
68
+ i += 1;
69
+ }
70
+ } else {
71
+ positionals.push(token);
72
+ }
73
+ }
74
+
75
+ return { positionals, options };
76
+ }
77
+
78
+ function splitList(value) {
79
+ if (!value) {
80
+ return [];
81
+ }
82
+ if (Array.isArray(value)) {
83
+ return value.flatMap(splitList);
84
+ }
85
+ return String(value).split(',').map(item => item.trim()).filter(Boolean);
86
+ }
87
+
88
+ function toPositiveInt(value, defaultValue) {
89
+ const parsed = Number.parseInt(value || `${defaultValue}`, 10);
90
+ if (!Number.isFinite(parsed) || parsed <= 0) {
91
+ return defaultValue;
92
+ }
93
+ return parsed;
94
+ }
95
+
96
+ function parseTimestamp(value, flagName) {
97
+ if (value === undefined || value === null || value === '') {
98
+ return undefined;
99
+ }
100
+ if (/^\d+$/.test(String(value))) {
101
+ return Number(value);
102
+ }
103
+ const normalized = String(value).trim().replace(/\//g, '-');
104
+ const parsed = Date.parse(normalized);
105
+ if (!Number.isFinite(parsed)) {
106
+ throw new Error(`${flagName} 不是有效时间:${value}`);
107
+ }
108
+ return parsed;
109
+ }
110
+
111
+ function parseRangeToken(token) {
112
+ const [appType, formUuid] = String(token).split(':').map(part => part && part.trim());
113
+ if (!appType || !formUuid) {
114
+ throw new Error(`代理范围格式必须是 appType:formUuid:${token}`);
115
+ }
116
+ return { appType, formUuid };
117
+ }
118
+
119
+ function parseRangeValue(options) {
120
+ if (options.range_file) {
121
+ return JSON.parse(fs.readFileSync(options.range_file, 'utf8'));
122
+ }
123
+ if (options.range_json) {
124
+ return JSON.parse(options.range_json);
125
+ }
126
+ const tokens = splitList(options.range_form || options.range_forms);
127
+ if (tokens.length > 0) {
128
+ return tokens.map(parseRangeToken);
129
+ }
130
+ return undefined;
131
+ }
132
+
133
+ function firstOption(options, keys) {
134
+ for (const key of keys) {
135
+ if (options[key] !== undefined) {
136
+ return options[key];
137
+ }
138
+ }
139
+ return undefined;
140
+ }
141
+
142
+ function buildMutationOptions(positionals, options) {
143
+ const typeFromPosition = ['normal', 'departure', 'depart', 'dismissed', 'NORMAL', 'DEPARTURE'].includes(positionals[0])
144
+ ? positionals.shift()
145
+ : undefined;
146
+ const rangeValue = parseRangeValue(options);
147
+ const rangeType = firstOption(options, ['range', 'agent_range_type', 'range_type']) || (rangeValue ? 'part' : undefined);
148
+ return {
149
+ type: firstOption(options, ['type', 'agent_type']) || typeFromPosition || 'normal',
150
+ sourceUserId: firstOption(options, ['source_user', 'source_user_id', 'from_user', 'source']),
151
+ targetUserId: firstOption(options, ['target_user', 'target_user_id', 'to_user', 'target']),
152
+ start: parseTimestamp(firstOption(options, ['start', 'gmt_start_date']), '--start'),
153
+ end: parseTimestamp(firstOption(options, ['end', 'gmt_end_date']), '--end'),
154
+ category: firstOption(options, ['category', 'agent_category']),
155
+ notifySource: firstOption(options, ['notify_source', 'origin_is_view']),
156
+ rangeType,
157
+ rangeValue,
158
+ };
159
+ }
160
+
161
+ function printJson(payload) {
162
+ console.log(JSON.stringify(payload, null, 2));
163
+ }
164
+
165
+ async function runList(options) {
166
+ printJson(await listAgentTasks({
167
+ status: options.status,
168
+ keyword: options.keyword || options.keywords,
169
+ page: toPositiveInt(options.page || options.page_index, 1),
170
+ size: toPositiveInt(options.size || options.page_size, 10),
171
+ }));
172
+ }
173
+
174
+ async function runSearchUser(positionals, options) {
175
+ const keyword = positionals[0];
176
+ if (!keyword) {
177
+ fail('缺少搜索关键词');
178
+ }
179
+ printJson(await searchUsers({
180
+ keyword,
181
+ dept: options.dept || options.department,
182
+ size: toPositiveInt(options.size, 50),
183
+ }));
184
+ }
185
+
186
+ async function runCreate(positionals, options) {
187
+ const mutation = buildMutationOptions(positionals, options);
188
+ printJson(await createAgentTask(mutation));
189
+ }
190
+
191
+ async function runUpdate(positionals, options) {
192
+ const agentUuid = positionals.shift();
193
+ if (!agentUuid) {
194
+ fail('缺少 agentUuid');
195
+ }
196
+ const mutation = buildMutationOptions(positionals, options);
197
+ printJson(await updateAgentTask({
198
+ ...mutation,
199
+ agentUuid,
200
+ }));
201
+ }
202
+
203
+ async function runCancel(positionals, options) {
204
+ const agentUuid = positionals[0];
205
+ if (!agentUuid) {
206
+ fail('缺少 agentUuid');
207
+ }
208
+ printJson(await cancelAgentTask({
209
+ agentUuid,
210
+ type: options.type || options.agent_type || positionals[1] || 'normal',
211
+ }));
212
+ }
213
+
214
+ async function runRange(positionals) {
215
+ const agentUuid = positionals[0];
216
+ if (!agentUuid) {
217
+ fail('缺少 agentUuid');
218
+ }
219
+ printJson(await getAgentRange({ agentUuid }));
220
+ }
221
+
222
+ async function run(args) {
223
+ const { positionals, options } = parseCliOptions(args);
224
+ const action = positionals.shift();
225
+
226
+ if (!action || action === '--help' || action === '-h') {
227
+ console.log(USAGE);
228
+ return;
229
+ }
230
+
231
+ if (action === 'list') {
232
+ await runList(options);
233
+ } else if (action === 'search-user') {
234
+ await runSearchUser(positionals, options);
235
+ } else if (action === 'create') {
236
+ await runCreate(positionals, options);
237
+ } else if (action === 'update') {
238
+ await runUpdate(positionals, options);
239
+ } else if (action === 'cancel' || action === 'revoke') {
240
+ await runCancel(positionals, options);
241
+ } else if (action === 'range') {
242
+ await runRange(positionals);
243
+ } else if (action === 'is-leader') {
244
+ printJson(await isLeaderShip());
245
+ } else if (action === 'last-departure') {
246
+ printJson(await getLastDepartureAgent());
247
+ } else {
248
+ fail(`未知 agent-center 子命令:${action}`);
249
+ }
250
+ }
251
+
252
+ module.exports = {
253
+ USAGE,
254
+ parseCliOptions,
255
+ splitList,
256
+ parseTimestamp,
257
+ parseRangeToken,
258
+ parseRangeValue,
259
+ buildMutationOptions,
260
+ run,
261
+ };