@ai-wendao/ant 0.3.15 → 0.3.16

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 (3) hide show
  1. package/README.md +2 -2
  2. package/client.js +95 -42
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,13 +6,13 @@ ANT (AI-native Teams) connects a DeepSeek Harness Desktop profile to its team's
6
6
 
7
7
  ## 企业精选技能
8
8
 
9
- 团队管理员可在 ANT 管理台从 GitHub 目录、ZIP、TAR、TAR.GZ/TGZ 或单份 `SKILL.md` 导入技能,核对来源、文件和依赖后发布。已连接团队的成员从 DSH 左侧“企业扩展”入口进入独立页面浏览并安装技能;ANT 插件设置页只处理连接、模型和更新。ANT Host 将固定版本的完整文件集放进 DSH 的用户技能目录,并重新核对本机文件;启用本地技能的 DSH 会话随后由原生技能提供者发现和使用。ANT 不用 Host 全局技能列表判断会话是否已发现技能。
9
+ 团队管理员可在 ANT 管理台从 GitHub 目录、ZIP、TAR、TAR.GZ/TGZ 或单份 `SKILL.md` 导入技能,核对来源、文件和依赖后发布。已连接团队的成员从 DSH 左侧“企业扩展”入口进入统一目录,默认同时浏览技能和插件,并可按类型、状态筛选或搜索;ANT 插件设置页只处理连接、模型和更新。ANT Host 将固定版本的完整文件集放进 DSH 的用户技能目录,并重新核对本机文件;启用本地技能的 DSH 会话随后由原生技能提供者发现和使用。ANT 不用 Host 全局技能列表判断会话是否已发现技能。
10
10
 
11
11
  安装不会自动运行技能脚本或安装 Python、Node 等系统依赖。ANT 只更新或卸载自己管理且本机内容未被修改的技能目录;发现同名个人技能或本机改动时会停止覆盖。
12
12
 
13
13
  ## 企业精选插件
14
14
 
15
- 管理员可从 npm 官方源的 DSH Bundle 精确版本创建草稿,填写源码、许可证、依赖和安装脚本的审核记录后发布。成员在“企业扩展 → 插件”查看审核信息和本机状态。对无新增依赖、无安装阶段脚本且归档符合首批准入条件的草稿,管理员可从 npm 官方源锁定实际 `.tgz` 并查看文件清单、下载核验制品;这类草稿经审核发布后,成员可让 DSH 从 ANT 的固定制品地址一键安装。其他版本仍是目录项,需联系管理员安排。安全撤回版本会停止新的 ANT 下载,但不会自动删除本机副本;ANT 设置页继续显示相应风险公告。范围与限制见[上线边界](../../docs/decisions/2026-10-15-plugin-center-rollout.md)。
15
+ 管理员可从 npm 官方源的 DSH Bundle 精确版本创建草稿,填写源码、许可证、依赖和安装脚本的审核记录后发布。成员在“企业扩展”总览或“插件”分类查看审核信息和本机状态。对无新增依赖、无安装阶段脚本且归档符合首批准入条件的草稿,管理员可从 npm 官方源锁定实际 `.tgz` 并查看文件清单、下载核验制品;这类草稿经审核发布后,成员可让 DSH 从 ANT 的固定制品地址一键安装。其他版本仍是目录项,需联系管理员安排。安全撤回版本会停止新的 ANT 下载,但不会自动删除本机副本;ANT 设置页继续显示相应风险公告。范围与限制见[上线边界](../../docs/decisions/2026-10-15-plugin-center-rollout.md)。
16
16
 
17
17
  ANT 自身更新使用单独的已审核安装包。管理员将与 npm 发布一致的 `.tgz` 上传到 ANT 服务端并登记版本;新版 ANT 页面可点击“更新”,DSH 原位替换同名 Bundle 后提示重启。旧版 `@ai-wendao/ant` 用户可打开团队服务的 `/ant-update` 指引,在 DSH“添加插件”中粘贴该安装包地址完成一次性原位更新,无需先卸载或使用终端。此入口只分发 ANT 自身,不启用扩展中心其他插件的一键安装。
18
18
 
package/client.js CHANGED
@@ -270,14 +270,18 @@ window.__ModuleLoader__.load({
270
270
  onServiceUrlChange: setServiceUrl, onConnectionChange }))
271
271
  }
272
272
 
273
- function SkillCenterPage({ onBack, onPlugins }) {
273
+ function SkillCenterPage({ remote, onBack, onAll, onSkills, onPlugins, openBundle,
274
+ includePlugins, query, onQueryChange }) {
274
275
  const [skills, setSkills] = useState([])
275
276
  const [loading, setLoading] = useState(false)
277
+ const [loadError, setLoadError] = useState(false)
276
278
  const [workingId, setWorkingId] = useState('')
277
279
  const [message, setMessage] = useState('')
278
- const [query, setQuery] = useState('')
279
280
  const [filter, setFilter] = useState('all')
281
+ const [refreshToken, setRefreshToken] = useState(0)
282
+ const refreshGeneration = useRef(0)
280
283
  const refresh = async () => {
284
+ const generation = ++refreshGeneration.current
281
285
  setLoading(true)
282
286
  try {
283
287
  const response = await fetch('/api/ant-teams/skills', { cache: 'no-store' })
@@ -286,13 +290,17 @@ window.__ModuleLoader__.load({
286
290
  ? '请返回 ANT 插件设置,先验证工作邮箱并连接团队。'
287
291
  : result.message || `读取技能失败(${response.status})。`)
288
292
  if (!Array.isArray(result.skills)) throw new Error('企业技能目录格式无效。')
293
+ if (generation !== refreshGeneration.current) return
289
294
  setSkills(result.skills)
295
+ setLoadError(false)
290
296
  setMessage(result.skills.length ? '' : '团队暂未发布精选技能。')
291
297
  } catch (error) {
298
+ if (generation !== refreshGeneration.current) return
292
299
  setSkills([])
300
+ setLoadError(true)
293
301
  setMessage(error instanceof Error ? error.message : '无法读取企业精选技能。')
294
302
  }
295
- finally { setLoading(false) }
303
+ finally { if (generation === refreshGeneration.current) setLoading(false) }
296
304
  }
297
305
  useEffect(() => { void refresh() }, [])
298
306
  const changeInstall = async (skill, remove = false) => {
@@ -317,40 +325,58 @@ window.__ModuleLoader__.load({
317
325
  finally { setWorkingId('') }
318
326
  }
319
327
  const visible = skills.filter((skill) => {
320
- const matchesFilter = filter === 'all' || skill.local_status === filter
328
+ const matchesFilter = filter === 'all'
329
+ || filter === 'available' && ['not-installed', 'update-available'].includes(skill.local_status)
330
+ || filter === 'installed' && ['installed', 'update-available'].includes(skill.local_status)
331
+ || filter === 'updates' && skill.local_status === 'update-available'
321
332
  const matchesQuery = !query.trim() || `${skill.title} ${skill.description} ${skill.dsh_name}`.toLowerCase().includes(query.trim().toLowerCase())
322
333
  return matchesFilter && matchesQuery
323
334
  })
324
335
  const statusLabel = { installed: '已放入本机目录', 'update-available': '可更新', 'not-installed': '未安装', conflict: '本机冲突' }
325
- return h('section', { 'aria-label': '企业精选技能', style: {
336
+ return h('section', { 'aria-label': includePlugins ? '企业扩展' : '企业精选技能', style: {
326
337
  height: '100%', overflowY: 'auto', boxSizing: 'border-box',
327
338
  padding: 'calc(var(--dsh-frame-top-clearance, 0px) + 20px) clamp(16px, 3vw, 36px) 48px',
328
339
  } }, h('div', { style: { maxWidth: 1440, margin: '0 auto', display: 'grid', gap: 22 } },
329
340
  h('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 } },
330
341
  h('nav', { 'aria-label': '企业扩展分类', style: { display: 'flex', gap: 6 } },
331
- h('span', { 'aria-current': 'page', style: { ...categoryButtonStyle, display: 'inline-flex', alignItems: 'center', cursor: 'default', backgroundColor: 'var(--dsw-alias-bg-layer-2)' } }, '技能'),
342
+ includePlugins
343
+ ? h('span', { 'aria-current': 'page', style: { ...categoryButtonStyle, display: 'inline-flex', alignItems: 'center', cursor: 'default', backgroundColor: 'var(--dsw-alias-bg-layer-2)' } }, '总览')
344
+ : h('button', { type: 'button', onClick: onAll, style: categoryButtonStyle }, '总览'),
345
+ includePlugins
346
+ ? h('button', { type: 'button', onClick: onSkills, style: categoryButtonStyle }, '技能')
347
+ : h('span', { 'aria-current': 'page', style: { ...categoryButtonStyle, display: 'inline-flex', alignItems: 'center', cursor: 'default', backgroundColor: 'var(--dsw-alias-bg-layer-2)' } }, '技能'),
332
348
  h('button', { type: 'button', onClick: onPlugins, style: categoryButtonStyle }, '插件')),
333
349
  h('button', { type: 'button', onClick: onBack, style: { ...categoryButtonStyle, marginLeft: 'auto' } }, 'ANT 设置')),
334
350
  h('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'end', justifyContent: 'space-between', gap: 16 } },
335
351
  h('div', null,
336
- h('h1', { style: { margin: 0, fontSize: 28 } }, '企业精选技能'),
337
- h('p', { style: { ...mutedTextStyle, marginTop: 6 } }, '团队管理员审核后发布;安装到这台 DSH 后,由 DSH 原生技能系统发现和使用。')),
338
- h('button', { type: 'button', disabled: loading || Boolean(workingId), onClick: () => void refresh(), style: secondaryButtonStyle }, loading ? '读取中…' : '刷新目录')),
352
+ h('h1', { style: { margin: 0, fontSize: 28 } }, includePlugins ? '企业扩展' : '企业精选技能'),
353
+ h('p', { style: { ...mutedTextStyle, marginTop: 6 } }, includePlugins
354
+ ? '浏览团队审核的技能与插件;选择需要的扩展安装到这台 DSH。'
355
+ : '团队管理员审核后发布;安装到这台 DSH 后,由 DSH 原生技能系统发现和使用。')),
356
+ h('button', { type: 'button', disabled: loading || Boolean(workingId), onClick: () => {
357
+ void refresh()
358
+ if (includePlugins) setRefreshToken((value) => value + 1)
359
+ }, style: secondaryButtonStyle }, loading ? '读取中…' : '刷新目录')),
339
360
  h(ExtensionRequestNotice),
340
361
  h('div', { style: { ...panelStyle, gap: 12 } },
341
- h('input', { type: 'search', value: query, onChange: (event) => setQuery(event.target.value), placeholder: '搜索技能名称或说明', 'aria-label': '搜索企业精选技能', style: inputStyle }),
362
+ h('input', { type: 'search', value: query, onChange: (event) => onQueryChange(event.target.value),
363
+ placeholder: includePlugins ? '搜索技能或插件名称、用途' : '搜索技能名称或说明',
364
+ 'aria-label': includePlugins ? '搜索企业扩展' : '搜索企业精选技能', style: inputStyle }),
342
365
  h('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 } },
343
- ...[['all', '全部'], ['not-installed', '可安装'], ['installed', '已安装'], ['update-available', '可更新']].map(([value, label]) =>
366
+ ...[['all', '全部'], ['available', '可安装或更新'], ['installed', '已安装'], ['updates', '可更新']].map(([value, label]) =>
344
367
  h('button', { key: value, type: 'button', onClick: () => setFilter(value), 'aria-pressed': filter === value,
345
368
  style: { ...secondaryButtonStyle, minHeight: 34, padding: '6px 12px', backgroundColor: filter === value ? 'var(--dsw-alias-bg-layer-2)' : secondaryButtonStyle.backgroundColor } }, label)),
346
- h('span', { style: { ...mutedTextStyle, marginLeft: 'auto' } }, `显示 ${visible.length} / ${skills.length} 个技能`))),
347
- message ? h('p', { role: 'status', style: mutedTextStyle }, message) : null,
369
+ includePlugins ? null : h('span', { style: { ...mutedTextStyle, marginLeft: 'auto' } }, `显示 ${visible.length} / ${skills.length} 个技能`))),
370
+ includePlugins ? h('h2', { style: { margin: 0, fontSize: 20 } }, loading ? '技能 · 读取中…' : `技能 · ${visible.length}`) : null,
371
+ message && (!includePlugins || loadError || skills.length) ? h('p', { role: loadError ? 'alert' : 'status', style: mutedTextStyle }, message) : null,
348
372
  visible.length ? h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 420px), 1fr))', gap: 16 } },
349
373
  ...visible.map((skill) => {
350
374
  const description = skill.description || ''
351
375
  return h('article', { key: skill.id, style: { ...panelStyle, gap: 13 } },
352
376
  h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 } },
353
- h('h2', { style: { margin: 0, fontSize: 19 } }, skill.title),
377
+ h('div', { style: { display: 'flex', alignItems: 'baseline', flexWrap: 'wrap', gap: 8 } },
378
+ h('h2', { style: { margin: 0, fontSize: 19 } }, skill.title),
379
+ includePlugins ? h('span', { style: mutedTextStyle }, '技能') : null),
354
380
  h('span', { style: mutedTextStyle }, statusLabel[skill.local_status] || '状态未知')),
355
381
  h('p', { style: mutedTextStyle }, description.length > 180 ? `${description.slice(0, 180)}…` : description),
356
382
  description.length > 180 ? h('details', null,
@@ -366,10 +392,16 @@ window.__ModuleLoader__.load({
366
392
  skill.local_status === 'update-available' ? '更新技能' : '安装到这台 DSH'),
367
393
  skill.local_status !== 'not-installed' ? h('button', { type: 'button', disabled: Boolean(workingId),
368
394
  onClick: () => void changeInstall(skill, true), style: secondaryButtonStyle }, '卸载') : null))
369
- })) : !loading && skills.length ? h('p', { style: mutedTextStyle }, '没有符合筛选条件的技能。') : null))
395
+ })) : !includePlugins && !loading && skills.length ? h('p', { style: mutedTextStyle }, '没有符合筛选条件的技能。') : null,
396
+ includePlugins ? h(PluginCenterPage, { remote, onBack, onAll, onSkills, openBundle,
397
+ embedded: true, query, onQueryChange, externalFilter: filter,
398
+ hasSkillMatches: visible.length > 0, skillCatalogReady: !loading && !loadError,
399
+ refreshToken }) : null))
370
400
  }
371
401
 
372
- function PluginCenterPage({ remote, onBack, onSkills, openBundle }) {
402
+ function PluginCenterPage({ remote, onBack, onAll, onSkills, openBundle,
403
+ embedded = false, query, onQueryChange, externalFilter = 'all',
404
+ hasSkillMatches = false, skillCatalogReady = false, refreshToken }) {
373
405
  const [plugins, setPlugins] = useState([])
374
406
  const [bundles, setBundles] = useState([])
375
407
  const [loading, setLoading] = useState(true)
@@ -378,9 +410,10 @@ window.__ModuleLoader__.load({
378
410
  const [uncertainId, setUncertainId] = useState('')
379
411
  const [completedId, setCompletedId] = useState('')
380
412
  const [message, setMessage] = useState('')
381
- const [query, setQuery] = useState('')
382
413
  const [filter, setFilter] = useState('all')
414
+ const refreshGeneration = useRef(0)
383
415
  const refresh = async () => {
416
+ const generation = ++refreshGeneration.current
384
417
  setLoading(true)
385
418
  try {
386
419
  const manager = remote?.pluginManager
@@ -392,18 +425,20 @@ window.__ModuleLoader__.load({
392
425
  if (!response.ok) throw new Error(result.message || `读取插件目录失败(${response.status})。`)
393
426
  if (!Array.isArray(result.plugins)) throw new Error('企业插件目录格式无效。')
394
427
  if (!listed.ok) throw new Error(listed.error?.message || '无法读取 DSH 本机插件。')
428
+ if (generation !== refreshGeneration.current) return
395
429
  setPlugins(result.plugins)
396
430
  setBundles(listed.value)
397
431
  setLoadError(false)
398
432
  setMessage(result.plugins.length ? '' : '团队暂未发布精选插件。')
399
433
  } catch (error) {
434
+ if (generation !== refreshGeneration.current) return
400
435
  setPlugins([])
401
436
  setBundles([])
402
437
  setLoadError(true)
403
438
  setMessage(error instanceof Error ? error.message : '无法读取企业精选插件。')
404
- } finally { setLoading(false) }
439
+ } finally { if (generation === refreshGeneration.current) setLoading(false) }
405
440
  }
406
- useEffect(() => { void refresh() }, [])
441
+ useEffect(() => { void refresh() }, [refreshToken])
407
442
  const install = async (plugin) => {
408
443
  const artifactUrl = approvedPluginArtifactUrl(plugin)
409
444
  if (!artifactUrl || workingId || uncertainId === plugin.id || completedId === plugin.id) return
@@ -488,35 +523,46 @@ window.__ModuleLoader__.load({
488
523
  setMessage(error instanceof Error ? error.message : '插件安装未完成,请稍后重试。')
489
524
  } finally { setWorkingId('') }
490
525
  }
526
+ const activeFilter = embedded ? externalFilter : filter
491
527
  const visible = plugins.filter((plugin) => {
492
528
  const installed = bundles.find((bundle) => bundle.name === plugin.package_name && bundle.installed)
493
529
  const artifactUrl = approvedPluginArtifactUrl(plugin)
494
530
  const matches = !query.trim() || `${plugin.title} ${plugin.description} ${plugin.package_name}`.toLowerCase().includes(query.trim().toLowerCase())
495
- return matches && (filter === 'all' || filter === 'installed' && Boolean(installed)
496
- || filter === 'available' && artifactUrl && (!installed || (installed.version && installed.version !== plugin.version))
497
- || filter === 'retired' && plugin.status !== 'published')
531
+ return matches && (activeFilter === 'all' || activeFilter === 'installed' && Boolean(installed)
532
+ || activeFilter === 'available' && artifactUrl && (!installed || (installed.version && installed.version !== plugin.version))
533
+ || activeFilter === 'updates' && artifactUrl && installed && installed.version && installed.version !== plugin.version
534
+ || activeFilter === 'retired' && plugin.status !== 'published')
498
535
  })
499
- return h('section', { 'aria-label': '企业精选插件', style: {
500
- height: '100%', overflowY: 'auto', boxSizing: 'border-box',
501
- padding: 'calc(var(--dsh-frame-top-clearance, 0px) + 20px) clamp(16px, 3vw, 36px) 48px',
502
- } }, h('div', { style: { maxWidth: 1440, margin: '0 auto', display: 'grid', gap: 22 } },
503
- h('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 } },
536
+ const noMatches = embedded
537
+ ? skillCatalogReady ? '没有找到符合条件的企业扩展。' : '插件中没有符合条件的结果。'
538
+ : activeFilter === 'available'
539
+ ? '当前没有可一键安装的插件。可在“全部”查看审核目录,或联系企业管理员。'
540
+ : '没有符合筛选条件的插件。'
541
+ return h('section', { 'aria-label': '企业精选插件', style: embedded
542
+ ? { display: 'grid', gap: 16 }
543
+ : { height: '100%', overflowY: 'auto', boxSizing: 'border-box',
544
+ padding: 'calc(var(--dsh-frame-top-clearance, 0px) + 20px) clamp(16px, 3vw, 36px) 48px' },
545
+ }, h('div', { style: embedded ? { display: 'grid', gap: 16 } : { maxWidth: 1440, margin: '0 auto', display: 'grid', gap: 22 } },
546
+ embedded ? h('h2', { style: { margin: 0, fontSize: 20 } }, loading ? '插件 · 读取中…' : `插件 · ${visible.length}`) : h('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 } },
504
547
  h('nav', { 'aria-label': '企业扩展分类', style: { display: 'flex', gap: 6 } },
548
+ h('button', { type: 'button', onClick: onAll, style: categoryButtonStyle }, '总览'),
505
549
  h('button', { type: 'button', onClick: onSkills, style: categoryButtonStyle }, '技能'),
506
550
  h('span', { 'aria-current': 'page', style: { ...categoryButtonStyle, display: 'inline-flex', alignItems: 'center', cursor: 'default', backgroundColor: 'var(--dsw-alias-bg-layer-2)' } }, '插件')),
507
551
  h('button', { type: 'button', onClick: onBack, style: { ...categoryButtonStyle, marginLeft: 'auto' } }, 'ANT 设置')),
508
- h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: 16 } },
552
+ embedded ? null : h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: 16 } },
509
553
  h('div', null,
510
554
  h('h1', { style: { margin: 0, fontSize: 28 } }, '企业精选插件'),
511
555
  h('p', { style: { ...mutedTextStyle, marginTop: 6 } }, '这里展示团队审核过的插件版本及本机状态。')),
512
556
  h('button', { type: 'button', disabled: loading, onClick: () => void refresh(), style: secondaryButtonStyle }, loading ? '读取中…' : '刷新目录')),
513
- !loading && !plugins.length && !loadError ? h('section', { role: 'status', style: panelStyle },
514
- h('h2', { style: { margin: 0, fontSize: 18 } }, '团队暂未发布精选插件'),
515
- h('p', { style: mutedTextStyle }, '需要某个插件?请联系企业管理员,说明用途或提供插件地址。审核发布后会显示在这里。')) : null,
557
+ !loading && !plugins.length && !loadError ? embedded
558
+ ? h('p', { role: 'status', style: mutedTextStyle }, '团队暂未发布精选插件。')
559
+ : h('section', { role: 'status', style: panelStyle },
560
+ h('h2', { style: { margin: 0, fontSize: 18 } }, '团队暂未发布精选插件'),
561
+ h('p', { style: mutedTextStyle }, '需要某个插件?请联系企业管理员,说明用途或提供插件地址。审核发布后会显示在这里。')) : null,
516
562
  !loading && loadError ? h('p', { role: 'alert', style: mutedTextStyle }, message) : null,
517
- plugins.length ? h(ExtensionRequestNotice) : null,
518
- plugins.length ? h('div', { style: panelStyle },
519
- h('input', { type: 'search', value: query, onChange: (event) => setQuery(event.target.value), placeholder: '搜索插件名称或用途', 'aria-label': '搜索企业精选插件', style: inputStyle }),
563
+ plugins.length && !embedded ? h(ExtensionRequestNotice) : null,
564
+ plugins.length && !embedded ? h('div', { style: panelStyle },
565
+ h('input', { type: 'search', value: query, onChange: (event) => onQueryChange(event.target.value), placeholder: '搜索插件名称或用途', 'aria-label': '搜索企业精选插件', style: inputStyle }),
520
566
  h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 8 } },
521
567
  ...[['all', '全部'], ['available', '可安装或升级'], ['installed', '已安装'], ['retired', '已废弃']].map(([value, label]) =>
522
568
  h('button', { key: value, type: 'button', onClick: () => setFilter(value), 'aria-pressed': filter === value,
@@ -541,7 +587,9 @@ window.__ModuleLoader__.load({
541
587
  return h('article', { key: plugin.id, style: security
542
588
  ? { ...panelStyle, borderColor: 'var(--dsw-alias-label-danger, #d44)' } : panelStyle },
543
589
  h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: 8 } },
544
- h('h2', { style: { margin: 0, fontSize: 19 } }, plugin.title),
590
+ h('div', { style: { display: 'flex', alignItems: 'baseline', flexWrap: 'wrap', gap: 8 } },
591
+ h('h2', { style: { margin: 0, fontSize: 19 } }, plugin.title),
592
+ embedded ? h('span', { style: mutedTextStyle }, '插件') : null),
545
593
  h('span', { style: security
546
594
  ? { ...mutedTextStyle, color: 'var(--dsw-alias-label-danger, #d44)', fontWeight: 650 } : mutedTextStyle }, status)),
547
595
  h('p', { style: mutedTextStyle }, plugin.description),
@@ -568,9 +616,8 @@ window.__ModuleLoader__.load({
568
616
  local || uncertainId === plugin.id ? h('button', { type: 'button', onClick: () => openBundle(plugin.package_name), style: secondaryButtonStyle }, '打开 DSH 插件管理') : null,
569
617
  local && !sameVersion && plugin.status === 'published' && !artifactUrl
570
618
  ? h('p', { style: mutedTextStyle }, '本机版本与团队审核版本不同;请联系企业管理员核对。') : null))
571
- })) : !loading && plugins.length ? h('p', { style: mutedTextStyle }, filter === 'available'
572
- ? '当前没有可一键安装的插件。可在“全部”查看审核目录,或联系企业管理员。'
573
- : '没有符合筛选条件的插件。') : null))
619
+ })) : !loading && plugins.length && (!embedded || !hasSkillMatches)
620
+ ? h('p', { style: mutedTextStyle }, noMatches) : null))
574
621
  }
575
622
 
576
623
  function ModelSyncFooter({ remote, serviceUrl, bindingReady, onServiceUrlChange, onConnectionChange }) {
@@ -1167,10 +1214,16 @@ window.__ModuleLoader__.load({
1167
1214
  }
1168
1215
 
1169
1216
  function EnterpriseExtensionsPage({ remote, onBack, openBundle }) {
1170
- const [tab, setTab] = useState('skills')
1171
- return tab === 'skills'
1172
- ? h(SkillCenterPage, { onBack, onPlugins: () => setTab('plugins') })
1173
- : h(PluginCenterPage, { remote, onBack, onSkills: () => setTab('skills'), openBundle })
1217
+ const [tab, setTab] = useState('all')
1218
+ const [query, setQuery] = useState('')
1219
+ const navigation = {
1220
+ onAll: () => setTab('all'), onSkills: () => setTab('skills'),
1221
+ onPlugins: () => setTab('plugins'),
1222
+ }
1223
+ return tab === 'plugins'
1224
+ ? h(PluginCenterPage, { remote, onBack, openBundle, query, onQueryChange: setQuery, ...navigation })
1225
+ : h(SkillCenterPage, { remote, onBack, openBundle, query, onQueryChange: setQuery,
1226
+ includePlugins: tab === 'all', ...navigation })
1174
1227
  }
1175
1228
 
1176
1229
  function apply(ctx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-wendao/ant",
3
- "version": "0.3.15",
3
+ "version": "0.3.16",
4
4
  "description": "ANT (AI-native Teams) connects a DeepSeek Harness Desktop profile to team identity and approved models.",
5
5
  "type": "module",
6
6
  "scripts": {