dsh-agentone 0.5.1 → 0.5.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.
- package/lib/index.js +76 -1
- package/lib/page.js +9 -4
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// + agent-default-model)与 .credentials.yaml(refs.AGENTONE_API_KEY,0600)。
|
|
14
14
|
// dsh 侧模型选择器随即出现「平台模型」,对话走平台代理,真实密钥不出平台。
|
|
15
15
|
import z from '@deepseek-ai/schemastery';
|
|
16
|
+
import { createServer } from 'node:http';
|
|
16
17
|
import { createRequire } from 'node:module';
|
|
17
18
|
import { readFile } from 'node:fs/promises';
|
|
18
19
|
import { join } from 'node:path';
|
|
@@ -456,6 +457,75 @@ async function cachedPlatformStatus(config, credentials) {
|
|
|
456
457
|
return { ...statusCache, capabilities };
|
|
457
458
|
}
|
|
458
459
|
|
|
460
|
+
/**
|
|
461
|
+
* 一次性本地回调服务(DSH Desktop 专用):desktop 宿主 webserver 只信
|
|
462
|
+
* Electron 内部请求,外部浏览器打 /agentone/callback 会 403。这里在插件
|
|
463
|
+
* 进程内起 127.0.0.1 随机端口的 http server,路径与宿主回调一致(code 换
|
|
464
|
+
* token + state 比对),收完第一个请求即关停;5 分钟无回调自动超时关闭。
|
|
465
|
+
* 返回外部浏览器可达的回调地址。
|
|
466
|
+
*/
|
|
467
|
+
function openCallbackServer(config, log) {
|
|
468
|
+
return new Promise((resolve, reject) => {
|
|
469
|
+
const server = createServer(async (req, res) => {
|
|
470
|
+
const close = () => server.close();
|
|
471
|
+
const params = new URL(req.url, 'http://localhost').searchParams;
|
|
472
|
+
const code = params.get('code') || '';
|
|
473
|
+
const finish = (ok) => {
|
|
474
|
+
// 内联完成页:外部浏览器里没有 dsh 可返回,给出明确结果与关闭指引
|
|
475
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
476
|
+
res.end(`<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><title>AgentOne</title>
|
|
477
|
+
<style>body{font-family:system-ui,"PingFang SC",sans-serif;background:#f6f8fa;color:#1f2328;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0}
|
|
478
|
+
.card{background:#fff;border:1px solid #d8dee4;border-radius:16px;padding:32px 36px;text-align:center;max-width:380px}
|
|
479
|
+
.big{font-size:17px;font-weight:600;margin:0 0 8px}p{color:#57606a;font-size:14px}
|
|
480
|
+
button{font:inherit;padding:9px 22px;border-radius:10px;border:none;cursor:pointer;background:#2f6feb;color:#fff;margin-top:8px}</style></head>
|
|
481
|
+
<body><div class="card"><p class="big">${ok ? '✓ 已连接 AgentOne 平台' : '授权未完成'}</p>
|
|
482
|
+
<p>${ok ? '模型与技能正在自动配置,返回 dsh 的 AgentOne 页面即可看到已登录。' : '可以关闭本页,回到 dsh 的 AgentOne 页面重新发起登录。'}</p>
|
|
483
|
+
<button onclick="window.close()">关闭本页</button></div></body></html>`);
|
|
484
|
+
close();
|
|
485
|
+
};
|
|
486
|
+
if (!code) {
|
|
487
|
+
log.warn('[dsh-agentone] desktop callback rejected: missing code');
|
|
488
|
+
finish(false);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
try {
|
|
492
|
+
const result = await exchangeCode(config.platformUrl, code);
|
|
493
|
+
if (!pendingStates.delete(String(result.state || ''))) {
|
|
494
|
+
log.warn('[dsh-agentone] desktop callback rejected: unknown state');
|
|
495
|
+
finish(false);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const expiresIn = Number(result.expires_in) || 0;
|
|
499
|
+
await saveCredentials(config, {
|
|
500
|
+
schema_version: 2,
|
|
501
|
+
access_token: result.access_token,
|
|
502
|
+
refresh_token: result.refresh_token || null,
|
|
503
|
+
platform_url: config.platformUrl,
|
|
504
|
+
saved_at: new Date().toISOString(),
|
|
505
|
+
expires_at: expiresIn ? new Date(Date.now() + expiresIn * 1000).toISOString() : null,
|
|
506
|
+
});
|
|
507
|
+
log.info('[dsh-agentone] platform login stored (desktop callback server)');
|
|
508
|
+
await syncPlatformModel(config, log).catch(() => {});
|
|
509
|
+
await syncPlanSkills(config, log, {
|
|
510
|
+
...(await loadCredentials(config)),
|
|
511
|
+
access_token: result.access_token,
|
|
512
|
+
}).catch(() => {});
|
|
513
|
+
finish(true);
|
|
514
|
+
} catch (error) {
|
|
515
|
+
log.warn(`[dsh-agentone] desktop exchange failed: ${error?.message || error}`);
|
|
516
|
+
finish(false);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
server.on('error', reject);
|
|
520
|
+
server.listen(0, '127.0.0.1', () => {
|
|
521
|
+
const { port } = server.address();
|
|
522
|
+
// 5 分钟兜底:授权窗一直没回来就关掉,不泄漏端口
|
|
523
|
+
setTimeout(() => server.close(), 5 * 60 * 1000).unref();
|
|
524
|
+
resolve(`http://127.0.0.1:${port}/agentone/callback`);
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
459
529
|
export function apply(ctx, config) {
|
|
460
530
|
const log = ctx.logger || console;
|
|
461
531
|
ctx.effect(() => {
|
|
@@ -537,7 +607,12 @@ export function apply(ctx, config) {
|
|
|
537
607
|
}
|
|
538
608
|
try {
|
|
539
609
|
const body = await readJsonBody(request);
|
|
540
|
-
|
|
610
|
+
// DSH Desktop:宿主 webserver 只信 Electron 内部请求,外部浏览器访问
|
|
611
|
+
// /agentone/callback 会 403。desktop 模式(body.desktop)改由插件在本
|
|
612
|
+
// 进程起一次性本地服务收回调(见 openCallbackServer),收完即关。
|
|
613
|
+
const callbackUrl = body.desktop
|
|
614
|
+
? await openCallbackServer(config, log)
|
|
615
|
+
: String(body.callback_url || '');
|
|
541
616
|
if (!/^https?:\/\/|^\/portal\//.test(callbackUrl)) {
|
|
542
617
|
sendJson(response, 400, { error: '回调地址不合法' });
|
|
543
618
|
return;
|
package/lib/page.js
CHANGED
|
@@ -630,13 +630,18 @@ const refresh = async () => {
|
|
|
630
630
|
$('login-btn').onclick = async () => {
|
|
631
631
|
const btn = $('login-btn');
|
|
632
632
|
const base = location.pathname.replace(/\\/agentone\\/?$/, '');
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
633
|
+
// DSH Desktop:页面 URL 带 dsh-desktop-mode 参数,且宿主对外请求 403——
|
|
634
|
+
// 传 desktop 标记让后端起一次性本地回调服务
|
|
635
|
+
const isDesktop = new URLSearchParams(location.search).has('dsh-desktop-mode');
|
|
636
|
+
const callbackUrl = isDesktop
|
|
637
|
+
? null
|
|
638
|
+
: location.pathname.startsWith('/portal/')
|
|
639
|
+
? base + '/agentone/callback'
|
|
640
|
+
: location.origin + base + '/agentone/callback';
|
|
636
641
|
const resp = await fetch('api/login', {
|
|
637
642
|
method: 'POST',
|
|
638
643
|
headers: { 'Content-Type': 'application/json' },
|
|
639
|
-
body: JSON.stringify({ callback_url: callbackUrl }),
|
|
644
|
+
body: JSON.stringify(isDesktop ? { desktop: true } : { callback_url: callbackUrl }),
|
|
640
645
|
});
|
|
641
646
|
const data = await resp.json();
|
|
642
647
|
if (!resp.ok) { notify(data.error || '发起登录失败', 'err'); return; }
|
package/package.json
CHANGED