@ai-wendao/ant 0.3.17 → 0.3.19

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/client.js CHANGED
@@ -382,7 +382,7 @@ window.__ModuleLoader__.load({
382
382
  if (generation !== refreshGeneration.current) return
383
383
  setSkills(result.skills)
384
384
  setLoadError(false)
385
- setMessage(result.warning || (result.skills.length ? '' : '暂无团队或市场精选技能;下方仍可查看 DSH 官方技能。'))
385
+ setMessage(result.warning || (result.skills.length ? '' : '当前没有可显示的全市场或本企业技能。管理员可能尚未启用,或已隐藏待启用的市场技能;下方仍可查看 DSH 官方技能。'))
386
386
  } catch (error) {
387
387
  if (generation !== refreshGeneration.current) return
388
388
  setSkills([])
@@ -398,7 +398,7 @@ window.__ModuleLoader__.load({
398
398
  ? skill.conflict_reason === 'other-source'
399
399
  ? '这台 DSH 已安装另一个来源的同名技能。确认卸载本机旧来源?已修改的本地文件不会被删除。'
400
400
  : `从这台 DSH 卸载 ${skill.title}?已修改的本地文件不会被删除。`
401
- : `将 ${skill.title} ${action}到这台 DSH?\n\n本机依赖:${skill.requirements}\n\n技能可能让 DSH 读取文件或执行脚本,仍受 DSH 的工具授权控制。ANT 不会自动安装系统依赖。`
401
+ : `将 ${skill.title} ${action}到这台 DSH?\n\n外部数据交互:${skill.data_interactions || '待管理员补充;使用前请先核实数据去向。'}\n\n本机依赖:${skill.requirements}\n\n技能可能让 DSH 读取文件或执行脚本,仍受 DSH 的工具授权控制。ANT 不会自动安装系统依赖。`
402
402
  if (!window.confirm(prompt)) return
403
403
  setWorkingId(skill.id)
404
404
  setMessage(`正在${action} ${skill.title}…`)
@@ -442,10 +442,11 @@ window.__ModuleLoader__.load({
442
442
  }
443
443
  }
444
444
  const visible = skills.filter((skill) => {
445
+ const canInstall = skill.scope !== 'market' || skill.team_enabled === true
445
446
  const matchesFilter = filter === 'all'
446
- || filter === 'available' && ['not-installed', 'update-available'].includes(skill.local_status)
447
+ || filter === 'available' && canInstall && ['not-installed', 'update-available'].includes(skill.local_status)
447
448
  || filter === 'installed' && ['installed', 'update-available'].includes(skill.local_status)
448
- || filter === 'updates' && skill.local_status === 'update-available'
449
+ || filter === 'updates' && canInstall && skill.local_status === 'update-available'
449
450
  const matchesQuery = !query.trim() || `${skill.title} ${skillIntroduction(skill)} ${skill.description} ${skill.dsh_name}`.toLowerCase().includes(query.trim().toLowerCase())
450
451
  return matchesFilter && matchesQuery
451
452
  && (scopeFilter === 'all' || (skill.scope || 'team') === scopeFilter)
@@ -518,25 +519,14 @@ window.__ModuleLoader__.load({
518
519
  ...categories.map((category) => h('option', { key: category, value: category }, category))))),
519
520
  ),
520
521
  includePlugins ? h('h2', { style: { margin: 0, fontSize: 20 } }, loading ? '技能 · 读取中…' : `技能 · ${visible.length + visibleOfficial.length}`) : null,
521
- message && (!includePlugins || loadError || skills.length) ? h('p', { role: loadError ? 'alert' : 'status', style: mutedTextStyle }, message) : null,
522
- visibleOfficial.length ? h('section', { 'aria-label': 'DSH 官方 Office 技能', style: { display: 'grid', gap: 12 } },
523
- h('div', null,
524
- h('h2', { style: { margin: 0, fontSize: 20 } }, 'DSH 官方 Office'),
525
- h('p', { style: { ...mutedTextStyle, marginTop: 4 } }, '这些能力随对应版本的 DSH 提供,ANT 无需重复安装。在新会话中直接描述任务即可;不计入 ANT 的本机安装筛选。'),
526
- h('a', { href: officialOfficeGuide, target: '_blank', rel: 'noopener noreferrer', style: { color: 'var(--dsw-alias-link)', fontSize: 13 } }, '查看中文官方说明 ↗')),
527
- h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 300px), 1fr))', gap: 14 } },
528
- ...visibleOfficial.map((skill) => h('article', { key: skill.name, style: { ...panelStyle, gap: 10 } },
529
- h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 } },
530
- h('h3', { style: { margin: 0, fontSize: 17 } }, skill.title),
531
- h('span', { style: mutedTextStyle }, 'DSH 官方')),
532
- h('p', { style: mutedTextStyle }, skill.description),
533
- h('p', { style: mutedTextStyle }, `在新会话中说:“${skill.prompt}”。也可输入 /${skill.name}。`),
534
- h('p', { style: mutedTextStyle }, `DSH ${skill.since} 起提供;旧版请使用 DSH 自带的检查更新。`),
535
- h('a', { href: officialOfficeEnglish(skill), target: '_blank', rel: 'noopener noreferrer',
536
- style: { ...secondaryButtonStyle, display: 'inline-flex', alignItems: 'center', width: 'fit-content', textDecoration: 'none' } }, '查看英文原文 ↗'))))) : null,
522
+ message && (!includePlugins || loadError || skills.length || (!loading && !query.trim()))
523
+ ? h('p', { role: loadError ? 'alert' : 'status', style: mutedTextStyle }, message) : null,
524
+ visible.length && !includePlugins ? h('h2', { style: { margin: 0, fontSize: 20 } }, '全市场与本企业技能') : null,
537
525
  visible.length ? h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 420px), 1fr))', gap: 16 } },
538
526
  ...visible.map((skill) => {
527
+ const marketPending = skill.scope === 'market' && skill.team_enabled !== true
539
528
  const description = skillIntroduction(skill)
529
+ const dataInteractions = skill.data_interactions?.trim() || '待管理员补充。使用前请核实这项技能是否调用外部服务,以及会发送哪些数据。'
540
530
  const originalEnglish = Boolean(curatedSkillIntroduction(skill)) || !hasChineseIntroduction(skill.description)
541
531
  const englishSource = skillEnglishSource(skill)
542
532
  const sourceRef = skill.source_ref || ''
@@ -544,34 +534,64 @@ window.__ModuleLoader__.load({
544
534
  const sourceLabel = /^https:\/\/github\.com\//u.test(skill.source_url || '') ? 'GitHub'
545
535
  : /^https:\/\/clawhub\.ai\//u.test(skill.source_url || '') ? 'ClawHub'
546
536
  : skill.source_kind === 'upload' ? '管理员上传' : '原作者来源'
537
+ const actions = !marketPending && skill.local_status !== 'conflict'
538
+ ? h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 8 } },
539
+ skill.local_status === 'installed' ? null : h('button', { type: 'button', disabled: Boolean(workingId),
540
+ onClick: () => void changeInstall(skill), style: primaryButtonStyle },
541
+ skill.local_status === 'update-available' ? '更新技能' : '安装到这台 DSH'),
542
+ skill.local_status === 'not-installed' ? null : h('button', { type: 'button', disabled: Boolean(workingId),
543
+ onClick: () => void changeInstall(skill, true), style: secondaryButtonStyle }, '卸载'))
544
+ : null
547
545
  return h('article', { key: skill.id, style: { ...panelStyle, gap: 13 } },
548
546
  h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 } },
549
547
  h('div', { style: { display: 'flex', alignItems: 'baseline', flexWrap: 'wrap', gap: 8 } },
550
548
  h('h2', { style: { margin: 0, fontSize: 19 } }, skill.title),
551
549
  h('span', { style: { ...mutedTextStyle, padding: '2px 7px', borderRadius: 6, backgroundColor: 'var(--dsw-alias-bg-layer-2)' } }, skill.scope === 'market' ? '全市场精选' : '本企业'),
552
550
  h('span', { style: mutedTextStyle }, skillCategory(skill))),
553
- h('span', { style: mutedTextStyle }, statusLabel[skill.local_status] || '状态未知')),
551
+ h('span', { style: mutedTextStyle }, marketPending
552
+ ? skill.team_connected ? '待企业启用' : '连接企业后查看启用状态'
553
+ : statusLabel[skill.local_status] || '状态未知')),
554
554
  h('p', { style: mutedTextStyle }, description.length > 180 ? `${description.slice(0, 180)}…` : description),
555
- englishSource ? h('a', { href: englishSource, target: '_blank', rel: 'noopener noreferrer',
556
- style: { color: 'var(--dsw-alias-link)', fontSize: 13 } }, originalEnglish ? '查看英文原文 ↗' : '查看原始说明 ↗')
557
- : h('button', { type: 'button', onClick: () => void openOriginal(skill),
558
- style: { border: 0, padding: 0, background: 'transparent', cursor: 'pointer',
559
- color: 'var(--dsw-alias-link)', fontSize: 13, textAlign: 'left' } },
560
- originalEnglish ? '查看英文原文 →' : '查看原始说明 →'),
561
- h('p', { style: mutedTextStyle }, `来源:${sourceLabel} · 许可:${skill.license}`),
555
+ h('section', { style: { display: 'grid', gap: 5, padding: '10px 12px', borderRadius: 8,
556
+ border: '0.5px solid var(--dsw-alias-border-l2)', backgroundColor: 'var(--dsw-alias-bg-layer-2)' } },
557
+ h('strong', { style: { fontSize: 13 } }, '外部数据交互'),
558
+ h('p', { style: { ...mutedTextStyle, whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' } }, dataInteractions)),
562
559
  description.length > 180 ? h('details', null,
563
560
  h('summary', { style: { cursor: 'pointer', fontSize: 13 } }, '查看完整说明'),
564
561
  h('p', { style: { ...mutedTextStyle, marginTop: 8, whiteSpace: 'pre-wrap' } }, description)) : null,
565
- h('details', null,
566
- h('summary', { style: { cursor: 'pointer', fontSize: 13 } }, '查看来源、文件与使用条件'),
567
- h('div', { style: { display: 'grid', gap: 5, marginTop: 9, overflowWrap: 'anywhere' } },
568
- h('p', { style: mutedTextStyle }, `${fileCountFormat.format(skill.file_count)} 个文件`),
569
- h('p', { style: mutedTextStyle }, `本机条件:${skill.requirements}`),
570
- h('p', { style: mutedTextStyle, title: sourceRef }, `固定版本:${versionLabel || '已锁定制品'}`),
571
- /^https:\/\//u.test(skill.source_url || '')
572
- ? h('a', { href: skill.source_url, target: '_blank', rel: 'noopener noreferrer', style: { fontSize: 13, color: 'var(--dsw-alias-link)' } }, '查看原始来源 ↗')
573
- : h('p', { style: mutedTextStyle }, '来源:管理员上传并审核'))),
574
- skill.local_status === 'conflict'
562
+ h('div', { style: { display: 'grid', gap: 5 } },
563
+ h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 8 } },
564
+ h('p', { style: { ...mutedTextStyle, flex: '1 1 180px' } }, `来源:${sourceLabel} · 许可:${skill.license}`),
565
+ actions),
566
+ h('details', null,
567
+ h('summary', { style: { cursor: 'pointer', fontSize: 13 } }, '查看来源、文件与使用条件'),
568
+ h('div', { style: { display: 'grid', gap: 5, marginTop: 9, overflowWrap: 'anywhere' } },
569
+ englishSource ? h('a', { href: englishSource, target: '_blank', rel: 'noopener noreferrer',
570
+ style: { color: 'var(--dsw-alias-link)', fontSize: 13 } }, originalEnglish ? '查看英文原文 ↗' : '查看原始说明 ↗')
571
+ : h('button', { type: 'button', onClick: () => void openOriginal(skill),
572
+ style: { border: 0, padding: 0, background: 'transparent', cursor: 'pointer',
573
+ color: 'var(--dsw-alias-link)', fontSize: 13, textAlign: 'left' } },
574
+ originalEnglish ? '查看英文原文 →' : '查看原始说明 →'),
575
+ h('p', { style: mutedTextStyle }, `${fileCountFormat.format(skill.file_count)} 个文件`),
576
+ h('p', { style: mutedTextStyle }, `本机条件:${skill.requirements}`),
577
+ h('p', { style: mutedTextStyle, title: sourceRef }, `固定版本:${versionLabel || '已锁定制品'}`),
578
+ /^https:\/\//u.test(skill.source_url || '')
579
+ ? h('a', { href: skill.source_url, target: '_blank', rel: 'noopener noreferrer', style: { fontSize: 13, color: 'var(--dsw-alias-link)' } }, '查看原始来源 ↗')
580
+ : h('p', { style: mutedTextStyle }, '来源:管理员上传并审核')))),
581
+ marketPending
582
+ ? h('div', { style: { display: 'grid', gap: 8, marginTop: 'auto' } },
583
+ h('p', { role: 'status', style: mutedTextStyle }, skill.team_connected
584
+ ? '本企业尚未启用这个固定版本。你可以先浏览介绍;需要使用时请联系企业管理员。'
585
+ : '连接企业并验证工作邮箱后,才能查看本企业是否启用并安装这个技能。'),
586
+ skill.local_status === 'conflict' && skill.conflict_reason === 'other-source'
587
+ ? h('button', { type: 'button', disabled: Boolean(workingId),
588
+ onClick: () => void changeInstall(skill, true), style: { ...secondaryButtonStyle, width: 'fit-content' } }, '卸载旧来源')
589
+ : null,
590
+ ['installed', 'update-available'].includes(skill.local_status)
591
+ ? h('button', { type: 'button', disabled: Boolean(workingId),
592
+ onClick: () => void changeInstall(skill, true), style: { ...secondaryButtonStyle, width: 'fit-content' } }, '卸载本机副本')
593
+ : null)
594
+ : skill.local_status === 'conflict'
575
595
  ? h('div', { style: { display: 'grid', gap: 8 } },
576
596
  h('p', { role: 'status', style: mutedTextStyle }, skill.conflict_reason === 'other-source'
577
597
  ? '本机已安装另一个来源的同名技能。可主动卸载本机旧来源,再安装此版本。'
@@ -580,13 +600,24 @@ window.__ModuleLoader__.load({
580
600
  ? h('button', { type: 'button', disabled: Boolean(workingId),
581
601
  onClick: () => void changeInstall(skill, true), style: { ...secondaryButtonStyle, width: 'fit-content' } }, '卸载旧来源')
582
602
  : null)
583
- : h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 'auto' } },
584
- skill.local_status === 'installed' ? null : h('button', { type: 'button', disabled: Boolean(workingId),
585
- onClick: () => void changeInstall(skill), style: primaryButtonStyle },
586
- skill.local_status === 'update-available' ? '更新技能' : '安装到这台 DSH'),
587
- skill.local_status !== 'not-installed' ? h('button', { type: 'button', disabled: Boolean(workingId),
588
- onClick: () => void changeInstall(skill, true), style: secondaryButtonStyle }, '卸载') : null))
603
+ : null)
589
604
  })) : !includePlugins && !loading && (skills.length || officialOfficeSkills.length) && !visibleOfficial.length ? h('p', { style: mutedTextStyle }, '没有符合筛选条件的技能。') : null,
605
+ visibleOfficial.length ? h('section', { 'aria-label': 'DSH 官方 Office 技能', style: { display: 'grid', gap: 12 } },
606
+ h('div', null,
607
+ h('h2', { style: { margin: 0, fontSize: 20 } }, 'DSH 官方 Office'),
608
+ h('p', { style: { ...mutedTextStyle, marginTop: 4 } }, '这些能力随对应版本的 DSH 提供,无需通过 ANT 安装。在新会话中直接描述任务即可;不计入 ANT 的本机安装筛选。'),
609
+ h('a', { href: officialOfficeGuide, target: '_blank', rel: 'noopener noreferrer', style: { color: 'var(--dsw-alias-link)', fontSize: 13 } }, '查看中文官方说明 ↗')),
610
+ h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 300px), 1fr))', gap: 14 } },
611
+ ...visibleOfficial.map((skill) => h('article', { key: skill.name, style: { ...panelStyle, gap: 10 } },
612
+ h('div', { style: { display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 } },
613
+ h('h3', { style: { margin: 0, fontSize: 17 } }, skill.title),
614
+ h('span', { style: { ...mutedTextStyle, padding: '2px 8px', borderRadius: 6,
615
+ backgroundColor: 'var(--dsw-alias-bg-layer-2)' } }, 'DSH 自带 · 无需在 ANT 安装')),
616
+ h('p', { style: mutedTextStyle }, skill.description),
617
+ h('p', { style: mutedTextStyle }, `在新会话中说:“${skill.prompt}”。也可输入 /${skill.name}。`),
618
+ h('p', { style: mutedTextStyle }, `DSH ${skill.since} 起提供;如果无法使用,请在 DSH 检查更新。`),
619
+ h('a', { href: officialOfficeEnglish(skill), target: '_blank', rel: 'noopener noreferrer',
620
+ style: { color: 'var(--dsw-alias-link)', fontSize: 13, lineHeight: 1.6, padding: '4px 0' } }, '英文原文 ↗'))))) : null,
590
621
  includePlugins ? h(PluginCenterPage, { remote, onBack, onAll, onSkills, openBundle,
591
622
  embedded: true, query, onQueryChange, externalFilter: filter,
592
623
  hasSkillMatches: visible.length + visibleOfficial.length > 0, skillCatalogReady: !loading && !loadError,
package/index.js CHANGED
@@ -376,7 +376,9 @@ async function fetchMemberSkills(request, credentials, settings) {
376
376
  catch { return { status: 'rejected' } }
377
377
  }
378
378
  const team = await settle(connection ? listSkills(connection) : Promise.resolve([]))
379
- const market = await settle(listSkills(marketSkillConnection(), 'market'))
379
+ const market = await settle(connection
380
+ ? listSkills({ ...connection, marketManaged: true }, 'market')
381
+ : listSkills(marketSkillConnection(), 'market'))
380
382
  if (market.status === 'rejected' && (team.status === 'rejected' || !connection)) {
381
383
  throw new Error('暂时无法读取公共技能市场;请稍后刷新。')
382
384
  }
@@ -406,10 +408,11 @@ async function fetchSkillOriginal(request, credentials, settings) {
406
408
  return jsonResponse(400, { message: '技能原文地址无效。' })
407
409
  }
408
410
  try {
409
- const connection = scope === 'market' ? marketSkillConnection()
410
- : await memberSkillConnection(credentials, settings)
411
+ const memberConnection = await memberSkillConnection(credentials, settings)
412
+ const connection = scope === 'market' ? memberConnection || marketSkillConnection() : memberConnection
411
413
  if (!connection) return jsonResponse(401, { message: '请先连接 ANT 团队。' })
412
- const path = scope === 'market' ? `/api/market/skills/${skillId}/original`
414
+ const path = scope === 'market' ? memberConnection
415
+ ? `/api/me/market-skills/${skillId}/original` : `/api/market/skills/${skillId}/original`
413
416
  : `/api/me/skills/${skillId}/original`
414
417
  const upstream = await fetch(new URL(path, connection.serviceUrl), {
415
418
  headers: connection.token ? { authorization: `Bearer ${connection.token}`, accept: 'text/plain' }
@@ -443,10 +446,10 @@ async function installMemberSkill(request, credentials, settings) {
443
446
  }
444
447
  try {
445
448
  const scope = body?.scope || 'team'
446
- const connection = scope === 'market' ? marketSkillConnection()
447
- : await memberSkillConnection(credentials, settings)
449
+ const connection = await memberSkillConnection(credentials, settings)
448
450
  if (!connection) return jsonResponse(401, { message: '请先连接 ANT 团队,或重新验证工作邮箱。' })
449
- return jsonResponse(200, await installSkill(connection, body?.skill_id, scope))
451
+ return jsonResponse(200, await installSkill(scope === 'market'
452
+ ? { ...connection, marketManaged: true } : connection, body?.skill_id, scope))
450
453
  } catch (error) {
451
454
  return jsonResponse(409, { message: error instanceof Error ? error.message : '技能安装失败。' })
452
455
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-wendao/ant",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
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": {
package/skill-install.js CHANGED
@@ -137,6 +137,7 @@ async function verifyManagedTree(root, name, marker) {
137
137
 
138
138
  async function boundedBytes(response, maxBytes) {
139
139
  if (response.status === 404) throw new Error('此技能可能已下架或不再可访问,请刷新目录后重试。')
140
+ if (response.status === 403) throw new Error('本企业尚未启用这个技能,或授权已撤销;请刷新目录。')
140
141
  if (!response.ok || !response.body) throw new Error(`技能来源无法提供文件(HTTP ${response.status})。`)
141
142
  const chunks = []
142
143
  let total = 0
@@ -156,7 +157,9 @@ async function fetchJson(url, token, timeoutMs = 20_000) {
156
157
  }
157
158
 
158
159
  export async function listSkills(connection, scope = 'team') {
159
- const path = scope === 'market' ? '/api/market/skills' : '/api/me/skills'
160
+ const path = scope === 'market'
161
+ ? connection.marketManaged ? '/api/me/market-skills' : '/api/market/skills'
162
+ : '/api/me/skills'
160
163
  const skills = await fetchJson(new URL(path, connection.serviceUrl), connection.token, scope === 'market' ? 8_000 : 20_000)
161
164
  if (!Array.isArray(skills)) throw new Error('技能目录格式无效。')
162
165
  const { root, conflicts } = await safeRoot()
@@ -165,7 +168,9 @@ export async function listSkills(connection, scope = 'team') {
165
168
  let local_status = conflicts.has(skill.dsh_name) ? 'conflict' : 'not-installed'
166
169
  let conflict_reason = ''
167
170
  const actualScope = skill.scope === 'market' ? 'market' : scope
168
- if (local_status === 'conflict') return { ...skill, scope: actualScope, local_status }
171
+ const marketState = actualScope === 'market' ? { team_enabled: Boolean(connection.marketManaged && skill.team_enabled === true),
172
+ team_connected: Boolean(connection.marketManaged) } : {}
173
+ if (local_status === 'conflict') return { ...skill, scope: actualScope, local_status, ...marketState }
169
174
  try {
170
175
  const marker = await readManaged(root, skill.dsh_name)
171
176
  if (marker) {
@@ -178,7 +183,7 @@ export async function listSkills(connection, scope = 'team') {
178
183
  local_status = marker.content_sha256 === skill.content_sha256 ? 'installed' : 'update-available'
179
184
  }
180
185
  } catch { local_status = 'conflict' }
181
- return { ...skill, scope: actualScope, local_status, conflict_reason }
186
+ return { ...skill, scope: actualScope, local_status, conflict_reason, ...marketState }
182
187
  }))
183
188
  }
184
189
 
@@ -217,7 +222,8 @@ function contentDigest(files) {
217
222
  export async function installSkill(connection, skillId, scope = 'team') {
218
223
  if (typeof skillId !== 'string' || !/^[0-9a-f-]{36}$/iu.test(skillId)) throw new Error('技能编号无效。')
219
224
  if (scope !== 'team' && scope !== 'market') throw new Error('技能来源无效。')
220
- const basePath = scope === 'market' ? '/api/market/skills' : '/api/me/skills'
225
+ if (scope === 'market' && !connection.marketManaged) throw new Error('请先连接团队,再安装本企业已启用的全市场技能。')
226
+ const basePath = scope === 'market' ? '/api/me/market-skills' : '/api/me/skills'
221
227
  const manifest = await fetchJson(new URL(`${basePath}/${skillId}/files`, connection.serviceUrl), connection.token)
222
228
  validateManifest(manifest, skillId)
223
229
  const { root, conflicts } = await safeRoot()