openyida 2026.7.14-2 → 2026.7.14
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 +22 -15
- package/bin/yida.js +220 -72
- package/lib/agent-center/api.js +2 -2
- package/lib/aggregate-table/aggregate-table.js +2 -2
- package/lib/ai/ai.js +12 -7
- package/lib/app/canvas-compile.js +2 -2
- package/lib/app/create-app.js +19 -5
- package/lib/app/create-form.js +76 -54
- package/lib/app/create-page.js +19 -4
- package/lib/app/er.js +8 -11
- package/lib/app/export-app.js +2 -2
- package/lib/app/externalize-form.js +10 -12
- package/lib/app/get-schema.js +10 -12
- package/lib/app/import-app.js +22 -6
- package/lib/app/list-forms.js +19 -3
- package/lib/app/nav-group.js +19 -6
- package/lib/app/publish.js +198 -60
- package/lib/app/update-app.js +18 -4
- package/lib/app/update-form-config.js +113 -20
- package/lib/app-permission/app-permission.js +2 -2
- package/lib/auth/auth.js +313 -0
- package/lib/auth/cdp-browser-login.js +390 -0
- package/lib/auth/codex-login.js +71 -0
- package/lib/auth/login.js +550 -0
- package/lib/auth/org.js +322 -169
- package/lib/auth/qr-login.js +1575 -0
- package/lib/basic-info/basic-info.js +12 -11
- package/lib/bridge/bridge.js +27 -29
- package/lib/connector/api.js +4 -4
- package/lib/core/agent-capabilities.js +8 -92
- package/lib/core/batch.js +8 -8
- package/lib/core/check-data.js +2 -2
- package/lib/core/command-manifest.js +3 -3
- package/lib/core/doctor.js +22 -19
- package/lib/core/env-cmd.js +3 -1
- package/lib/core/env-manager.js +121 -8
- package/lib/core/env.js +72 -30
- package/lib/core/locales/ar.js +5 -5
- package/lib/core/locales/de.js +5 -5
- package/lib/core/locales/en.js +26 -26
- package/lib/core/locales/es.js +5 -5
- package/lib/core/locales/fr.js +5 -5
- package/lib/core/locales/hi.js +5 -5
- package/lib/core/locales/ja.js +14 -14
- package/lib/core/locales/ko.js +5 -5
- package/lib/core/locales/pt.js +5 -5
- package/lib/core/locales/vi.js +5 -5
- package/lib/core/locales/zh-HK.js +15 -15
- package/lib/core/locales/zh.js +26 -26
- package/lib/core/query-data.js +2 -2
- package/lib/core/task-center.js +2 -2
- package/lib/core/utils.js +400 -156
- package/lib/core/yida-client.js +22 -57
- package/lib/corp-efficiency/corp-efficiency.js +3 -3
- package/lib/corp-manager/api.js +2 -2
- package/lib/db/db-seq-fix.js +25 -20
- package/lib/flash-note/flash-to-prd.js +2 -2
- package/lib/i18n-management/i18n-management.js +2 -2
- package/lib/integration/integration-check.js +7 -10
- package/lib/integration/integration-create.js +8 -11
- package/lib/integration/integration-list.js +8 -11
- package/lib/mcp/server.js +54 -5
- package/lib/page-config/get-page-config.js +2 -2
- package/lib/page-config/save-share-config.js +2 -2
- package/lib/page-config/verify-short-url.js +2 -2
- package/lib/permission/get-permission.js +2 -2
- package/lib/permission/save-permission.js +2 -2
- package/lib/process/ai-form-setting.js +2 -2
- package/lib/process/create-process.js +2 -2
- package/lib/process/preview-process.js +2 -2
- package/lib/report/append.js +3 -3
- package/lib/report/index.js +3 -3
- package/package.json +1 -1
- package/scripts/check-syntax.js +0 -6
- package/scripts/e2e-real/full-runner.js +10 -2
- package/scripts/e2e-real/runner.js +31 -0
- package/scripts/eval/screenshot.js +69 -27
- package/scripts/nightly-smoke.js +34 -16
- package/scripts/postinstall.js +2 -6
- package/yida-skills/SKILL.md +6 -10
- package/yida-skills/references/development-rules.md +2 -2
- package/yida-skills/references/setup-and-env.md +9 -10
- package/yida-skills/skills/sls-log-workbench/SKILL.md +2 -2
- package/yida-skills/skills/sls-log-workbench/sls-query.js +54 -27
- package/yida-skills/skills/yida-flash-note-to-prd/SKILL.md +1 -1
- package/yida-skills/skills/yida-integration/SKILL.md +3 -3
- package/yida-skills/skills/yida-login/SKILL.md +74 -56
- package/yida-skills/skills/yida-logout/SKILL.md +12 -13
- package/yida-skills/skills/yida-process-rule/SKILL.md +1 -1
- package/yida-skills/skills/yida-publish-page/SKILL.md +1 -1
- package/yida-skills/skills/yida-report/references/report-api-guide.md +20 -4
- package/yida-skills/skills-index.json +4 -4
- package/lib/auth/oauth-loopback.js +0 -156
- package/lib/auth/token-auth.js +0 -346
- package/lib/auth/token-store.js +0 -174
package/README.md
CHANGED
|
@@ -55,10 +55,10 @@ If Codex is already installed, OpenYida also imports a local Codex plugin during
|
|
|
55
55
|
Run this from the AI coding workspace where you want OpenYida to operate:
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
|
-
openyida agent-capabilities --
|
|
58
|
+
openyida agent-capabilities --json
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
OpenYida
|
|
61
|
+
OpenYida detects the active agent environment, workspace path, login state, organization context, command manifest, and side-effect hints in one machine-readable snapshot. `openyida commands --json` remains available when an agent only needs the command manifest.
|
|
62
62
|
|
|
63
63
|
### 3. Log In
|
|
64
64
|
|
|
@@ -66,20 +66,27 @@ OpenYida returns a compact machine-readable summary with the version, login stat
|
|
|
66
66
|
openyida login
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
In Codex, QoderWork, Qoder, Wukong, Claude Code, MuleRun, 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.
|
|
70
70
|
|
|
71
|
-
When the user names a target Yida entry URL, pass it to the login command so OpenYida can select the matching environment and
|
|
71
|
+
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`:
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
74
|
openyida login https://yida-group.alibaba-inc.com/
|
|
75
75
|
openyida login --alibaba
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
The explicit QR polling command remains available:
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
+
openyida login --agent-qr
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For terminal QR login, use:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
openyida login --qr
|
|
88
|
+
openyida login --qr --corp-id dingxxxxxxxx
|
|
81
89
|
openyida login --check-only --json
|
|
82
|
-
openyida auth status
|
|
83
90
|
```
|
|
84
91
|
|
|
85
92
|
OpenYida does not install Playwright by default.
|
|
@@ -232,7 +239,7 @@ OPENYIDA_E2E=1 OPENYIDA_E2E_FULL_STAGES=auth,app,form,process npm run test:e2e:r
|
|
|
232
239
|
npm run test:e2e:real:skills
|
|
233
240
|
```
|
|
234
241
|
|
|
235
|
-
The runner creates a disposable app, form, and custom page with an `OY_E2E_*` prefix, then verifies
|
|
242
|
+
The runner creates a disposable app, form, and custom page with an `OY_E2E_*` prefix, then verifies login, app listing, schema fetch, data query, and page publish. It writes a registry to `project/.cache/e2e-real/` so created resources can be audited later. To inject CI cookies without relying on a local login cache, pass `OPENYIDA_E2E_COOKIES_BASE64` as a base64 encoded cookie array or `{ "cookies": [...] }` object.
|
|
236
243
|
|
|
237
244
|
`test:e2e:real:full` extends the smoke path into a broad deterministic feature matrix: auth/env, app update, form update and option mutation, page build/compile/generate/publish, data create/get/update/query, permission read, page config and short URL check, report create/append, dashboard skill verification, export/import, batch, task-center, formula/doctor/sample/CDN config, and local connector parsing/template generation. AI-backed commands such as `flash-to-prd` are available as the optional `ai` stage because they depend on remote model availability. Workflow mutation is available as the opt-in `process` stage; it creates and republishes a workflow on the disposable E2E form and records advanced official-node fixtures for review.
|
|
238
245
|
|
|
@@ -332,11 +339,11 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
332
339
|
|
|
333
340
|
| Command | Description |
|
|
334
341
|
|---------|-------------|
|
|
335
|
-
| `openyida login [target-url] [--env <name>\|--intl\|--overseas\|--global\|--yidaapps\|--alibaba] [--
|
|
336
|
-
| `openyida logout` | Logout /
|
|
337
|
-
| `openyida auth <status\|login\|refresh\|logout>` |
|
|
338
|
-
| `openyida org <list\|switch
|
|
339
|
-
| `openyida env [--json\|setup\|list\|show\|switch\|add\|remove] [options]` | Detect AI tool environment &
|
|
342
|
+
| `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) |
|
|
343
|
+
| `openyida logout` | Logout / switch account |
|
|
344
|
+
| `openyida auth <status\|login\|refresh\|logout>` | Login state management |
|
|
345
|
+
| `openyida org <list\|switch>` | Organization management (list / switch) |
|
|
346
|
+
| `openyida env [--json\|setup\|list\|show\|switch\|add\|remove] [options]` | Detect AI tool environment & login state |
|
|
340
347
|
|
|
341
348
|
### App Management
|
|
342
349
|
|
|
@@ -450,7 +457,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
450
457
|
| Command | Description |
|
|
451
458
|
|---------|-------------|
|
|
452
459
|
| `openyida commands [--json]` | Output machine-readable command manifest |
|
|
453
|
-
| `openyida agent-capabilities [--json]
|
|
460
|
+
| `openyida agent-capabilities [--json]` | Output one-shot agent capability snapshot |
|
|
454
461
|
| `openyida a2a <serve\|agent-card> [options]` | Start local read-only A2A adapter or print Agent Card |
|
|
455
462
|
| `openyida bridge start [--token <pair-token>] [--port 6736] [--origin https://demo.aliwork.com] [--open\|--no-open]` | Start OpenYida local web bridge service |
|
|
456
463
|
| `openyida copy [--force]` | Copy project working directory |
|
|
@@ -578,9 +585,9 @@ When adding new CLI commands, register the route in `bin/yida.js`, add it to `li
|
|
|
578
585
|
|
|
579
586
|
## Security and Configuration
|
|
580
587
|
|
|
581
|
-
-
|
|
588
|
+
- Login cookies are cached locally and should never be hard-coded into source files.
|
|
582
589
|
- Private deployment environments are managed through `lib/core/env-manager.js`.
|
|
583
|
-
- Yida API requests should use the active environment base URL and
|
|
590
|
+
- Yida API requests should use the active environment base URL and authenticated cookies.
|
|
584
591
|
- For multi-organization accounts, prefer explicit `--corp-id` values in non-interactive automation.
|
|
585
592
|
|
|
586
593
|
## Community
|
package/bin/yida.js
CHANGED
|
@@ -211,38 +211,6 @@ function handleFirstRunGuide() {
|
|
|
211
211
|
console.log('');
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
const TOKEN_OUTPUT_SECRET_KEYS = new Set([
|
|
215
|
-
'access_token',
|
|
216
|
-
'accessToken',
|
|
217
|
-
'refresh_token',
|
|
218
|
-
'refreshToken',
|
|
219
|
-
'ai_app_user_auth_token',
|
|
220
|
-
'aiAppUserAuthToken',
|
|
221
|
-
'tianshu_csrf_token',
|
|
222
|
-
'tianshuCsrfToken',
|
|
223
|
-
'csrf_token',
|
|
224
|
-
'csrfToken',
|
|
225
|
-
]);
|
|
226
|
-
|
|
227
|
-
function maskSensitiveAuthOutput(value) {
|
|
228
|
-
if (!value || typeof value !== 'object') {
|
|
229
|
-
return value;
|
|
230
|
-
}
|
|
231
|
-
const { maskToken } = require('../lib/auth/token-store');
|
|
232
|
-
if (Array.isArray(value)) {
|
|
233
|
-
return value.map((item) => maskSensitiveAuthOutput(item));
|
|
234
|
-
}
|
|
235
|
-
const output = {};
|
|
236
|
-
Object.entries(value).forEach(([key, item]) => {
|
|
237
|
-
if (TOKEN_OUTPUT_SECRET_KEYS.has(key)) {
|
|
238
|
-
output[key] = maskToken(item);
|
|
239
|
-
} else {
|
|
240
|
-
output[key] = maskSensitiveAuthOutput(item);
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
return output;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
214
|
function printLoginResult(result) {
|
|
247
215
|
noteLoginCommandResult(result);
|
|
248
216
|
|
|
@@ -256,21 +224,49 @@ function printLoginResult(result) {
|
|
|
256
224
|
return;
|
|
257
225
|
}
|
|
258
226
|
|
|
259
|
-
|
|
227
|
+
if (result && (result.status === 'need_qr_scan' || result.status === 'need_corp_selection')) {
|
|
228
|
+
console.log(JSON.stringify(result));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (result && result.status === 'need_codex_browser_login') {
|
|
233
|
+
const handoff = {
|
|
234
|
+
status: result.status,
|
|
235
|
+
handoff_type: result.handoff_type || 'browser',
|
|
236
|
+
can_auto_use: false,
|
|
237
|
+
browser: result.browser,
|
|
238
|
+
login_url: result.login_url,
|
|
239
|
+
message: result.message,
|
|
240
|
+
};
|
|
241
|
+
[
|
|
242
|
+
'agent_action',
|
|
243
|
+
'browser_open_strategy',
|
|
244
|
+
'browser_use_local_redirect_fallback',
|
|
245
|
+
'required_agent_tool',
|
|
246
|
+
'required_runtime_tool',
|
|
247
|
+
'cookie_export_file',
|
|
248
|
+
'cookie_file',
|
|
249
|
+
'post_login_check_command',
|
|
250
|
+
'fallback_command',
|
|
251
|
+
].forEach((key) => {
|
|
252
|
+
if (result[key]) {handoff[key] = result[key];}
|
|
253
|
+
});
|
|
254
|
+
console.log(JSON.stringify(handoff));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (result.status && result.status !== 'ok' && !result.csrf_token) {
|
|
259
|
+
console.log(JSON.stringify(result));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
260
263
|
const summary = {
|
|
261
|
-
ok:
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
expires_at: result.expires_at ? new Date(result.expires_at).toISOString() : undefined,
|
|
268
|
-
base_url: result.base_url,
|
|
269
|
-
corp_id: result.corp_id,
|
|
270
|
-
user_id: result.user_id,
|
|
271
|
-
user_name: result.user_name,
|
|
272
|
-
message: result.message,
|
|
273
|
-
raw: tokenUsable ? undefined : result.raw,
|
|
264
|
+
ok: true,
|
|
265
|
+
base_url: result && result.base_url,
|
|
266
|
+
corp_id: result && result.corp_id,
|
|
267
|
+
user_id: result && result.user_id,
|
|
268
|
+
csrf_token: result && result.csrf_token ? `${result.csrf_token.slice(0, 16)}...` : undefined,
|
|
269
|
+
cookies_count: Array.isArray(result && result.cookies) ? result.cookies.length : (result.cookies_count || 0),
|
|
274
270
|
};
|
|
275
271
|
console.log(JSON.stringify(summary));
|
|
276
272
|
}
|
|
@@ -281,11 +277,15 @@ function noteLoginCommandResult(result) {
|
|
|
281
277
|
let status = 'failed';
|
|
282
278
|
let reason = 'login_failed';
|
|
283
279
|
|
|
284
|
-
|
|
285
|
-
(result.access_token || (result.status === 'ok' && result.can_auto_use));
|
|
286
|
-
if (result && (tokenLoginOk || (result.status === 'ok' && result.can_auto_use))) {
|
|
280
|
+
if (result && (result.csrf_token || (result.status === 'ok' && result.can_auto_use))) {
|
|
287
281
|
status = 'success';
|
|
288
282
|
reason = 'login_ok';
|
|
283
|
+
} else if (result && result.status === 'need_qr_scan') {
|
|
284
|
+
status = 'need_qr_scan';
|
|
285
|
+
reason = 'need_qr_scan';
|
|
286
|
+
} else if (result && result.status === 'need_codex_browser_login') {
|
|
287
|
+
status = 'need_browser_login';
|
|
288
|
+
reason = 'need_browser_login';
|
|
289
289
|
} else if (result && result.status === 'need_corp_selection') {
|
|
290
290
|
status = 'success';
|
|
291
291
|
reason = 'need_corp_selection';
|
|
@@ -306,6 +306,40 @@ function noteLoginCommandResult(result) {
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
function isAgentConversationEnvironment() {
|
|
310
|
+
const { detectActiveTool } = require('../lib/core/utils');
|
|
311
|
+
return !!detectActiveTool() || process.env.OPENYIDA_AGENT_MODE === '1';
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function shouldUseBrowserHandoffLogin(cliArgs) {
|
|
315
|
+
if (cliArgs.includes('--qr') || cliArgs.includes('--codex-qr') || cliArgs.includes('--agent-qr')) {return false;}
|
|
316
|
+
if (cliArgs.includes('--browser') || cliArgs.includes('--codex') || cliArgs.includes('--qoder') || cliArgs.includes('--wukong')) {return true;}
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function shouldUseAgentLogin(cliArgs) {
|
|
321
|
+
if (cliArgs.includes('--qr') || cliArgs.includes('--codex-qr') || cliArgs.includes('--agent-qr')) {return false;}
|
|
322
|
+
if (shouldUseBrowserHandoffLogin(cliArgs)) {return false;}
|
|
323
|
+
return isAgentConversationEnvironment();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function shouldUsePlaywrightFallbackInAgentLogin() {
|
|
327
|
+
const { hasDesktopEnvironment } = require('../lib/core/utils');
|
|
328
|
+
return hasDesktopEnvironment() || process.env.OPENYIDA_AGENT_PLAYWRIGHT_FALLBACK === '1';
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function shouldUseLocalBrowserLogin(options = {}) {
|
|
332
|
+
const { hasLocalBrowserLoginCapability } = require('../lib/auth/login');
|
|
333
|
+
return hasLocalBrowserLoginCapability({
|
|
334
|
+
playwrightFallback: options.playwrightFallback,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function shouldUseCodexQrLogin(cliArgs) {
|
|
339
|
+
if (cliArgs.includes('--codex-qr') || cliArgs.includes('--agent-qr')) {return true;}
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
|
|
309
343
|
function getArgValue(cliArgs, name) {
|
|
310
344
|
const index = cliArgs.indexOf(name);
|
|
311
345
|
if (index === -1 || !cliArgs[index + 1] || cliArgs[index + 1].startsWith('--')) {
|
|
@@ -380,9 +414,11 @@ function applyLoginEnvironmentFlags(cliArgs, options = {}) {
|
|
|
380
414
|
'--intranet': 'alibaba',
|
|
381
415
|
};
|
|
382
416
|
const valuePassthroughFlags = new Set([
|
|
417
|
+
'--agent-poll',
|
|
418
|
+
'--codex-poll',
|
|
419
|
+
'--agent-select',
|
|
420
|
+
'--codex-select',
|
|
383
421
|
'--corp-id',
|
|
384
|
-
'--client-id',
|
|
385
|
-
'--user-id',
|
|
386
422
|
]);
|
|
387
423
|
const targetUrlFlags = new Set([
|
|
388
424
|
'--endpoint',
|
|
@@ -527,42 +563,129 @@ async function main() {
|
|
|
527
563
|
}
|
|
528
564
|
|
|
529
565
|
case 'login': {
|
|
566
|
+
const { checkLoginOnly } = require('../lib/auth/login');
|
|
530
567
|
const loginArgs = applyLoginEnvironmentFlags(args, { inferTargetUrl: true });
|
|
531
|
-
const {
|
|
532
|
-
if (loginArgs.includes('--
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
const result = await
|
|
536
|
-
|
|
537
|
-
quiet: loginArgs.includes('--quiet'),
|
|
568
|
+
const { isEnvAuthMode } = require('../lib/core/utils');
|
|
569
|
+
if (loginArgs.includes('--agent-poll') || loginArgs.includes('--codex-poll')) {
|
|
570
|
+
const sessionFile = getArgValue(loginArgs, '--agent-poll') || getArgValue(loginArgs, '--codex-poll');
|
|
571
|
+
const { pollCodexQrLogin } = require('../lib/auth/qr-login');
|
|
572
|
+
const result = await pollCodexQrLogin(sessionFile, {
|
|
573
|
+
corpId: getArgValue(loginArgs, '--corp-id'),
|
|
538
574
|
});
|
|
539
575
|
printLoginResult(result);
|
|
576
|
+
} else if (loginArgs.includes('--agent-select') || loginArgs.includes('--codex-select')) {
|
|
577
|
+
const sessionFile = getArgValue(loginArgs, '--agent-select') || getArgValue(loginArgs, '--codex-select');
|
|
578
|
+
const { selectCodexQrCorp } = require('../lib/auth/qr-login');
|
|
579
|
+
const result = await selectCodexQrCorp(sessionFile, {
|
|
580
|
+
corpId: getArgValue(loginArgs, '--corp-id'),
|
|
581
|
+
});
|
|
582
|
+
printLoginResult(result);
|
|
583
|
+
} else if (loginArgs.includes('--check-only')) {
|
|
584
|
+
const result = checkLoginOnly({ includeSecrets: loginArgs.includes('--with-cookies') });
|
|
585
|
+
console.log(JSON.stringify(result, null, 2));
|
|
586
|
+
} else if (isEnvAuthMode()) {
|
|
587
|
+
const result = checkLoginOnly({ includeSecrets: true });
|
|
588
|
+
printLoginResult(result);
|
|
589
|
+
} else if (shouldUseCodexQrLogin(loginArgs)) {
|
|
590
|
+
const { startCodexQrLogin } = require('../lib/auth/qr-login');
|
|
591
|
+
const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
592
|
+
printLoginResult(result);
|
|
593
|
+
} else if (loginArgs.includes('--browser')) {
|
|
594
|
+
const { interactiveLogin } = require('../lib/auth/login');
|
|
595
|
+
const result = interactiveLogin({ force: true });
|
|
596
|
+
printLoginResult(result);
|
|
597
|
+
} else if (loginArgs.includes('--qoder') || loginArgs.includes('--wukong')) {
|
|
598
|
+
const { codexLogin } = require('../lib/auth/codex-login');
|
|
599
|
+
const result = await codexLogin({ tool: loginArgs.includes('--qoder') ? 'qoder' : 'wukong' });
|
|
600
|
+
printLoginResult(result);
|
|
601
|
+
} else if (loginArgs.includes('--qr')) {
|
|
602
|
+
const { qrLogin } = require('../lib/auth/qr-login');
|
|
603
|
+
const result = await qrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
604
|
+
printLoginResult(result);
|
|
605
|
+
} else if (shouldUseAgentLogin(loginArgs)) {
|
|
606
|
+
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
607
|
+
if (cachedResult.status === 'ok') {
|
|
608
|
+
printLoginResult(cachedResult);
|
|
609
|
+
} else {
|
|
610
|
+
const { interactiveLogin } = require('../lib/auth/login');
|
|
611
|
+
const playwrightFallback = shouldUsePlaywrightFallbackInAgentLogin();
|
|
612
|
+
const browserResult = shouldUseLocalBrowserLogin({ playwrightFallback })
|
|
613
|
+
? interactiveLogin({ playwrightFallback })
|
|
614
|
+
: null;
|
|
615
|
+
if (browserResult) {
|
|
616
|
+
printLoginResult(browserResult);
|
|
617
|
+
} else {
|
|
618
|
+
const { startCodexQrLogin } = require('../lib/auth/qr-login');
|
|
619
|
+
const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
620
|
+
printLoginResult(result);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
} else if (shouldUseBrowserHandoffLogin(loginArgs)) {
|
|
624
|
+
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
625
|
+
if (cachedResult.status === 'ok') {
|
|
626
|
+
printLoginResult(cachedResult);
|
|
627
|
+
} else {
|
|
628
|
+
const { codexLogin } = require('../lib/auth/codex-login');
|
|
629
|
+
const result = await codexLogin({ tool: loginArgs.includes('--codex') ? 'codex' : undefined });
|
|
630
|
+
printLoginResult(result);
|
|
631
|
+
}
|
|
632
|
+
} else {
|
|
633
|
+
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
634
|
+
if (cachedResult.status === 'ok') {
|
|
635
|
+
printLoginResult(cachedResult);
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
if (shouldUseLocalBrowserLogin({ playwrightFallback: true })) {
|
|
639
|
+
const { interactiveLogin } = require('../lib/auth/login');
|
|
640
|
+
const browserResult = interactiveLogin({ playwrightFallback: true });
|
|
641
|
+
if (browserResult) {
|
|
642
|
+
printLoginResult(browserResult);
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
const { qrLogin } = require('../lib/auth/qr-login');
|
|
647
|
+
const result = await qrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
648
|
+
printLoginResult(result);
|
|
540
649
|
}
|
|
541
650
|
break;
|
|
542
651
|
}
|
|
543
652
|
|
|
544
653
|
case 'logout': {
|
|
545
|
-
const {
|
|
546
|
-
|
|
654
|
+
const { logout } = require('../lib/auth/login');
|
|
655
|
+
logout();
|
|
547
656
|
break;
|
|
548
657
|
}
|
|
549
658
|
|
|
550
659
|
case 'auth': {
|
|
551
660
|
const subCommand = args[0];
|
|
552
|
-
const
|
|
553
|
-
|
|
661
|
+
const { authStatus, authLogin, authRefresh, authLogout } = require('../lib/auth/auth');
|
|
662
|
+
|
|
554
663
|
if (subCommand === 'status') {
|
|
555
|
-
|
|
664
|
+
authStatus();
|
|
556
665
|
} else if (subCommand === 'login') {
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
666
|
+
const authArgs = applyLoginEnvironmentFlags(args.slice(1), { inferTargetUrl: true });
|
|
667
|
+
let loginType = 'qrcode';
|
|
668
|
+
if (authArgs.includes('--codex')) {
|
|
669
|
+
loginType = 'codex';
|
|
670
|
+
} else if (authArgs.includes('--qoder')) {
|
|
671
|
+
loginType = 'qoder';
|
|
672
|
+
} else if (authArgs.includes('--wukong')) {
|
|
673
|
+
loginType = 'wukong';
|
|
674
|
+
} else if (authArgs.includes('--browser')) {
|
|
675
|
+
loginType = 'browser';
|
|
676
|
+
}
|
|
677
|
+
const result = await authLogin({
|
|
678
|
+
type: loginType,
|
|
679
|
+
corpId: getArgValue(authArgs, '--corp-id'),
|
|
680
|
+
forceTerminalQr: authArgs.includes('--qr'),
|
|
560
681
|
});
|
|
561
|
-
|
|
682
|
+
if (result) {
|
|
683
|
+
printLoginResult(result);
|
|
684
|
+
}
|
|
562
685
|
} else if (subCommand === 'refresh') {
|
|
563
|
-
|
|
686
|
+
authRefresh();
|
|
564
687
|
} else if (subCommand === 'logout') {
|
|
565
|
-
|
|
688
|
+
authLogout();
|
|
566
689
|
} else {
|
|
567
690
|
throwCliUsage(t('cli.auth_usage'), t('cli.auth_example'));
|
|
568
691
|
}
|
|
@@ -570,9 +693,34 @@ async function main() {
|
|
|
570
693
|
}
|
|
571
694
|
|
|
572
695
|
case 'org': {
|
|
573
|
-
const
|
|
574
|
-
const {
|
|
575
|
-
|
|
696
|
+
const subCommand = args[0];
|
|
697
|
+
const { listOrganizations, switchOrganization, interactiveSwitch } = require('../lib/auth/org');
|
|
698
|
+
const { loadCookieData } = require('../lib/core/utils');
|
|
699
|
+
|
|
700
|
+
if (subCommand === 'list') {
|
|
701
|
+
const cookieData = loadCookieData();
|
|
702
|
+
if (!cookieData || !cookieData.cookies) {
|
|
703
|
+
throwNeedLogin(t('org.no_login'));
|
|
704
|
+
}
|
|
705
|
+
await listOrganizations(cookieData);
|
|
706
|
+
} else if (subCommand === 'switch') {
|
|
707
|
+
const cookieData = loadCookieData();
|
|
708
|
+
if (!cookieData || !cookieData.cookies) {
|
|
709
|
+
throwNeedLogin(t('org.no_login'));
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// 解析 --corp-id 参数
|
|
713
|
+
const corpIdIndex = args.indexOf('--corp-id');
|
|
714
|
+
if (corpIdIndex !== -1 && args[corpIdIndex + 1]) {
|
|
715
|
+
const targetCorpId = args[corpIdIndex + 1];
|
|
716
|
+
await switchOrganization(targetCorpId, cookieData);
|
|
717
|
+
} else {
|
|
718
|
+
// 交互式选择
|
|
719
|
+
await interactiveSwitch(cookieData);
|
|
720
|
+
}
|
|
721
|
+
} else {
|
|
722
|
+
throwCliUsage(t('cli.org_usage'), t('cli.org_example'));
|
|
723
|
+
}
|
|
576
724
|
break;
|
|
577
725
|
}
|
|
578
726
|
|
package/lib/agent-center/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { createAuthRef, createYidaClient
|
|
3
|
+
const { createAuthRef, createYidaClient } = require('../core/yida-client');
|
|
4
4
|
|
|
5
5
|
const AGENT_TYPE_ALIASES = {
|
|
6
6
|
normal: 'NORMAL',
|
|
@@ -70,7 +70,7 @@ const AGENT_RANGE_ALIASES = {
|
|
|
70
70
|
|
|
71
71
|
function getAuthRef() {
|
|
72
72
|
const authRef = createAuthRef();
|
|
73
|
-
if (!
|
|
73
|
+
if (!authRef.cookies || !authRef.cookies.length || !authRef.csrfToken) {
|
|
74
74
|
throw new Error('无法获取有效登录态或 CSRF Token');
|
|
75
75
|
}
|
|
76
76
|
return authRef;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const querystring = require('querystring');
|
|
5
5
|
|
|
6
|
-
const { createAuthRef: createCoreAuthRef, createYidaClient
|
|
6
|
+
const { createAuthRef: createCoreAuthRef, createYidaClient } = require('../core/yida-client');
|
|
7
7
|
const { t } = require('../core/i18n');
|
|
8
8
|
const { buildYidaTitleI18n, normalizeYidaLocale, resolveContentLocale } = require('../core/yida-i18n');
|
|
9
9
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
@@ -97,7 +97,7 @@ function assertSuccess(result, action) {
|
|
|
97
97
|
|
|
98
98
|
async function createAuthRef() {
|
|
99
99
|
const authRef = createCoreAuthRef();
|
|
100
|
-
if (!
|
|
100
|
+
if (!authRef.cookies || authRef.cookies.length === 0) {
|
|
101
101
|
throw new Error(t('aggregate_table.no_login'));
|
|
102
102
|
}
|
|
103
103
|
return authRef;
|
package/lib/ai/ai.js
CHANGED
|
@@ -15,7 +15,7 @@ const {
|
|
|
15
15
|
findProjectRoot,
|
|
16
16
|
} = require('../core/utils');
|
|
17
17
|
const { CliError } = require('../core/cli-error');
|
|
18
|
-
const { createAuthRef, createYidaClient
|
|
18
|
+
const { createAuthRef, createYidaClient } = require('../core/yida-client');
|
|
19
19
|
|
|
20
20
|
const DEFAULT_MAX_TOKENS = 3000;
|
|
21
21
|
const DEFAULT_IMAGE_CONNECTOR = {
|
|
@@ -46,7 +46,7 @@ function printHelp() {
|
|
|
46
46
|
image 上传本地图片并调用识图连接器;也可直接传入 --image-url
|
|
47
47
|
|
|
48
48
|
image 选项:
|
|
49
|
-
--app-type <APP_XXX> 上传图片使用的宜搭应用 ID;未传时尝试读取当前 project/config.json
|
|
49
|
+
--app-type <APP_XXX> 上传图片使用的宜搭应用 ID;未传时尝试读取当前 project/config.json 或 Cookie
|
|
50
50
|
--form-uuid <FORM_XXX> 可选,上传回调关联的表单 ID
|
|
51
51
|
--connector-id <id> 识图 HTTP 连接器 ID,默认使用 HAR 中的植物识别连接器
|
|
52
52
|
--action-id <id> 识图动作 ID,默认 flowerrecognize
|
|
@@ -146,7 +146,7 @@ function getAuthRef(options = {}) {
|
|
|
146
146
|
if (options.baseUrl) {
|
|
147
147
|
authRef.baseUrl = options.baseUrl;
|
|
148
148
|
}
|
|
149
|
-
if (!
|
|
149
|
+
if (!authRef.cookies || authRef.cookies.length === 0 || !authRef.csrfToken) {
|
|
150
150
|
throw new CliError('未获取到有效宜搭登录态,请先执行 openyida login', {
|
|
151
151
|
code: 'NEED_LOGIN',
|
|
152
152
|
});
|
|
@@ -154,7 +154,12 @@ function getAuthRef(options = {}) {
|
|
|
154
154
|
return authRef;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
function
|
|
157
|
+
function getCookieValue(authRef, name) {
|
|
158
|
+
const matched = (authRef.cookies || []).filter(cookie => cookie.name === name);
|
|
159
|
+
return matched.length ? matched[0].value : '';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function inferAppType(options, authRef) {
|
|
158
163
|
if (options.appType) {
|
|
159
164
|
return options.appType;
|
|
160
165
|
}
|
|
@@ -168,11 +173,11 @@ function inferAppType(options) {
|
|
|
168
173
|
return config.appType;
|
|
169
174
|
}
|
|
170
175
|
} catch {
|
|
171
|
-
// ignore invalid local config and continue with
|
|
176
|
+
// ignore invalid local config and continue with cookie fallback
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
179
|
|
|
175
|
-
return '';
|
|
180
|
+
return getCookieValue(authRef, 'tianshu_app_type');
|
|
176
181
|
}
|
|
177
182
|
|
|
178
183
|
function getSuccessContent(response, fallbackMessage, code = 'AI_REQUEST_FAILED') {
|
|
@@ -329,7 +334,7 @@ async function uploadImageForAI(filePath, options, authRef) {
|
|
|
329
334
|
});
|
|
330
335
|
}
|
|
331
336
|
|
|
332
|
-
const appType = inferAppType(options);
|
|
337
|
+
const appType = inferAppType(options, authRef);
|
|
333
338
|
if (!appType) {
|
|
334
339
|
throw new CliError('上传图片需要 appType,请传入 --app-type APP_XXX', {
|
|
335
340
|
code: 'AI_IMAGE_APP_TYPE_REQUIRED',
|
|
@@ -273,8 +273,8 @@ function compileCanvasLocal(source) {
|
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
/**
|
|
276
|
-
*
|
|
277
|
-
* 本地编译不需要 endpoint,options 保留但忽略。
|
|
276
|
+
* 兼容既有调用方(publish.js `await compileCanvas(src, { cookies })`)的异步入口。
|
|
277
|
+
* 本地编译不需要 cookies/endpoint,options 保留但忽略。
|
|
278
278
|
* @param {string} source
|
|
279
279
|
* @param {object} [options] 兼容占位,未使用
|
|
280
280
|
* @returns {Promise<{ runtimeCode: string, importedModules: string }>}
|
package/lib/app/create-app.js
CHANGED
|
@@ -10,10 +10,12 @@ const fs = require('fs');
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const querystring = require('querystring');
|
|
12
12
|
const {
|
|
13
|
+
loadCookieData,
|
|
14
|
+
triggerLogin,
|
|
15
|
+
resolveBaseUrl,
|
|
13
16
|
httpPost,
|
|
14
17
|
requestWithAutoLogin,
|
|
15
18
|
} = require('../core/utils');
|
|
16
|
-
const { createAuthRef } = require('../core/yida-client');
|
|
17
19
|
const { t } = require('../core/i18n');
|
|
18
20
|
const { buildYidaI18n, normalizeYidaLocale, resolveContentLocale } = require('../core/yida-i18n');
|
|
19
21
|
const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
|
|
@@ -230,7 +232,18 @@ async function run(args) {
|
|
|
230
232
|
|
|
231
233
|
// Step 1: 读取登录态
|
|
232
234
|
step(1, t('common.step_login', 1));
|
|
233
|
-
|
|
235
|
+
let cookieData = loadCookieData();
|
|
236
|
+
if (!cookieData) {
|
|
237
|
+
info(t('common.login_no_cache'));
|
|
238
|
+
cookieData = triggerLogin();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const authRef = {
|
|
242
|
+
csrfToken: cookieData.csrf_token,
|
|
243
|
+
cookies: cookieData.cookies,
|
|
244
|
+
baseUrl: resolveBaseUrl(cookieData),
|
|
245
|
+
cookieData,
|
|
246
|
+
};
|
|
234
247
|
chalkSuccess(t('common.login_ready', authRef.baseUrl));
|
|
235
248
|
|
|
236
249
|
const contentLocale = resolveContentLocale({ locale: params.locale, baseUrl: authRef.baseUrl });
|
|
@@ -247,7 +260,8 @@ async function run(args) {
|
|
|
247
260
|
const corpConfig = await httpPost(
|
|
248
261
|
authRef.baseUrl,
|
|
249
262
|
`/query/exclusive/queryCorpAppConfig.json?_api=Global.queryCorpAppConfig&_mock=false&_csrf_token=${authRef.csrfToken}&_locale_time_zone_offset=28800000&_stamp=${Date.now()}`,
|
|
250
|
-
''
|
|
263
|
+
'',
|
|
264
|
+
authRef.cookies
|
|
251
265
|
);
|
|
252
266
|
if (corpConfig && corpConfig.content) {
|
|
253
267
|
if (corpConfig.content.forceExclusiveDb === 'y') {openExclusive = 'y';}
|
|
@@ -275,14 +289,14 @@ async function run(args) {
|
|
|
275
289
|
openExclusiveUnit: 'n',
|
|
276
290
|
group: 'ALL',
|
|
277
291
|
});
|
|
278
|
-
return httpPost(auth.baseUrl, '/query/app/registerApp.json', postData);
|
|
292
|
+
return httpPost(auth.baseUrl, '/query/app/registerApp.json', postData, auth.cookies);
|
|
279
293
|
}, authRef);
|
|
280
294
|
|
|
281
295
|
// 输出结果
|
|
282
296
|
if (response && response.success && response.content) {
|
|
283
297
|
const appType = response.content;
|
|
284
298
|
const appUrl = `${authRef.baseUrl}/${appType}/admin`;
|
|
285
|
-
const corpId = authRef.
|
|
299
|
+
const corpId = authRef.cookieData.corp_id || '';
|
|
286
300
|
|
|
287
301
|
chalkResult(true, t('create_app.success'), [
|
|
288
302
|
['appType', appType],
|