@ai-wendao/ant 0.3.13 → 0.3.14
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 +5 -3
- package/client.js +292 -35
- package/index.js +38 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,15 +6,17 @@ 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`
|
|
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
|
|
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
|
+
|
|
19
|
+
企业精选是团队推荐目录,不是强制白名单;ANT 不能阻止成员从 DSH 原生插件管理页自行安装其他包。第一批一键安装只分发 ANT 已核验并保存的顶层包,不把有依赖或安装脚本的版本伪装成已受控;DSH RC2 后续包管理能否一直保留这一固定制品仍需真机验收。上线边界见[待决策记录](../../docs/decisions/2026-10-15-plugin-center-rollout.md)。
|
|
18
20
|
|
|
19
21
|
## Existing `ant` alias installations
|
|
20
22
|
|
package/client.js
CHANGED
|
@@ -9,6 +9,7 @@ window.__ModuleLoader__.load({
|
|
|
9
9
|
const DEVICE_ID_STORAGE_KEY = 'ant-team-device-id'
|
|
10
10
|
const ANT_BUNDLE_PACKAGE_NAME = '@ai-wendao/ant'
|
|
11
11
|
const ANT_API_PROTOCOL_VERSIONS = [1]
|
|
12
|
+
const PLUGIN_INSTALL_RECORD_PREFIX = 'ant-reviewed-plugin-install:'
|
|
12
13
|
const fileCountFormat = new Intl.NumberFormat('zh-CN')
|
|
13
14
|
const panelStyle = {
|
|
14
15
|
display: 'grid', alignContent: 'start', gap: 14, padding: 18,
|
|
@@ -40,7 +41,7 @@ window.__ModuleLoader__.load({
|
|
|
40
41
|
gap: 5,
|
|
41
42
|
} },
|
|
42
43
|
h('h2', { style: { margin: 0, fontSize: 16 } }, '没有找到想用的技能或插件?'),
|
|
43
|
-
h('p', { style: mutedTextStyle }, '
|
|
44
|
+
h('p', { style: mutedTextStyle }, '目录里没有想用的扩展,或插件没有安装按钮?请联系企业管理员,说明你希望完成的任务或提供扩展地址。已开放安装的技能和插件可在这里直接安装;勿自行安装未经审核的扩展。'))
|
|
44
45
|
}
|
|
45
46
|
const normalizeServiceUrl = (value) => {
|
|
46
47
|
let url
|
|
@@ -97,6 +98,35 @@ window.__ModuleLoader__.load({
|
|
|
97
98
|
: ''
|
|
98
99
|
}
|
|
99
100
|
|
|
101
|
+
function approvedArtifactUrl(release) {
|
|
102
|
+
const expectedPath = `/api/ant-bundles/${release?.version}/package.tgz`
|
|
103
|
+
let url
|
|
104
|
+
try { url = new URL(release?.artifact_url) } catch { return null }
|
|
105
|
+
return normalizeServiceUrl(url.origin) === url.origin
|
|
106
|
+
&& !url.username && !url.password && !url.search && !url.hash
|
|
107
|
+
&& url.pathname === expectedPath && release?.artifact_path === expectedPath
|
|
108
|
+
&& /^[a-f0-9]{64}$/u.test(release?.artifact_sha256 || '')
|
|
109
|
+
? url.href : null
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function approvedPluginArtifactUrl(plugin) {
|
|
113
|
+
if (plugin?.status !== 'published' || typeof plugin.id !== 'string'
|
|
114
|
+
|| !/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/iu.test(plugin.id)) return null
|
|
115
|
+
const expectedPath = `/api/plugin-artifacts/${plugin.id}/package.tgz`
|
|
116
|
+
let url
|
|
117
|
+
try { url = new URL(plugin.artifact_url) } catch { return null }
|
|
118
|
+
return normalizeServiceUrl(url.origin) === url.origin
|
|
119
|
+
&& !url.username && !url.password && !url.search && !url.hash
|
|
120
|
+
&& url.pathname === expectedPath && plugin.artifact_path === expectedPath
|
|
121
|
+
&& /^[a-f0-9]{64}$/u.test(plugin.artifact_sha256 || '')
|
|
122
|
+
? url.href : null
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function previouslyInstalledReviewedPlugin(plugin) {
|
|
126
|
+
try { return localStorage.getItem(`${PLUGIN_INSTALL_RECORD_PREFIX}${plugin.id}`) === plugin.artifact_sha256 }
|
|
127
|
+
catch { return false }
|
|
128
|
+
}
|
|
129
|
+
|
|
100
130
|
function loadServiceUrl() {
|
|
101
131
|
try { return normalizeServiceUrl(localStorage.getItem(SERVICE_URL_STORAGE_KEY) || '') || '' } catch { return '' }
|
|
102
132
|
}
|
|
@@ -116,7 +146,7 @@ window.__ModuleLoader__.load({
|
|
|
116
146
|
return deviceId
|
|
117
147
|
}
|
|
118
148
|
|
|
119
|
-
function TeamServiceConfig({ remote,
|
|
149
|
+
function TeamServiceConfig({ remote, openInstalledPlugin }) {
|
|
120
150
|
const [serviceUrl, setServiceUrl] = useState(loadServiceUrl)
|
|
121
151
|
const [draft, setDraft] = useState(serviceUrl)
|
|
122
152
|
const [message, setMessage] = useState('')
|
|
@@ -181,16 +211,12 @@ window.__ModuleLoader__.load({
|
|
|
181
211
|
h('div', { style: { display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 12 } },
|
|
182
212
|
message ? h('p', { role: 'status', style: mutedTextStyle }, message) : null,
|
|
183
213
|
link ? h('a', { href: link, target: '_blank', rel: 'noopener noreferrer', style: { color: 'var(--dsw-alias-link)', fontSize: 13 } }, '打开团队管理 ↗') : null)),
|
|
184
|
-
h('section', { style: { ...panelStyle, display: 'flex', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between' } },
|
|
185
|
-
h('div', null,
|
|
186
|
-
h('h3', { style: { margin: 0, fontSize: 16, fontWeight: 650 } }, '企业精选扩展'),
|
|
187
|
-
h('p', { style: { ...mutedTextStyle, marginTop: 4 } }, '浏览团队审核发布的技能与插件;技能可在这里安装,插件安全安装暂未开放。没有找到需要的扩展时,请联系企业管理员上架。')),
|
|
188
|
-
h('button', { type: 'button', onClick: openSkillCenter, style: primaryButtonStyle }, '打开扩展中心 →')),
|
|
189
214
|
pluginAlerts.length ? h('section', { role: 'alert', style: { ...panelStyle, borderColor: 'var(--dsw-alias-label-danger, #d44)' } },
|
|
190
215
|
h('h3', { style: { margin: 0, fontSize: 16 } }, '已安装插件存在安全撤回公告'),
|
|
191
216
|
...pluginAlerts.map((plugin) => h('p', { key: plugin.id, style: mutedTextStyle },
|
|
192
217
|
`${plugin.title} ${plugin.version}${plugin.versionUnknown ? '(本机版本暂无法读取,请核对是否受影响)' : ''}:${plugin.withdrawal_reason}`)),
|
|
193
|
-
h('button', {
|
|
218
|
+
...pluginAlerts.map((plugin) => h('button', { key: `${plugin.id}-open`, type: 'button',
|
|
219
|
+
onClick: () => openInstalledPlugin(plugin.package_name), style: secondaryButtonStyle }, `在 DSH 中查看 ${plugin.title}`))) : null,
|
|
194
220
|
h(ModelSyncFooter, { remote, serviceUrl, onServiceUrlChange: setServiceUrl }))
|
|
195
221
|
}
|
|
196
222
|
|
|
@@ -295,6 +321,9 @@ window.__ModuleLoader__.load({
|
|
|
295
321
|
const [plugins, setPlugins] = useState([])
|
|
296
322
|
const [bundles, setBundles] = useState([])
|
|
297
323
|
const [loading, setLoading] = useState(false)
|
|
324
|
+
const [workingId, setWorkingId] = useState('')
|
|
325
|
+
const [uncertainId, setUncertainId] = useState('')
|
|
326
|
+
const [completedId, setCompletedId] = useState('')
|
|
298
327
|
const [message, setMessage] = useState('')
|
|
299
328
|
const [query, setQuery] = useState('')
|
|
300
329
|
const [filter, setFilter] = useState('all')
|
|
@@ -320,11 +349,96 @@ window.__ModuleLoader__.load({
|
|
|
320
349
|
} finally { setLoading(false) }
|
|
321
350
|
}
|
|
322
351
|
useEffect(() => { void refresh() }, [])
|
|
352
|
+
const install = async (plugin) => {
|
|
353
|
+
const artifactUrl = approvedPluginArtifactUrl(plugin)
|
|
354
|
+
if (!artifactUrl || workingId || uncertainId === plugin.id || completedId === plugin.id) return
|
|
355
|
+
const manager = remote?.pluginManager
|
|
356
|
+
if (typeof manager?.installBundle !== 'function') {
|
|
357
|
+
setMessage('当前 DSH 未提供插件安装接口,请联系管理员。')
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
const local = bundles.find((bundle) => bundle.name === plugin.package_name && bundle.installed)
|
|
361
|
+
const action = local ? local.version === plugin.version ? '重新安装' : '更新' : '安装'
|
|
362
|
+
if (!window.confirm(`在这台 DSH ${action}团队审核的 ${plugin.title} ${plugin.version}?插件将在本机运行,完成后需要完全重启 DSH。`)) return
|
|
363
|
+
setWorkingId(plugin.id)
|
|
364
|
+
setMessage(`正在安装 ${plugin.title},请不要退出 DSH…`)
|
|
365
|
+
try {
|
|
366
|
+
const response = await fetch('/api/ant-teams/plugins', { cache: 'no-store' })
|
|
367
|
+
const catalog = await readLocalJsonResponse(response)
|
|
368
|
+
const latest = Array.isArray(catalog?.plugins)
|
|
369
|
+
? catalog.plugins.find((item) => item.id === plugin.id) : null
|
|
370
|
+
if (!response.ok || latest?.package_name !== plugin.package_name
|
|
371
|
+
|| latest?.version !== plugin.version || latest?.artifact_sha256 !== plugin.artifact_sha256
|
|
372
|
+
|| approvedPluginArtifactUrl(latest) !== artifactUrl) {
|
|
373
|
+
throw new Error('插件审核信息已变化,请刷新目录后重试。')
|
|
374
|
+
}
|
|
375
|
+
const requestId = crypto.randomUUID()
|
|
376
|
+
let result
|
|
377
|
+
try { result = await manager.installBundle(artifactUrl, { enabled: true, requestId }) }
|
|
378
|
+
catch { result = null }
|
|
379
|
+
if (!result?.ok) {
|
|
380
|
+
let recovered = null
|
|
381
|
+
if (typeof manager.waitForInstall === 'function') {
|
|
382
|
+
try {
|
|
383
|
+
const pending = await manager.waitForInstall(requestId)
|
|
384
|
+
if (pending.ok && pending.value) recovered = { ok: true, value: pending.value }
|
|
385
|
+
} catch {}
|
|
386
|
+
}
|
|
387
|
+
if (!recovered) {
|
|
388
|
+
setUncertainId(plugin.id)
|
|
389
|
+
setMessage(`暂时无法确认 ${plugin.title} 的安装结果。请先在 DSH 插件列表核对,勿重复点击安装。`)
|
|
390
|
+
return
|
|
391
|
+
}
|
|
392
|
+
result = recovered
|
|
393
|
+
}
|
|
394
|
+
const outcome = result.value
|
|
395
|
+
if (!outcome || typeof outcome !== 'object') {
|
|
396
|
+
setUncertainId(plugin.id)
|
|
397
|
+
setMessage(`DSH 未返回 ${plugin.title} 的安装结果。请先在插件列表核对,勿重复点击安装。`)
|
|
398
|
+
return
|
|
399
|
+
}
|
|
400
|
+
if (outcome.application === 'failed' || outcome.application === 'cancelled') {
|
|
401
|
+
if (outcome.error?.code === 'ambiguous-install' && local?.version === plugin.version) {
|
|
402
|
+
setMessage(`DSH 无法确定 ${plugin.title} 本次安装的唯一结果,未确认完成。请先在 DSH 插件列表核对;若已经正常使用同版则无需重复安装,仍需核对来源时请联系管理员。`)
|
|
403
|
+
return
|
|
404
|
+
}
|
|
405
|
+
const diagnostic = typeof outcome.error?.diagnostic === 'string'
|
|
406
|
+
? outcome.error.diagnostic.slice(0, 180) : ''
|
|
407
|
+
setMessage(`${plugin.title} 安装未完成。请在 DSH 插件管理查看状态或联系管理员。${diagnostic ? `原因:${diagnostic}` : ''}`)
|
|
408
|
+
return
|
|
409
|
+
}
|
|
410
|
+
if (outcome.bundle !== plugin.package_name
|
|
411
|
+
|| !['restart-required', 'applied'].includes(outcome.application)) {
|
|
412
|
+
setUncertainId(plugin.id)
|
|
413
|
+
setMessage(`DSH 未确认 ${plugin.title} 已安装。请先在插件列表核对,勿重复点击安装。`)
|
|
414
|
+
return
|
|
415
|
+
}
|
|
416
|
+
let observed = null
|
|
417
|
+
try {
|
|
418
|
+
const installed = await manager.listBundles()
|
|
419
|
+
if (installed.ok && Array.isArray(installed.value)) {
|
|
420
|
+
observed = installed.value.find((bundle) => bundle.name === plugin.package_name && bundle.installed) || null
|
|
421
|
+
}
|
|
422
|
+
} catch {}
|
|
423
|
+
if ((outcome.version && outcome.version !== plugin.version) || observed?.version !== plugin.version) {
|
|
424
|
+
setUncertainId(plugin.id)
|
|
425
|
+
setMessage(`DSH 未确认 ${plugin.title} 的审核版本已安装。请先在插件列表核对,勿重复点击安装。`)
|
|
426
|
+
return
|
|
427
|
+
}
|
|
428
|
+
await refresh()
|
|
429
|
+
try { localStorage.setItem(`${PLUGIN_INSTALL_RECORD_PREFIX}${plugin.id}`, plugin.artifact_sha256) } catch {}
|
|
430
|
+
setCompletedId(plugin.id)
|
|
431
|
+
setMessage(`${plugin.title} 已安装。请完全退出并重新启动 DSH 后使用。`)
|
|
432
|
+
} catch (error) {
|
|
433
|
+
setMessage(error instanceof Error ? error.message : '插件安装未完成,请稍后重试。')
|
|
434
|
+
} finally { setWorkingId('') }
|
|
435
|
+
}
|
|
323
436
|
const visible = plugins.filter((plugin) => {
|
|
324
437
|
const installed = bundles.find((bundle) => bundle.name === plugin.package_name && bundle.installed)
|
|
438
|
+
const artifactUrl = approvedPluginArtifactUrl(plugin)
|
|
325
439
|
const matches = !query.trim() || `${plugin.title} ${plugin.description} ${plugin.package_name}`.toLowerCase().includes(query.trim().toLowerCase())
|
|
326
440
|
return matches && (filter === 'all' || filter === 'installed' && installed?.version === plugin.version
|
|
327
|
-
|| filter === 'available' &&
|
|
441
|
+
|| filter === 'available' && artifactUrl && (!installed || (installed.version && installed.version !== plugin.version))
|
|
328
442
|
|| filter === 'retired' && plugin.status !== 'published')
|
|
329
443
|
})
|
|
330
444
|
return h('section', { 'aria-label': '企业精选插件', style: {
|
|
@@ -340,13 +454,13 @@ window.__ModuleLoader__.load({
|
|
|
340
454
|
h('p', { style: { ...mutedTextStyle, marginTop: 6 } }, '这里展示团队审核过的插件版本及本机状态。')),
|
|
341
455
|
h('button', { type: 'button', disabled: loading, onClick: () => void refresh(), style: secondaryButtonStyle }, loading ? '读取中…' : '刷新目录')),
|
|
342
456
|
h('aside', { role: 'note', style: { ...panelStyle, borderColor: 'var(--dsw-alias-label-danger, #d44)' } },
|
|
343
|
-
h('strong', null, '
|
|
344
|
-
h('p', { style: mutedTextStyle }, '
|
|
457
|
+
h('strong', null, '只安装团队锁定的固定版本'),
|
|
458
|
+
h('p', { style: mutedTextStyle }, '显示“安装”按钮的版本已锁定实际安装包并由管理员发布;其他目录项仅供查看,如需使用请联系企业管理员。')),
|
|
345
459
|
h(ExtensionRequestNotice),
|
|
346
460
|
h('div', { style: panelStyle },
|
|
347
461
|
h('input', { type: 'search', value: query, onChange: (event) => setQuery(event.target.value), placeholder: '搜索插件名称或用途', 'aria-label': '搜索企业精选插件', style: inputStyle }),
|
|
348
462
|
h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 8 } },
|
|
349
|
-
...[['all', '全部'], ['available', '
|
|
463
|
+
...[['all', '全部'], ['available', '可安装或升级'], ['installed', '已安装'], ['retired', '已废弃']].map(([value, label]) =>
|
|
350
464
|
h('button', { key: value, type: 'button', onClick: () => setFilter(value), 'aria-pressed': filter === value,
|
|
351
465
|
style: { ...secondaryButtonStyle, minHeight: 34, backgroundColor: filter === value ? 'var(--dsw-alias-bg-layer-2)' : secondaryButtonStyle.backgroundColor } }, label)))),
|
|
352
466
|
message ? h('p', { role: 'status', style: mutedTextStyle }, message) : null,
|
|
@@ -355,10 +469,17 @@ window.__ModuleLoader__.load({
|
|
|
355
469
|
const local = bundles.find((bundle) => bundle.name === plugin.package_name && bundle.installed)
|
|
356
470
|
const sameVersion = local?.version === plugin.version
|
|
357
471
|
const security = plugin.status === 'security_withdrawn'
|
|
472
|
+
const artifactUrl = approvedPluginArtifactUrl(plugin)
|
|
473
|
+
const sourceKnown = typeof local?.source === 'string'
|
|
474
|
+
const verifiedLocal = sameVersion && artifactUrl && sourceKnown && local.source === artifactUrl
|
|
475
|
+
const recordedInstall = sameVersion && !sourceKnown && previouslyInstalledReviewedPlugin(plugin)
|
|
358
476
|
const status = security ? '已废弃(安全风险)'
|
|
359
|
-
: plugin.status === 'deprecated' ? '已废弃' : sameVersion
|
|
360
|
-
?
|
|
361
|
-
|
|
477
|
+
: plugin.status === 'deprecated' ? '已废弃' : local?.error ? '加载异常' : sameVersion
|
|
478
|
+
? verifiedLocal ? local.enabled ? '本机已装(团队来源,已启用)' : '本机已装(团队来源,未启用)'
|
|
479
|
+
: sourceKnown ? '本机同版,来源不同' : recordedInstall
|
|
480
|
+
? '本机同版,曾由企业扩展安装;当前 DSH 无法复核来源' : '本机同版,当前 DSH 无法核对来源'
|
|
481
|
+
: artifactUrl ? local ? local.version ? `可更新 · 本机 ${local.version}` : '本机版本暂无法读取' : '可安装'
|
|
482
|
+
: local ? `本机版本 ${local.version || '暂无法读取'}` : '已审核,暂需管理员安装'
|
|
362
483
|
return h('article', { key: plugin.id, style: security
|
|
363
484
|
? { ...panelStyle, borderColor: 'var(--dsw-alias-label-danger, #d44)' } : panelStyle },
|
|
364
485
|
h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', gap: 8 } },
|
|
@@ -374,13 +495,24 @@ window.__ModuleLoader__.load({
|
|
|
374
495
|
? { ...mutedTextStyle, color: 'var(--dsw-alias-label-danger, #d44)' } : mutedTextStyle },
|
|
375
496
|
plugin.withdrawal_reason || '团队已停止推荐此版本。') : null,
|
|
376
497
|
local?.error ? h('p', { role: 'status', style: mutedTextStyle }, local.error.message || String(local.error)) : null,
|
|
498
|
+
sameVersion && !sourceKnown && artifactUrl ? h('p', { style: mutedTextStyle }, recordedInstall
|
|
499
|
+
? '此前曾由企业扩展安装;当前 DSH 无法再次核对来源。正常使用无需重复安装;若后来换过来源,可以重新安装。'
|
|
500
|
+
: '已装同版且使用正常时无需重复安装;若想改用团队审核包,可自愿安装。') : null,
|
|
377
501
|
h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 8 } },
|
|
378
|
-
|
|
502
|
+
artifactUrl && (!local || (local.version && !verifiedLocal))
|
|
503
|
+
? h('button', { type: 'button', disabled: Boolean(workingId) || uncertainId === plugin.id || completedId === plugin.id,
|
|
504
|
+
onClick: () => void install(plugin), style: primaryButtonStyle },
|
|
505
|
+
workingId === plugin.id ? '安装中…' : uncertainId === plugin.id ? '先核对安装结果'
|
|
506
|
+
: completedId === plugin.id ? '重启 DSH 后生效'
|
|
507
|
+
: local ? sameVersion ? '按团队审核包重新安装' : '更新到审核版本' : '安装到这台 DSH') : null,
|
|
508
|
+
plugin.status === 'published' && !local && !artifactUrl
|
|
379
509
|
? h('p', { style: mutedTextStyle }, '如需安装,请联系企业管理员安排。') : null,
|
|
380
|
-
local ? h('button', { type: 'button', onClick: () => openBundle(plugin.package_name), style: secondaryButtonStyle }, '打开 DSH 插件管理') : null,
|
|
381
|
-
local && !sameVersion && plugin.status === 'published'
|
|
510
|
+
local || uncertainId === plugin.id ? h('button', { type: 'button', onClick: () => openBundle(plugin.package_name), style: secondaryButtonStyle }, '打开 DSH 插件管理') : null,
|
|
511
|
+
local && !sameVersion && plugin.status === 'published' && !artifactUrl
|
|
382
512
|
? h('p', { style: mutedTextStyle }, '本机版本与团队审核版本不同;请联系企业管理员核对。') : null))
|
|
383
|
-
})) : !loading && plugins.length ? h('p', { style: mutedTextStyle }, '
|
|
513
|
+
})) : !loading && plugins.length ? h('p', { style: mutedTextStyle }, filter === 'available'
|
|
514
|
+
? '当前没有可一键安装的插件。可在“全部”查看审核目录,或联系企业管理员。'
|
|
515
|
+
: '没有符合筛选条件的插件。') : null))
|
|
384
516
|
}
|
|
385
517
|
|
|
386
518
|
function ModelSyncFooter({ remote, serviceUrl, onServiceUrlChange }) {
|
|
@@ -396,6 +528,7 @@ window.__ModuleLoader__.load({
|
|
|
396
528
|
const [bundleRelease, setBundleRelease] = useState(null)
|
|
397
529
|
const [bundleUpdate, setBundleUpdate] = useState({ state: 'idle', currentVersion: '', message: '' })
|
|
398
530
|
const [serviceCompatibility, setServiceCompatibility] = useState({ state: 'idle', message: '' })
|
|
531
|
+
const [pinnedServiceUrl, setPinnedServiceUrl] = useState(null)
|
|
399
532
|
|
|
400
533
|
const connectionErrorMessage = (result, status) => {
|
|
401
534
|
const message = result?.message || `请求失败(${status})`
|
|
@@ -563,16 +696,105 @@ window.__ModuleLoader__.load({
|
|
|
563
696
|
throw new Error(`当前 DSH 未找到已安装的 ${release.package_name} Bundle。`)
|
|
564
697
|
}
|
|
565
698
|
const available = newerVersion(release.version, installed.version)
|
|
699
|
+
if (release.artifact_status === 'revoked') {
|
|
700
|
+
setBundleUpdate({ state: 'revoked', currentVersion: installed.version,
|
|
701
|
+
message: installed.version === release.version
|
|
702
|
+
? `当前 ANT ${installed.version} 的安装包已因安全问题停用。请联系企业管理员获取处理方式;ANT 不会自动删除本机副本。`
|
|
703
|
+
: `发布版本 ${release.version} 的安装包已因安全问题停用,请等待管理员发布修复版本。` })
|
|
704
|
+
return
|
|
705
|
+
}
|
|
706
|
+
const artifactUrl = approvedArtifactUrl(release)
|
|
566
707
|
setBundleUpdate({
|
|
567
|
-
state: available ? 'available' : 'current',
|
|
708
|
+
state: available ? artifactUrl ? 'available' : 'artifact-missing' : 'current',
|
|
568
709
|
currentVersion: installed.version,
|
|
569
|
-
message: available
|
|
710
|
+
message: available
|
|
711
|
+
? artifactUrl
|
|
712
|
+
? `发现新版本 ${release.version},可直接更新。`
|
|
713
|
+
: `发现新版本 ${release.version},但管理员尚未提供已审核安装包。请联系管理员。`
|
|
714
|
+
: `当前已是最新发布版本(${installed.version})。`,
|
|
570
715
|
})
|
|
571
716
|
} catch (error) {
|
|
572
717
|
setBundleUpdate({ state: 'failed', currentVersion: '', message: error instanceof Error ? error.message : '检查 ANT 更新失败。' })
|
|
573
718
|
}
|
|
574
719
|
}
|
|
575
720
|
|
|
721
|
+
const installBundleUpdate = async () => {
|
|
722
|
+
if (bundleUpdate.state !== 'available') return
|
|
723
|
+
const artifactUrl = approvedArtifactUrl(bundleRelease)
|
|
724
|
+
if (!artifactUrl) return
|
|
725
|
+
const manager = remote?.pluginManager
|
|
726
|
+
if (typeof manager?.installBundle !== 'function') {
|
|
727
|
+
setBundleUpdate((current) => ({ ...current, state: 'failed', message: '当前 DSH 未提供 Bundle 更新接口。' }))
|
|
728
|
+
return
|
|
729
|
+
}
|
|
730
|
+
setBusy(true)
|
|
731
|
+
setBundleUpdate((current) => ({ ...current, state: 'installing', message: '正在由 DSH 安装已审核的 ANT 更新…' }))
|
|
732
|
+
try {
|
|
733
|
+
const releaseResponse = await fetch('/api/ant-teams/bundle-release', {
|
|
734
|
+
cache: 'no-store', headers: {
|
|
735
|
+
'x-ant-bundle-capabilities': 'direct-package-install',
|
|
736
|
+
'x-ant-bundle-update-mode': 'check-only',
|
|
737
|
+
},
|
|
738
|
+
})
|
|
739
|
+
const latest = await readLocalJsonResponse(releaseResponse)
|
|
740
|
+
if (!releaseResponse.ok || latest.version !== bundleRelease.version
|
|
741
|
+
|| latest.artifact_sha256 !== bundleRelease.artifact_sha256
|
|
742
|
+
|| approvedArtifactUrl(latest) !== artifactUrl) {
|
|
743
|
+
throw new Error('ANT 更新信息已变化,请重新检查更新。')
|
|
744
|
+
}
|
|
745
|
+
const requestId = crypto.randomUUID()
|
|
746
|
+
let result
|
|
747
|
+
try {
|
|
748
|
+
result = await manager.installBundle(artifactUrl, { enabled: true, requestId })
|
|
749
|
+
} catch {
|
|
750
|
+
result = null
|
|
751
|
+
}
|
|
752
|
+
if (!result?.ok) {
|
|
753
|
+
let recovered = null
|
|
754
|
+
if (typeof manager.waitForInstall === 'function') {
|
|
755
|
+
try {
|
|
756
|
+
const pending = await manager.waitForInstall(requestId)
|
|
757
|
+
if (pending.ok && pending.value) recovered = { ok: true, value: pending.value }
|
|
758
|
+
} catch {}
|
|
759
|
+
}
|
|
760
|
+
if (!recovered) {
|
|
761
|
+
setBundleUpdate((current) => ({ ...current, state: 'unknown',
|
|
762
|
+
message: 'DSH 连接中断,更新结果暂时无法确认。请先在 DSH 插件列表查看 ANT 版本,勿重复点击更新。' }))
|
|
763
|
+
return
|
|
764
|
+
}
|
|
765
|
+
result = recovered
|
|
766
|
+
}
|
|
767
|
+
const outcome = result.value
|
|
768
|
+
if (outcome.application === 'failed' || outcome.application === 'cancelled') {
|
|
769
|
+
const reason = outcome.error?.diagnostic || outcome.packageResult?.output || '安装未完成。'
|
|
770
|
+
setBundleUpdate((current) => ({ ...current, state: 'failed', message: `更新失败:${reason}` }))
|
|
771
|
+
return
|
|
772
|
+
}
|
|
773
|
+
if (outcome.bundle !== ANT_BUNDLE_PACKAGE_NAME
|
|
774
|
+
|| !['restart-required', 'applied'].includes(outcome.application)) {
|
|
775
|
+
throw new Error('DSH 未确认 ANT 安装成功,请联系管理员检查插件状态。')
|
|
776
|
+
}
|
|
777
|
+
let observed = null
|
|
778
|
+
try {
|
|
779
|
+
const installed = await manager.listBundles()
|
|
780
|
+
if (installed.ok && Array.isArray(installed.value)) {
|
|
781
|
+
observed = installed.value.find((bundle) => bundle.name === ANT_BUNDLE_PACKAGE_NAME && bundle.installed) || null
|
|
782
|
+
}
|
|
783
|
+
} catch {}
|
|
784
|
+
if ((outcome.version && outcome.version !== bundleRelease.version) || observed?.version !== bundleRelease.version) {
|
|
785
|
+
setBundleUpdate((current) => ({ ...current, state: 'unknown',
|
|
786
|
+
message: 'DSH 未确认新版本已安装。请先在 DSH 插件列表核对 ANT 版本,勿重复点击更新。' }))
|
|
787
|
+
return
|
|
788
|
+
}
|
|
789
|
+
setBundleUpdate({ state: 'done', currentVersion: bundleRelease.version,
|
|
790
|
+
message: `ANT ${bundleRelease.version} 已安装。请完全退出并重新启动 DSH 后生效。` })
|
|
791
|
+
} catch (error) {
|
|
792
|
+
setBundleUpdate((current) => ({ ...current, state: 'failed', message: error instanceof Error ? error.message : '更新未完成。' }))
|
|
793
|
+
} finally {
|
|
794
|
+
setBusy(false)
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
576
798
|
const clearLocalConnection = async () => {
|
|
577
799
|
if (typeof remote?.settings?.mutate !== 'function') throw new Error('DSH 未提供模型设置接口。')
|
|
578
800
|
const settingsResult = await remote.settings.mutate('llm-pi-ai', [
|
|
@@ -643,6 +865,23 @@ window.__ModuleLoader__.load({
|
|
|
643
865
|
return () => { current = false }
|
|
644
866
|
}, [remote])
|
|
645
867
|
|
|
868
|
+
useEffect(() => {
|
|
869
|
+
let current = true
|
|
870
|
+
if (credentialConfigured !== true) {
|
|
871
|
+
setPinnedServiceUrl(null)
|
|
872
|
+
return () => { current = false }
|
|
873
|
+
}
|
|
874
|
+
const readPinnedOrigin = async () => {
|
|
875
|
+
try {
|
|
876
|
+
const response = await fetch('/api/ant-teams/connection-origin', { cache: 'no-store' })
|
|
877
|
+
const result = await readLocalJsonResponse(response)
|
|
878
|
+
if (current) setPinnedServiceUrl(response.ok ? normalizeServiceUrl(result.service_url) : null)
|
|
879
|
+
} catch { if (current) setPinnedServiceUrl(null) }
|
|
880
|
+
}
|
|
881
|
+
void readPinnedOrigin()
|
|
882
|
+
return () => { current = false }
|
|
883
|
+
}, [remote, credentialConfigured])
|
|
884
|
+
|
|
646
885
|
useEffect(() => {
|
|
647
886
|
void inspectServiceCompatibility(serviceUrl, credentialConfigured === true)
|
|
648
887
|
}, [remote, serviceUrl, credentialConfigured])
|
|
@@ -746,6 +985,9 @@ window.__ModuleLoader__.load({
|
|
|
746
985
|
}
|
|
747
986
|
|
|
748
987
|
const showConnectForm = credentialConfigured !== true || reauthenticate || needsReconnect
|
|
988
|
+
const canCheckUpdate = credentialConfigured === true && !needsReconnect
|
|
989
|
+
const updateGuideUrl = pinnedServiceUrl
|
|
990
|
+
? new URL('/ant-update', pinnedServiceUrl).href : null
|
|
749
991
|
return h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 400px), 1fr))', alignItems: 'start', gap: 16 } },
|
|
750
992
|
h('section', { style: panelStyle },
|
|
751
993
|
h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12 } },
|
|
@@ -772,15 +1014,20 @@ window.__ModuleLoader__.load({
|
|
|
772
1014
|
h('button', { type: 'button', disabled: busy, onClick: () => void refreshModels(), style: primaryButtonStyle }, busy ? '刷新中…' : '刷新团队模型'),
|
|
773
1015
|
h('button', { type: 'button', disabled: busy, onClick: () => { setReauthenticate(true); setMessage('') }, style: secondaryButtonStyle }, '重新验证邮箱'),
|
|
774
1016
|
h('button', { type: 'button', disabled: busy, onClick: () => { if (window.confirm('断开当前设备与 ANT 的连接?本机 ANT 凭证和模型设置将被清除,团队服务地址会保留。')) void disconnect() }, style: secondaryButtonStyle }, '断开当前设备')) : null,
|
|
775
|
-
|
|
1017
|
+
h('section', { style: { ...panelStyle, padding: 14, gap: 10 } },
|
|
776
1018
|
h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 } },
|
|
777
1019
|
h('h4', { style: { margin: 0, fontSize: 14, fontWeight: 650 } }, 'ANT 插件更新'),
|
|
778
|
-
h('button', { type: 'button', disabled: busy || bundleUpdate.state === 'checking', onClick: () => void checkBundleUpdate(), style: secondaryButtonStyle }, bundleUpdate.state === 'checking' ? '检查中…' : '检查更新')),
|
|
779
|
-
|
|
780
|
-
|
|
1020
|
+
h('button', { type: 'button', disabled: busy || !canCheckUpdate || bundleUpdate.state === 'checking', onClick: () => void checkBundleUpdate(), style: secondaryButtonStyle }, bundleUpdate.state === 'checking' ? '检查中…' : '检查更新')),
|
|
1021
|
+
!canCheckUpdate ? h('p', { role: 'status', style: mutedTextStyle }, '连接团队后可在这里检查并安装 ANT 更新;需要先恢复插件时,可打开团队管理台的更新指引。') : null,
|
|
1022
|
+
updateGuideUrl ? h('a', { href: updateGuideUrl, target: '_blank', rel: 'noopener noreferrer', style: { color: 'var(--dsw-alias-link)', fontSize: 13 } }, `打开 ${pinnedServiceUrl} 的更新指引 ↗`)
|
|
1023
|
+
: !canCheckUpdate ? h('p', { style: mutedTextStyle }, '无法核对原团队地址时,请向企业管理员索取更新指引。') : null,
|
|
1024
|
+
bundleUpdate.message ? h('p', { role: 'status', style: bundleUpdate.state === 'revoked'
|
|
1025
|
+
? { ...mutedTextStyle, color: 'var(--dsw-alias-state-error-primary)' } : mutedTextStyle }, bundleUpdate.message) : null,
|
|
1026
|
+
canCheckUpdate && bundleRelease?.version && ['available', 'artifact-missing'].includes(bundleUpdate.state) ? h('div', { style: { display: 'grid', gap: 8 } },
|
|
781
1027
|
h('p', { style: mutedTextStyle }, `发布版本:${bundleRelease.version} · 精确包名:${directInstallSpec(bundleRelease)}`),
|
|
782
1028
|
bundleRelease.release_notes ? h('p', { style: mutedTextStyle }, bundleRelease.release_notes) : null,
|
|
783
|
-
|
|
1029
|
+
bundleUpdate.state === 'available'
|
|
1030
|
+
? h('button', { type: 'button', disabled: busy, onClick: () => void installBundleUpdate(), style: primaryButtonStyle }, busy ? '更新中…' : '更新 ANT') : null) : null),
|
|
784
1031
|
showConnectForm ? h('form', { onSubmit: requestCode, style: { display: 'grid', gap: 9, maxWidth: 560 } },
|
|
785
1032
|
h('label', { htmlFor: 'ant-team-model-email', style: { fontSize: 13, fontWeight: 550 } }, '工作邮箱'),
|
|
786
1033
|
h('input', {
|
|
@@ -822,6 +1069,20 @@ window.__ModuleLoader__.load({
|
|
|
822
1069
|
|
|
823
1070
|
}
|
|
824
1071
|
|
|
1072
|
+
function EnterpriseExtensionsPanelIcon({ size }) {
|
|
1073
|
+
return h('span', { 'aria-hidden': true, style: {
|
|
1074
|
+
display: 'inline-grid', placeItems: 'center', width: size, height: size,
|
|
1075
|
+
fontSize: size, lineHeight: 1,
|
|
1076
|
+
} }, '✦')
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
function EnterpriseExtensionsPage({ remote, onBack, openBundle }) {
|
|
1080
|
+
const [tab, setTab] = useState('skills')
|
|
1081
|
+
return tab === 'skills'
|
|
1082
|
+
? h(SkillCenterPage, { onBack, onPlugins: () => setTab('plugins') })
|
|
1083
|
+
: h(PluginCenterPage, { remote, onBack, onSkills: () => setTab('skills'), openBundle })
|
|
1084
|
+
}
|
|
1085
|
+
|
|
825
1086
|
function apply(ctx) {
|
|
826
1087
|
const remote = {
|
|
827
1088
|
credentials: ctx.remote.credentials,
|
|
@@ -829,17 +1090,14 @@ window.__ModuleLoader__.load({
|
|
|
829
1090
|
pluginManager: ctx.remote.pluginManager,
|
|
830
1091
|
}
|
|
831
1092
|
ctx.slots.inject('main', () => ctx.slots.register({ name: 'main', key: 'ant-skills' },
|
|
832
|
-
() => h(
|
|
833
|
-
onBack: () => ctx.pluginNavigation.openBundle(ANT_BUNDLE_PACKAGE_NAME),
|
|
834
|
-
onPlugins: () => ctx.layout.selectPanel('ant-plugins'),
|
|
835
|
-
})))
|
|
836
|
-
ctx.slots.inject('main', () => ctx.slots.register({ name: 'main', key: 'ant-plugins' },
|
|
837
|
-
() => h(PluginCenterPage, {
|
|
1093
|
+
() => h(EnterpriseExtensionsPage, {
|
|
838
1094
|
remote,
|
|
839
1095
|
onBack: () => ctx.pluginNavigation.openBundle(ANT_BUNDLE_PACKAGE_NAME),
|
|
840
|
-
onSkills: () => ctx.layout.selectPanel('ant-skills'),
|
|
841
1096
|
openBundle: (name) => ctx.pluginNavigation.openBundle(name),
|
|
842
1097
|
})))
|
|
1098
|
+
ctx.slots.inject('sidebar.panellist', () => ctx.slots.register({
|
|
1099
|
+
name: 'sidebar.panellist', id: 'ant-skills', order: 5, label: '企业扩展',
|
|
1100
|
+
}, EnterpriseExtensionsPanelIcon))
|
|
843
1101
|
ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({
|
|
844
1102
|
name: 'plugins.bundle.config',
|
|
845
1103
|
key: ANT_BUNDLE_PACKAGE_NAME,
|
|
@@ -848,8 +1106,7 @@ window.__ModuleLoader__.load({
|
|
|
848
1106
|
? h('p', null, 'ANT 团队服务入口。')
|
|
849
1107
|
: h(TeamServiceConfig, {
|
|
850
1108
|
remote: injectedRemote,
|
|
851
|
-
|
|
852
|
-
openPluginCenter: () => ctx.layout.selectPanel('ant-plugins'),
|
|
1109
|
+
openInstalledPlugin: (name) => ctx.pluginNavigation.openBundle(name),
|
|
853
1110
|
})))
|
|
854
1111
|
}
|
|
855
1112
|
|
package/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export const inject = []
|
|
|
8
8
|
const MODEL_SYNC_PATH = '/api/ant-teams/models'
|
|
9
9
|
const SERVICE_INFO_PATH = '/api/ant-teams/service-info'
|
|
10
10
|
const BUNDLE_RELEASE_PATH = '/api/ant-teams/bundle-release'
|
|
11
|
+
const CONNECTION_ORIGIN_PATH = '/api/ant-teams/connection-origin'
|
|
11
12
|
const DISCONNECT_PATH = '/api/ant-teams/disconnect'
|
|
12
13
|
const REQUEST_CODE_PATH = '/api/ant-teams/request-code'
|
|
13
14
|
const CONNECT_PATH = '/api/ant-teams/connect'
|
|
@@ -292,19 +293,37 @@ async function fetchBundleRelease(request, credentials, settings) {
|
|
|
292
293
|
const directInstallSpec = release?.package_name && release?.version
|
|
293
294
|
? `${release.package_name}@${release.version}`
|
|
294
295
|
: ''
|
|
296
|
+
const artifactPath = release?.version ? `/api/ant-bundles/${release.version}/package.tgz` : ''
|
|
297
|
+
const hasArtifact = release?.artifact_path === artifactPath
|
|
298
|
+
&& /^[a-f0-9]{64}$/u.test(release?.artifact_sha256 || '')
|
|
299
|
+
const noArtifact = !release?.artifact_path && !release?.artifact_sha256
|
|
295
300
|
if (release?.bundle_name !== 'ant' || !validPackageName || !validVersion
|
|
296
301
|
|| typeof release?.install_spec !== 'string' || typeof release?.release_notes !== 'string'
|
|
297
302
|
|| (release.version && release.install_spec !== installSpec)
|
|
298
303
|
|| (!release.version && release.install_spec !== '')
|
|
299
|
-
|| (release.direct_install_spec !== undefined && release.direct_install_spec !== directInstallSpec)
|
|
304
|
+
|| (release.direct_install_spec !== undefined && release.direct_install_spec !== directInstallSpec)
|
|
305
|
+
|| (!hasArtifact && !noArtifact)) {
|
|
300
306
|
return jsonResponse(502, { message: 'ANT 更新信息字段无效。' })
|
|
301
307
|
}
|
|
302
|
-
return jsonResponse(200,
|
|
308
|
+
return jsonResponse(200, hasArtifact ? {
|
|
309
|
+
...release,
|
|
310
|
+
artifact_url: new URL(artifactPath, connection.serviceUrl).href,
|
|
311
|
+
} : release)
|
|
303
312
|
} catch {
|
|
304
313
|
return jsonResponse(502, { message: '无法连接 ANT 更新服务。' })
|
|
305
314
|
}
|
|
306
315
|
}
|
|
307
316
|
|
|
317
|
+
async function fetchConnectionOrigin(request, credentials, settings) {
|
|
318
|
+
if (request.method !== 'GET') return jsonResponse(405, { message: '只支持 GET 请求' })
|
|
319
|
+
try {
|
|
320
|
+
const connection = await readMemberConnection(credentials, settings)
|
|
321
|
+
return jsonResponse(200, { service_url: connection?.serviceUrl || null })
|
|
322
|
+
} catch {
|
|
323
|
+
return jsonResponse(500, { message: '无法核对已绑定的 ANT 团队地址。' })
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
308
327
|
async function disconnectMember(request, credentials, settings) {
|
|
309
328
|
if (request.method !== 'POST') return jsonResponse(405, { message: '只支持 POST 请求' })
|
|
310
329
|
let connection
|
|
@@ -397,7 +416,17 @@ async function fetchMemberPlugins(request, credentials, settings) {
|
|
|
397
416
|
{ message: '无法读取企业精选插件目录。' })
|
|
398
417
|
const plugins = JSON.parse(text)
|
|
399
418
|
if (!Array.isArray(plugins)) throw new Error('插件目录格式无效。')
|
|
400
|
-
return jsonResponse(200, { plugins
|
|
419
|
+
return jsonResponse(200, { plugins: plugins.map((plugin) => {
|
|
420
|
+
const validId = typeof plugin?.id === 'string'
|
|
421
|
+
&& /^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/iu.test(plugin.id)
|
|
422
|
+
const validDigest = /^[0-9a-f]{64}$/u.test(plugin?.artifact_sha256 || '')
|
|
423
|
+
if (plugin?.status !== 'published' || !validId || !validDigest) {
|
|
424
|
+
return { ...plugin, artifact_sha256: null }
|
|
425
|
+
}
|
|
426
|
+
const artifactPath = `/api/plugin-artifacts/${plugin.id}/package.tgz`
|
|
427
|
+
return { ...plugin, artifact_path: artifactPath,
|
|
428
|
+
artifact_url: new URL(artifactPath, connection.serviceUrl).href }
|
|
429
|
+
}) })
|
|
401
430
|
} catch {
|
|
402
431
|
return jsonResponse(502, { message: '无法读取企业精选插件目录。' })
|
|
403
432
|
}
|
|
@@ -505,6 +534,12 @@ export function apply(ctx) {
|
|
|
505
534
|
requestBody: 'buffered',
|
|
506
535
|
fetch: (request) => fetchBundleRelease(request, connectionCtx.credentials, connectionCtx.settings),
|
|
507
536
|
}), 'ant-teams: authenticated Bundle release relay')
|
|
537
|
+
connectionCtx.effect(() => connectionCtx.connection.fetch.register({
|
|
538
|
+
path: CONNECTION_ORIGIN_PATH,
|
|
539
|
+
methods: ['GET'],
|
|
540
|
+
requestBody: 'buffered',
|
|
541
|
+
fetch: (request) => fetchConnectionOrigin(request, connectionCtx.credentials, connectionCtx.settings),
|
|
542
|
+
}), 'ant-teams: pinned connection origin for update guide')
|
|
508
543
|
connectionCtx.effect(() => connectionCtx.connection.fetch.register({
|
|
509
544
|
path: SKILLS_PATH, methods: ['GET'], requestBody: 'buffered',
|
|
510
545
|
fetch: (request) => fetchMemberSkills(request, connectionCtx.credentials, connectionCtx.settings),
|