openyida 2026.8.3-beta.1 → 2026.8.4
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/bin/yida.js +5 -1
- package/lib/auth/oauth-loopback.js +95 -19
- package/lib/bridge/bridge.js +3 -3
- package/package.json +1 -1
package/bin/yida.js
CHANGED
|
@@ -35,11 +35,15 @@ function isAgentEnvironment(env) {
|
|
|
35
35
|
env.QODER_IDE ||
|
|
36
36
|
env.QODER_AGENT ||
|
|
37
37
|
env.QODERCLI_INTEGRATION_MODE ||
|
|
38
|
+
env.QWENWORK_INTEGRATION_MODE ||
|
|
39
|
+
env.QWENWORKCN_INTEGRATION_MODE ||
|
|
38
40
|
env.CURSOR_TRACE_ID ||
|
|
39
41
|
env.AGENT_WORK_ROOT ||
|
|
40
42
|
env.OPENYIDA_AGENT_MODE ||
|
|
41
43
|
(env.__CFBundleIdentifier || '').toLowerCase().includes('codex') ||
|
|
42
|
-
(env.__CFBundleIdentifier || '').toLowerCase().includes('qoder')
|
|
44
|
+
(env.__CFBundleIdentifier || '').toLowerCase().includes('qoder') ||
|
|
45
|
+
(env.__CFBundleIdentifier || '').toLowerCase().includes('qwenwork') ||
|
|
46
|
+
(env.__CFBundleIdentifier || '').toLowerCase().includes('qwen-work')
|
|
43
47
|
);
|
|
44
48
|
}
|
|
45
49
|
|
|
@@ -287,55 +287,128 @@ function resolveBrowserLauncher(url, platform = process.platform, openMode = 'le
|
|
|
287
287
|
return { command: 'xdg-open', args: [url] };
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
function
|
|
290
|
+
function isQwenWorkEnvironment(env = process.env) {
|
|
291
|
+
const bundleId = String(env.__CFBundleIdentifier || '').toLowerCase();
|
|
292
|
+
const product = String(env.QODER_WORK_INTEGRATION_PRODUCT || '').toLowerCase();
|
|
293
|
+
const qoderConfigDir = String(env.QODER_CONFIG_DIR || env.QODERCN_CONFIG_DIR || '');
|
|
294
|
+
return !!(
|
|
295
|
+
env.QWENWORK_INTEGRATION_MODE ||
|
|
296
|
+
env.QWENWORKCN_INTEGRATION_MODE ||
|
|
297
|
+
product.includes('qwenwork') ||
|
|
298
|
+
product.includes('qwen-work') ||
|
|
299
|
+
qoderConfigDir.includes('.qwenworkcn') ||
|
|
300
|
+
bundleId.includes('qwenwork') ||
|
|
301
|
+
bundleId.includes('qwen-work')
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function browserLaunchFailureMessage(launcher, error) {
|
|
306
|
+
const detail = error && error.message ? ` (${error.message})` : '';
|
|
307
|
+
return `OpenYida could not auto-open the browser via ${launcher.command}${detail}. Please use the login URL above.`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function launchBrowserLauncher(launcher, onError, deps = {}) {
|
|
311
|
+
const spawnImpl = deps.spawn || spawn;
|
|
312
|
+
let handledFailure = false;
|
|
313
|
+
const notifyFailure = (error) => {
|
|
314
|
+
if (handledFailure) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
handledFailure = true;
|
|
318
|
+
if (onError) {
|
|
319
|
+
return onError(error) === true;
|
|
320
|
+
}
|
|
321
|
+
return false;
|
|
322
|
+
};
|
|
323
|
+
|
|
291
324
|
try {
|
|
292
|
-
const child =
|
|
325
|
+
const child = spawnImpl(launcher.command, launcher.args, {
|
|
293
326
|
detached: true,
|
|
294
327
|
stdio: 'ignore',
|
|
295
328
|
});
|
|
296
|
-
child.unref
|
|
297
|
-
|
|
298
|
-
child.once('error', onError);
|
|
329
|
+
if (child && typeof child.unref === 'function') {
|
|
330
|
+
child.unref();
|
|
299
331
|
}
|
|
300
|
-
return true;
|
|
301
|
-
} catch {
|
|
302
332
|
if (onError) {
|
|
303
|
-
|
|
333
|
+
child.once('error', notifyFailure);
|
|
334
|
+
child.once('exit', (code, signal) => {
|
|
335
|
+
if (code && code !== 0) {
|
|
336
|
+
notifyFailure(new Error(`browser launcher exited with code ${code}`));
|
|
337
|
+
} else if (signal) {
|
|
338
|
+
notifyFailure(new Error(`browser launcher exited with signal ${signal}`));
|
|
339
|
+
}
|
|
340
|
+
});
|
|
304
341
|
}
|
|
305
|
-
return
|
|
342
|
+
return true;
|
|
343
|
+
} catch (error) {
|
|
344
|
+
return notifyFailure(error);
|
|
306
345
|
}
|
|
307
346
|
}
|
|
308
347
|
|
|
309
|
-
function openBrowser(url) {
|
|
310
|
-
|
|
348
|
+
function openBrowser(url, options = {}) {
|
|
349
|
+
const env = options.env || process.env;
|
|
350
|
+
if (env.OPENYIDA_NO_BROWSER === '1') {
|
|
311
351
|
return false;
|
|
312
352
|
}
|
|
313
353
|
|
|
314
|
-
const platform = process.platform;
|
|
354
|
+
const platform = options.platform || process.platform;
|
|
355
|
+
const detectBrowser = options.detectDefaultBrowser || detectDefaultBrowser;
|
|
356
|
+
const launchDeps = { spawn: options.spawn };
|
|
357
|
+
const warnLaunchFailure = (launcher) => (error) => {
|
|
358
|
+
process.stderr.write(`${browserLaunchFailureMessage(launcher, error)}\n`);
|
|
359
|
+
};
|
|
315
360
|
const legacyLauncher = resolveBrowserLauncher(url, platform, 'legacy');
|
|
316
|
-
const runLegacy = (
|
|
361
|
+
const runLegacy = (onError = warnLaunchFailure(legacyLauncher)) =>
|
|
362
|
+
launchBrowserLauncher(legacyLauncher, onError, launchDeps);
|
|
317
363
|
|
|
318
364
|
let browser = null;
|
|
319
365
|
try {
|
|
320
|
-
browser =
|
|
366
|
+
browser = detectBrowser(platform);
|
|
321
367
|
} catch {
|
|
322
368
|
browser = null;
|
|
323
369
|
}
|
|
324
370
|
|
|
371
|
+
const hasNewWindowFallback = browser && SUPPORTED_BROWSER_FAMILIES.has(browser.family);
|
|
372
|
+
const newWindowLauncher = hasNewWindowFallback
|
|
373
|
+
? resolveBrowserLauncher(url, platform, 'newWindow', browser)
|
|
374
|
+
: null;
|
|
375
|
+
|
|
376
|
+
// QwenWork runs inside a desktop shell. Prefer the OS default-browser opener
|
|
377
|
+
// first so the login page is visible outside the host app; use new-window
|
|
378
|
+
// launch only as a fallback when the system opener itself fails.
|
|
379
|
+
if (isQwenWorkEnvironment(env)) {
|
|
380
|
+
let fallbackUsed = false;
|
|
381
|
+
const runNewWindowFallback = (error) => {
|
|
382
|
+
if (fallbackUsed) {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
fallbackUsed = true;
|
|
386
|
+
if (newWindowLauncher) {
|
|
387
|
+
return launchBrowserLauncher(
|
|
388
|
+
newWindowLauncher,
|
|
389
|
+
warnLaunchFailure(newWindowLauncher),
|
|
390
|
+
launchDeps
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
warnLaunchFailure(legacyLauncher)(error);
|
|
394
|
+
return false;
|
|
395
|
+
};
|
|
396
|
+
return runLegacy(runNewWindowFallback);
|
|
397
|
+
}
|
|
398
|
+
|
|
325
399
|
// Default browser detected and supported → open a real new window in that
|
|
326
400
|
// browser, falling back to the plain default-browser open if launch errors.
|
|
327
|
-
if (
|
|
328
|
-
const newWindowLauncher = resolveBrowserLauncher(url, platform, 'newWindow', browser);
|
|
401
|
+
if (newWindowLauncher) {
|
|
329
402
|
let fallbackUsed = false;
|
|
330
|
-
const runFallback = () => {
|
|
403
|
+
const runFallback = (error) => {
|
|
331
404
|
if (fallbackUsed) {
|
|
332
405
|
return false;
|
|
333
406
|
}
|
|
334
407
|
fallbackUsed = true;
|
|
335
|
-
return runLegacy();
|
|
408
|
+
return runLegacy(warnLaunchFailure(legacyLauncher)) || warnLaunchFailure(newWindowLauncher)(error);
|
|
336
409
|
};
|
|
337
410
|
|
|
338
|
-
const launched = launchBrowserLauncher(newWindowLauncher, runFallback);
|
|
411
|
+
const launched = launchBrowserLauncher(newWindowLauncher, runFallback, launchDeps);
|
|
339
412
|
if (!launched) {
|
|
340
413
|
return runFallback();
|
|
341
414
|
}
|
|
@@ -506,6 +579,9 @@ module.exports = {
|
|
|
506
579
|
buildDingtalkOAuthUrl,
|
|
507
580
|
resolveBrowserLauncher,
|
|
508
581
|
detectDefaultBrowser,
|
|
582
|
+
openBrowser,
|
|
583
|
+
isQwenWorkEnvironment,
|
|
584
|
+
launchBrowserLauncher,
|
|
509
585
|
classifyMacBundleId,
|
|
510
586
|
classifyWindowsProgId,
|
|
511
587
|
classifyLinuxDesktop,
|
package/lib/bridge/bridge.js
CHANGED
|
@@ -557,7 +557,7 @@ function sanitizeQrLoginStart(result = {}, loginSessionId) {
|
|
|
557
557
|
qrImageOpened: !!result.qr_image_opened,
|
|
558
558
|
pollable: true,
|
|
559
559
|
pollIntervalMs: 1000,
|
|
560
|
-
message: result.message || '
|
|
560
|
+
message: result.message || 'Complete login in the browser, then poll login status.',
|
|
561
561
|
};
|
|
562
562
|
}
|
|
563
563
|
|
|
@@ -623,7 +623,7 @@ async function defaultStartLogin() {
|
|
|
623
623
|
status: 'token_login_required',
|
|
624
624
|
auth_mode: 'token',
|
|
625
625
|
can_auto_use: false,
|
|
626
|
-
message: 'Token-only auth does not support bridge
|
|
626
|
+
message: 'Token-only auth does not support bridge-managed login. Run openyida login first.',
|
|
627
627
|
};
|
|
628
628
|
}
|
|
629
629
|
|
|
@@ -632,7 +632,7 @@ async function defaultPollLogin() {
|
|
|
632
632
|
status: 'token_login_required',
|
|
633
633
|
auth_mode: 'token',
|
|
634
634
|
can_auto_use: false,
|
|
635
|
-
message: 'Token-only auth does not support bridge
|
|
635
|
+
message: 'Token-only auth does not support bridge login polling. Run openyida login first.',
|
|
636
636
|
};
|
|
637
637
|
}
|
|
638
638
|
|