openyida 2026.5.13 → 2026.5.15
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 +4 -1
- package/bin/yida.js +66 -22
- package/lib/auth/qr-login.js +23 -11
- package/lib/core/command-manifest.js +6 -2
- package/lib/core/env-cmd.js +171 -18
- package/lib/core/env-manager.js +78 -1
- package/lib/core/locales/ar.js +39 -0
- package/lib/core/locales/de.js +39 -0
- package/lib/core/locales/en.js +41 -1
- package/lib/core/locales/es.js +39 -0
- package/lib/core/locales/fr.js +39 -0
- package/lib/core/locales/hi.js +39 -0
- package/lib/core/locales/ja.js +39 -0
- package/lib/core/locales/ko.js +39 -0
- package/lib/core/locales/pt.js +39 -0
- package/lib/core/locales/vi.js +39 -0
- package/lib/core/locales/zh-HK.js +39 -0
- package/lib/core/locales/zh.js +41 -1
- package/lib/core/utils.js +8 -4
- package/lib/corp-efficiency/corp-efficiency.js +672 -0
- package/lib/integration/integration-api.js +149 -2
- package/lib/integration/integration-check.js +703 -0
- package/package.json +1 -1
- package/scripts/e2e-real/skill-coverage.js +2 -0
- package/yida-skills/SKILL.md +2 -0
- package/yida-skills/skills/sls-log-workbench/SKILL.md +637 -0
- package/yida-skills/skills/sls-log-workbench/sls-query.js +322 -0
- package/yida-skills/skills/yida-corp-efficiency/SKILL.md +100 -0
- package/yida-skills/skills/yida-integration/SKILL.md +14 -0
- package/yida-skills/skills/yida-integration/references/integration-node-schemas.md +21 -1
package/README.md
CHANGED
|
@@ -167,6 +167,7 @@ openyida/
|
|
|
167
167
|
openyida create-app "CRM"
|
|
168
168
|
openyida create-app --name "CRM" --desc "Customer management" --theme deepBlue
|
|
169
169
|
openyida app-list --size 20
|
|
170
|
+
openyida corp-efficiency
|
|
170
171
|
openyida create-form create APP_XXX "Customer" .cache/openyida/forms/customer-fields.json
|
|
171
172
|
openyida create-form update APP_XXX FORM_XXX .cache/openyida/forms/customer-changes.json
|
|
172
173
|
openyida get-schema APP_XXX FORM_XXX
|
|
@@ -254,9 +255,10 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
254
255
|
| Command | Description |
|
|
255
256
|
|---------|-------------|
|
|
256
257
|
| `openyida env [--json]` | Detect the active AI tool environment and login state |
|
|
258
|
+
| `openyida env setup` | Choose a customer-friendly login environment preset: public, overseas, Alibaba intranet, or private deployment |
|
|
257
259
|
| `openyida env <list\|show\|switch\|add\|remove>` | Manage public/private Yida environment profiles |
|
|
258
260
|
| `openyida commands [--json]` | Emit the machine-readable command manifest |
|
|
259
|
-
| `openyida login [--qr\|--agent-qr\|--codex\|--browser] [--corp-id <corpId>]` | Log in to Yida |
|
|
261
|
+
| `openyida login [--qr\|--agent-qr\|--codex\|--browser] [--env <name>\|--overseas] [--corp-id <corpId>]` | Log in to Yida |
|
|
260
262
|
| `openyida logout` | Log out or switch account |
|
|
261
263
|
| `openyida auth <status\|login\|refresh\|logout>` | Manage login status |
|
|
262
264
|
| `openyida org list` | List accessible organizations |
|
|
@@ -267,6 +269,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
267
269
|
| Command | Description |
|
|
268
270
|
|---------|-------------|
|
|
269
271
|
| `openyida app-list [--size N]` | List Yida applications |
|
|
272
|
+
| `openyida corp-efficiency [overview\|details\|detail\|groups\|notify] [options] [--open\|--no-open]` | Query enterprise efficiency metrics, detail report entries, and related notification actions |
|
|
270
273
|
| `openyida create-app "<name>"\|--name <name> [options] [--open\|--no-open]` | Create an application and output `appType` |
|
|
271
274
|
| `openyida update-app <appType> --name "..."` | Update application metadata |
|
|
272
275
|
| `openyida export <appType> [output]` | Export an application migration package |
|
package/bin/yida.js
CHANGED
|
@@ -284,6 +284,39 @@ function getArgValue(cliArgs, name) {
|
|
|
284
284
|
return cliArgs[index + 1];
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
function applyLoginEnvironmentFlags(cliArgs) {
|
|
288
|
+
const envFlagMap = {
|
|
289
|
+
'--public': 'public',
|
|
290
|
+
'--intl': 'intl',
|
|
291
|
+
'--overseas': 'intl',
|
|
292
|
+
'--international': 'intl',
|
|
293
|
+
'--global': 'intl',
|
|
294
|
+
'--alibaba': 'alibaba',
|
|
295
|
+
'--internal': 'alibaba',
|
|
296
|
+
'--intranet': 'alibaba',
|
|
297
|
+
};
|
|
298
|
+
const filteredArgs = [];
|
|
299
|
+
|
|
300
|
+
for (let index = 0; index < cliArgs.length; index++) {
|
|
301
|
+
const arg = cliArgs[index];
|
|
302
|
+
if (arg === '--env') {
|
|
303
|
+
const envName = cliArgs[index + 1];
|
|
304
|
+
if (envName && !envName.startsWith('--')) {
|
|
305
|
+
process.env.OPENYIDA_ENV = envName;
|
|
306
|
+
index++;
|
|
307
|
+
}
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (envFlagMap[arg]) {
|
|
311
|
+
process.env.OPENYIDA_ENV = envFlagMap[arg];
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
filteredArgs.push(arg);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return filteredArgs;
|
|
318
|
+
}
|
|
319
|
+
|
|
287
320
|
// 解析全局 --quiet 开关:从 args 中剔除并设置 YIDA_QUIET=1,让 chalk.js
|
|
288
321
|
// 的所有装饰输出(banner/step/info/...)变 no-op,AI 即可直接 `... --quiet | jq`。
|
|
289
322
|
function applyQuietFlag() {
|
|
@@ -352,40 +385,41 @@ async function main() {
|
|
|
352
385
|
|
|
353
386
|
case 'login': {
|
|
354
387
|
const { checkLoginOnly } = require('../lib/auth/login');
|
|
355
|
-
|
|
356
|
-
|
|
388
|
+
const loginArgs = applyLoginEnvironmentFlags(args);
|
|
389
|
+
if (loginArgs.includes('--agent-poll') || loginArgs.includes('--codex-poll')) {
|
|
390
|
+
const sessionFile = getArgValue(loginArgs, '--agent-poll') || getArgValue(loginArgs, '--codex-poll');
|
|
357
391
|
const { pollCodexQrLogin } = require('../lib/auth/qr-login');
|
|
358
392
|
const result = await pollCodexQrLogin(sessionFile, {
|
|
359
|
-
corpId: getArgValue(
|
|
393
|
+
corpId: getArgValue(loginArgs, '--corp-id'),
|
|
360
394
|
});
|
|
361
395
|
printLoginResult(result);
|
|
362
|
-
} else if (
|
|
363
|
-
const sessionFile = getArgValue(
|
|
396
|
+
} else if (loginArgs.includes('--agent-select') || loginArgs.includes('--codex-select')) {
|
|
397
|
+
const sessionFile = getArgValue(loginArgs, '--agent-select') || getArgValue(loginArgs, '--codex-select');
|
|
364
398
|
const { selectCodexQrCorp } = require('../lib/auth/qr-login');
|
|
365
399
|
const result = await selectCodexQrCorp(sessionFile, {
|
|
366
|
-
corpId: getArgValue(
|
|
400
|
+
corpId: getArgValue(loginArgs, '--corp-id'),
|
|
367
401
|
});
|
|
368
402
|
printLoginResult(result);
|
|
369
|
-
} else if (
|
|
370
|
-
const result = checkLoginOnly({ includeSecrets:
|
|
403
|
+
} else if (loginArgs[0] === '--check-only') {
|
|
404
|
+
const result = checkLoginOnly({ includeSecrets: loginArgs.includes('--with-cookies') });
|
|
371
405
|
console.log(JSON.stringify(result, null, 2));
|
|
372
|
-
} else if (shouldUseCodexQrLogin(
|
|
406
|
+
} else if (shouldUseCodexQrLogin(loginArgs)) {
|
|
373
407
|
const { startCodexQrLogin } = require('../lib/auth/qr-login');
|
|
374
|
-
const result = await startCodexQrLogin({ corpId: getArgValue(
|
|
408
|
+
const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
375
409
|
printLoginResult(result);
|
|
376
|
-
} else if (
|
|
410
|
+
} else if (loginArgs.includes('--browser')) {
|
|
377
411
|
const { interactiveLogin } = require('../lib/auth/login');
|
|
378
412
|
const result = interactiveLogin({ force: true });
|
|
379
413
|
printLoginResult(result);
|
|
380
|
-
} else if (
|
|
414
|
+
} else if (loginArgs.includes('--qoder') || loginArgs.includes('--wukong')) {
|
|
381
415
|
const { codexLogin } = require('../lib/auth/codex-login');
|
|
382
|
-
const result = await codexLogin({ tool:
|
|
416
|
+
const result = await codexLogin({ tool: loginArgs.includes('--qoder') ? 'qoder' : 'wukong' });
|
|
383
417
|
printLoginResult(result);
|
|
384
|
-
} else if (
|
|
418
|
+
} else if (loginArgs.includes('--qr')) {
|
|
385
419
|
const { qrLogin } = require('../lib/auth/qr-login');
|
|
386
|
-
const result = await qrLogin({ corpId: getArgValue(
|
|
420
|
+
const result = await qrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
387
421
|
console.log(JSON.stringify(result));
|
|
388
|
-
} else if (shouldUseAgentLogin(
|
|
422
|
+
} else if (shouldUseAgentLogin(loginArgs)) {
|
|
389
423
|
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
390
424
|
if (cachedResult.status === 'ok') {
|
|
391
425
|
printLoginResult(cachedResult);
|
|
@@ -398,17 +432,17 @@ async function main() {
|
|
|
398
432
|
printLoginResult(browserResult);
|
|
399
433
|
} else {
|
|
400
434
|
const { startCodexQrLogin } = require('../lib/auth/qr-login');
|
|
401
|
-
const result = await startCodexQrLogin({ corpId: getArgValue(
|
|
435
|
+
const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
402
436
|
printLoginResult(result);
|
|
403
437
|
}
|
|
404
438
|
}
|
|
405
|
-
} else if (shouldUseBrowserHandoffLogin(
|
|
439
|
+
} else if (shouldUseBrowserHandoffLogin(loginArgs)) {
|
|
406
440
|
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
407
441
|
if (cachedResult.status === 'ok') {
|
|
408
442
|
printLoginResult(cachedResult);
|
|
409
443
|
} else {
|
|
410
444
|
const { codexLogin } = require('../lib/auth/codex-login');
|
|
411
|
-
const result = await codexLogin({ tool:
|
|
445
|
+
const result = await codexLogin({ tool: loginArgs.includes('--codex') ? 'codex' : undefined });
|
|
412
446
|
printLoginResult(result);
|
|
413
447
|
}
|
|
414
448
|
} else {
|
|
@@ -418,7 +452,7 @@ async function main() {
|
|
|
418
452
|
break;
|
|
419
453
|
}
|
|
420
454
|
const { qrLogin } = require('../lib/auth/qr-login');
|
|
421
|
-
const result = await qrLogin({ corpId: getArgValue(
|
|
455
|
+
const result = await qrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
422
456
|
console.log(JSON.stringify(result));
|
|
423
457
|
}
|
|
424
458
|
break;
|
|
@@ -437,8 +471,9 @@ async function main() {
|
|
|
437
471
|
if (subCommand === 'status') {
|
|
438
472
|
authStatus();
|
|
439
473
|
} else if (subCommand === 'login') {
|
|
440
|
-
const
|
|
441
|
-
|
|
474
|
+
const authArgs = [subCommand, ...applyLoginEnvironmentFlags(args.slice(1))];
|
|
475
|
+
const loginType = shouldUseBrowserHandoffLogin(authArgs) ? 'browser' : 'qrcode';
|
|
476
|
+
await authLogin({ type: loginType, corpId: getArgValue(authArgs, '--corp-id') });
|
|
442
477
|
} else if (subCommand === 'refresh') {
|
|
443
478
|
authRefresh();
|
|
444
479
|
} else if (subCommand === 'logout') {
|
|
@@ -493,6 +528,12 @@ async function main() {
|
|
|
493
528
|
break;
|
|
494
529
|
}
|
|
495
530
|
|
|
531
|
+
case 'corp-efficiency': {
|
|
532
|
+
const { run } = require('../lib/corp-efficiency/corp-efficiency');
|
|
533
|
+
await run(args);
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
|
|
496
537
|
case 'create-app': {
|
|
497
538
|
const { run } = require('../lib/app/create-app');
|
|
498
539
|
await run(args);
|
|
@@ -879,6 +920,9 @@ async function main() {
|
|
|
879
920
|
} else if (subCommand === 'disable') {
|
|
880
921
|
const { runDisable } = require('../lib/integration/integration-list');
|
|
881
922
|
await runDisable(subArgs);
|
|
923
|
+
} else if (subCommand === 'check') {
|
|
924
|
+
const { run: runIntegrationCheck } = require('../lib/integration/integration-check');
|
|
925
|
+
await runIntegrationCheck(subArgs);
|
|
882
926
|
} else {
|
|
883
927
|
warn(t('cli.integration_unknown', subCommand));
|
|
884
928
|
warn(t('cli.integration_help_hint'));
|
package/lib/auth/qr-login.js
CHANGED
|
@@ -24,7 +24,7 @@ const { saveCookieCache } = require('./login');
|
|
|
24
24
|
const { t } = require('../core/i18n');
|
|
25
25
|
const { warn } = require('../core/chalk');
|
|
26
26
|
|
|
27
|
-
const { resolveLoginUrl, resolveEndpoint, deriveBaseUrlFromUrl } = require('../core/env-manager');
|
|
27
|
+
const { resolveLoginUrl, resolveEndpoint, deriveBaseUrlFromUrl, getCurrentEnvConfig } = require('../core/env-manager');
|
|
28
28
|
|
|
29
29
|
function shellQuote(value) {
|
|
30
30
|
return `'${String(value).replace(/'/g, "'\\''")}'`;
|
|
@@ -34,9 +34,11 @@ function getTargetCorpId(options = {}, session = {}) {
|
|
|
34
34
|
return options.corpId || options.targetCorpId || session.targetCorpId || null;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
function buildCodexPollCommand(sessionFile, targetCorpId) {
|
|
37
|
+
function buildCodexPollCommand(sessionFile, targetCorpId, envName) {
|
|
38
38
|
const baseCommand = `openyida login --agent-poll ${shellQuote(sessionFile)}`;
|
|
39
|
-
|
|
39
|
+
const envArg = envName ? ` --env ${shellQuote(envName)}` : '';
|
|
40
|
+
const corpArg = targetCorpId ? ` --corp-id ${shellQuote(targetCorpId)}` : '';
|
|
41
|
+
return `${baseCommand}${envArg}${corpArg}`;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
function buildQrImageMarkdown(qrImageFile) {
|
|
@@ -55,7 +57,7 @@ function buildAgentQrResponseMarkdown(result) {
|
|
|
55
57
|
return lines.join('\n');
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
function buildNeedQrScanResult({ qrUrl, qrImageFile, sessionFile, targetCorpId }) {
|
|
60
|
+
function buildNeedQrScanResult({ qrUrl, qrImageFile, sessionFile, targetCorpId, envName }) {
|
|
59
61
|
const qrImageMarkdown = buildQrImageMarkdown(qrImageFile);
|
|
60
62
|
const result = {
|
|
61
63
|
status: 'need_qr_scan',
|
|
@@ -65,7 +67,7 @@ function buildNeedQrScanResult({ qrUrl, qrImageFile, sessionFile, targetCorpId }
|
|
|
65
67
|
qr_image_file: qrImageFile || null,
|
|
66
68
|
qr_image_markdown: qrImageMarkdown,
|
|
67
69
|
session_file: sessionFile,
|
|
68
|
-
poll_command: buildCodexPollCommand(sessionFile, targetCorpId),
|
|
70
|
+
poll_command: buildCodexPollCommand(sessionFile, targetCorpId, envName),
|
|
69
71
|
message: 'Scan the QR code with DingTalk, then run poll_command.',
|
|
70
72
|
};
|
|
71
73
|
result.agent_response_markdown = buildAgentQrResponseMarkdown(result);
|
|
@@ -366,8 +368,9 @@ async function writeQrCodeImage(url, filePath, options = {}) {
|
|
|
366
368
|
function isDingtalkOAuthChallengeUrl(url) {
|
|
367
369
|
try {
|
|
368
370
|
const parsedUrl = new URL(url);
|
|
369
|
-
|
|
370
|
-
|
|
371
|
+
const hostname = parsedUrl.hostname;
|
|
372
|
+
const isDingtalkDomain = hostname.endsWith('dingtalk.com') || hostname.endsWith('dingtalk.io');
|
|
373
|
+
return isDingtalkDomain && parsedUrl.pathname.startsWith('/oauth2/');
|
|
371
374
|
} catch {
|
|
372
375
|
return false;
|
|
373
376
|
}
|
|
@@ -1012,7 +1015,8 @@ function buildCodexCorpInteraction(corpList) {
|
|
|
1012
1015
|
};
|
|
1013
1016
|
}
|
|
1014
1017
|
|
|
1015
|
-
function buildNeedCorpSelectionResult(sessionFile, corpList) {
|
|
1018
|
+
function buildNeedCorpSelectionResult(sessionFile, corpList, envName) {
|
|
1019
|
+
const envArg = envName ? ` --env ${shellQuote(envName)}` : '';
|
|
1016
1020
|
return {
|
|
1017
1021
|
status: 'need_corp_selection',
|
|
1018
1022
|
handoff_type: 'codex_native_select',
|
|
@@ -1024,7 +1028,7 @@ function buildNeedCorpSelectionResult(sessionFile, corpList) {
|
|
|
1024
1028
|
main_org: !!corp.mainOrg,
|
|
1025
1029
|
})),
|
|
1026
1030
|
interaction: buildCodexCorpInteraction(corpList),
|
|
1027
|
-
select_command_template: `openyida login --codex-select ${shellQuote(sessionFile)} --corp-id <corpId>`,
|
|
1031
|
+
select_command_template: `openyida login --codex-select ${shellQuote(sessionFile)}${envArg} --corp-id <corpId>`,
|
|
1028
1032
|
};
|
|
1029
1033
|
}
|
|
1030
1034
|
|
|
@@ -1086,7 +1090,7 @@ async function maybeReturnCorpSelectionAfterExchange(session, sessionFile, optio
|
|
|
1086
1090
|
stage: 'pending_corp_switch',
|
|
1087
1091
|
updatedAt: new Date().toISOString(),
|
|
1088
1092
|
});
|
|
1089
|
-
return buildNeedCorpSelectionResult(sessionFile, corpList);
|
|
1093
|
+
return buildNeedCorpSelectionResult(sessionFile, corpList, session.currentEnvName);
|
|
1090
1094
|
}
|
|
1091
1095
|
|
|
1092
1096
|
if (!selectedCorp && corpList.length === 1) {
|
|
@@ -1100,6 +1104,7 @@ function buildFakeCodexQrLoginResult(options = {}) {
|
|
|
1100
1104
|
const sessionId = 'test-session';
|
|
1101
1105
|
const { sessionFile, qrImageFile } = getCodexQrSessionPaths(sessionId);
|
|
1102
1106
|
const targetCorpId = getTargetCorpId(options);
|
|
1107
|
+
const currentEnvName = getCurrentEnvConfig().name;
|
|
1103
1108
|
saveCodexQrSession(sessionFile, {
|
|
1104
1109
|
schema_version: 1,
|
|
1105
1110
|
mode: 'codex_qr_login',
|
|
@@ -1110,6 +1115,7 @@ function buildFakeCodexQrLoginResult(options = {}) {
|
|
|
1110
1115
|
cookieHeader: '',
|
|
1111
1116
|
context: { type: 'legacy' },
|
|
1112
1117
|
targetCorpId,
|
|
1118
|
+
currentEnvName,
|
|
1113
1119
|
createdAt: new Date().toISOString(),
|
|
1114
1120
|
});
|
|
1115
1121
|
|
|
@@ -1118,6 +1124,7 @@ function buildFakeCodexQrLoginResult(options = {}) {
|
|
|
1118
1124
|
qrImageFile,
|
|
1119
1125
|
sessionFile,
|
|
1120
1126
|
targetCorpId,
|
|
1127
|
+
envName: currentEnvName,
|
|
1121
1128
|
});
|
|
1122
1129
|
}
|
|
1123
1130
|
|
|
@@ -1128,6 +1135,7 @@ async function startCodexQrLogin(options = {}) {
|
|
|
1128
1135
|
|
|
1129
1136
|
const baseUrl = (options.baseUrl || resolveEndpoint(null)).replace(/\/+$/, '');
|
|
1130
1137
|
const targetCorpId = getTargetCorpId(options);
|
|
1138
|
+
const currentEnvName = getCurrentEnvConfig().name;
|
|
1131
1139
|
const sessionId = options.sessionId || createCodexQrSessionId();
|
|
1132
1140
|
const { sessionFile, qrImageFile } = getCodexQrSessionPaths(sessionId);
|
|
1133
1141
|
|
|
@@ -1157,6 +1165,7 @@ async function startCodexQrLogin(options = {}) {
|
|
|
1157
1165
|
cookieHeader,
|
|
1158
1166
|
context,
|
|
1159
1167
|
targetCorpId,
|
|
1168
|
+
currentEnvName,
|
|
1160
1169
|
createdAt: new Date().toISOString(),
|
|
1161
1170
|
});
|
|
1162
1171
|
|
|
@@ -1165,6 +1174,7 @@ async function startCodexQrLogin(options = {}) {
|
|
|
1165
1174
|
qrImageFile: imageWritten ? qrImageFile : null,
|
|
1166
1175
|
sessionFile,
|
|
1167
1176
|
targetCorpId,
|
|
1177
|
+
envName: currentEnvName,
|
|
1168
1178
|
});
|
|
1169
1179
|
}
|
|
1170
1180
|
|
|
@@ -1199,9 +1209,10 @@ async function pollCodexQrLogin(sessionFile, options = {}) {
|
|
|
1199
1209
|
corpList,
|
|
1200
1210
|
stage: 'pending_dingtalk_oauth_org',
|
|
1201
1211
|
targetCorpId,
|
|
1212
|
+
currentEnvName: session.currentEnvName,
|
|
1202
1213
|
updatedAt: new Date().toISOString(),
|
|
1203
1214
|
});
|
|
1204
|
-
return buildNeedCorpSelectionResult(sessionFile, corpList);
|
|
1215
|
+
return buildNeedCorpSelectionResult(sessionFile, corpList, session.currentEnvName);
|
|
1205
1216
|
}
|
|
1206
1217
|
}
|
|
1207
1218
|
|
|
@@ -1436,5 +1447,6 @@ module.exports = {
|
|
|
1436
1447
|
buildNeedQrScanResult,
|
|
1437
1448
|
getTargetCorpId,
|
|
1438
1449
|
deriveAliworkBaseUrl,
|
|
1450
|
+
isDingtalkOAuthChallengeUrl,
|
|
1439
1451
|
},
|
|
1440
1452
|
};
|
|
@@ -20,7 +20,7 @@ const COMMAND_GROUPS = [
|
|
|
20
20
|
id: 'auth',
|
|
21
21
|
titleKey: 'help.group_auth',
|
|
22
22
|
commands: [
|
|
23
|
-
command('login', ['login'], 'login [--qr|--agent-qr|--codex|--browser] [--corp-id <corpId>]', 'help.cmd_login', {
|
|
23
|
+
command('login', ['login'], 'login [--qr|--agent-qr|--codex|--browser] [--env <name>|--overseas] [--corp-id <corpId>]', 'help.cmd_login', {
|
|
24
24
|
requiresLogin: false,
|
|
25
25
|
output: 'json',
|
|
26
26
|
}),
|
|
@@ -31,7 +31,7 @@ const COMMAND_GROUPS = [
|
|
|
31
31
|
requiresLogin: false,
|
|
32
32
|
output: 'text|json',
|
|
33
33
|
}),
|
|
34
|
-
command('env-management', ['env'], 'env <list|show|switch|add|remove>', 'help.cmd_env_management', {
|
|
34
|
+
command('env-management', ['env'], 'env <setup|list|show|switch|add|remove>', 'help.cmd_env_management', {
|
|
35
35
|
requiresLogin: false,
|
|
36
36
|
}),
|
|
37
37
|
],
|
|
@@ -41,6 +41,9 @@ const COMMAND_GROUPS = [
|
|
|
41
41
|
titleKey: 'help.group_app',
|
|
42
42
|
commands: [
|
|
43
43
|
command('app-list', ['app-list'], 'app-list [--size N]', 'help.cmd_app_list'),
|
|
44
|
+
command('corp-efficiency', ['corp-efficiency'], 'corp-efficiency [overview|details|detail|groups|notify] [options] [--open|--no-open]', 'help.cmd_corp_efficiency', {
|
|
45
|
+
output: 'json',
|
|
46
|
+
}),
|
|
44
47
|
command('create-app', ['create-app'], 'create-app "<name>"|--name <name> [options] [--open|--no-open]', 'help.cmd_create_app'),
|
|
45
48
|
command('update-app', ['update-app'], 'update-app <appType> --name "..."', 'help.cmd_update_app'),
|
|
46
49
|
command('export', ['export'], 'export <appType> [output]', 'help.cmd_export'),
|
|
@@ -128,6 +131,7 @@ const COMMAND_GROUPS = [
|
|
|
128
131
|
titleKey: 'help.group_integration',
|
|
129
132
|
commands: [
|
|
130
133
|
command('integration.create', ['integration', 'create'], 'integration create <appType> ...', 'help.cmd_integration'),
|
|
134
|
+
command('integration.check', ['integration', 'check'], 'integration check <appType...>', 'help.cmd_integration_check'),
|
|
131
135
|
command('dws', ['dws'], 'dws <command> [args]', 'help.cmd_dws'),
|
|
132
136
|
command('dingtalk-link', ['dingtalk-link'], 'dingtalk-link <url> [--target fullScreen] [--legacy-scheme] [--json]', 'help.cmd_dingtalk_link', {
|
|
133
137
|
requiresLogin: false,
|
package/lib/core/env-cmd.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
+
const { execSync } = require('child_process');
|
|
14
15
|
const readline = require('readline');
|
|
15
16
|
const { warn } = require('./chalk');
|
|
16
17
|
const {
|
|
@@ -18,6 +19,10 @@ const {
|
|
|
18
19
|
saveEnvsConfig,
|
|
19
20
|
DEFAULT_BASE_URL,
|
|
20
21
|
DEFAULT_LOGIN_URL,
|
|
22
|
+
DEFAULT_PUBLIC_ENV,
|
|
23
|
+
DEFAULT_INTERNATIONAL_ENV,
|
|
24
|
+
DEFAULT_ALIBABA_INTERNAL_ENV,
|
|
25
|
+
resolveEnvNameAlias,
|
|
21
26
|
} = require('./env-manager');
|
|
22
27
|
|
|
23
28
|
// ── 颜色常量 ──────────────────────────────────────────
|
|
@@ -67,6 +72,79 @@ function formatEnvLabel(envName, currentEnv) {
|
|
|
67
72
|
return `${CYAN}${envName}${RESET}`;
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
function getLoginHost(loginUrl) {
|
|
76
|
+
try {
|
|
77
|
+
return new URL(loginUrl || DEFAULT_LOGIN_URL).hostname;
|
|
78
|
+
} catch {
|
|
79
|
+
return loginUrl || DEFAULT_LOGIN_URL;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isBuiltinEnvName(envName) {
|
|
84
|
+
return ['public', 'intl', 'alibaba'].includes(envName);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function isDingTalkWukongRunning() {
|
|
88
|
+
if (process.platform !== 'darwin') {return false;}
|
|
89
|
+
try {
|
|
90
|
+
return execSync('ps -axo args', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })
|
|
91
|
+
.includes('/Applications/DingTalkWuKong.app/');
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function detectSetupRecommendation() {
|
|
98
|
+
if (process.env.OPENYIDA_ENV) {
|
|
99
|
+
return resolveEnvNameAlias(process.env.OPENYIDA_ENV);
|
|
100
|
+
}
|
|
101
|
+
if ((process.env.OPENYIDA_LOGIN_URL || '').includes('login.dingtalk.io')) {
|
|
102
|
+
return 'intl';
|
|
103
|
+
}
|
|
104
|
+
if ((process.env.OPENYIDA_ENDPOINT || '').includes('alibaba-inc.com')) {
|
|
105
|
+
return 'alibaba';
|
|
106
|
+
}
|
|
107
|
+
if (isDingTalkWukongRunning()) {
|
|
108
|
+
return 'intl';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let activeTool = null;
|
|
112
|
+
try {
|
|
113
|
+
activeTool = require('./utils').detectActiveTool();
|
|
114
|
+
} catch {
|
|
115
|
+
activeTool = null;
|
|
116
|
+
}
|
|
117
|
+
if (activeTool && activeTool.tool === 'wukong') {
|
|
118
|
+
return 'intl';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return 'public';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function switchToEnv(envName) {
|
|
125
|
+
const resolvedEnvName = resolveEnvNameAlias(envName);
|
|
126
|
+
const config = loadEnvsConfig();
|
|
127
|
+
|
|
128
|
+
if (!config.environments[resolvedEnvName]) {
|
|
129
|
+
warn(`${RED}错误:环境 "${envName}" 不存在${RESET}`);
|
|
130
|
+
warn(`使用 ${CYAN}openyida env list${RESET} 查看所有环境`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const previousEnv = config.current;
|
|
135
|
+
config.current = resolvedEnvName;
|
|
136
|
+
saveEnvsConfig(config);
|
|
137
|
+
|
|
138
|
+
console.log('');
|
|
139
|
+
console.log(`${GREEN}✅ 已切换环境${RESET}`);
|
|
140
|
+
console.log(` ${DIM}${previousEnv}${RESET} → ${GREEN}${BOLD}${resolvedEnvName}${RESET}`);
|
|
141
|
+
console.log(` 地址:${config.environments[resolvedEnvName].baseUrl}`);
|
|
142
|
+
console.log(` 登录:${getLoginHost(config.environments[resolvedEnvName].loginUrl)}`);
|
|
143
|
+
console.log('');
|
|
144
|
+
console.log(`${DIM}下一步:运行 openyida login;在悟空中可运行 openyida login --wukong${RESET}`);
|
|
145
|
+
console.log('');
|
|
146
|
+
}
|
|
147
|
+
|
|
70
148
|
// ── 子命令实现 ────────────────────────────────────────
|
|
71
149
|
|
|
72
150
|
/**
|
|
@@ -88,6 +166,7 @@ function cmdList() {
|
|
|
88
166
|
const label = formatEnvLabel(envName, config.current);
|
|
89
167
|
console.log(` ${label}`);
|
|
90
168
|
console.log(` ${DIM}地址:${RESET}${envConfig.baseUrl || DEFAULT_BASE_URL}`);
|
|
169
|
+
console.log(` ${DIM}登录:${RESET}${getLoginHost(envConfig.loginUrl || DEFAULT_LOGIN_URL)}`);
|
|
91
170
|
if (envConfig.description) {
|
|
92
171
|
console.log(` ${DIM}描述:${RESET}${envConfig.description}`);
|
|
93
172
|
}
|
|
@@ -95,7 +174,7 @@ function cmdList() {
|
|
|
95
174
|
}
|
|
96
175
|
|
|
97
176
|
console.log('');
|
|
98
|
-
console.log(`${DIM}使用 openyida env switch <name> 切换环境${RESET}`);
|
|
177
|
+
console.log(`${DIM}使用 openyida env setup 进入向导,或 openyida env switch <name> 切换环境${RESET}`);
|
|
99
178
|
console.log(`${DIM}使用 openyida env add <name> 添加私有化环境${RESET}`);
|
|
100
179
|
console.log('');
|
|
101
180
|
}
|
|
@@ -106,7 +185,7 @@ function cmdList() {
|
|
|
106
185
|
*/
|
|
107
186
|
function cmdShow(envName) {
|
|
108
187
|
const config = loadEnvsConfig();
|
|
109
|
-
const targetName = envName || config.current;
|
|
188
|
+
const targetName = resolveEnvNameAlias(envName || config.current);
|
|
110
189
|
const envConfig = config.environments[targetName];
|
|
111
190
|
|
|
112
191
|
if (!envConfig) {
|
|
@@ -146,30 +225,21 @@ function cmdSwitch(envName) {
|
|
|
146
225
|
process.exit(1);
|
|
147
226
|
}
|
|
148
227
|
|
|
228
|
+
const resolvedEnvName = resolveEnvNameAlias(envName);
|
|
149
229
|
const config = loadEnvsConfig();
|
|
150
230
|
|
|
151
|
-
if (!config.environments[
|
|
231
|
+
if (!config.environments[resolvedEnvName]) {
|
|
152
232
|
warn(`${RED}错误:环境 "${envName}" 不存在${RESET}`);
|
|
153
233
|
warn(`使用 ${CYAN}openyida env list${RESET} 查看所有环境`);
|
|
154
234
|
process.exit(1);
|
|
155
235
|
}
|
|
156
236
|
|
|
157
|
-
if (config.current ===
|
|
158
|
-
console.log(`${YELLOW}当前已在 "${
|
|
237
|
+
if (config.current === resolvedEnvName) {
|
|
238
|
+
console.log(`${YELLOW}当前已在 "${resolvedEnvName}" 环境,无需切换${RESET}`);
|
|
159
239
|
return;
|
|
160
240
|
}
|
|
161
241
|
|
|
162
|
-
|
|
163
|
-
config.current = envName;
|
|
164
|
-
saveEnvsConfig(config);
|
|
165
|
-
|
|
166
|
-
console.log('');
|
|
167
|
-
console.log(`${GREEN}✅ 已切换环境${RESET}`);
|
|
168
|
-
console.log(` ${DIM}${previousEnv}${RESET} → ${GREEN}${BOLD}${envName}${RESET}`);
|
|
169
|
-
console.log(` 地址:${config.environments[envName].baseUrl}`);
|
|
170
|
-
console.log('');
|
|
171
|
-
console.log(`${DIM}提示:登录态已自动切换,如需重新登录请运行 openyida login --qr${RESET}`);
|
|
172
|
-
console.log('');
|
|
242
|
+
switchToEnv(resolvedEnvName);
|
|
173
243
|
}
|
|
174
244
|
|
|
175
245
|
/**
|
|
@@ -183,8 +253,9 @@ function cmdRemove(envName) {
|
|
|
183
253
|
process.exit(1);
|
|
184
254
|
}
|
|
185
255
|
|
|
186
|
-
|
|
187
|
-
|
|
256
|
+
envName = resolveEnvNameAlias(envName);
|
|
257
|
+
if (isBuiltinEnvName(envName)) {
|
|
258
|
+
warn(`${RED}错误:不能删除内置环境 "${envName}"${RESET}`);
|
|
188
259
|
process.exit(1);
|
|
189
260
|
}
|
|
190
261
|
|
|
@@ -235,6 +306,11 @@ async function cmdAdd(envName) {
|
|
|
235
306
|
process.exit(1);
|
|
236
307
|
}
|
|
237
308
|
|
|
309
|
+
if (resolveEnvNameAlias(envName) !== envName || isBuiltinEnvName(envName)) {
|
|
310
|
+
warn(`${RED}错误:"${envName}" 是内置环境或内置别名,不能作为私有化环境名称${RESET}`);
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
|
|
238
314
|
const config = loadEnvsConfig();
|
|
239
315
|
const existingConfig = config.environments[envName];
|
|
240
316
|
|
|
@@ -302,6 +378,75 @@ async function cmdAdd(envName) {
|
|
|
302
378
|
console.log('');
|
|
303
379
|
}
|
|
304
380
|
|
|
381
|
+
async function cmdSetup() {
|
|
382
|
+
const config = loadEnvsConfig();
|
|
383
|
+
const recommendedEnv = detectSetupRecommendation();
|
|
384
|
+
const options = [
|
|
385
|
+
{
|
|
386
|
+
key: 'public',
|
|
387
|
+
title: '阿里云公有云 / 国内钉钉',
|
|
388
|
+
baseUrl: DEFAULT_PUBLIC_ENV.baseUrl,
|
|
389
|
+
loginUrl: DEFAULT_PUBLIC_ENV.loginUrl,
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
key: 'intl',
|
|
393
|
+
title: '海外 DingTalk / Dingtalk Wukong',
|
|
394
|
+
baseUrl: DEFAULT_INTERNATIONAL_ENV.baseUrl,
|
|
395
|
+
loginUrl: DEFAULT_INTERNATIONAL_ENV.loginUrl,
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
key: 'alibaba',
|
|
399
|
+
title: '阿里内网员工环境',
|
|
400
|
+
baseUrl: DEFAULT_ALIBABA_INTERNAL_ENV.baseUrl,
|
|
401
|
+
loginUrl: DEFAULT_ALIBABA_INTERNAL_ENV.loginUrl,
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
key: 'custom',
|
|
405
|
+
title: '私有化部署 / 专属域名',
|
|
406
|
+
baseUrl: '自定义',
|
|
407
|
+
loginUrl: '自定义',
|
|
408
|
+
},
|
|
409
|
+
];
|
|
410
|
+
const defaultIndex = Math.max(0, options.findIndex((item) => item.key === recommendedEnv));
|
|
411
|
+
|
|
412
|
+
console.log('');
|
|
413
|
+
console.log(`${BOLD}OpenYida 环境设置向导${RESET}`);
|
|
414
|
+
console.log(`${'─'.repeat(50)}`);
|
|
415
|
+
console.log(`${DIM}请选择客户实际登录入口。可随时用 openyida env switch 切换。${RESET}`);
|
|
416
|
+
console.log('');
|
|
417
|
+
|
|
418
|
+
options.forEach((item, index) => {
|
|
419
|
+
const isRecommended = index === defaultIndex;
|
|
420
|
+
console.log(` ${CYAN}${index + 1}.${RESET} ${item.title}${isRecommended ? ` ${GREEN}← 推荐${RESET}` : ''}`);
|
|
421
|
+
console.log(` ${DIM}地址:${item.baseUrl}${RESET}`);
|
|
422
|
+
console.log(` ${DIM}登录:${getLoginHost(item.loginUrl)}${RESET}`);
|
|
423
|
+
});
|
|
424
|
+
console.log('');
|
|
425
|
+
|
|
426
|
+
const answer = await askQuestion(`${BOLD}选择环境${RESET}(1-${options.length}):`, String(defaultIndex + 1));
|
|
427
|
+
const selectedIndex = Number.parseInt(answer, 10) - 1;
|
|
428
|
+
const selected = options[selectedIndex];
|
|
429
|
+
if (!selected) {
|
|
430
|
+
warn(`${RED}错误:无效选择${RESET}`);
|
|
431
|
+
process.exit(1);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (selected.key === 'custom') {
|
|
435
|
+
const envName = await askQuestion(`${BOLD}私有化环境名称${RESET}(如 private-prod):`, '');
|
|
436
|
+
await cmdAdd(envName);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (config.current === selected.key) {
|
|
441
|
+
console.log('');
|
|
442
|
+
console.log(`${YELLOW}当前已在 "${selected.key}" 环境,无需切换${RESET}`);
|
|
443
|
+
console.log('');
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
switchToEnv(selected.key);
|
|
448
|
+
}
|
|
449
|
+
|
|
305
450
|
/**
|
|
306
451
|
* 显示 env 命令帮助信息。
|
|
307
452
|
*/
|
|
@@ -314,6 +459,7 @@ function showHelp() {
|
|
|
314
459
|
console.log('');
|
|
315
460
|
console.log(`${CYAN}子命令:${RESET}`);
|
|
316
461
|
console.log(` ${GREEN}list${RESET} 列出所有环境及当前激活环境`);
|
|
462
|
+
console.log(` ${GREEN}setup${RESET} 交互式选择公有云、海外、内网或私有化环境`);
|
|
317
463
|
console.log(` ${GREEN}add <name>${RESET} 交互式添加私有化环境配置`);
|
|
318
464
|
console.log(` ${GREEN}switch <name>${RESET} 切换当前激活环境`);
|
|
319
465
|
console.log(` ${GREEN}remove <name>${RESET} 移除环境配置`);
|
|
@@ -321,6 +467,7 @@ function showHelp() {
|
|
|
321
467
|
console.log('');
|
|
322
468
|
console.log(`${CYAN}示例:${RESET}`);
|
|
323
469
|
console.log(` ${BLUE}openyida env list${RESET} 查看所有环境`);
|
|
470
|
+
console.log(` ${BLUE}openyida env setup${RESET} 进入环境设置向导`);
|
|
324
471
|
console.log(` ${BLUE}openyida env add private-prod${RESET} 添加私有化生产环境`);
|
|
325
472
|
console.log(` ${BLUE}openyida env switch private-prod${RESET} 切换到私有化环境`);
|
|
326
473
|
console.log(` ${BLUE}openyida env show private-prod${RESET} 查看环境详情`);
|
|
@@ -358,6 +505,12 @@ async function run(args) {
|
|
|
358
505
|
cmdSwitch(subArgs[0]);
|
|
359
506
|
break;
|
|
360
507
|
|
|
508
|
+
case 'setup':
|
|
509
|
+
case 'init':
|
|
510
|
+
case 'configure':
|
|
511
|
+
await cmdSetup();
|
|
512
|
+
break;
|
|
513
|
+
|
|
361
514
|
case 'remove':
|
|
362
515
|
case 'rm':
|
|
363
516
|
case 'delete':
|