dsh-agentone 1.0.4 → 1.0.5

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/README.md CHANGED
@@ -70,6 +70,9 @@ lark-cli / ccpg-cli 状态探测。
70
70
  (改名不影响、被删自动重建);设置页「云盘」tab 支持初始化/重新定位/
71
71
  粘贴链接收养其他文件夹(`POST /agentone/api/drive/home/resolve`)。
72
72
  独立 dsh 未装 better-sidebar 时静默不注册该页签。
73
+ 宿主适配:页签与 footer 入口**所有宿主恒注册**(官方桌面版 `dsh-app://` 不再被
74
+ 误伤);个别会静默拦跨源 iframe 的桌面壳由页签内运行时探测兜底——`onLoad` 后
75
+ `contentDocument` 仍可读即白屏,换退路卡片(新窗口打开 + 重试)。
73
76
  内容变化时自动刷新:服务端对根清单算指纹(`GET /agentone/api/drive/rev`,10s 节流),
74
77
  页签 ready 后每 8s 轮询,指纹变了才重挂载 iframe。用户正在云盘里浏览时不硬刷新
75
78
  (重载会回到根视图):顶部弹蓝色横幅「云盘内容有更新 / 立即刷新」,右下角常驻
package/lib/client.js CHANGED
@@ -353,6 +353,7 @@ window.__ModuleLoader__.load({
353
353
  const [retryTick, setRetryTick] = React.useState(0);
354
354
  const [reloadTick, setReloadTick] = React.useState(0);
355
355
  const [stale, setStale] = React.useState(false);
356
+ const [blocked, setBlocked] = React.useState(false);
356
357
  React.useEffect(() => {
357
358
  let cancelled = false;
358
359
  setPhase({ kind: 'loading' });
@@ -402,6 +403,25 @@ window.__ModuleLoader__.load({
402
403
  return () => { stopped = true; clearInterval(timer); };
403
404
  }, [phase.kind === 'ready' ? phase.url : '']);
404
405
 
406
+ // 白屏宿主探测:个别桌面壳(如 DSH NEXT)会静默拦下跨源 iframe
407
+ // (CSP/COEP),页签里只剩一张白屏。注册期无法预判——官方桌面版与
408
+ // NEXT 同为 dsh-app://,宿主侧没有可靠标识可分(按协议隐藏曾把官方
409
+ // 桌面版一起误伤)。只能在 load 后实测:被拦的 iframe 停在初始
410
+ // about:blank,contentDocument 可读且非 null;正常跨源加载后 Chrome
411
+ // 里 contentDocument 为 null。探到被拦换退路卡片(新窗口打开 + 重试),
412
+ // url/重挂载变化时复位重探。
413
+ React.useEffect(() => {
414
+ setBlocked(false);
415
+ }, [phase.kind === 'ready' ? phase.url : '', reloadTick]);
416
+
417
+ const probeFrameLoad = (event) => {
418
+ const el = event && event.target;
419
+ if (!el) return;
420
+ let blockedNow = false;
421
+ try { blockedNow = el.contentDocument != null; } catch { blockedNow = false; }
422
+ if (blockedNow) setBlocked(true);
423
+ };
424
+
405
425
  // 手动刷新:立即重载 iframe 并重新寻址(资料夹被重新定位/收养过也能跟上);
406
426
  // 寻址失败保留当前画面不打断
407
427
  const refreshDrive = () => {
@@ -419,10 +439,42 @@ window.__ModuleLoader__.load({
419
439
  }, '正在定位你的飞书云盘文件夹…');
420
440
  }
421
441
  if (phase.kind === 'ready') {
442
+ if (blocked) {
443
+ return React.createElement('div', {
444
+ style: {
445
+ padding: '28px 20px', textAlign: 'center',
446
+ color: 'var(--dsw-alias-label-secondary, #57606a)', fontSize: '13px', lineHeight: '1.7',
447
+ },
448
+ },
449
+ React.createElement('p', {
450
+ style: { margin: '0 0 6px', fontSize: '14px', color: 'var(--dsw-alias-label-primary, #3c434d)' },
451
+ }, '当前桌面壳不支持在页签里内嵌网页'),
452
+ React.createElement('p', { style: { margin: '0 0 16px' } },
453
+ '可以改用系统浏览器打开云盘文件夹,上传和管理不受影响。'),
454
+ React.createElement('button', {
455
+ type: 'button',
456
+ style: {
457
+ padding: '7px 18px', fontSize: '13px', borderRadius: '9px', border: 'none',
458
+ cursor: 'pointer', background: '#2f6feb', color: '#fff', marginRight: '8px',
459
+ },
460
+ onClick: () => window.open(phase.url, '_blank', 'noopener'),
461
+ }, '新窗口打开云盘'),
462
+ React.createElement('button', {
463
+ type: 'button',
464
+ style: {
465
+ padding: '7px 18px', fontSize: '13px', borderRadius: '9px', border: 'none',
466
+ cursor: 'pointer',
467
+ background: 'var(--dsw-alias-fill-secondary, #f2f3f5)',
468
+ color: 'var(--dsw-alias-label-primary, #3c434d)',
469
+ },
470
+ onClick: () => { setBlocked(false); setReloadTick((t) => t + 1); },
471
+ }, '重试'));
472
+ }
422
473
  // 不设 sandbox:飞书登录态依赖真实第三方 cookie 上下文(spike 实测
423
474
  // 无 sandbox 时登录页可渲染、登录后云盘可用)。key 随 reloadTick 变化
424
475
  // 即重挂载 = 重载(跨域 iframe 不能调 contentWindow.location.reload)。
425
476
  // 用户浏览中时刷新被推迟:顶部横幅 + 胶囊按钮变色双提示(见上面轮询注释)。
477
+ // onLoad 探测白屏宿主(见 probeFrameLoad 注释)。
426
478
  const refreshTitle = stale ? DRIVE_STALE_TITLE : DRIVE_REFRESH_TITLE;
427
479
  const banner = React.createElement('div', {
428
480
  key: 'stale-banner',
@@ -447,6 +499,7 @@ window.__ModuleLoader__.load({
447
499
  key: `drive-frame-${reloadTick}`,
448
500
  src: phase.url,
449
501
  title: '飞书云盘',
502
+ onLoad: probeFrameLoad,
450
503
  style: {
451
504
  border: 'none', width: '100%', height: '100%', minHeight: '320px',
452
505
  background: '#fff', display: 'block',
@@ -610,13 +663,10 @@ window.__ModuleLoader__.load({
610
663
  // 那个窗口里取到 null 会静默跳过且永不重试(真机事故:侧边栏找不到云盘入口)。
611
664
  function registerFeishuDriveTab(ctx) {
612
665
  if (typeof ctx.inject !== 'function') return () => {};
613
- // DSH NEXT 桌面壳(dsh-app://,secure 自定义协议)里跨源 https iframe
614
- // 静默白屏(2026-10-13 真机:官方桌面端 http 宿主正常,DSH NEXT 不行,
615
- // 宿主 will-attach-webview 又拒绝无 lease 的 webview)——嵌入展示在该
616
- // 宿主不可用,整块隐藏:不注册页签、不监听消息桥。web/官方桌面端不受
617
- // 影响;设置页「打开云盘」经消息桥超时自动退化为系统浏览器打开。
618
- if (typeof window !== 'undefined' && window.location
619
- && window.location.protocol === 'dsh-app:') return () => {};
666
+ // 所有宿主一律注册:官方桌面版(dsh-app://)的跨源 iframe 实际可用
667
+ // (r12-r14 真机长期验证,免扫码),按协议隐藏会把它误伤。个别会拦
668
+ // iframe 的桌面壳(如 DSH NEXT)由 FeishuDriveTab 里的 onLoad 运行时
669
+ // 探测兜底(白屏 → 退路卡片),不在注册期猜宿主。
620
670
  return ctx.inject(['betterSidebar'], (scope) => {
621
671
  const sidebar = scope.betterSidebar;
622
672
  setDriveSidebarService(sidebar);
@@ -716,12 +766,9 @@ window.__ModuleLoader__.load({
716
766
 
717
767
  function apply(ctx) {
718
768
  setupNavIcon();
719
- // 飞书云盘侧边栏 tab(better-sidebar 缺失时内部静默跳过;DSH NEXT 桌面壳
720
- // 同样跳过——页签与 footer 入口一起隐藏,见 registerFeishuDriveTab 注释)
769
+ // 飞书云盘侧边栏 tab(better-sidebar 缺失时内部静默跳过;所有宿主
770
+ // 恒注册,白屏宿主由页签内探测兜底,见 registerFeishuDriveTab 注释)
721
771
  registerFeishuDriveTab(ctx);
722
- const driveEntryHidden = typeof window !== 'undefined' && window.location
723
- && window.location.protocol === 'dsh-app:';
724
- if (!driveEntryHidden)
725
772
  ctx.slots.inject('sidebar.footer.action', () =>
726
773
  ctx.slots.register(
727
774
  {
package/lib/page.js CHANGED
@@ -1203,13 +1203,10 @@ const renderDrive = async () => {
1203
1203
  if (seq !== renderDrive._seq) return;
1204
1204
  renderDrive._data = data;
1205
1205
  if (data.state === 'ready') {
1206
- // DSH NEXT 桌面壳(srcdoc 加载)没有云盘页签可进——文案引导走「打开云盘」
1207
- // 按钮(宿主消息桥超时后自动退化为系统浏览器打开)。
1208
- const inDesktopShell = window.__AGENTONE_DESKTOP__ === true;
1206
+ // 云盘页签在所有宿主恒注册(官方桌面版不再被误伤);个别白屏宿主由
1207
+ // 页签内运行时探测换退路卡片,这里的文案不再按宿主分叉。
1209
1208
  statusEl.innerHTML = '<span class="pill ok">已就绪</span>'
1210
- + (inDesktopShell
1211
- ? '点「打开云盘」会在浏览器中进入这个文件夹。'
1212
- : '侧边栏「飞书云盘」页签会直接进入这个文件夹。');
1209
+ + '点「打开云盘」会在侧边栏的「飞书云盘」页签里进入这个文件夹。';
1213
1210
  if (data.url) {
1214
1211
  linkEl.textContent = data.name || 'AgentOne';
1215
1212
  linkEl.href = data.url;
@@ -1536,9 +1533,10 @@ const searchCatalog = async () => {
1536
1533
  const action = known
1537
1534
  ? '<span class="pill ok" style="font-size:11px">已安装</span>'
1538
1535
  : '<button class="btn small primary" data-install="' + esc(item.slug) + '">安装</button>';
1536
+ const tag = item.category ? '<span class="tag" data-cat="' + esc(item.category) + '">' + esc(item.category) + '</span>' : '';
1539
1537
  return '<div class="skill-item"><div class="skill-info"><div class="skill-name">'
1540
1538
  + esc(item.display_name || item.slug)
1541
- + '<span class="tag" data-cat="' + esc(item.category || '') + '">' + esc(item.category || '技能') + '</span></div><div class="skill-sub">'
1539
+ + tag + '</div><div class="skill-sub">'
1542
1540
  + esc(item.summary || item.slug) + ' · ' + (item.downloads || 0) + ' 次安装</div></div>' + action + '</div>';
1543
1541
  });
1544
1542
  $('search-results').innerHTML = rows.length
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-agentone",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "AgentOne 平台集成:平台模型、SkillHub 技能、套餐、CLI、飞书云盘共享文件夹(web/官方桌面端侧栏页签 + 左栏底部入口;「启用云盘」后 AI 可读取/搜索资料、看最近更新、存文档、传本地文件)",
5
5
  "type": "module",
6
6
  "scripts": {