openyida 2026.6.3-beta.0 → 2026.6.11-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/bin/yida.js +87 -3
- package/lib/core/command-manifest.js +1 -1
- package/lib/core/env-manager.js +29 -0
- package/package.json +1 -1
- package/yida-skills/SKILL.md +2 -0
- package/yida-skills/skills/yida-login/SKILL.md +9 -0
package/README.md
CHANGED
|
@@ -71,6 +71,13 @@ openyida login
|
|
|
71
71
|
|
|
72
72
|
In Codex, QoderWork, Qoder, Wukong, Claude Code, OpenCode, Cursor, and other detected AI tools, OpenYida first tries local Chrome/Edge/Chromium CDP when no valid cached login exists. If local CDP is unavailable, it falls back to an AI-dialog QR handoff. The agent should render `qr_image_markdown` or paste `agent_response_markdown` directly in the conversation so the QR code is visible, then run `poll_command` after the user scans it with DingTalk. If image rendering is unavailable, fall back to `qr_url`. The explicit `openyida login --browser` command still prefers CDP first and uses Playwright as an optional browser fallback.
|
|
73
73
|
|
|
74
|
+
When the user names a target Yida entry URL, pass it to the login command so OpenYida can select the matching environment and cookie file. For example, Alibaba intranet Yida uses `cookies-alibaba.json`:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
openyida login https://yida-group.alibaba-inc.com/
|
|
78
|
+
openyida login --alibaba
|
|
79
|
+
```
|
|
80
|
+
|
|
74
81
|
The explicit QR polling command remains available:
|
|
75
82
|
|
|
76
83
|
```bash
|
|
@@ -279,7 +286,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
279
286
|
|
|
280
287
|
| Command | Description |
|
|
281
288
|
|---------|-------------|
|
|
282
|
-
| `openyida login [--qr\|--agent-qr\|--codex\|--browser] [--env <name>\|--intl\|--overseas\|--global\|--yidaapps] [--corp-id <corpId>]` | Login (cache first, --browser or --agent-qr when needed) |
|
|
289
|
+
| `openyida login [target-url] [--qr\|--agent-qr\|--codex\|--browser] [--env <name>\|--intl\|--overseas\|--global\|--yidaapps\|--alibaba] [--corp-id <corpId>]` | Login (cache first, --browser or --agent-qr when needed) |
|
|
283
290
|
| `openyida logout` | Logout / switch account |
|
|
284
291
|
| `openyida auth <status\|login\|refresh\|logout>` | Login state management |
|
|
285
292
|
| `openyida org <list\|switch>` | Organization management (list / switch) |
|
package/bin/yida.js
CHANGED
|
@@ -329,7 +329,60 @@ function getArgValue(cliArgs, name) {
|
|
|
329
329
|
return cliArgs[index + 1];
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
-
function
|
|
332
|
+
function parseLoginTargetArg(value) {
|
|
333
|
+
const raw = String(value || '').trim();
|
|
334
|
+
if (!raw) {return null;}
|
|
335
|
+
|
|
336
|
+
const hasProtocol = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw);
|
|
337
|
+
if (!hasProtocol) {
|
|
338
|
+
if (raw.startsWith('/') || raw.startsWith('.') || raw.includes('\\')) {return null;}
|
|
339
|
+
const hostPart = raw.split('/')[0];
|
|
340
|
+
if (!hostPart.includes('.') && hostPart !== 'localhost') {return null;}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
return new URL(hasProtocol ? raw : `https://${raw}`);
|
|
345
|
+
} catch {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function applyLoginTargetUrl(value) {
|
|
351
|
+
const parsedUrl = parseLoginTargetArg(value);
|
|
352
|
+
if (!parsedUrl) {return false;}
|
|
353
|
+
|
|
354
|
+
const {
|
|
355
|
+
deriveBaseUrlFromDingtalkOAuthUrl,
|
|
356
|
+
inferEnvironmentNameFromUrl,
|
|
357
|
+
inferLoginUrlForBaseUrl,
|
|
358
|
+
normalizeBaseUrl,
|
|
359
|
+
normalizeHostname,
|
|
360
|
+
} = require('../lib/core/env-manager');
|
|
361
|
+
|
|
362
|
+
const targetHref = parsedUrl.href;
|
|
363
|
+
const redirectBaseUrl = deriveBaseUrlFromDingtalkOAuthUrl(targetHref, null);
|
|
364
|
+
const endpoint = normalizeBaseUrl(redirectBaseUrl || parsedUrl.origin, null);
|
|
365
|
+
const inferredEnv = inferEnvironmentNameFromUrl(redirectBaseUrl || targetHref);
|
|
366
|
+
|
|
367
|
+
if (inferredEnv) {
|
|
368
|
+
process.env.OPENYIDA_ENV = inferredEnv;
|
|
369
|
+
}
|
|
370
|
+
if (endpoint) {
|
|
371
|
+
process.env.OPENYIDA_ENDPOINT = endpoint;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const host = normalizeHostname(targetHref);
|
|
375
|
+
const isDingtalkLoginHost = host.endsWith('dingtalk.com') || host.endsWith('dingtalk.io');
|
|
376
|
+
const normalizedPath = parsedUrl.pathname.replace(/\/+$/, '') || '/';
|
|
377
|
+
const hasCustomLoginPath = normalizedPath !== '/' && normalizedPath !== '/workPlatform';
|
|
378
|
+
process.env.OPENYIDA_LOGIN_URL = isDingtalkLoginHost || hasCustomLoginPath
|
|
379
|
+
? targetHref
|
|
380
|
+
: inferLoginUrlForBaseUrl(endpoint || parsedUrl.origin);
|
|
381
|
+
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function applyLoginEnvironmentFlags(cliArgs, options = {}) {
|
|
333
386
|
const envFlagMap = {
|
|
334
387
|
'--public': 'public',
|
|
335
388
|
'--intl': 'intl',
|
|
@@ -341,6 +394,19 @@ function applyLoginEnvironmentFlags(cliArgs) {
|
|
|
341
394
|
'--internal': 'alibaba',
|
|
342
395
|
'--intranet': 'alibaba',
|
|
343
396
|
};
|
|
397
|
+
const valuePassthroughFlags = new Set([
|
|
398
|
+
'--agent-poll',
|
|
399
|
+
'--codex-poll',
|
|
400
|
+
'--agent-select',
|
|
401
|
+
'--codex-select',
|
|
402
|
+
'--corp-id',
|
|
403
|
+
]);
|
|
404
|
+
const targetUrlFlags = new Set([
|
|
405
|
+
'--endpoint',
|
|
406
|
+
'--base-url',
|
|
407
|
+
'--login-url',
|
|
408
|
+
]);
|
|
409
|
+
const inferTargetUrl = !!options.inferTargetUrl;
|
|
344
410
|
const filteredArgs = [];
|
|
345
411
|
|
|
346
412
|
for (let index = 0; index < cliArgs.length; index++) {
|
|
@@ -353,10 +419,28 @@ function applyLoginEnvironmentFlags(cliArgs) {
|
|
|
353
419
|
}
|
|
354
420
|
continue;
|
|
355
421
|
}
|
|
422
|
+
if (inferTargetUrl && targetUrlFlags.has(arg)) {
|
|
423
|
+
const targetUrl = cliArgs[index + 1];
|
|
424
|
+
if (targetUrl && !targetUrl.startsWith('--') && applyLoginTargetUrl(targetUrl)) {
|
|
425
|
+
index++;
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (valuePassthroughFlags.has(arg)) {
|
|
430
|
+
filteredArgs.push(arg);
|
|
431
|
+
if (cliArgs[index + 1] && !cliArgs[index + 1].startsWith('--')) {
|
|
432
|
+
filteredArgs.push(cliArgs[index + 1]);
|
|
433
|
+
index++;
|
|
434
|
+
}
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
356
437
|
if (envFlagMap[arg]) {
|
|
357
438
|
process.env.OPENYIDA_ENV = envFlagMap[arg];
|
|
358
439
|
continue;
|
|
359
440
|
}
|
|
441
|
+
if (inferTargetUrl && !arg.startsWith('--') && applyLoginTargetUrl(arg)) {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
360
444
|
filteredArgs.push(arg);
|
|
361
445
|
}
|
|
362
446
|
|
|
@@ -455,7 +539,7 @@ async function main() {
|
|
|
455
539
|
|
|
456
540
|
case 'login': {
|
|
457
541
|
const { checkLoginOnly } = require('../lib/auth/login');
|
|
458
|
-
const loginArgs = applyLoginEnvironmentFlags(args);
|
|
542
|
+
const loginArgs = applyLoginEnvironmentFlags(args, { inferTargetUrl: true });
|
|
459
543
|
if (loginArgs.includes('--agent-poll') || loginArgs.includes('--codex-poll')) {
|
|
460
544
|
const sessionFile = getArgValue(loginArgs, '--agent-poll') || getArgValue(loginArgs, '--codex-poll');
|
|
461
545
|
const { pollCodexQrLogin } = require('../lib/auth/qr-login');
|
|
@@ -559,7 +643,7 @@ async function main() {
|
|
|
559
643
|
if (subCommand === 'status') {
|
|
560
644
|
authStatus();
|
|
561
645
|
} else if (subCommand === 'login') {
|
|
562
|
-
const authArgs = applyLoginEnvironmentFlags(args.slice(1));
|
|
646
|
+
const authArgs = applyLoginEnvironmentFlags(args.slice(1), { inferTargetUrl: true });
|
|
563
647
|
let loginType = 'qrcode';
|
|
564
648
|
if (authArgs.includes('--codex')) {
|
|
565
649
|
loginType = 'codex';
|
|
@@ -21,7 +21,7 @@ const COMMAND_GROUPS = [
|
|
|
21
21
|
id: 'auth',
|
|
22
22
|
titleKey: 'help.group_auth',
|
|
23
23
|
commands: [
|
|
24
|
-
command('login', ['login'], 'login [--qr|--agent-qr|--codex|--browser] [--env <name>|--intl|--overseas|--global|--yidaapps] [--corp-id <corpId>]', 'help.cmd_login', {
|
|
24
|
+
command('login', ['login'], 'login [target-url] [--qr|--agent-qr|--codex|--browser] [--env <name>|--intl|--overseas|--global|--yidaapps|--alibaba] [--corp-id <corpId>]', 'help.cmd_login', {
|
|
25
25
|
requiresLogin: false,
|
|
26
26
|
output: 'json',
|
|
27
27
|
}),
|
package/lib/core/env-manager.js
CHANGED
|
@@ -265,6 +265,34 @@ function isYidaAppsHost(hostname) {
|
|
|
265
265
|
return host === 'yidaapps.com' || host.endsWith('.yidaapps.com');
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
function inferEnvironmentNameFromUrl(value) {
|
|
269
|
+
const redirectBaseUrl = deriveBaseUrlFromDingtalkOAuthUrl(value, null);
|
|
270
|
+
if (redirectBaseUrl) {
|
|
271
|
+
return inferEnvironmentNameFromUrl(redirectBaseUrl);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const host = normalizeHostname(value);
|
|
275
|
+
if (!host) { return null; }
|
|
276
|
+
|
|
277
|
+
if (host === 'login.dingtalk.io' || host.endsWith('.dingtalk.io')) {
|
|
278
|
+
return 'intl';
|
|
279
|
+
}
|
|
280
|
+
if (host === 'yidaapps.com' || host.endsWith('.yidaapps.com')) {
|
|
281
|
+
return 'intl';
|
|
282
|
+
}
|
|
283
|
+
if (host === 'aliwork.com' || host.endsWith('.aliwork.com')) {
|
|
284
|
+
return 'public';
|
|
285
|
+
}
|
|
286
|
+
if (host === 'yida-group.alibaba-inc.com') {
|
|
287
|
+
return 'alibaba';
|
|
288
|
+
}
|
|
289
|
+
if (host.endsWith('.alibaba-inc.com') && isYidaServiceHost(host)) {
|
|
290
|
+
return 'alibaba';
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
|
|
268
296
|
function isDefaultWorkPlatformLoginUrl(loginUrl, baseUrl) {
|
|
269
297
|
const loginOrigin = normalizeBaseUrl(loginUrl, null);
|
|
270
298
|
const baseOrigin = normalizeBaseUrl(baseUrl, null);
|
|
@@ -564,6 +592,7 @@ module.exports = {
|
|
|
564
592
|
normalizeHostname,
|
|
565
593
|
isYidaServiceHost,
|
|
566
594
|
isYidaAppsHost,
|
|
595
|
+
inferEnvironmentNameFromUrl,
|
|
567
596
|
inferLoginUrlForBaseUrl,
|
|
568
597
|
deriveBaseUrlFromDingtalkOAuthUrl,
|
|
569
598
|
deriveBaseUrlFromCookies,
|
package/package.json
CHANGED
package/yida-skills/SKILL.md
CHANGED
|
@@ -67,6 +67,8 @@ openyida login --check-only --json
|
|
|
67
67
|
|
|
68
68
|
`openyida env --json` 用于确认当前 AI 工具、项目根目录、配置文件和登录态拆解项;`openyida login --check-only --json` 只读取本地登录缓存,不触发登录、不打开浏览器、不创建任何资源。
|
|
69
69
|
|
|
70
|
+
若用户明确要求登录某个宜搭入口 URL,登录命令必须携带该 URL 或对应环境 flag。例如 `https://yida-group.alibaba-inc.com/` 是阿里内网宜搭,应执行 `openyida login https://yida-group.alibaba-inc.com/` 或 `openyida login --alibaba`,不要退化成裸 `openyida login`,否则会落到默认公有云 `www.aliwork.com` / `cookies-public.json`。
|
|
71
|
+
|
|
70
72
|
**悟空(Wukong)降级规则**:如果在悟空环境中本地命令执行入口连续失败,不要继续重试,也不要判断为 OpenYida 登录失败。进入人工协同诊断模式,请用户在可用终端执行以下低风险命令并贴回输出:
|
|
71
73
|
|
|
72
74
|
```bash
|
|
@@ -48,6 +48,15 @@ openyida login
|
|
|
48
48
|
|
|
49
49
|
默认登录路径不需要 Playwright:优先复用缓存;Codex、Qoder、悟空、Claude Code、OpenCode、Cursor 等可检测到的 AI 工具先尝试本地 Chrome/Edge/Chromium CDP 登录,CDP 不可用时再使用二维码 handoff;其他终端环境使用二维码登录。`openyida login --browser` 优先使用本地 Chrome/Edge/Chromium CDP,CDP 不可用时才用 Playwright 兜底。
|
|
50
50
|
|
|
51
|
+
若用户明确给出宜搭入口 URL,必须把该 URL 传给登录命令,或使用对应环境 flag;不要退化成裸 `openyida login`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
openyida login https://yida-group.alibaba-inc.com/
|
|
55
|
+
openyida login --alibaba
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`https://yida-group.alibaba-inc.com/` 属于阿里内网宜搭,登录态应写入 `cookies-alibaba.json`;`www.aliwork.com`/`cookies-public.json` 表示走了默认公有云环境。
|
|
59
|
+
|
|
51
60
|
### AI 工具二维码登录模式
|
|
52
61
|
|
|
53
62
|
在 AI 对话框环境中没有有效缓存,且本地 CDP 浏览器登录不可用时,`openyida login` 返回 `need_qr_scan` JSON,包含 `qr_image_markdown`、`agent_response_markdown`、`qr_image_file`、`qr_url`、`poll_command` 和 `session_file`。
|