yidaconnector 2026.6.11
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/LICENSE +21 -0
- package/README.md +383 -0
- package/bin/yida.js +670 -0
- package/lib/app/form-navigation.js +58 -0
- package/lib/app/get-schema.js +538 -0
- package/lib/auth/auth.js +294 -0
- package/lib/auth/cdp-browser-login.js +390 -0
- package/lib/auth/codex-login.js +71 -0
- package/lib/auth/login.js +475 -0
- package/lib/auth/org.js +363 -0
- package/lib/auth/qr-login.js +1563 -0
- package/lib/core/chalk.js +384 -0
- package/lib/core/check-update.js +82 -0
- package/lib/core/cli-error.js +39 -0
- package/lib/core/command-manifest.js +106 -0
- package/lib/core/env-cmd.js +545 -0
- package/lib/core/env-manager.js +601 -0
- package/lib/core/env.js +287 -0
- package/lib/core/i18n.js +177 -0
- package/lib/core/locales/ar.js +805 -0
- package/lib/core/locales/de.js +805 -0
- package/lib/core/locales/en.js +1623 -0
- package/lib/core/locales/es.js +805 -0
- package/lib/core/locales/fr.js +805 -0
- package/lib/core/locales/hi.js +805 -0
- package/lib/core/locales/ja.js +1197 -0
- package/lib/core/locales/ko.js +807 -0
- package/lib/core/locales/pt.js +805 -0
- package/lib/core/locales/vi.js +805 -0
- package/lib/core/locales/zh-HK.js +1233 -0
- package/lib/core/locales/zh.js +1584 -0
- package/lib/core/query-data.js +781 -0
- package/lib/core/redact.js +100 -0
- package/lib/core/utils.js +799 -0
- package/lib/core/yida-client.js +117 -0
- package/package.json +94 -0
- package/project/config.json +4 -0
- package/project/pages/src/demo-birthday-game.oyd.jsx +832 -0
- package/project/pages/src/demo-chip-insight.oyd.jsx +983 -0
- package/project/pages/src/demo-compat-smoke.oyd.jsx +58 -0
- package/project/pages/src/demo-crm-batch-entry.oyd.jsx +805 -0
- package/project/pages/src/demo-crm-dashboard.oyd.jsx +677 -0
- package/project/pages/src/demo-future-vision-2026.oyd.jsx +1102 -0
- package/project/pages/src/demo-ppt.oyd.jsx +1192 -0
- package/project/pages/src/demo-salary-calculator.oyd.jsx +904 -0
- package/project/pages/src/yidaconnector-knowledge-doc.oyd.jsx +1714 -0
- package/project/prd/demo-birthday-game.md +39 -0
- package/project/prd/demo-crm.md +463 -0
- package/project/prd/demo-dingtalk-ai-solution-center.md +425 -0
- package/project/prd/demo-future-vision-2026.md +78 -0
- package/project/prd/demo-salary-calculator.md +101 -0
- package/scripts/build-skills-package.js +406 -0
- package/scripts/check-syntax.js +59 -0
- package/scripts/demo-dws.sh +106 -0
- package/scripts/e2e-real/cleanup.js +67 -0
- package/scripts/e2e-real/fixtures/form-fields.json +18 -0
- package/scripts/e2e-real/full-runner.js +1566 -0
- package/scripts/e2e-real/runner.js +293 -0
- package/scripts/e2e-real/skill-coverage.js +115 -0
- package/scripts/generate-command-docs.js +109 -0
- package/scripts/nightly-smoke.js +134 -0
- package/scripts/postinstall.js +545 -0
- package/scripts/solution-center-runner.js +368 -0
- package/scripts/validate-ci.sh +50 -0
- package/scripts/validate-command-manifest.js +119 -0
- package/scripts/validate-package-size.js +78 -0
- package/scripts/validate-skills.js +247 -0
- package/scripts/validate-structure.js +66 -0
- package/yida-skills/SKILL.md +163 -0
- package/yida-skills/references/yida-api.md +1309 -0
- package/yida-skills/skills/large-file-write/SKILL.md +91 -0
- package/yida-skills/skills/large-file-write/references/write-patterns.md +149 -0
- package/yida-skills/skills/large-file-write/scripts/write.js +157 -0
- package/yida-skills/skills/yida-data-management/SKILL.md +252 -0
- package/yida-skills/skills/yida-data-management/references/api-matrix.md +49 -0
- package/yida-skills/skills/yida-data-management/references/data-format-guide.md +159 -0
- package/yida-skills/skills/yida-data-management/references/verified-endpoints.md +62 -0
- package/yida-skills/skills/yida-login/SKILL.md +159 -0
- package/yida-skills/skills/yida-logout/SKILL.md +67 -0
package/bin/yida.js
ADDED
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* yidaconnector - 宜搭命令行工具
|
|
4
|
+
*
|
|
5
|
+
* 安装:npm install -g yidaconnector
|
|
6
|
+
* 用法:yidaconnector <命令> [参数](别名:yida)
|
|
7
|
+
*
|
|
8
|
+
* 命令清单维护在 lib/core/command-manifest.js,供 help 和 agent JSON 共用。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const { version: currentVersion } = require('../package.json');
|
|
14
|
+
const { t } = require('../lib/core/i18n');
|
|
15
|
+
const { warn } = require('../lib/core/chalk');
|
|
16
|
+
const { CliError, isCliError, toErrorPayload } = require('../lib/core/cli-error');
|
|
17
|
+
const { COMMAND_GROUPS, buildCommandManifest } = require('../lib/core/command-manifest');
|
|
18
|
+
|
|
19
|
+
const command = process.argv[2];
|
|
20
|
+
const args = process.argv.slice(3);
|
|
21
|
+
|
|
22
|
+
function isAgentEnvironment(env) {
|
|
23
|
+
return !!(
|
|
24
|
+
env.CODEX_SHELL ||
|
|
25
|
+
env.CODEX_CI ||
|
|
26
|
+
env.CODEX_THREAD_ID ||
|
|
27
|
+
env.CODEX_HOME ||
|
|
28
|
+
env.CLAUDE_CODE ||
|
|
29
|
+
env.CLAUDE_CODE_ENTRYPOINT ||
|
|
30
|
+
env.OPENCODE ||
|
|
31
|
+
env.OPENCODE_CLIENT ||
|
|
32
|
+
env.QODER_IDE ||
|
|
33
|
+
env.QODER_AGENT ||
|
|
34
|
+
env.QODERCLI_INTEGRATION_MODE ||
|
|
35
|
+
env.CURSOR_TRACE_ID ||
|
|
36
|
+
env.AGENT_WORK_ROOT ||
|
|
37
|
+
env.YIDACONNECTOR_AGENT_MODE ||
|
|
38
|
+
(env.__CFBundleIdentifier || '').toLowerCase().includes('codex') ||
|
|
39
|
+
(env.__CFBundleIdentifier || '').toLowerCase().includes('qoder')
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function shouldRunUpdateCheck() {
|
|
44
|
+
if (process.env.YIDACONNECTOR_SKIP_UPDATE_CHECK || process.env.NO_UPDATE_NOTIFIER) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (process.env.CI || isAgentEnvironment(process.env)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if (!process.stderr.isTTY) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (!command || command === '--help' || command === '-h' || command === '--version' || command === '-v') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (command === 'commands') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (args.includes('--json') || args.includes('--check-only')) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function maybeCheckForUpdate() {
|
|
66
|
+
if (!shouldRunUpdateCheck()) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const { checkUpdate } = require('../lib/core/check-update');
|
|
70
|
+
checkUpdate(currentVersion).catch(() => {});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
maybeCheckForUpdate();
|
|
74
|
+
|
|
75
|
+
function printHelp() {
|
|
76
|
+
const RESET = '\x1b[0m';
|
|
77
|
+
const BOLD = '\x1b[1m';
|
|
78
|
+
const DIM = '\x1b[2m';
|
|
79
|
+
const CYAN = '\x1b[36m';
|
|
80
|
+
const GREEN = '\x1b[32m';
|
|
81
|
+
const YELLOW = '\x1b[33m';
|
|
82
|
+
|
|
83
|
+
const SEP = `${DIM}${'─'.repeat(60)}${RESET}`;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 渲染一组命令列表。
|
|
87
|
+
* @param {string} groupTitle - 分组标题
|
|
88
|
+
* @param {Array<[string, string]>} commands - [命令, 描述] 数组
|
|
89
|
+
*/
|
|
90
|
+
function renderGroup(groupTitle, commands) {
|
|
91
|
+
console.log(`\n ${BOLD}${CYAN}${groupTitle}${RESET}`);
|
|
92
|
+
const maxCmdLen = Math.max(...commands.map(([cmd]) => cmd.length));
|
|
93
|
+
const padWidth = Math.min(maxCmdLen + 2, 50);
|
|
94
|
+
for (const [cmd, desc] of commands) {
|
|
95
|
+
if (cmd.length >= padWidth) {
|
|
96
|
+
console.log(` ${GREEN}${cmd}${RESET}`);
|
|
97
|
+
console.log(` ${DIM}${desc}${RESET}`);
|
|
98
|
+
} else {
|
|
99
|
+
console.log(` ${GREEN}${cmd.padEnd(padWidth)}${RESET}${DIM}${desc}${RESET}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ── 标题 ──
|
|
105
|
+
console.log('');
|
|
106
|
+
console.log(` ${BOLD}${CYAN}YidaConnector${RESET} ${DIM}v${currentVersion}${RESET}`);
|
|
107
|
+
console.log(` ${DIM}${t('help.subtitle')}${RESET}`);
|
|
108
|
+
console.log(` ${DIM}"We are on the verge of the Singularity"${RESET}`);
|
|
109
|
+
console.log('');
|
|
110
|
+
console.log(` ${YELLOW}${t('help.usage')}${RESET} yidaconnector <command> [args...]`);
|
|
111
|
+
console.log(` ${DIM}${t('help.alias')}${RESET} yida`);
|
|
112
|
+
console.log(SEP);
|
|
113
|
+
|
|
114
|
+
for (const group of COMMAND_GROUPS) {
|
|
115
|
+
renderGroup(
|
|
116
|
+
t(group.titleKey),
|
|
117
|
+
group.commands
|
|
118
|
+
.filter(entry => !entry.hidden)
|
|
119
|
+
.map(entry => [entry.usage, t(entry.descriptionKey)])
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ── 快速上手 ──
|
|
124
|
+
console.log(SEP);
|
|
125
|
+
console.log(`\n ${BOLD}${CYAN}${t('help.quickstart_title')}${RESET}`);
|
|
126
|
+
console.log(` ${DIM}${RESET} yidaconnector data query form APP_XXX FORM_XXX --page 1 --size 20`);
|
|
127
|
+
console.log('');
|
|
128
|
+
console.log(` ${DIM}${t('help.docs')} https://github.com/bunnyrui/yidaconnector${RESET}`);
|
|
129
|
+
console.log('');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* 检测是否首次运行(安装后第一次执行 yidaconnector 命令)。
|
|
134
|
+
* 通过 ~/.yidaconnector/first-run-done 标记文件判断。
|
|
135
|
+
* 若是首次运行,打印新手引导并写入标记文件。
|
|
136
|
+
*/
|
|
137
|
+
function handleFirstRunGuide() {
|
|
138
|
+
const os = require('os');
|
|
139
|
+
const path = require('path');
|
|
140
|
+
const fs = require('fs');
|
|
141
|
+
|
|
142
|
+
const YIDACONNECTOR_DIR = path.join(os.homedir(), '.yidaconnector');
|
|
143
|
+
const FIRST_RUN_FLAG = path.join(YIDACONNECTOR_DIR, 'first-run-done');
|
|
144
|
+
|
|
145
|
+
// 已运行过,跳过引导
|
|
146
|
+
if (fs.existsSync(FIRST_RUN_FLAG)) {return;}
|
|
147
|
+
|
|
148
|
+
// 写入标记,避免重复展示
|
|
149
|
+
try {
|
|
150
|
+
fs.mkdirSync(YIDACONNECTOR_DIR, { recursive: true });
|
|
151
|
+
fs.writeFileSync(FIRST_RUN_FLAG, new Date().toISOString(), 'utf8');
|
|
152
|
+
} catch {
|
|
153
|
+
// 写入失败不影响主流程
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const RESET = '\x1b[0m';
|
|
157
|
+
const BOLD = '\x1b[1m';
|
|
158
|
+
const DIM = '\x1b[2m';
|
|
159
|
+
const CYAN = '\x1b[36m';
|
|
160
|
+
const GREEN = '\x1b[32m';
|
|
161
|
+
const YELLOW = '\x1b[33m';
|
|
162
|
+
const BLUE = '\x1b[34m';
|
|
163
|
+
const MAGENTA = '\x1b[35m';
|
|
164
|
+
const BG_CYAN = '\x1b[46m';
|
|
165
|
+
const WHITE = '\x1b[37m';
|
|
166
|
+
|
|
167
|
+
const SEP = `${DIM}${'─'.repeat(60)}${RESET}`;
|
|
168
|
+
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(`${BG_CYAN}${WHITE}${BOLD}${t('cli.first_run_title')}${RESET}`);
|
|
171
|
+
console.log(SEP);
|
|
172
|
+
console.log(t('cli.first_run_welcome', `${GREEN}${BOLD}`, RESET));
|
|
173
|
+
console.log('');
|
|
174
|
+
console.log(`${BOLD}${CYAN}${t('cli.first_run_way1_title')}${RESET}`);
|
|
175
|
+
console.log(t('cli.first_run_way1_desc'));
|
|
176
|
+
console.log('');
|
|
177
|
+
console.log(` ${YELLOW}${t('cli.first_run_prompt1')}${RESET}`);
|
|
178
|
+
console.log(` ${YELLOW}${t('cli.first_run_prompt2')}${RESET}`);
|
|
179
|
+
console.log(` ${YELLOW}${t('cli.first_run_prompt3')}${RESET}`);
|
|
180
|
+
console.log('');
|
|
181
|
+
console.log(`${BOLD}${CYAN}${t('cli.first_run_way2_title')}${RESET}`);
|
|
182
|
+
console.log('');
|
|
183
|
+
console.log(` ${YELLOW}${t('cli.first_run_prompt4')}${RESET}`);
|
|
184
|
+
console.log('');
|
|
185
|
+
console.log(`${BOLD}${CYAN}${t('cli.first_run_examples_title')}${RESET}`);
|
|
186
|
+
console.log('');
|
|
187
|
+
console.log(` ${MAGENTA}•${RESET} ${t('cli.first_run_examples')}`);
|
|
188
|
+
console.log('');
|
|
189
|
+
console.log(SEP);
|
|
190
|
+
console.log(`${BOLD}${BLUE}${t('cli.first_run_tips_title')}${RESET}`);
|
|
191
|
+
console.log('');
|
|
192
|
+
console.log(t('cli.first_run_tip1', CYAN, RESET));
|
|
193
|
+
console.log(t('cli.first_run_tip2', CYAN, RESET));
|
|
194
|
+
console.log(t('cli.first_run_tip3'));
|
|
195
|
+
console.log('');
|
|
196
|
+
console.log(SEP);
|
|
197
|
+
console.log(` ${DIM}${t('cli.first_run_footer1')}${RESET}`);
|
|
198
|
+
console.log(` ${DIM}${t('cli.first_run_footer2')}${RESET}`);
|
|
199
|
+
console.log('');
|
|
200
|
+
console.log(` ${DIM}${t('cli.first_run_footer3')}${RESET}`);
|
|
201
|
+
console.log('');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function parseLoginTargetArg(value) {
|
|
205
|
+
const raw = String(value || '').trim();
|
|
206
|
+
if (!raw) {return null;}
|
|
207
|
+
|
|
208
|
+
const hasProtocol = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw);
|
|
209
|
+
if (!hasProtocol) {
|
|
210
|
+
if (raw.startsWith('/') || raw.startsWith('.') || raw.includes('\\')) {return null;}
|
|
211
|
+
const hostPart = raw.split('/')[0];
|
|
212
|
+
if (!hostPart.includes('.') && hostPart !== 'localhost') {return null;}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
return new URL(hasProtocol ? raw : `https://${raw}`);
|
|
217
|
+
} catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function applyLoginTargetUrl(value) {
|
|
223
|
+
const parsedUrl = parseLoginTargetArg(value);
|
|
224
|
+
if (!parsedUrl) {return false;}
|
|
225
|
+
|
|
226
|
+
const {
|
|
227
|
+
deriveBaseUrlFromDingtalkOAuthUrl,
|
|
228
|
+
inferEnvironmentNameFromUrl,
|
|
229
|
+
inferLoginUrlForBaseUrl,
|
|
230
|
+
normalizeBaseUrl,
|
|
231
|
+
normalizeHostname,
|
|
232
|
+
} = require('../lib/core/env-manager');
|
|
233
|
+
|
|
234
|
+
const targetHref = parsedUrl.href;
|
|
235
|
+
const redirectBaseUrl = deriveBaseUrlFromDingtalkOAuthUrl(targetHref, null);
|
|
236
|
+
const endpoint = normalizeBaseUrl(redirectBaseUrl || parsedUrl.origin, null);
|
|
237
|
+
const inferredEnv = inferEnvironmentNameFromUrl(redirectBaseUrl || targetHref);
|
|
238
|
+
|
|
239
|
+
if (inferredEnv) {
|
|
240
|
+
process.env.YIDACONNECTOR_ENV = inferredEnv;
|
|
241
|
+
}
|
|
242
|
+
if (endpoint) {
|
|
243
|
+
process.env.YIDACONNECTOR_ENDPOINT = endpoint;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const host = normalizeHostname(targetHref);
|
|
247
|
+
const isDingtalkLoginHost = host.endsWith('dingtalk.com') || host.endsWith('dingtalk.io');
|
|
248
|
+
const normalizedPath = parsedUrl.pathname.replace(/\/+$/, '') || '/';
|
|
249
|
+
const hasCustomLoginPath = normalizedPath !== '/' && normalizedPath !== '/workPlatform';
|
|
250
|
+
process.env.YIDACONNECTOR_LOGIN_URL = isDingtalkLoginHost || hasCustomLoginPath
|
|
251
|
+
? targetHref
|
|
252
|
+
: inferLoginUrlForBaseUrl(endpoint || parsedUrl.origin);
|
|
253
|
+
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function applyLoginEnvironmentFlags(cliArgs, options = {}) {
|
|
258
|
+
const envFlagMap = {
|
|
259
|
+
'--public': 'public',
|
|
260
|
+
'--intl': 'intl',
|
|
261
|
+
'--overseas': 'intl',
|
|
262
|
+
'--international': 'intl',
|
|
263
|
+
'--global': 'intl',
|
|
264
|
+
'--yidaapps': 'intl',
|
|
265
|
+
'--alibaba': 'alibaba',
|
|
266
|
+
'--internal': 'alibaba',
|
|
267
|
+
'--intranet': 'alibaba',
|
|
268
|
+
};
|
|
269
|
+
const valuePassthroughFlags = new Set([
|
|
270
|
+
'--agent-poll',
|
|
271
|
+
'--codex-poll',
|
|
272
|
+
'--agent-select',
|
|
273
|
+
'--codex-select',
|
|
274
|
+
'--corp-id',
|
|
275
|
+
]);
|
|
276
|
+
const targetUrlFlags = new Set([
|
|
277
|
+
'--endpoint',
|
|
278
|
+
'--base-url',
|
|
279
|
+
'--login-url',
|
|
280
|
+
]);
|
|
281
|
+
const inferTargetUrl = !!options.inferTargetUrl;
|
|
282
|
+
const filteredArgs = [];
|
|
283
|
+
|
|
284
|
+
for (let index = 0; index < cliArgs.length; index++) {
|
|
285
|
+
const arg = cliArgs[index];
|
|
286
|
+
if (arg === '--env') {
|
|
287
|
+
const envName = cliArgs[index + 1];
|
|
288
|
+
if (envName && !envName.startsWith('--')) {
|
|
289
|
+
process.env.YIDACONNECTOR_ENV = envName;
|
|
290
|
+
index++;
|
|
291
|
+
}
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (inferTargetUrl && targetUrlFlags.has(arg)) {
|
|
295
|
+
const targetUrl = cliArgs[index + 1];
|
|
296
|
+
if (targetUrl && !targetUrl.startsWith('--') && applyLoginTargetUrl(targetUrl)) {
|
|
297
|
+
index++;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (valuePassthroughFlags.has(arg)) {
|
|
302
|
+
filteredArgs.push(arg);
|
|
303
|
+
if (cliArgs[index + 1] && !cliArgs[index + 1].startsWith('--')) {
|
|
304
|
+
filteredArgs.push(cliArgs[index + 1]);
|
|
305
|
+
index++;
|
|
306
|
+
}
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (envFlagMap[arg]) {
|
|
310
|
+
process.env.YIDACONNECTOR_ENV = envFlagMap[arg];
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (inferTargetUrl && !arg.startsWith('--') && applyLoginTargetUrl(arg)) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
filteredArgs.push(arg);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return filteredArgs;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function applyGlobalEnvironmentFlags() {
|
|
323
|
+
const filteredArgs = applyLoginEnvironmentFlags(args);
|
|
324
|
+
args.splice(0, args.length, ...filteredArgs);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// 解析全局 --quiet 开关:从 args 中剔除并设置 YIDA_QUIET=1,让 chalk.js
|
|
328
|
+
// 的所有装饰输出(banner/step/info/...)变 no-op,AI 即可直接 `... --quiet | jq`。
|
|
329
|
+
function applyQuietFlag() {
|
|
330
|
+
const idx = args.indexOf('--quiet');
|
|
331
|
+
if (idx !== -1) {
|
|
332
|
+
process.env.YIDA_QUIET = '1';
|
|
333
|
+
args.splice(idx, 1);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function throwCliUsage(...lines) {
|
|
338
|
+
throw new CliError(lines.filter(Boolean).join('\n'), {
|
|
339
|
+
code: 'INVALID_ARGUMENTS',
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function throwNeedLogin(message) {
|
|
344
|
+
throw new CliError(message, {
|
|
345
|
+
code: 'NEED_LOGIN',
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function shouldUseEnvManagement(argsList) {
|
|
350
|
+
const subCommand = argsList[0];
|
|
351
|
+
return !!subCommand && subCommand !== '--json';
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function getArgValue(cliArgs, name) {
|
|
355
|
+
const index = cliArgs.indexOf(name);
|
|
356
|
+
if (index === -1 || !cliArgs[index + 1] || cliArgs[index + 1].startsWith('--')) {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
return cliArgs[index + 1];
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function isAgentConversationEnvironment() {
|
|
363
|
+
const { detectActiveTool } = require('../lib/core/utils');
|
|
364
|
+
return !!detectActiveTool() || process.env.YIDACONNECTOR_AGENT_MODE === '1';
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function shouldUseBrowserHandoffLogin(cliArgs) {
|
|
368
|
+
if (cliArgs.includes('--qr') || cliArgs.includes('--codex-qr') || cliArgs.includes('--agent-qr')) {return false;}
|
|
369
|
+
if (cliArgs.includes('--browser') || cliArgs.includes('--codex') || cliArgs.includes('--qoder') || cliArgs.includes('--wukong')) {return true;}
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function shouldUseAgentLogin(cliArgs) {
|
|
374
|
+
if (cliArgs.includes('--qr') || cliArgs.includes('--codex-qr') || cliArgs.includes('--agent-qr')) {return false;}
|
|
375
|
+
if (shouldUseBrowserHandoffLogin(cliArgs)) {return false;}
|
|
376
|
+
return isAgentConversationEnvironment();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function shouldUsePlaywrightFallbackInAgentLogin() {
|
|
380
|
+
const { hasDesktopEnvironment } = require('../lib/core/utils');
|
|
381
|
+
return hasDesktopEnvironment() || process.env.YIDACONNECTOR_AGENT_PLAYWRIGHT_FALLBACK === '1';
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function shouldUseDesktopBrowserLogin() {
|
|
385
|
+
const { hasDesktopEnvironment } = require('../lib/core/utils');
|
|
386
|
+
return hasDesktopEnvironment();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function shouldUseCodexQrLogin(cliArgs) {
|
|
390
|
+
if (cliArgs.includes('--codex-qr') || cliArgs.includes('--agent-qr')) {return true;}
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// feedback 登录死循环检测已移除(依赖已删的 feedback 模块)。
|
|
395
|
+
// 保留为 no-op,保证 printLoginResult 调用链不断裂。
|
|
396
|
+
function noteLoginCommandResult() {}
|
|
397
|
+
|
|
398
|
+
function printLoginResult(result) {
|
|
399
|
+
noteLoginCommandResult(result);
|
|
400
|
+
|
|
401
|
+
if (result && (result.status === 'need_qr_scan' || result.status === 'need_corp_selection')) {
|
|
402
|
+
console.log(JSON.stringify(result));
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (result && result.status === 'need_codex_browser_login') {
|
|
407
|
+
const handoff = {
|
|
408
|
+
status: result.status,
|
|
409
|
+
handoff_type: result.handoff_type || 'browser',
|
|
410
|
+
can_auto_use: false,
|
|
411
|
+
browser: result.browser,
|
|
412
|
+
login_url: result.login_url,
|
|
413
|
+
message: result.message,
|
|
414
|
+
};
|
|
415
|
+
[
|
|
416
|
+
'agent_action',
|
|
417
|
+
'browser_open_strategy',
|
|
418
|
+
'browser_use_local_redirect_fallback',
|
|
419
|
+
'required_agent_tool',
|
|
420
|
+
'required_runtime_tool',
|
|
421
|
+
'cookie_export_file',
|
|
422
|
+
'cookie_file',
|
|
423
|
+
'post_login_check_command',
|
|
424
|
+
'fallback_command',
|
|
425
|
+
].forEach((key) => {
|
|
426
|
+
if (result[key]) {handoff[key] = result[key];}
|
|
427
|
+
});
|
|
428
|
+
console.log(JSON.stringify(handoff));
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const summary = {
|
|
433
|
+
ok: true,
|
|
434
|
+
base_url: result && result.base_url,
|
|
435
|
+
corp_id: result && result.corp_id,
|
|
436
|
+
user_id: result && result.user_id,
|
|
437
|
+
csrf_token: result && result.csrf_token ? `${result.csrf_token.slice(0, 16)}...` : undefined,
|
|
438
|
+
cookies_count: Array.isArray(result && result.cookies) ? result.cookies.length : 0,
|
|
439
|
+
};
|
|
440
|
+
console.log(JSON.stringify(summary));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function main() {
|
|
444
|
+
applyQuietFlag();
|
|
445
|
+
applyGlobalEnvironmentFlags();
|
|
446
|
+
|
|
447
|
+
if (!command || command === '--help' || command === '-h') {
|
|
448
|
+
handleFirstRunGuide();
|
|
449
|
+
printHelp();
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (command === '--version' || command === '-v') {
|
|
454
|
+
console.log(currentVersion);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
switch (command) {
|
|
459
|
+
case 'commands': {
|
|
460
|
+
const manifest = buildCommandManifest({ t, version: currentVersion });
|
|
461
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
case 'env': {
|
|
466
|
+
if (shouldUseEnvManagement(args)) {
|
|
467
|
+
const { run } = require('../lib/core/env-cmd');
|
|
468
|
+
await run(args);
|
|
469
|
+
} else {
|
|
470
|
+
const { run } = require('../lib/core/env');
|
|
471
|
+
run(args);
|
|
472
|
+
}
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
case 'login': {
|
|
477
|
+
const { checkLoginOnly } = require('../lib/auth/login');
|
|
478
|
+
const loginArgs = applyLoginEnvironmentFlags(args, { inferTargetUrl: true });
|
|
479
|
+
if (loginArgs.includes('--agent-poll') || loginArgs.includes('--codex-poll')) {
|
|
480
|
+
const sessionFile = getArgValue(loginArgs, '--agent-poll') || getArgValue(loginArgs, '--codex-poll');
|
|
481
|
+
const { pollCodexQrLogin } = require('../lib/auth/qr-login');
|
|
482
|
+
const result = await pollCodexQrLogin(sessionFile, {
|
|
483
|
+
corpId: getArgValue(loginArgs, '--corp-id'),
|
|
484
|
+
});
|
|
485
|
+
printLoginResult(result);
|
|
486
|
+
} else if (loginArgs.includes('--agent-select') || loginArgs.includes('--codex-select')) {
|
|
487
|
+
const sessionFile = getArgValue(loginArgs, '--agent-select') || getArgValue(loginArgs, '--codex-select');
|
|
488
|
+
const { selectCodexQrCorp } = require('../lib/auth/qr-login');
|
|
489
|
+
const result = await selectCodexQrCorp(sessionFile, {
|
|
490
|
+
corpId: getArgValue(loginArgs, '--corp-id'),
|
|
491
|
+
});
|
|
492
|
+
printLoginResult(result);
|
|
493
|
+
} else if (loginArgs[0] === '--check-only') {
|
|
494
|
+
const result = checkLoginOnly({ includeSecrets: loginArgs.includes('--with-cookies') });
|
|
495
|
+
console.log(JSON.stringify(result, null, 2));
|
|
496
|
+
} else if (shouldUseCodexQrLogin(loginArgs)) {
|
|
497
|
+
const { startCodexQrLogin } = require('../lib/auth/qr-login');
|
|
498
|
+
const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
499
|
+
printLoginResult(result);
|
|
500
|
+
} else if (loginArgs.includes('--browser')) {
|
|
501
|
+
const { interactiveLogin } = require('../lib/auth/login');
|
|
502
|
+
const result = interactiveLogin({ force: true });
|
|
503
|
+
printLoginResult(result);
|
|
504
|
+
} else if (loginArgs.includes('--qoder') || loginArgs.includes('--wukong')) {
|
|
505
|
+
const { codexLogin } = require('../lib/auth/codex-login');
|
|
506
|
+
const result = await codexLogin({ tool: loginArgs.includes('--qoder') ? 'qoder' : 'wukong' });
|
|
507
|
+
printLoginResult(result);
|
|
508
|
+
} else if (loginArgs.includes('--qr')) {
|
|
509
|
+
const { qrLogin } = require('../lib/auth/qr-login');
|
|
510
|
+
const result = await qrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
511
|
+
printLoginResult(result);
|
|
512
|
+
} else if (shouldUseAgentLogin(loginArgs)) {
|
|
513
|
+
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
514
|
+
if (cachedResult.status === 'ok') {
|
|
515
|
+
printLoginResult(cachedResult);
|
|
516
|
+
} else {
|
|
517
|
+
const { detectActiveTool } = require('../lib/core/utils');
|
|
518
|
+
const activeTool = detectActiveTool();
|
|
519
|
+
const { interactiveLogin } = require('../lib/auth/login');
|
|
520
|
+
const browserResult = interactiveLogin({
|
|
521
|
+
playwrightFallback: shouldUsePlaywrightFallbackInAgentLogin(),
|
|
522
|
+
});
|
|
523
|
+
if (browserResult) {
|
|
524
|
+
printLoginResult(browserResult);
|
|
525
|
+
} else {
|
|
526
|
+
if (activeTool && (activeTool.tool === 'wukong' || activeTool.tool === 'qoderwork')) {
|
|
527
|
+
const { codexLogin } = require('../lib/auth/codex-login');
|
|
528
|
+
const result = await codexLogin({ tool: activeTool.tool });
|
|
529
|
+
printLoginResult(result);
|
|
530
|
+
} else {
|
|
531
|
+
const { startCodexQrLogin } = require('../lib/auth/qr-login');
|
|
532
|
+
const result = await startCodexQrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
533
|
+
printLoginResult(result);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
} else if (shouldUseBrowserHandoffLogin(loginArgs)) {
|
|
538
|
+
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
539
|
+
if (cachedResult.status === 'ok') {
|
|
540
|
+
printLoginResult(cachedResult);
|
|
541
|
+
} else {
|
|
542
|
+
const { codexLogin } = require('../lib/auth/codex-login');
|
|
543
|
+
const result = await codexLogin({ tool: loginArgs.includes('--codex') ? 'codex' : undefined });
|
|
544
|
+
printLoginResult(result);
|
|
545
|
+
}
|
|
546
|
+
} else {
|
|
547
|
+
const cachedResult = checkLoginOnly({ includeSecrets: true });
|
|
548
|
+
if (cachedResult.status === 'ok') {
|
|
549
|
+
printLoginResult(cachedResult);
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
if (shouldUseDesktopBrowserLogin()) {
|
|
553
|
+
const { interactiveLogin } = require('../lib/auth/login');
|
|
554
|
+
const browserResult = interactiveLogin({ playwrightFallback: true });
|
|
555
|
+
if (browserResult) {
|
|
556
|
+
printLoginResult(browserResult);
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
const { qrLogin } = require('../lib/auth/qr-login');
|
|
561
|
+
const result = await qrLogin({ corpId: getArgValue(loginArgs, '--corp-id') });
|
|
562
|
+
printLoginResult(result);
|
|
563
|
+
}
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
case 'logout': {
|
|
568
|
+
const { logout } = require('../lib/auth/login');
|
|
569
|
+
logout();
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
case 'auth': {
|
|
574
|
+
const subCommand = args[0];
|
|
575
|
+
const { authStatus, authLogin, authRefresh, authLogout } = require('../lib/auth/auth');
|
|
576
|
+
|
|
577
|
+
if (subCommand === 'status') {
|
|
578
|
+
authStatus();
|
|
579
|
+
} else if (subCommand === 'login') {
|
|
580
|
+
const authArgs = applyLoginEnvironmentFlags(args.slice(1), { inferTargetUrl: true });
|
|
581
|
+
let loginType = 'qrcode';
|
|
582
|
+
if (authArgs.includes('--codex')) {
|
|
583
|
+
loginType = 'codex';
|
|
584
|
+
} else if (authArgs.includes('--qoder')) {
|
|
585
|
+
loginType = 'qoder';
|
|
586
|
+
} else if (authArgs.includes('--wukong')) {
|
|
587
|
+
loginType = 'wukong';
|
|
588
|
+
} else if (authArgs.includes('--browser')) {
|
|
589
|
+
loginType = 'browser';
|
|
590
|
+
}
|
|
591
|
+
const result = await authLogin({
|
|
592
|
+
type: loginType,
|
|
593
|
+
corpId: getArgValue(authArgs, '--corp-id'),
|
|
594
|
+
forceTerminalQr: authArgs.includes('--qr'),
|
|
595
|
+
});
|
|
596
|
+
if (result) {
|
|
597
|
+
printLoginResult(result);
|
|
598
|
+
}
|
|
599
|
+
} else if (subCommand === 'refresh') {
|
|
600
|
+
authRefresh();
|
|
601
|
+
} else if (subCommand === 'logout') {
|
|
602
|
+
authLogout();
|
|
603
|
+
} else {
|
|
604
|
+
throwCliUsage(t('cli.auth_usage'), t('cli.auth_example'));
|
|
605
|
+
}
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
case 'org': {
|
|
610
|
+
const subCommand = args[0];
|
|
611
|
+
const { listOrganizations, switchOrganization, interactiveSwitch } = require('../lib/auth/org');
|
|
612
|
+
const { loadCookieData } = require('../lib/core/utils');
|
|
613
|
+
|
|
614
|
+
if (subCommand === 'list') {
|
|
615
|
+
const cookieData = loadCookieData();
|
|
616
|
+
if (!cookieData || !cookieData.cookies) {
|
|
617
|
+
throwNeedLogin(t('org.no_login'));
|
|
618
|
+
}
|
|
619
|
+
await listOrganizations(cookieData);
|
|
620
|
+
} else if (subCommand === 'switch') {
|
|
621
|
+
const cookieData = loadCookieData();
|
|
622
|
+
if (!cookieData || !cookieData.cookies) {
|
|
623
|
+
throwNeedLogin(t('org.no_login'));
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
const corpIdIndex = args.indexOf('--corp-id');
|
|
627
|
+
if (corpIdIndex !== -1 && args[corpIdIndex + 1]) {
|
|
628
|
+
const targetCorpId = args[corpIdIndex + 1];
|
|
629
|
+
await switchOrganization(targetCorpId, cookieData);
|
|
630
|
+
} else {
|
|
631
|
+
await interactiveSwitch(cookieData);
|
|
632
|
+
}
|
|
633
|
+
} else {
|
|
634
|
+
throwCliUsage(t('cli.org_usage'), t('cli.org_example'));
|
|
635
|
+
}
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
case 'data': {
|
|
640
|
+
if (args.length < 2) {
|
|
641
|
+
throwCliUsage(
|
|
642
|
+
'用法: yidaconnector data <action> <resource> [args] [options]',
|
|
643
|
+
'示例: yidaconnector data query form APP_XXX FORM_XXX --page 1 --size 20'
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
const { run: runDataManagement } = require('../lib/core/query-data');
|
|
647
|
+
await runDataManagement(args);
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
default: {
|
|
652
|
+
throwCliUsage(t('cli.unknown_command', command), t('cli.run_help'));
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
main()
|
|
658
|
+
.catch((err) => {
|
|
659
|
+
if (isCliError(err) && args.includes('--json')) {
|
|
660
|
+
console.error(JSON.stringify(toErrorPayload(err), null, 2));
|
|
661
|
+
} else if (isCliError(err)) {
|
|
662
|
+
warn(t('cli.exec_failed', err.message));
|
|
663
|
+
if (err.usage) {
|
|
664
|
+
warn(err.usage);
|
|
665
|
+
}
|
|
666
|
+
} else {
|
|
667
|
+
warn(t('cli.exec_failed', err.message));
|
|
668
|
+
}
|
|
669
|
+
process.exit(err && err.exitCode ? err.exitCode : 1);
|
|
670
|
+
});
|