openyida 2026.7.13 → 2026.7.14-2

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.
Files changed (95) hide show
  1. package/README.md +15 -22
  2. package/bin/yida.js +72 -220
  3. package/lib/agent-center/api.js +2 -2
  4. package/lib/aggregate-table/aggregate-table.js +2 -2
  5. package/lib/ai/ai.js +7 -12
  6. package/lib/app/canvas-compile.js +2 -2
  7. package/lib/app/create-app.js +5 -19
  8. package/lib/app/create-form.js +54 -76
  9. package/lib/app/create-page.js +4 -19
  10. package/lib/app/er.js +11 -8
  11. package/lib/app/export-app.js +2 -2
  12. package/lib/app/externalize-form.js +12 -10
  13. package/lib/app/get-schema.js +12 -10
  14. package/lib/app/import-app.js +6 -22
  15. package/lib/app/list-forms.js +3 -19
  16. package/lib/app/nav-group.js +6 -19
  17. package/lib/app/publish.js +60 -198
  18. package/lib/app/update-app.js +4 -18
  19. package/lib/app/update-form-config.js +20 -113
  20. package/lib/app-permission/app-permission.js +2 -2
  21. package/lib/auth/oauth-loopback.js +156 -0
  22. package/lib/auth/org.js +169 -322
  23. package/lib/auth/token-auth.js +346 -0
  24. package/lib/auth/token-store.js +174 -0
  25. package/lib/basic-info/basic-info.js +11 -12
  26. package/lib/bridge/bridge.js +29 -27
  27. package/lib/connector/api.js +4 -4
  28. package/lib/core/agent-capabilities.js +92 -8
  29. package/lib/core/batch.js +8 -8
  30. package/lib/core/check-data.js +2 -2
  31. package/lib/core/command-manifest.js +3 -3
  32. package/lib/core/doctor.js +19 -22
  33. package/lib/core/env-cmd.js +1 -3
  34. package/lib/core/env-manager.js +8 -121
  35. package/lib/core/env.js +30 -72
  36. package/lib/core/locales/ar.js +5 -5
  37. package/lib/core/locales/de.js +5 -5
  38. package/lib/core/locales/en.js +26 -26
  39. package/lib/core/locales/es.js +5 -5
  40. package/lib/core/locales/fr.js +5 -5
  41. package/lib/core/locales/hi.js +5 -5
  42. package/lib/core/locales/ja.js +14 -14
  43. package/lib/core/locales/ko.js +5 -5
  44. package/lib/core/locales/pt.js +5 -5
  45. package/lib/core/locales/vi.js +5 -5
  46. package/lib/core/locales/zh-HK.js +15 -15
  47. package/lib/core/locales/zh.js +26 -26
  48. package/lib/core/query-data.js +2 -2
  49. package/lib/core/task-center.js +2 -2
  50. package/lib/core/utils.js +156 -400
  51. package/lib/core/yida-client.js +57 -22
  52. package/lib/corp-efficiency/corp-efficiency.js +3 -3
  53. package/lib/corp-manager/api.js +2 -2
  54. package/lib/db/db-seq-fix.js +20 -25
  55. package/lib/flash-note/flash-to-prd.js +2 -2
  56. package/lib/i18n-management/i18n-management.js +2 -2
  57. package/lib/integration/integration-check.js +10 -7
  58. package/lib/integration/integration-create.js +11 -8
  59. package/lib/integration/integration-list.js +11 -8
  60. package/lib/mcp/server.js +5 -54
  61. package/lib/page-config/get-page-config.js +2 -2
  62. package/lib/page-config/save-share-config.js +2 -2
  63. package/lib/page-config/verify-short-url.js +2 -2
  64. package/lib/permission/get-permission.js +2 -2
  65. package/lib/permission/save-permission.js +2 -2
  66. package/lib/process/ai-form-setting.js +2 -2
  67. package/lib/process/create-process.js +2 -2
  68. package/lib/process/preview-process.js +2 -2
  69. package/lib/report/append.js +3 -3
  70. package/lib/report/index.js +3 -3
  71. package/package.json +1 -1
  72. package/scripts/check-syntax.js +6 -0
  73. package/scripts/e2e-real/full-runner.js +2 -10
  74. package/scripts/e2e-real/runner.js +0 -31
  75. package/scripts/eval/screenshot.js +27 -69
  76. package/scripts/nightly-smoke.js +16 -34
  77. package/scripts/postinstall.js +6 -2
  78. package/yida-skills/SKILL.md +10 -6
  79. package/yida-skills/references/development-rules.md +2 -2
  80. package/yida-skills/references/setup-and-env.md +10 -9
  81. package/yida-skills/skills/sls-log-workbench/SKILL.md +2 -2
  82. package/yida-skills/skills/sls-log-workbench/sls-query.js +27 -54
  83. package/yida-skills/skills/yida-flash-note-to-prd/SKILL.md +1 -1
  84. package/yida-skills/skills/yida-integration/SKILL.md +3 -3
  85. package/yida-skills/skills/yida-login/SKILL.md +56 -74
  86. package/yida-skills/skills/yida-logout/SKILL.md +13 -12
  87. package/yida-skills/skills/yida-process-rule/SKILL.md +1 -1
  88. package/yida-skills/skills/yida-publish-page/SKILL.md +1 -1
  89. package/yida-skills/skills/yida-report/references/report-api-guide.md +4 -20
  90. package/yida-skills/skills-index.json +4 -4
  91. package/lib/auth/auth.js +0 -313
  92. package/lib/auth/cdp-browser-login.js +0 -390
  93. package/lib/auth/codex-login.js +0 -71
  94. package/lib/auth/login.js +0 -550
  95. package/lib/auth/qr-login.js +0 -1575
package/lib/auth/org.js CHANGED
@@ -1,363 +1,210 @@
1
- /**
2
- * org.js - 组织管理模块
3
- *
4
- * 提供组织切换能力,支持:
5
- * - 列出用户可访问的组织
6
- * - 切换组织(无需重新登录)
7
- * - 交互式组织选择
8
- *
9
- * 切换组织原理:
10
- * 通过一系列 HTTP 请求完成组织切换,无需重新登录。
11
- * 流程:
12
- * 1. GET /start.html?corpid={corpId}&switchCorp=true
13
- * 2. GET /start.html?corpid={corpId}&
14
- * 3. 跟随重定向获取新 Cookie
15
- *
16
- * 导出函数:
17
- * listOrganizations() - 列出可访问的组织
18
- * switchOrganization() - 切换到指定组织
19
- * interactiveSwitch() - 交互式组织选择
20
- */
21
-
22
1
  'use strict';
23
2
 
24
- const https = require('https');
25
- const http = require('http');
26
- const { extractInfoFromCookies, resolveBaseUrl } = require('../core/utils');
27
- const { saveCookieCache } = require('./login');
28
- const { saveAuthConfig, loadAuthConfig } = require('./auth');
29
- const { t } = require('../core/i18n');
30
-
31
- // ── HTTP 请求工具 ─────────────────────────────────────
32
-
33
- /**
34
- * 发送 HTTP GET 请求并跟随重定向,提取响应中的 Cookie
35
- * @param {string} url - 完整 URL
36
- * @param {Array} cookies - 当前 Cookie 列表
37
- * @param {boolean} _followRedirect - 是否跟随重定向(保留参数以保持 API 一致性)
38
- * @returns {Promise<{statusCode: number, headers: object, cookies: Array}>}
39
- */
40
- function httpGetWithCookies(url, cookies, _followRedirect = true) {
41
- return new Promise((resolve, reject) => {
42
- const cookieHeader = cookies.map((c) => `${c.name}=${c.value}`).join('; ');
43
- const parsedUrl = new URL(url);
44
- const isHttps = parsedUrl.protocol === 'https:';
45
- const requestModule = isHttps ? https : http;
46
-
47
- const options = {
48
- hostname: parsedUrl.hostname,
49
- port: parsedUrl.port || (isHttps ? 443 : 80),
50
- path: parsedUrl.pathname + parsedUrl.search,
51
- method: 'GET',
52
- headers: {
53
- 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
54
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
55
- 'Cookie': cookieHeader,
56
- },
57
- timeout: 30000,
58
- };
59
-
60
- // 不自动跟随重定向,手动处理以提取 Cookie
61
- const req = requestModule.request(options, (res) => {
62
- let data = '';
63
- res.on('data', (chunk) => { data += chunk; });
64
- res.on('end', () => {
65
- // 提取 Set-Cookie 中的新 Cookie
66
- const setCookies = res.headers['set-cookie'] || [];
67
- const newCookies = parseSetCookies(setCookies, cookies);
3
+ const { createAuthRef, createYidaClient } = require('../core/yida-client');
4
+ const { loadTokenSession, clearTokenSession } = require('./token-store');
5
+ const { tokenLogin, tokenLogout } = require('./token-auth');
68
6
 
69
- resolve({
70
- statusCode: res.statusCode,
71
- headers: res.headers,
72
- cookies: newCookies,
73
- location: res.headers.location,
74
- body: data,
75
- });
76
- });
77
- });
7
+ const LIST_CORP_INFOS_PATH = '/query/userservice/listCorpInfos.json';
78
8
 
79
- req.on('timeout', () => { req.destroy(); reject(new Error(t('common.request_timeout'))); });
80
- req.on('error', reject);
81
- req.end();
82
- });
9
+ function getArgValue(args, name) {
10
+ const index = args.indexOf(name);
11
+ if (index === -1 || !args[index + 1] || args[index + 1].startsWith('--')) {
12
+ return null;
13
+ }
14
+ return args[index + 1];
83
15
  }
84
16
 
85
- /**
86
- * 解析 Set-Cookie 响应头,合并到现有 Cookie 中
87
- * @param {Array<string>} setCookies - Set-Cookie 响应头数组
88
- * @param {Array} existingCookies - 现有 Cookie 列表
89
- * @returns {Array} 合并后的 Cookie 列表
90
- */
91
- function parseSetCookies(setCookies, existingCookies) {
92
- const cookieMap = new Map();
93
-
94
- // 先添加现有 Cookie
95
- for (const cookie of existingCookies) {
96
- cookieMap.set(cookie.name, cookie);
97
- }
17
+ function hasFlag(args, name) {
18
+ return args.includes(name);
19
+ }
98
20
 
99
- // 解析并更新 Cookie
100
- for (const setCookie of setCookies) {
101
- const parts = setCookie.split(';')[0].split('=');
102
- if (parts.length >= 2) {
103
- const name = parts[0].trim();
104
- const value = parts.slice(1).join('=').trim();
105
- cookieMap.set(name, { name, value });
106
- }
21
+ function getPayload(response) {
22
+ if (!response || typeof response !== 'object') {
23
+ return response;
107
24
  }
108
-
109
- return Array.from(cookieMap.values());
25
+ return response.content || response.data || response.result || response;
110
26
  }
111
27
 
112
- // ── 组织列表获取 ──────────────────────────────────────
113
-
114
- /**
115
- * 获取用户可访问的组织列表
116
- * @param {object} cookieData - Cookie 数据
117
- * @returns {Promise<Array>} 组织列表
118
- */
119
- async function listOrganizations(cookieData) {
120
- const { c, banner, warn, sep } = require('../core/chalk');
121
-
122
- banner(t('org.list_title'), { stderr: false });
123
-
124
- const cookies = cookieData.cookies;
125
-
126
- // 从 Cookie 中提取当前组织信息
127
- const { corpId } = extractInfoFromCookies(cookies);
28
+ function normalizeCorpList(response) {
29
+ const payload = getPayload(response);
30
+ const list = Array.isArray(payload)
31
+ ? payload
32
+ : Array.isArray(payload && payload.list)
33
+ ? payload.list
34
+ : Array.isArray(payload && payload.corpInfos)
35
+ ? payload.corpInfos
36
+ : [];
37
+
38
+ return list
39
+ .map((corp) => ({
40
+ corpId: corp.corpId || corp.corp_id || corp.id,
41
+ corpName: corp.corpName || corp.corp_name || corp.name || corp.corpId || corp.id,
42
+ logo: corp.logo,
43
+ namespace: corp.namespace || '',
44
+ }))
45
+ .filter((corp) => corp.corpId);
46
+ }
128
47
 
129
- if (!corpId) {
130
- warn(t('org.no_corp_id'), false);
131
- console.log(` ${sep()}\n`);
132
- return [];
48
+ async function listOrganizations(options = {}) {
49
+ const authRef = createAuthRef();
50
+ const response = await createYidaClient({ authRef }).get(LIST_CORP_INFOS_PATH);
51
+ if (response && response.success === false) {
52
+ throw new Error(response.errorMsg || response.message || response.errorCode || 'list corp infos failed');
133
53
  }
54
+ const organizations = normalizeCorpList(response);
55
+ return {
56
+ ok: true,
57
+ auth_mode: 'token',
58
+ status: 'ok',
59
+ current_corp_id: authRef.corpId,
60
+ count: organizations.length,
61
+ organizations: organizations.map((corp) => ({
62
+ ...corp,
63
+ isCurrent: !!authRef.corpId && corp.corpId === authRef.corpId,
64
+ })),
65
+ raw: options.includeRaw ? response : undefined,
66
+ };
67
+ }
134
68
 
135
- // 尝试调用 API 获取组织列表
136
- // 注意:宜搭没有直接的组织列表 API,我们从 Cookie 和 auth 配置中获取
137
- const authConfig = loadAuthConfig();
138
- const recentCorps = authConfig?.recentCorps || [];
139
-
140
- // 构建组织列表
141
- const organizations = [];
142
-
143
- // 添加当前组织
144
- organizations.push({
145
- corpId,
146
- name: t('org.current_org'),
147
- isCurrent: true,
148
- lastUsed: new Date().toISOString(),
149
- });
150
-
151
- // 添加历史组织
152
- for (const org of recentCorps) {
153
- if (org.corpId !== corpId) {
154
- organizations.push({
155
- corpId: org.corpId,
156
- name: org.name || org.corpId,
157
- isCurrent: false,
158
- lastUsed: org.lastUsed,
159
- });
160
- }
69
+ async function switchOrganization(targetCorpId, options = {}) {
70
+ if (!targetCorpId) {
71
+ throw new Error('corpId is required. Usage: openyida org switch --corp-id dingXXX');
161
72
  }
162
73
 
163
- // 显示组织列表
164
- if (organizations.length === 0) {
165
- warn(t('org.no_organizations'), false);
166
- } else {
167
- for (const org of organizations) {
168
- const statusIcon = org.isCurrent ? `${c.green}✔${c.reset}` : `${c.dim}○${c.reset}`;
169
- const current = org.isCurrent ? ` ${c.green}(${t('org.current')})${c.reset}` : '';
170
- console.log(` ${statusIcon} ${org.name}${current}`);
171
- console.log(` ${c.dim}corpId: ${org.corpId}${c.reset}`);
172
- }
74
+ const currentSession = loadTokenSession(options);
75
+ if (currentSession && currentSession.corp_id === targetCorpId) {
76
+ return {
77
+ ok: true,
78
+ auth_mode: 'token',
79
+ status: 'already_in_org',
80
+ can_auto_use: true,
81
+ corp_id: currentSession.corp_id,
82
+ user_id: currentSession.user_id,
83
+ user_name: currentSession.user_name,
84
+ base_url: currentSession.base_url,
85
+ message: 'already in target organization',
86
+ };
173
87
  }
174
88
 
175
- console.log(`\n ${sep()}\n`);
176
- return organizations;
177
- }
178
-
179
- // ── 组织切换 ──────────────────────────────────────────
180
-
181
- /**
182
- * 切换到指定组织(无需重新登录)
183
- * @param {string} targetCorpId - 目标组织 ID
184
- * @param {object} cookieData - 当前 Cookie 数据
185
- * @returns {Promise<object>} 切换结果
186
- */
187
- async function switchOrganization(targetCorpId, cookieData) {
188
- const { c, banner, label, info, success: chalkSuccess, warn: chalkWarn, fail: chalkFail, step, sep } = require('../core/chalk');
189
-
190
- banner(t('org.switch_title'), { stderr: false });
191
-
192
- const cookies = cookieData.cookies;
193
- const { corpId: currentCorpId } = extractInfoFromCookies(cookies);
89
+ const loginOptions = {
90
+ ...options,
91
+ endpoint: options.endpoint || (currentSession && currentSession.base_url),
92
+ clientId: options.clientId || (currentSession && currentSession.client_id),
93
+ };
194
94
 
195
- label('From', currentCorpId || t('org.unknown'), { stderr: false });
196
- label('To', `${c.green}${targetCorpId}${c.reset}`, { stderr: false });
95
+ if (currentSession) {
96
+ await tokenLogout(options);
97
+ } else {
98
+ clearTokenSession(options);
99
+ }
197
100
 
198
- if (currentCorpId === targetCorpId) {
199
- chalkWarn(t('org.already_in_org'), false);
200
- console.log(` ${sep()}\n`);
101
+ const loginResult = await tokenLogin(loginOptions);
102
+ if (!loginResult || !loginResult.access_token) {
103
+ clearTokenSession(options);
201
104
  return {
202
- success: true,
203
- corpId: targetCorpId,
204
- message: 'Already in target organization',
105
+ ...(loginResult || {}),
106
+ ok: false,
107
+ auth_mode: 'token',
108
+ status: 'token_not_issued',
109
+ can_auto_use: false,
110
+ message: (loginResult && loginResult.message) || 'login did not issue access_token',
205
111
  };
206
112
  }
207
113
 
208
- try {
209
- const baseUrl = resolveBaseUrl(cookieData);
210
-
211
- // Step 1: 发起切换请求
212
- step(1, t('org.step1'), false);
213
- const step1Url = `${baseUrl}/start.html?corpid=${targetCorpId}&switchCorp=true`;
214
- const step1Result = await httpGetWithCookies(step1Url, cookies, false);
215
-
216
- // Step 2: 确认切换
217
- step(2, t('org.step2'), false);
218
- const step2Url = `${baseUrl}/start.html?corpid=${targetCorpId}&`;
219
- const step2Result = await httpGetWithCookies(step2Url, step1Result.cookies, false);
220
-
221
- // Step 3-4: 获取新 Cookie(跟随重定向)
222
- step(3, t('org.step3'), false);
223
- const step3Url = `${baseUrl}/start.html?corpid=${targetCorpId}&`;
224
- const step3Result = await httpGetWithCookies(step3Url, step2Result.cookies, false);
225
-
226
- // 处理重定向
227
- let finalCookies = step3Result.cookies;
228
- let currentUrl = step3Result.location;
229
-
230
- // 跟随重定向最多 5 次
231
- let redirectCount = 0;
232
- while (currentUrl && redirectCount < 5) {
233
- redirectCount++;
234
- info(`${t('org.redirect', redirectCount)}`, false);
235
-
236
- // 构建完整 URL
237
- if (!currentUrl.startsWith('http')) {
238
- currentUrl = new URL(currentUrl, baseUrl).toString();
239
- }
240
-
241
- const redirectResult = await httpGetWithCookies(currentUrl, finalCookies, false);
242
- finalCookies = redirectResult.cookies;
243
- currentUrl = redirectResult.location;
244
-
245
- // 如果到达工作台,停止
246
- if (currentUrl && currentUrl.includes('workPlatform')) {
247
- break;
248
- }
249
- }
250
-
251
- // 提取新的 csrf_token 和 corpId
252
- const { csrfToken, corpId: newCorpId, userId } = extractInfoFromCookies(finalCookies);
253
-
254
- if (!csrfToken) {
255
- chalkFail(t('org.switch_failed_no_csrf'), { exit: false });
256
- console.log(` ${sep()}\n`);
257
- return {
258
- success: false,
259
- message: 'No csrf_token in new cookies',
260
- };
261
- }
262
-
263
- // 保存新的 Cookie
264
- const newBaseUrl = baseUrl;
265
- saveCookieCache(finalCookies, newBaseUrl);
266
-
267
- // 更新 auth 配置
268
- const authConfig = loadAuthConfig() || {};
269
- authConfig.corpId = newCorpId;
270
- authConfig.userId = userId;
271
- authConfig.switchTime = new Date().toISOString();
272
-
273
- // 更新历史组织列表
274
- if (!authConfig.recentCorps) {
275
- authConfig.recentCorps = [];
276
- }
277
-
278
- // 移除旧记录,添加新记录
279
- authConfig.recentCorps = authConfig.recentCorps.filter((c) => c.corpId !== newCorpId);
280
- authConfig.recentCorps.unshift({
281
- corpId: newCorpId,
282
- name: t('org.switched_org'),
283
- lastUsed: new Date().toISOString(),
284
- });
285
-
286
- // 保留最近 10 个组织
287
- authConfig.recentCorps = authConfig.recentCorps.slice(0, 10);
288
- saveAuthConfig(authConfig);
114
+ if (loginResult.corp_id !== targetCorpId) {
115
+ await tokenLogout(options);
116
+ const error = new Error(`登录到的组织与目标组织不一致:target=${targetCorpId}, actual=${loginResult.corp_id || 'unknown'}`);
117
+ error.code = 'ORG_SWITCH_CORP_MISMATCH';
118
+ error.targetCorpId = targetCorpId;
119
+ error.actualCorpId = loginResult.corp_id;
120
+ throw error;
121
+ }
289
122
 
290
- chalkSuccess(t('org.switch_success'), false);
291
- label('Corp ID', newCorpId, { stderr: false });
292
- label('CSRF', `${csrfToken.slice(0, 16)}…`, { stderr: false });
293
- console.log(` ${sep()}\n`);
123
+ return {
124
+ ok: true,
125
+ auth_mode: 'token',
126
+ status: 'switched',
127
+ can_auto_use: true,
128
+ previous_corp_id: currentSession && currentSession.corp_id,
129
+ corp_id: loginResult.corp_id,
130
+ user_id: loginResult.user_id,
131
+ user_name: loginResult.user_name,
132
+ base_url: loginResult.base_url,
133
+ message: 'switched organization by OAuth re-login',
134
+ };
135
+ }
294
136
 
295
- return {
296
- success: true,
297
- corpId: newCorpId,
298
- csrfToken,
299
- userId,
300
- baseUrl: newBaseUrl,
301
- cookies: finalCookies,
302
- };
303
- } catch (error) {
304
- chalkFail(t('org.switch_error', error.message), { exit: false });
137
+ function printList(result) {
138
+ const { c, banner, sep } = require('../core/chalk');
139
+ banner('openyida org list - 组织列表', { stderr: false });
140
+ if (!result.organizations.length) {
141
+ console.log(' 暂无可访问组织');
305
142
  console.log(` ${sep()}\n`);
306
- return {
307
- success: false,
308
- message: error.message,
309
- };
143
+ return;
310
144
  }
145
+ result.organizations.forEach((corp) => {
146
+ const icon = corp.isCurrent ? `${c.green}✔${c.reset}` : `${c.dim}○${c.reset}`;
147
+ const current = corp.isCurrent ? ` ${c.green}(当前)${c.reset}` : '';
148
+ console.log(` ${icon} ${corp.corpName}${current}`);
149
+ console.log(` ${c.dim}corpId: ${corp.corpId}${c.reset}`);
150
+ });
151
+ console.log(`\n ${sep()}\n`);
311
152
  }
312
153
 
313
- // ── 交互式组织选择 ────────────────────────────────────
314
-
315
- /**
316
- * 交互式组织选择
317
- * @param {object} cookieData - Cookie 数据
318
- * @returns {Promise<object>} 切换结果
319
- */
320
- async function interactiveSwitch(cookieData) {
321
- const organizations = await listOrganizations(cookieData);
322
-
323
- if (organizations.length === 0) {
324
- return {
325
- success: false,
326
- message: 'No organizations available',
327
- };
154
+ function printSwitch(result) {
155
+ const { banner, label, success, warn, sep } = require('../core/chalk');
156
+ banner('openyida org switch - 组织切换', { stderr: false });
157
+ if (result.status === 'already_in_org') {
158
+ warn('已在目标组织中,无需切换', false);
159
+ } else {
160
+ success('组织切换成功', false);
161
+ }
162
+ if (result.previous_corp_id) {
163
+ label('From', result.previous_corp_id, { stderr: false });
164
+ }
165
+ label('Corp ID', result.corp_id || '', { stderr: false });
166
+ if (result.user_id) {
167
+ label('User ID', result.user_id, { stderr: false });
328
168
  }
169
+ console.log(` ${sep()}\n`);
170
+ }
329
171
 
330
- // 过滤掉当前组织
331
- const switchableOrgs = organizations.filter((org) => !org.isCurrent);
172
+ async function run(args = []) {
173
+ const subCommand = args[0];
174
+ const json = hasFlag(args, '--json');
175
+ const options = {
176
+ quiet: hasFlag(args, '--quiet') || json,
177
+ clientId: getArgValue(args, '--client-id'),
178
+ };
332
179
 
333
- if (switchableOrgs.length === 0) {
334
- const { info: chalkInfo2 } = require('../core/chalk');
335
- chalkInfo2(t('org.only_one_org'), false);
336
- return {
337
- success: false,
338
- message: 'Only one organization available',
339
- };
180
+ if (subCommand === 'list') {
181
+ const result = await listOrganizations(options);
182
+ if (json) {
183
+ console.log(JSON.stringify(result, null, 2));
184
+ } else {
185
+ printList(result);
186
+ }
187
+ return result;
340
188
  }
341
189
 
342
- // 显示可选组织
343
- const { c: oc, hint: chalkHint2 } = require('../core/chalk');
344
- console.log(`\n ${oc.bold}${t('org.select_prompt')}${oc.reset}`);
345
- switchableOrgs.forEach((org, index) => {
346
- console.log(` ${oc.cyan}${index + 1}.${oc.reset} ${org.name} ${oc.dim}(${org.corpId})${oc.reset}`);
347
- });
348
-
349
- // 在非交互模式下,提示用户使用 --corp-id 参数
350
- chalkHint2(t('org.use_corp_id_hint'), false);
190
+ if (subCommand === 'switch') {
191
+ const targetCorpId = getArgValue(args, '--corp-id') || args.slice(1).find(arg => !arg.startsWith('--'));
192
+ const result = await switchOrganization(targetCorpId, options);
193
+ if (json) {
194
+ console.log(JSON.stringify(result, null, 2));
195
+ } else {
196
+ printSwitch(result);
197
+ }
198
+ return result;
199
+ }
351
200
 
352
- return {
353
- success: false,
354
- message: 'Interactive mode not supported, please use --corp-id option',
355
- organizations: switchableOrgs,
356
- };
201
+ throw new Error('Usage: openyida org <list|switch>');
357
202
  }
358
203
 
359
204
  module.exports = {
205
+ LIST_CORP_INFOS_PATH,
360
206
  listOrganizations,
207
+ normalizeCorpList,
208
+ run,
361
209
  switchOrganization,
362
- interactiveSwitch,
363
210
  };