@ai-wendao/ant 0.4.8 → 0.4.10

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 +88 -49
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -20,11 +20,11 @@ ANT (AI-native Teams) connects a DeepSeek Harness Desktop profile to its team's
20
20
 
21
21
  ## 企业精选插件
22
22
 
23
- 管理员可从 npm 官方源的 DSH Bundle 精确版本创建草稿,填写源码、许可证、依赖和安装脚本的审核记录后发布。成员在“企业扩展”总览或“插件”分类查看审核信息和本机状态。对无新增依赖、无安装阶段脚本且归档符合首批准入条件的草稿,管理员可从 npm 官方源锁定实际 `.tgz` 并查看文件清单、下载核验制品;这类草稿经审核发布后,成员可让 DSH 从 ANT 的固定制品地址一键安装。其他版本仍是目录项,需联系管理员安排。安全撤回版本会停止新的 ANT 下载,但不会自动删除本机副本;ANT 设置页继续显示相应风险公告。范围与限制见[上线边界](../../docs/decisions/2026-10-15-plugin-center-rollout.md)。
23
+ 管理员从 npm 官方源的 DSH Bundle 精确版本创建草稿,填写源码、许可证、依赖和安装脚本的审核记录后发布。成员在“企业扩展”总览或“插件”分类查看审核信息和本机状态;发布后可让 DSH 官方插件管理器从 npm 安装目录中的精确版本,无须先由管理员锁定 ANT tarball。ANT 也保留可选的固定 tarball 安装路径。直接安装时,DSH 按 registry/fallback 配置解析依赖,设备间版本可能不同;ANT 不会批准依赖构建脚本,如安装因此中断需按 DSH 提示转到原生插件管理页处理。ANT 目录不控制插件之后的自更新;部分插件可提供自己的更新器,DSH 原生插件管理页也可更换版本。安全撤回版本会停止通过 ANT 目录发起的新安装,但不会自动删除本机副本。范围与限制见[上线边界](../../docs/decisions/2026-10-15-plugin-center-rollout.md)。
24
24
 
25
25
  ANT 自身更新使用单独的已审核安装包。管理员将与 npm 发布一致的 `.tgz` 上传到 ANT 服务端并登记版本;新版 ANT 页面可点击“更新”,DSH 原位替换同名 Bundle 后提示重启。旧版 `@ai-wendao/ant` 用户可打开团队服务的 `/ant-update` 指引,在 DSH“添加插件”中粘贴该安装包地址完成一次性原位更新,无需先卸载或使用终端。此入口只分发 ANT 自身,不启用扩展中心其他插件的一键安装。
26
26
 
27
- 企业精选是团队推荐目录,不是强制白名单;ANT 不能阻止成员从 DSH 原生插件管理页自行安装其他包。第一批一键安装只分发 ANT 已核验并保存的顶层包,不把有依赖或安装脚本的版本伪装成已受控;DSH RC2 后续包管理能否一直保留这一固定制品仍需真机验收。上线边界见[待决策记录](../../docs/decisions/2026-10-15-plugin-center-rollout.md)。
27
+ 企业精选是团队推荐目录,不是强制白名单;ANT 不能阻止成员从 DSH 原生插件管理页或插件自身更新器安装其他版本。DSH `0.2.0-rc.2` 本身不自动更新已安装 Bundle;插件可以提供自己的更新操作。ANT 目录只约束它发起的安装,不对本机安装后的版本持续强制管理。上线边界见[待决策记录](../../docs/decisions/2026-10-15-plugin-center-rollout.md)。
28
28
 
29
29
  ## Existing `ant` alias installations
30
30
 
package/client.js CHANGED
@@ -227,6 +227,12 @@ window.__ModuleLoader__.load({
227
227
  ? url.href : null
228
228
  }
229
229
 
230
+ function pluginInstallSpec(plugin) {
231
+ if (plugin?.status !== 'published' || typeof plugin.package_name !== 'string'
232
+ || typeof plugin.version !== 'string' || !plugin.package_name || !plugin.version) return ''
233
+ return approvedPluginArtifactUrl(plugin) || directInstallSpec(plugin)
234
+ }
235
+
230
236
  function previouslyInstalledReviewedPlugin(plugin) {
231
237
  try { return localStorage.getItem(`${PLUGIN_INSTALL_RECORD_PREFIX}${plugin.id}`) === plugin.artifact_sha256 }
232
238
  catch { return false }
@@ -435,7 +441,8 @@ window.__ModuleLoader__.load({
435
441
  border: '0', borderBottom: activeTab === tab ? '2px solid var(--dsw-alias-state-business-primary)' : '2px solid transparent',
436
442
  backgroundColor: 'transparent',
437
443
  } }, tab === 'updates' && updateNeedsAttention ? `${label} · ${updateSummary.state === 'available' ? '有新版' : '需处理'}` : label)))),
438
- h('div', { id: 'ant-settings-content', role: 'tabpanel', 'aria-labelledby': `ant-settings-tab-${activeTab}` },
444
+ h('div', { id: 'ant-settings-content', role: 'tabpanel', 'aria-labelledby': `ant-settings-tab-${activeTab}`,
445
+ style: { display: 'grid', gap: activeTab === 'connection' ? 12 : 0 } },
439
446
  teamServicePanel,
440
447
  h(ModelSyncFooter, { remote, serviceUrl, bindingReady: binding.state === 'ready', activeTab,
441
448
  onServiceUrlChange: setServiceUrl, onConnectionChange,
@@ -657,7 +664,7 @@ window.__ModuleLoader__.load({
657
664
  const result = await readLocalJsonResponse(response)
658
665
  if (!response.ok) throw new Error(result.message || '无法获取身份绑定码。')
659
666
  setBindingCode(result.code)
660
- setMessage('绑定码 5 分钟有效。请你本人私聊这个机器人完成绑定。')
667
+ setMessage('')
661
668
  } catch (error) { setMessage(error.message) }
662
669
  finally { setBusy(false) }
663
670
  }
@@ -949,7 +956,8 @@ window.__ModuleLoader__.load({
949
956
  h('p', { role: 'status', style: mutedTextStyle }, '私聊与群聊可同时开启;每项能力一次只授权给一个私聊或一个群。普通对话不会自动获得读取电脑、调用工具或访问其他群的权限。'),
950
957
  loadFailures.length ? h('p', { role: 'status', style: mutedTextStyle },
951
958
  `部分协作信息暂时无法读取:${loadFailures.map((path) => loadNames[path]).join('、')}。已读取的信息仍显示,请稍后刷新状态。`) : null,
952
- h('span', { role: 'status', style: mutedTextStyle }, loading ? '正在读取机器人与任务状态…'
959
+ h('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'flex-start', justifyContent: 'space-between', gap: 8 } },
960
+ h('span', { role: 'status', style: { ...mutedTextStyle, flex: '1 1 260px', minWidth: 0 } }, loading ? '正在读取机器人与任务状态…'
953
961
  : botLoadError ? '暂时无法读取机器人状态。请刷新后再试。'
954
962
  : connectedBots.length === 0 ? '尚未发现已连接的机器人。请先在 DSH-IM 中连接飞书机器人。'
955
963
  : selectedBot && !botConnected ? `“${selectedBot.name}”当前离线;请先在 DSH-IM 恢复连接。`
@@ -965,6 +973,10 @@ window.__ModuleLoader__.load({
965
973
  : !dmChatEnabled ? `“${selectedBot.name}”已启用协作;私聊已关闭,群聊仍按各自设置工作。`
966
974
  : selectedTaskCount === 0 ? `“${selectedBot.name}”已启用协作;下一步开放一项能力。你也可以先私聊自测普通聊天。`
967
975
  : `“${selectedBot.name}”已启用协作 · ${selectedTaskCount} 项能力已开放。可以私聊自测。`),
976
+ h('button', { type: 'button', disabled: loading || busy,
977
+ onClick: () => void load().catch((error) => setMessage(error.message)),
978
+ style: { ...secondaryButtonStyle, whiteSpace: 'nowrap' } },
979
+ loading ? '正在刷新…' : '刷新状态')),
968
980
  bots.length ? h('label', null, '我的机器人', h('select', { id: 'ant-bot-selector', value: botId,
969
981
  onChange: (event) => { setBotId(event.target.value); setGroupId(''); setChatGroupId(''); setBindingCode('');
970
982
  setTrustedOrigin(enrolled.find((bot) => bot.bot_id === event.target.value)?.gitea_origin || '') }, style: inputStyle },
@@ -991,13 +1003,29 @@ window.__ModuleLoader__.load({
991
1003
  h('button', { type: 'button', disabled: busy || !trustedOrigin.trim() || (!selectedEnrollmentBound && !botConnected),
992
1004
  onClick: () => void (selectedEnrollmentBound ? saveTrustedOrigin() : enrollBot()), style: secondaryButtonStyle },
993
1005
  selectedEnrollmentBound ? '保存可信地址' : botConnected ? '绑定机器人并保存地址' : '先连接机器人'))) : null,
1006
+ selectedBot && selectedEnrollmentBound ? h('div', { role: 'region', 'aria-label': '群任务所有者身份验证',
1007
+ style: { display: 'grid', gap: 8, padding: 10, border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8,
1008
+ backgroundColor: 'var(--dsw-alias-bg-layer-1)' } },
1009
+ h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 8 } },
1010
+ h('strong', null, '群任务所有者身份'),
1011
+ h('span', { role: 'status', style: { ...mutedTextStyle, color: selectedEnrollment.owner_bound
1012
+ ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-warning-primary, var(--dsw-alias-label-secondary))' } },
1013
+ selectedEnrollment.owner_bound ? '已绑定' : '尚未绑定')),
1014
+ h('p', { style: mutedTextStyle }, '绑定只针对当前机器人,所有群共用。只有允许群成员请求已开放能力时才需要;普通群聊无需绑定。绑定后,群任务仍需你在目标群按机器人提示确认。'),
1015
+ h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } },
1016
+ h('button', { type: 'button', disabled: busy || !botConnected || enrollmentLoadError,
1017
+ onClick: () => void issueBindingCode(), style: secondaryButtonStyle },
1018
+ selectedEnrollment.owner_bound ? '重新获取绑定码' : '获取绑定码'),
1019
+ bindingCode ? h('span', { role: 'status', style: mutedTextStyle },
1020
+ `请你本人私聊“${selectedBot.name}”发送“绑定身份 ${bindingCode}”。绑定码 5 分钟有效。`) : null)) : null,
994
1021
  setupStepper,
995
1022
  chatScopePanel,
996
1023
  selectedEnrollmentBound && botConnected ? h('p', { style: mutedTextStyle },
997
1024
  dmChatEnabled
998
1025
  ? `自测:私聊“${selectedBot.name}”发送“你能做什么”;发起任务后可问“刚才的任务怎么样了”。群聊请先在目标群 @机器人,再开放能力时选择该群。`
999
1026
  : '私聊当前已关闭;如要恢复,请在上方开启。群聊请先在目标群 @机器人,再开放能力时选择该群。') : null,
1000
- selectedEnrollmentBound && botConnected ? h('div', { style: { display: 'grid', gap: 8 } },
1027
+ selectedEnrollmentBound && botConnected ? h('div', { role: 'region', 'aria-label': '群聊白名单',
1028
+ style: { display: 'grid', gap: 8 } },
1001
1029
  h('strong', null, '群聊白名单'),
1002
1030
  h('span', { role: 'status', style: mutedTextStyle }, groupChatLoadFailed
1003
1031
  ? '群聊列表与当前权限暂时无法读取,请刷新后再更改;仍可填写群 ID。'
@@ -1020,28 +1048,16 @@ window.__ModuleLoader__.load({
1020
1048
  onChange: (event) => setChatGroupId(event.target.value.trim()),
1021
1049
  placeholder: '输入群 ID', style: inputStyle })),
1022
1050
  selectedChatGroup?.chat_enabled && selectedGroupHasTasks ? h('span', { style: mutedTextStyle },
1023
- '本群还有开放能力;关闭普通聊天前请先停止这些能力。') : null,
1024
- h('div', { style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap', paddingTop: 4,
1025
- borderTop: '1px solid var(--dsw-alias-border-l2)' } },
1026
- h('span', { style: mutedTextStyle }, '群内所有者身份'),
1027
- h('span', { style: { ...mutedTextStyle, color: selectedEnrollment.owner_bound
1028
- ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-warning-primary, var(--dsw-alias-label-secondary))' } },
1029
- selectedEnrollment.owner_bound ? '已绑定' : '尚未绑定'),
1030
- h('button', { type: 'button', disabled: busy || !chatGroupId.trim(),
1031
- onClick: () => void issueBindingCode(), style: secondaryButtonStyle },
1032
- selectedEnrollment.owner_bound ? '重新获取绑定码' : '获取绑定码')),
1033
- h('span', { style: mutedTextStyle }, '仅当允许群成员发起受限能力时需要;验证后由机器人所有者在群内确认。'),
1034
- bindingCode ? h('p', { role: 'status', style: mutedTextStyle },
1035
- `请你本人私聊机器人发送“绑定身份 ${bindingCode}”,再回到群里 @机器人完成确认。`) : null) : null,
1036
- h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' } },
1037
- h('button', { type: 'button', onClick: () => { setCreateOpen(true); onSelectTab('capability') },
1038
- style: primaryButtonStyle }, '开放新能力'),
1039
- h('button', { type: 'button', onClick: () => { preparePrExample(); onSelectTab('capability') }, style: secondaryButtonStyle }, '使用 PR 差异审查示例'),
1040
- h('button', { type: 'button', onClick: () => void load().catch((error) => setMessage(error.message)),
1041
- style: secondaryButtonStyle }, '刷新状态'))),
1051
+ '本群还有开放能力;关闭普通聊天前请先停止这些能力。') : null) : null),
1042
1052
  h('div', { id: 'ant-capability-list', role: 'region', 'aria-label': '已开放能力列表', tabIndex: -1,
1043
1053
  style: { display: activeTab === 'capability' ? 'grid' : 'none', gap: 12 } },
1044
- h('h4', { style: sectionTitleStyle }, `我开放的能力 · ${authorizationLoadError ? '暂未读取' : activeCards.length}`),
1054
+ h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 10, flexWrap: 'wrap' } },
1055
+ h('h4', { style: sectionTitleStyle }, `我开放的能力 · ${authorizationLoadError ? '暂未读取' : activeCards.length}`),
1056
+ h('div', { role: 'toolbar', 'aria-label': '能力授权操作', style: { display: 'flex', gap: 8, flexWrap: 'wrap' } },
1057
+ h('button', { type: 'button', onClick: () => { setCreateOpen(true); onSelectTab('capability') },
1058
+ style: primaryButtonStyle }, '开放新能力'),
1059
+ h('button', { type: 'button', onClick: () => { preparePrExample(); onSelectTab('capability') },
1060
+ style: secondaryButtonStyle }, '使用 PR 差异审查示例'))),
1045
1061
  h('p', { style: mutedTextStyle }, '当前一项能力只能绑定一个范围:私聊,或某一个群。若要给其他群或私聊开放相同任务,目前需分别建立能力卡;它们的请求人和有效期独立。'),
1046
1062
  ...activeCards.map((card) => {
1047
1063
  const expiresAt = Number(card.expires_at) * 1000
@@ -1257,18 +1273,21 @@ window.__ModuleLoader__.load({
1257
1273
  h('button', { type: 'button', onClick: () => void load().catch((error) => setMessage(error.message)), style: secondaryButtonStyle }, '刷新')),
1258
1274
  loadFailures.includes('local-settings') ? h('p', { role: 'status', style: mutedTextStyle },
1259
1275
  '本机处理设置暂未读取;请刷新后重试。')
1260
- : h('form', { onSubmit: saveLocalProcessingSettings, style: { display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'end' } },
1261
- h('label', null, '这台电脑最多同时处理',
1276
+ : h('form', { onSubmit: saveLocalProcessingSettings, style: { display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'end' } },
1277
+ h('label', { style: { display: 'grid', gap: 5, flex: '0 1 280px', maxWidth: '100%' } }, '这台电脑最多同时处理',
1262
1278
  h('select', { value: localConcurrency == null ? '' : String(localConcurrency),
1263
- onChange: (event) => setLocalConcurrency(event.target.value), style: inputStyle },
1279
+ onChange: (event) => setLocalConcurrency(event.target.value), style: { ...inputStyle, width: '100%' } },
1264
1280
  h('option', { value: '' }, '跟随团队默认'),
1265
1281
  ...Array.from({ length: 8 }, (_, index) => h('option', { key: index + 1, value: index + 1 }, `${index + 1} 项任务`)))),
1266
- h('label', null, '这台电脑 PR 仓库缓存上限(GiB)',
1267
- h('input', { type: 'number', min: 1, max: 100, step: 1, required: true,
1282
+ h('label', { style: { display: 'grid', gap: 5, flex: '0 1 200px', maxWidth: '100%' } },
1283
+ '这台电脑 PR 仓库缓存上限(GiB)',
1284
+ h('input', { 'aria-label': '这台电脑 PR 仓库缓存上限(GiB)', type: 'number', min: 1, max: 100, step: 1, required: true,
1268
1285
  value: repositoryCacheLimitGib,
1269
- onChange: (event) => setRepositoryCacheLimitGib(event.target.value), style: inputStyle }),
1270
- h('span', { style: mutedTextStyle }, '默认 10 GiB,范围 1–100 GiB,按长期仓库文件逻辑大小计算(不含临时工作区和文件系统分配开销)。日常不会淘汰仍启用能力的缓存;停用或到期能力会在刷新时回收。单次拉取若实际越界,为恢复预算会清理这项能力的仓库缓存(旧 PR 可重新下载)。')),
1271
- h('button', { disabled: busy, style: secondaryButtonStyle }, '保存本机处理设置')),
1286
+ onChange: (event) => setRepositoryCacheLimitGib(event.target.value),
1287
+ style: { ...inputStyle, width: 128, maxWidth: '100%', boxSizing: 'border-box' } })),
1288
+ h('button', { disabled: busy, style: secondaryButtonStyle }, '保存本机处理设置'),
1289
+ h('p', { style: { ...mutedTextStyle, flex: '1 1 100%', margin: 0 } },
1290
+ '默认 10 GiB,范围 1–100 GiB,按长期仓库文件逻辑大小计算(不含临时工作区和文件系统分配开销)。日常不会淘汰仍启用能力的缓存;停用或到期能力会在刷新时回收。单次拉取若实际越界,为恢复预算会清理这项能力的仓库缓存(旧 PR 可重新下载)。')),
1272
1291
  h('p', { style: mutedTextStyle }, `本机检测到的执行方:${executors.map((item) => `${item.title}${item.available ? '(可用)' : `(${item.reason || '未启用或未找到'})`}`).join('、') || '暂未读取到'}。只有能力配置下拉框中列出的执行方能接收委托。`))))
1273
1292
  }
1274
1293
 
@@ -1583,15 +1602,21 @@ window.__ModuleLoader__.load({
1583
1602
  useEffect(() => { void refresh() }, [refreshToken])
1584
1603
  const install = async (plugin) => {
1585
1604
  const artifactUrl = approvedPluginArtifactUrl(plugin)
1586
- if (!artifactUrl || workingId || uncertainId === plugin.id || completedId === plugin.id) return
1605
+ const installSpec = pluginInstallSpec(plugin)
1606
+ if (!installSpec || workingId || uncertainId === plugin.id || completedId === plugin.id) return
1587
1607
  const manager = remote?.pluginManager
1588
1608
  if (typeof manager?.installBundle !== 'function') {
1589
1609
  setMessage('当前 DSH 未提供插件安装接口,请联系管理员。')
1590
1610
  return
1591
1611
  }
1592
1612
  const local = bundles.find((bundle) => bundle.name === plugin.package_name && bundle.installed)
1593
- const action = local ? local.version === plugin.version ? '重新安装' : '更新' : '安装'
1594
- if (!window.confirm(`在这台 DSH ${action}团队审核的 ${plugin.title} ${plugin.version}?插件将在本机运行,完成后需要完全重启 DSH。`)) return
1613
+ const localAhead = local?.version && newerVersion(local.version, plugin.version)
1614
+ const action = localAhead ? '回退到团队版本' : local ? local.version === plugin.version ? '重新安装' : '更新' : '安装'
1615
+ const sourceNotice = artifactUrl
1616
+ ? 'DSH 将安装 ANT 固定的顶层制品。'
1617
+ : `DSH 将优先从 npm 官方源以 ${installSpec} 安装此精确版本,并按其配置回退 registry;依赖版本可能因设备不同。`
1618
+ const updateNotice = 'ANT 不会批准依赖构建脚本;插件自身的更新器或 DSH 原生管理页之后仍可安装其他版本。'
1619
+ if (!window.confirm(`在这台 DSH ${action}团队审核的 ${plugin.title} ${plugin.version}?${sourceNotice}${updateNotice} 插件将在本机运行,完成后需要完全重启 DSH。`)) return
1595
1620
  setWorkingId(plugin.id)
1596
1621
  setMessage(`正在安装 ${plugin.title},请不要退出 DSH…`)
1597
1622
  try {
@@ -1600,13 +1625,15 @@ window.__ModuleLoader__.load({
1600
1625
  const latest = Array.isArray(catalog?.plugins)
1601
1626
  ? catalog.plugins.find((item) => item.id === plugin.id) : null
1602
1627
  if (!response.ok || latest?.package_name !== plugin.package_name
1603
- || latest?.version !== plugin.version || latest?.artifact_sha256 !== plugin.artifact_sha256
1604
- || approvedPluginArtifactUrl(latest) !== artifactUrl) {
1628
+ || latest?.version !== plugin.version || pluginInstallSpec(latest) !== installSpec) {
1605
1629
  throw new Error('插件审核信息已变化,请刷新目录后重试。')
1606
1630
  }
1607
1631
  const requestId = crypto.randomUUID()
1608
1632
  let result
1609
- try { result = await manager.installBundle(artifactUrl, { enabled: true, requestId }) }
1633
+ const options = artifactUrl
1634
+ ? { enabled: true, requestId }
1635
+ : { enabled: true, requestId, registry: 'https://registry.npmjs.org/' }
1636
+ try { result = await manager.installBundle(installSpec, options) }
1610
1637
  catch { result = null }
1611
1638
  if (!result?.ok) {
1612
1639
  let recovered = null
@@ -1658,7 +1685,9 @@ window.__ModuleLoader__.load({
1658
1685
  return
1659
1686
  }
1660
1687
  await refresh()
1661
- try { localStorage.setItem(`${PLUGIN_INSTALL_RECORD_PREFIX}${plugin.id}`, plugin.artifact_sha256) } catch {}
1688
+ if (artifactUrl && plugin.artifact_sha256) {
1689
+ try { localStorage.setItem(`${PLUGIN_INSTALL_RECORD_PREFIX}${plugin.id}`, plugin.artifact_sha256) } catch {}
1690
+ }
1662
1691
  setCompletedId(plugin.id)
1663
1692
  setMessage(`${plugin.title} 已安装。请完全退出并重新启动 DSH 后使用。`)
1664
1693
  } catch (error) {
@@ -1669,10 +1698,12 @@ window.__ModuleLoader__.load({
1669
1698
  const visible = plugins.filter((plugin) => {
1670
1699
  const installed = bundles.find((bundle) => bundle.name === plugin.package_name && bundle.installed)
1671
1700
  const artifactUrl = approvedPluginArtifactUrl(plugin)
1701
+ const installSpec = pluginInstallSpec(plugin)
1702
+ const localAhead = installed?.version && newerVersion(installed.version, plugin.version)
1672
1703
  const matches = !query.trim() || `${plugin.title} ${plugin.description} ${plugin.package_name}`.toLowerCase().includes(query.trim().toLowerCase())
1673
1704
  return matches && (activeFilter === 'all' || activeFilter === 'installed' && Boolean(installed)
1674
- || activeFilter === 'available' && artifactUrl && (!installed || (installed.version && installed.version !== plugin.version))
1675
- || activeFilter === 'updates' && artifactUrl && installed && installed.version && installed.version !== plugin.version
1705
+ || activeFilter === 'available' && installSpec && !localAhead && (!installed || (installed.version && installed.version !== plugin.version))
1706
+ || activeFilter === 'updates' && installSpec && installed && installed.version && installed.version !== plugin.version && !localAhead
1676
1707
  || activeFilter === 'retired' && plugin.status !== 'published')
1677
1708
  })
1678
1709
  const noMatches = embedded
@@ -1694,7 +1725,7 @@ window.__ModuleLoader__.load({
1694
1725
  embedded ? null : h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: 16 } },
1695
1726
  h('div', null,
1696
1727
  h('h1', { style: { margin: 0, fontSize: 28 } }, '企业精选插件'),
1697
- h('p', { style: { ...mutedTextStyle, marginTop: 6 } }, '这里展示团队审核过的插件版本及本机状态。')),
1728
+ h('p', { style: { ...mutedTextStyle, marginTop: 6 } }, '这里展示团队审核过的插件版本及本机状态。DSH 0.2.0-rc.2 不会自动更新 Bundle;插件自身的更新器可能绕过此目录安装其他版本。')),
1698
1729
  h('button', { type: 'button', disabled: loading, onClick: () => void refresh(), style: secondaryButtonStyle }, loading ? '读取中…' : '刷新目录')),
1699
1730
  !loading && !plugins.length && !loadError ? embedded
1700
1731
  ? h('p', { role: 'status', style: mutedTextStyle }, '团队暂未发布精选插件。')
@@ -1716,16 +1747,19 @@ window.__ModuleLoader__.load({
1716
1747
  const sameVersion = local?.version === plugin.version
1717
1748
  const security = plugin.status === 'security_withdrawn'
1718
1749
  const artifactUrl = approvedPluginArtifactUrl(plugin)
1750
+ const installSpec = pluginInstallSpec(plugin)
1751
+ const localAhead = local?.version && newerVersion(local.version, plugin.version)
1719
1752
  const sourceKnown = typeof local?.source === 'string'
1720
1753
  const verifiedLocal = sameVersion && artifactUrl && sourceKnown && local.source === artifactUrl
1721
1754
  const recordedInstall = sameVersion && !sourceKnown && previouslyInstalledReviewedPlugin(plugin)
1722
1755
  const status = security ? '已废弃(安全风险)'
1723
- : plugin.status === 'deprecated' ? '已废弃' : local?.error ? '加载异常' : sameVersion
1756
+ : plugin.status === 'deprecated' ? '已废弃' : local?.error ? '加载异常' : localAhead
1757
+ ? '本机版本高于团队目录版本' : sameVersion
1724
1758
  ? verifiedLocal ? local.enabled ? '本机已装(团队来源,已启用)' : '本机已装(团队来源,未启用)'
1725
1759
  : sourceKnown ? '本机同版,来源不同' : recordedInstall
1726
1760
  ? '本机同版,曾由企业扩展安装;当前 DSH 无法复核来源' : '本机同版,当前 DSH 无法核对来源'
1727
- : artifactUrl ? local ? local.version ? `可更新 · 本机 ${local.version}` : '本机版本暂无法读取' : '可安装'
1728
- : local ? `本机版本 ${local.version || '暂无法读取'}` : '已审核,暂需管理员安装'
1761
+ : installSpec ? local ? local.version ? `可更新 · 本机 ${local.version}` : '本机版本暂无法读取' : artifactUrl ? '可安装' : '可从 npm 安装'
1762
+ : local ? `本机版本 ${local.version || '暂无法读取'}` : '已发布版本暂不可安装'
1729
1763
  return h('article', { key: plugin.id, style: security
1730
1764
  ? { ...panelStyle, borderColor: 'var(--dsw-alias-label-danger, #d44)' } : panelStyle },
1731
1765
  h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: 8 } },
@@ -1738,6 +1772,10 @@ window.__ModuleLoader__.load({
1738
1772
  h('p', { style: mutedTextStyle }, `${plugin.package_name}@${plugin.version} · 许可证:${plugin.license || '未声明'}`),
1739
1773
  h('p', { style: mutedTextStyle }, `来源:${plugin.source_url || '未提供'} · DSH 版本要求:${plugin.peer_range || '包未声明'}`),
1740
1774
  h('p', { style: mutedTextStyle }, `额外配置:${plugin.requirements || '无'}`),
1775
+ installSpec && !artifactUrl ? h('p', { role: 'note', style: mutedTextStyle },
1776
+ 'ANT 通过 DSH 包管理器安装目录中的精确 npm 版本;实际下载和依赖解析由 DSH 执行。ANT 不批准依赖构建脚本;若 DSH 因此拒绝安装,请按 DSH 提示在原生插件管理页处理。插件自身更新器或 DSH 原生管理也可更新到目录外的版本。') : null,
1777
+ plugin.dependencies && artifactUrl ? h('p', { role: 'note', style: mutedTextStyle },
1778
+ '此插件声明了依赖。ANT 固定插件包本身;DSH 会在本机按当前配置解析依赖,不同设备可能得到不同版本。依赖构建脚本由 DSH 单独请求批准。') : null,
1741
1779
  plugin.scripts ? h('p', { style: mutedTextStyle }, `包自身的安装脚本:${plugin.scripts}`) : null,
1742
1780
  plugin.status !== 'published' ? h('p', { role: 'status', style: security
1743
1781
  ? { ...mutedTextStyle, color: 'var(--dsw-alias-label-danger, #d44)' } : mutedTextStyle },
@@ -1747,16 +1785,17 @@ window.__ModuleLoader__.load({
1747
1785
  ? '此前曾由企业扩展安装;当前 DSH 无法再次核对来源。正常使用无需重复安装;若后来换过来源,可以重新安装。'
1748
1786
  : '已装同版且使用正常时无需重复安装;若想改用团队审核包,可自愿安装。') : null,
1749
1787
  h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 8 } },
1750
- artifactUrl && (!local || (local.version && !verifiedLocal))
1788
+ installSpec && (!local || (local.version && local.version !== plugin.version && (!localAhead || artifactUrl))
1789
+ || (artifactUrl && sameVersion && !verifiedLocal))
1751
1790
  ? h('button', { type: 'button', disabled: Boolean(workingId) || uncertainId === plugin.id || completedId === plugin.id,
1752
1791
  onClick: () => void install(plugin), style: primaryButtonStyle },
1753
1792
  workingId === plugin.id ? '安装中…' : uncertainId === plugin.id ? '先核对安装结果'
1754
1793
  : completedId === plugin.id ? '重启 DSH 后生效'
1755
- : local ? sameVersion ? '按团队审核包重新安装' : '更新到审核版本' : '安装到这台 DSH') : null,
1756
- plugin.status === 'published' && !local && !artifactUrl
1794
+ : local ? sameVersion || localAhead ? '按团队审核包重新安装' : '更新到审核版本' : '安装到这台 DSH') : null,
1795
+ plugin.status === 'published' && !local && !installSpec
1757
1796
  ? h('p', { style: mutedTextStyle }, '如需安装,请联系企业管理员安排。') : null,
1758
1797
  local || uncertainId === plugin.id ? h('button', { type: 'button', onClick: () => openBundle(plugin.package_name), style: secondaryButtonStyle }, '打开 DSH 插件管理') : null,
1759
- local && !sameVersion && plugin.status === 'published' && !artifactUrl
1798
+ local && !sameVersion && plugin.status === 'published' && !installSpec
1760
1799
  ? h('p', { style: mutedTextStyle }, '本机版本与团队审核版本不同;请联系企业管理员核对。') : null))
1761
1800
  })) : !loading && plugins.length && (!embedded || !hasSkillMatches)
1762
1801
  ? h('p', { style: mutedTextStyle }, noMatches) : null))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-wendao/ant",
3
- "version": "0.4.8",
3
+ "version": "0.4.10",
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": {