dsh-agentone 0.5.31 → 0.5.33
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/client.js +93 -9
- package/lib/page.js +32 -10
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -16,18 +16,102 @@ window.__ModuleLoader__.load({
|
|
|
16
16
|
factory: (require) => {
|
|
17
17
|
const React = require('react');
|
|
18
18
|
|
|
19
|
+
// ==desktop-srcdoc-begin==
|
|
20
|
+
// DSH NEXT 桌面壳(dsh-app:// 协议)的转发层只给「主框架的子资源请求」注入
|
|
21
|
+
// x-dsh-desktop-renderer 令牌;iframe 子框架导航拿不到令牌,/agentone/ 被
|
|
22
|
+
// 403 空响应——这是桌面端设置区白屏的根因。桌面端改为主框架 fetch 取回页面
|
|
23
|
+
// HTML 后用 srcdoc 渲染,并注入两样东西:
|
|
24
|
+
// 1. <base href="/agentone/"> —— 页面相对路径(fetch('api/...'))的解析
|
|
25
|
+
// 基准与真实 iframe 一致;
|
|
26
|
+
// 2. fetch 代理 shim —— srcdoc 子框架自己发请求同样没有令牌,一律先按
|
|
27
|
+
// document.baseURI 解析成绝对 URL,再转主框架 parent.fetch 发出(同源
|
|
28
|
+
// srcdoc,令牌随主框架请求注入);同时打 __AGENTONE_DESKTOP__ 标记,
|
|
29
|
+
// 供页面登录流程走桌面本地回调。
|
|
30
|
+
const DESKTOP_PAGE_SHIM =
|
|
31
|
+
'<script>(function(){' +
|
|
32
|
+
'window.__AGENTONE_DESKTOP__=true;' +
|
|
33
|
+
'var pf=window.parent.fetch.bind(window.parent);' +
|
|
34
|
+
'window.fetch=function(input,init){' +
|
|
35
|
+
'if(typeof input==="string")input=new URL(input,document.baseURI).href;' +
|
|
36
|
+
'return pf(input,init);' +
|
|
37
|
+
'};' +
|
|
38
|
+
'})();</scr' + 'ipt>';
|
|
39
|
+
|
|
40
|
+
function buildDesktopSrcdoc(html) {
|
|
41
|
+
const preamble = '<base href="/agentone/">\n' + DESKTOP_PAGE_SHIM + '\n';
|
|
42
|
+
const head = /<head[^>]*>/i.exec(html);
|
|
43
|
+
if (head) {
|
|
44
|
+
const at = head.index + head[0].length;
|
|
45
|
+
return html.slice(0, at) + '\n' + preamble + html.slice(at);
|
|
46
|
+
}
|
|
47
|
+
return preamble + html;
|
|
48
|
+
}
|
|
49
|
+
// ==desktop-srcdoc-end==
|
|
50
|
+
|
|
51
|
+
const SECTION_IFRAME_STYLE = {
|
|
52
|
+
border: 'none',
|
|
53
|
+
width: '100%',
|
|
54
|
+
height: '100%',
|
|
55
|
+
minHeight: '480px',
|
|
56
|
+
borderRadius: '12px',
|
|
57
|
+
background: 'transparent',
|
|
58
|
+
};
|
|
59
|
+
|
|
19
60
|
function AgentOneSection() {
|
|
61
|
+
// dsh-app:// 即 DSH NEXT 桌面壳;http(s) 为 web/旧桌面(cookie 鉴权,iframe 直连可用)
|
|
62
|
+
const isDesktop = window.location.protocol === 'dsh-app:';
|
|
63
|
+
const [doc, setDoc] = React.useState(null);
|
|
64
|
+
const [loadError, setLoadError] = React.useState(false);
|
|
65
|
+
const [retryTick, setRetryTick] = React.useState(0);
|
|
66
|
+
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
if (!isDesktop) return undefined;
|
|
69
|
+
let cancelled = false;
|
|
70
|
+
setDoc(null);
|
|
71
|
+
setLoadError(false);
|
|
72
|
+
fetch('/agentone/')
|
|
73
|
+
.then((response) => {
|
|
74
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
75
|
+
return response.text();
|
|
76
|
+
})
|
|
77
|
+
.then((html) => { if (!cancelled) setDoc(buildDesktopSrcdoc(html)); })
|
|
78
|
+
.catch(() => { if (!cancelled) setLoadError(true); });
|
|
79
|
+
return () => { cancelled = true; };
|
|
80
|
+
}, [isDesktop, retryTick]);
|
|
81
|
+
|
|
82
|
+
if (!isDesktop) {
|
|
83
|
+
return React.createElement('iframe', {
|
|
84
|
+
src: '/agentone/',
|
|
85
|
+
title: 'AgentOne',
|
|
86
|
+
style: SECTION_IFRAME_STYLE,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (loadError) {
|
|
90
|
+
return React.createElement(
|
|
91
|
+
'div',
|
|
92
|
+
{ style: { padding: '24px', textAlign: 'center', color: 'var(--dsw-alias-label-secondary, #57606a)' } },
|
|
93
|
+
React.createElement('p', null, 'AgentOne 面板加载失败,请重试'),
|
|
94
|
+
React.createElement(
|
|
95
|
+
'button',
|
|
96
|
+
{
|
|
97
|
+
onClick: () => setRetryTick((tick) => tick + 1),
|
|
98
|
+
style: { padding: '8px 20px', borderRadius: '10px', border: 'none', cursor: 'pointer', background: '#2f6feb', color: '#fff' },
|
|
99
|
+
},
|
|
100
|
+
'重新加载',
|
|
101
|
+
),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (doc === null) {
|
|
105
|
+
return React.createElement(
|
|
106
|
+
'div',
|
|
107
|
+
{ style: { padding: '24px', textAlign: 'center', color: 'var(--dsw-alias-label-secondary, #57606a)' } },
|
|
108
|
+
'加载中…',
|
|
109
|
+
);
|
|
110
|
+
}
|
|
20
111
|
return React.createElement('iframe', {
|
|
21
|
-
|
|
112
|
+
srcDoc: doc,
|
|
22
113
|
title: 'AgentOne',
|
|
23
|
-
style:
|
|
24
|
-
border: 'none',
|
|
25
|
-
width: '100%',
|
|
26
|
-
height: '100%',
|
|
27
|
-
minHeight: '480px',
|
|
28
|
-
borderRadius: '12px',
|
|
29
|
-
background: 'transparent',
|
|
30
|
-
},
|
|
114
|
+
style: SECTION_IFRAME_STYLE,
|
|
31
115
|
});
|
|
32
116
|
}
|
|
33
117
|
|
package/lib/page.js
CHANGED
|
@@ -149,11 +149,13 @@ let lastStatus = null;
|
|
|
149
149
|
// 上一次轮询到的套餐状态(pending→active 自动同步模型用)
|
|
150
150
|
let lastPlanState = null;
|
|
151
151
|
const notify = (message, kind) => {
|
|
152
|
-
|
|
152
|
+
// 保留 toast-fixed:覆盖 className 会把它一起抹掉,常驻可视区顶部的定位
|
|
153
|
+
// 失效,页面滚动后操作反馈落在视口外(CSS 注释里的「仍可见」不再成立)
|
|
154
|
+
toast.className = 'banner toast-fixed ' + (kind || 'ok');
|
|
153
155
|
toast.textContent = message;
|
|
154
156
|
clearTimeout(toastTimer);
|
|
155
157
|
// 错误信息可能较长(含平台原因),给足阅读时间;成功提示维持 4s
|
|
156
|
-
toastTimer = setTimeout(() => { toast.className = 'banner'; }, kind === 'err' ? 10000 : 4000);
|
|
158
|
+
toastTimer = setTimeout(() => { toast.className = 'banner toast-fixed'; }, kind === 'err' ? 10000 : 4000);
|
|
157
159
|
};
|
|
158
160
|
// withLoading 收尾的刷新分两档:
|
|
159
161
|
// 'status'(默认)——拉 /api/status 并整页 refresh()。模型/SkillHub/登录类
|
|
@@ -888,9 +890,15 @@ const renderPlugins = async () => {
|
|
|
888
890
|
}).then(() => renderPlugins()), '插件已卸载');
|
|
889
891
|
});
|
|
890
892
|
};
|
|
893
|
+
// ==about-upgrade-begin==
|
|
891
894
|
// 关于页版本行:aboutSelf(GET api/plugin/self)有值时展示升级入口或
|
|
892
895
|
// 「已安装待重启」提示;尚未取到时退化为运行中版本(状态轮询自带字段)。
|
|
893
896
|
let aboutSelf = null;
|
|
897
|
+
// 升级进行中标记。本行没有插件/技能列表那样的指纹保护:refresh() 的 5s 状态
|
|
898
|
+
// 轮询每次都会重建它,而升级本身(pnpm view + pnpm add)要几十秒。不把这个态
|
|
899
|
+
// 跨渲染保留,点击后的「升级中…」会在一次轮询内被抹回「升级」——按钮原样弹
|
|
900
|
+
// 回,用户看到的就是「点了没反应」,且能再点一次触发并发重复升级。
|
|
901
|
+
let aboutUpgrading = false;
|
|
894
902
|
const aboutVersionRow = () => {
|
|
895
903
|
const self = aboutSelf;
|
|
896
904
|
if (!self) {
|
|
@@ -899,7 +907,9 @@ const aboutVersionRow = () => {
|
|
|
899
907
|
let value;
|
|
900
908
|
if (self.latest && !self.self_managed) {
|
|
901
909
|
value = 'v' + esc(self.version || '?') + ' → <b>v' + esc(self.latest) + '</b>'
|
|
902
|
-
+
|
|
910
|
+
+ (aboutUpgrading
|
|
911
|
+
? ' <button id="about-upgrade-btn" class="btn small primary" disabled><span class="spin"></span>升级中…</button>'
|
|
912
|
+
: ' <button id="about-upgrade-btn" class="btn small primary" data-loading="升级中…">升级</button>');
|
|
903
913
|
} else if (self.version && self.running && self.version !== self.running) {
|
|
904
914
|
value = 'v' + esc(self.running) + '(运行中)· v' + esc(self.version) + ' 已安装,重启 DSH 后生效';
|
|
905
915
|
} else {
|
|
@@ -909,8 +919,11 @@ const aboutVersionRow = () => {
|
|
|
909
919
|
};
|
|
910
920
|
const wireAboutUpgrade = () => {
|
|
911
921
|
const btn = $('about-upgrade-btn');
|
|
912
|
-
|
|
922
|
+
// 升级中:行里已经是 disabled + spinner(aboutVersionRow 按 aboutUpgrading 渲染),
|
|
923
|
+
// 不重复接线;disabled 按钮本身也点不动,起不了第二个升级
|
|
924
|
+
if (!btn || aboutUpgrading || btn.onclick) return;
|
|
913
925
|
btn.onclick = async () => {
|
|
926
|
+
aboutUpgrading = true;
|
|
914
927
|
btn.disabled = true;
|
|
915
928
|
btn.innerHTML = '<span class="spin"></span>升级中…';
|
|
916
929
|
try {
|
|
@@ -921,15 +934,22 @@ const wireAboutUpgrade = () => {
|
|
|
921
934
|
});
|
|
922
935
|
const data = await resp.json().catch(() => ({}));
|
|
923
936
|
if (!resp.ok) throw new Error(data.error || '插件升级失败');
|
|
937
|
+
aboutUpgrading = false;
|
|
924
938
|
notify('插件已升级,重启 DSH 后生效');
|
|
925
939
|
await refreshAboutSelf(true);
|
|
926
940
|
} catch (error) {
|
|
941
|
+
aboutUpgrading = false;
|
|
927
942
|
notify(error.message || '插件升级失败', 'err');
|
|
928
|
-
|
|
929
|
-
|
|
943
|
+
// 轮询可能刚重建过本行:按可见性整体重渲染,别只改手里这个已脱离文档的节点
|
|
944
|
+
rerenderAbout();
|
|
930
945
|
}
|
|
931
946
|
};
|
|
932
947
|
};
|
|
948
|
+
// 关于页重渲染,仅在「关于」tab 可见时执行:切 tab 拿到版本信息、升级结束后刷新
|
|
949
|
+
const rerenderAbout = () => {
|
|
950
|
+
if (!$('about-body') || document.getElementById('pane-about').hidden) return;
|
|
951
|
+
renderAbout(lastStatus);
|
|
952
|
+
};
|
|
933
953
|
// 版本 + latest 查询有网络开销(pnpm view 打 registry):1 分钟节流,
|
|
934
954
|
// 切到「关于」tab 或升级完成后刷新
|
|
935
955
|
const refreshAboutSelf = async (force = false) => {
|
|
@@ -944,8 +964,7 @@ const refreshAboutSelf = async (force = false) => {
|
|
|
944
964
|
} catch {
|
|
945
965
|
return; // 查询失败保持现状,版本行退化为运行中版本
|
|
946
966
|
}
|
|
947
|
-
|
|
948
|
-
renderAbout(lastStatus);
|
|
967
|
+
rerenderAbout();
|
|
949
968
|
};
|
|
950
969
|
const renderAbout = (s) => {
|
|
951
970
|
const lines = [
|
|
@@ -958,6 +977,7 @@ const renderAbout = (s) => {
|
|
|
958
977
|
$('about-body').innerHTML = lines.join('');
|
|
959
978
|
wireAboutUpgrade();
|
|
960
979
|
};
|
|
980
|
+
// ==about-upgrade-end==
|
|
961
981
|
const searchCatalog = async () => {
|
|
962
982
|
const btn = $('search-btn');
|
|
963
983
|
const q = $('search-input').value.trim();
|
|
@@ -1084,8 +1104,10 @@ $('login-btn').onclick = async () => {
|
|
|
1084
1104
|
const btn = $('login-btn');
|
|
1085
1105
|
const base = location.pathname.replace(/\\/agentone\\/?$/, '');
|
|
1086
1106
|
// DSH Desktop:页面 URL 带 dsh-desktop-mode 参数,且宿主对外请求 403——
|
|
1087
|
-
// 传 desktop
|
|
1088
|
-
|
|
1107
|
+
// 传 desktop 标记让后端起一次性本地回调服务。DSH NEXT 桌面壳下页面经
|
|
1108
|
+
// srcdoc 加载(无 URL 参数),由 client.js 注入的 __AGENTONE_DESKTOP__ 兜底。
|
|
1109
|
+
const isDesktop = new URLSearchParams(location.search).has('dsh-desktop-mode')
|
|
1110
|
+
|| window.__AGENTONE_DESKTOP__ === true;
|
|
1089
1111
|
const callbackUrl = isDesktop
|
|
1090
1112
|
? null
|
|
1091
1113
|
: location.pathname.startsWith('/portal/')
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-agentone",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "AgentOne 平台集成插件:飞书登录、平台模型(直连 Token Hub 不过境平台、同步失败自愈重试)、SkillHub 技能(升级检测一键升级、装后即时刷新、套餐技能自动同步)、套餐申请、插件管理与自助升级、lark-cli / ccpg-cli 探测与一键安装(请求超时与错误码透传、令牌轮换 single-flight、凭据损坏容错与并发安全写入、状态页 UX 增强、全局中文回复默认(AGENTS.md
|
|
3
|
+
"version": "0.5.33",
|
|
4
|
+
"description": "AgentOne 平台集成插件:飞书登录、平台模型(直连 Token Hub 不过境平台、同步失败自愈重试)、SkillHub 技能(升级检测一键升级、装后即时刷新、套餐技能自动同步)、套餐申请、插件管理与自助升级、lark-cli / ccpg-cli 探测与一键安装(请求超时与错误码透传、令牌轮换 single-flight、凭据损坏容错与并发安全写入、状态页 UX 增强、全局中文回复默认(AGENTS.md 受标记管理、永不覆盖用户设置)、桌面版设置页白屏修复(iframe 子框架导航无桌面令牌改走主框架 fetch + srcdoc 渲染)、「关于」页升级中态跨状态轮询保留(点升级不再像没反应、不再并发重复升级)与 toast 常驻定位修复)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"smoke": "node scripts/env-matrix-smoke.mjs"
|