@vibe-forge/workspace-assets 2.0.1 → 2.0.3
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/__tests__/__snapshots__/workspace-assets-rich.snapshot.json +1 -1
- package/__tests__/adapter-asset-plan.spec.ts +65 -67
- package/__tests__/bundle.spec.ts +138 -213
- package/__tests__/prompt-builders.spec.ts +39 -0
- package/__tests__/skill-dependencies.spec.ts +80 -0
- package/package.json +4 -4
- package/src/bundle-internal.ts +3 -18
- package/src/bundle.ts +0 -2
- package/src/prompt-builders.ts +4 -0
- package/src/prompt-selection.ts +2 -2
- package/src/selection-internal.ts +2 -2
- package/src/skill-dependencies.ts +78 -17
- package/src/skill-registry.ts +345 -0
- package/src/task-tool-guidance.ts +15 -0
- package/src/workspace-prompt.ts +4 -0
- package/vibe-forge-workspace-assets-2.0.2.tgz +0 -0
- package/__tests__/skill-dependencies-cli.spec.ts +0 -175
- package/src/configured-skills.ts +0 -99
- package/src/skills-cli-dependency.ts +0 -208
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
generateSkillsRoutePrompt,
|
|
10
10
|
generateSpecRoutePrompt
|
|
11
11
|
} from '#~/prompt-builders.js'
|
|
12
|
+
import { generateWorkspaceRoutePrompt } from '#~/workspace-prompt.js'
|
|
12
13
|
|
|
13
14
|
describe('workspace asset prompt builders', () => {
|
|
14
15
|
it('builds skill prompts with stable names, descriptions, and relative paths', () => {
|
|
@@ -175,12 +176,50 @@ describe('workspace asset prompt builders', () => {
|
|
|
175
176
|
expect(prompt).toContain('reviewer: 负责代码审查')
|
|
176
177
|
expect(prompt).toContain('`VibeForge.StartTasks`')
|
|
177
178
|
expect(prompt).toContain('`VibeForge.GetTaskInfo`')
|
|
179
|
+
expect(prompt).toContain('Task tool guide:')
|
|
180
|
+
expect(prompt).toContain('After starting a task')
|
|
181
|
+
expect(prompt).toContain('10 most recent log entries')
|
|
182
|
+
expect(prompt).toContain('`logLimit`')
|
|
183
|
+
expect(prompt).toContain('`logOrder`')
|
|
184
|
+
expect(prompt).toContain('`VibeForge.SendTaskMessage`')
|
|
185
|
+
expect(prompt).toContain('`{ taskId, message, mode }`')
|
|
186
|
+
expect(prompt).toContain('Choose `mode: "direct"`')
|
|
187
|
+
expect(prompt).toContain('Choose `mode: "steer"`')
|
|
188
|
+
expect(prompt).toContain('`VibeForge.SubmitTaskInput`')
|
|
189
|
+
expect(prompt).toContain('Do not use it for ordinary follow-up instructions or queued steer turns')
|
|
190
|
+
expect(prompt).toContain('If a task is `completed` or `failed`')
|
|
178
191
|
expect(prompt).toContain('`wait`')
|
|
179
192
|
expect(prompt).not.toContain('run-tasks')
|
|
180
193
|
expect(prompt).not.toContain('需要关注变更风险')
|
|
181
194
|
expect(prompt).not.toContain('hidden')
|
|
182
195
|
})
|
|
183
196
|
|
|
197
|
+
it('builds workspace routes with managed task guidance', () => {
|
|
198
|
+
const cwd = '/tmp/project'
|
|
199
|
+
|
|
200
|
+
const prompt = generateWorkspaceRoutePrompt(cwd, [
|
|
201
|
+
{
|
|
202
|
+
id: 'billing',
|
|
203
|
+
cwd: join(cwd, 'packages/billing'),
|
|
204
|
+
path: join(cwd, '.ai/workspaces/billing.md'),
|
|
205
|
+
description: 'Billing workspace'
|
|
206
|
+
}
|
|
207
|
+
])
|
|
208
|
+
|
|
209
|
+
expect(prompt).toContain('The project includes the following registered workspaces')
|
|
210
|
+
expect(prompt).toContain('Identifier: billing')
|
|
211
|
+
expect(prompt).toContain('`VibeForge.StartTasks`')
|
|
212
|
+
expect(prompt).toContain('type: "workspace"')
|
|
213
|
+
expect(prompt).toContain('Task tool guide:')
|
|
214
|
+
expect(prompt).toContain('`VibeForge.GetTaskInfo`')
|
|
215
|
+
expect(prompt).toContain('`VibeForge.ListTasks`')
|
|
216
|
+
expect(prompt).toContain('`VibeForge.SendTaskMessage`')
|
|
217
|
+
expect(prompt).toContain('`VibeForge.SubmitTaskInput`')
|
|
218
|
+
expect(prompt).toContain('Choose `mode: "direct"`')
|
|
219
|
+
expect(prompt).toContain('Choose `mode: "steer"`')
|
|
220
|
+
expect(prompt).toContain('Do not directly edit files inside a registered workspace')
|
|
221
|
+
})
|
|
222
|
+
|
|
184
223
|
it('builds skill route prompts without preloading content', () => {
|
|
185
224
|
const cwd = '/tmp/project'
|
|
186
225
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import { buildAdapterAssetPlan, resolveWorkspaceAssetBundle } from '#~/index.js'
|
|
6
|
+
import { normalizeSkillDependency } from '#~/skill-dependencies.js'
|
|
7
|
+
|
|
8
|
+
import { createWorkspace, writeDocument } from './test-helpers'
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.unstubAllGlobals()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
describe('skill dependency normalization', () => {
|
|
15
|
+
it('parses legacy non-structured registry strings', () => {
|
|
16
|
+
expect(
|
|
17
|
+
normalizeSkillDependency('https://bnpm.byted.org@skills.byted.org/lynx/skills@lynx-devtool@1.0.3')
|
|
18
|
+
).toEqual({
|
|
19
|
+
ref: 'https://bnpm.byted.org@skills.byted.org/lynx/skills@lynx-devtool@1.0.3',
|
|
20
|
+
name: 'lynx-devtool',
|
|
21
|
+
source: 'lynx/skills',
|
|
22
|
+
registry: 'https://skills.byted.org',
|
|
23
|
+
version: '1.0.3',
|
|
24
|
+
packageRegistry: 'https://bnpm.byted.org'
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('installs legacy non-structured registry dependencies through the skill registry API', async () => {
|
|
29
|
+
const workspace = await createWorkspace()
|
|
30
|
+
const fetchMock = vi.fn(async (url: string) => {
|
|
31
|
+
if (url === 'https://skills.byted.org/api/download/lynx/skills/lynx-devtool?version=1.0.3') {
|
|
32
|
+
return new Response(JSON.stringify({
|
|
33
|
+
files: [{
|
|
34
|
+
path: 'SKILL.md',
|
|
35
|
+
contents: '---\nname: lynx-devtool\ndescription: Lynx device debugging\n---\nUse devtool.\n'
|
|
36
|
+
}]
|
|
37
|
+
}))
|
|
38
|
+
}
|
|
39
|
+
return new Response('not found', { status: 404 })
|
|
40
|
+
})
|
|
41
|
+
vi.stubGlobal('fetch', fetchMock)
|
|
42
|
+
|
|
43
|
+
await writeDocument(
|
|
44
|
+
join(workspace, '.ai/skills/debug-lynx/SKILL.md'),
|
|
45
|
+
[
|
|
46
|
+
'---',
|
|
47
|
+
'name: debug-lynx',
|
|
48
|
+
'description: Debug Lynx on device',
|
|
49
|
+
'dependencies:',
|
|
50
|
+
' - https://bnpm.byted.org@skills.byted.org/lynx/skills@lynx-devtool@1.0.3',
|
|
51
|
+
'---',
|
|
52
|
+
'Run the full debugging workflow.'
|
|
53
|
+
].join('\n')
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const bundle = await resolveWorkspaceAssetBundle({
|
|
57
|
+
cwd: workspace,
|
|
58
|
+
configs: [undefined, undefined],
|
|
59
|
+
useDefaultVibeForgeMcpServer: false
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
await buildAdapterAssetPlan({
|
|
63
|
+
adapter: 'opencode',
|
|
64
|
+
bundle,
|
|
65
|
+
options: {
|
|
66
|
+
skills: {
|
|
67
|
+
include: ['debug-lynx']
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
73
|
+
'https://skills.byted.org/api/download/lynx/skills/lynx-devtool?version=1.0.3',
|
|
74
|
+
expect.any(Object)
|
|
75
|
+
)
|
|
76
|
+
expect(bundle.skills.find(asset => asset.name === 'lynx-devtool')?.sourcePath).toContain(
|
|
77
|
+
'/.ai/caches/skill-dependencies/skills.byted.org/lynx/skills/lynx-devtool/1.0.3/'
|
|
78
|
+
)
|
|
79
|
+
})
|
|
80
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-forge/workspace-assets",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Workspace asset resolution and adapter asset planning for Vibe Forge",
|
|
5
5
|
"imports": {
|
|
6
6
|
"#~/*.js": {
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"fast-glob": "^3.3.3",
|
|
31
31
|
"front-matter": "^4.0.2",
|
|
32
32
|
"js-yaml": "^4.1.1",
|
|
33
|
-
"@vibe-forge/
|
|
34
|
-
"@vibe-forge/
|
|
35
|
-
"@vibe-forge/definition-core": "^2.0.
|
|
33
|
+
"@vibe-forge/types": "^2.0.2",
|
|
34
|
+
"@vibe-forge/utils": "^2.0.3",
|
|
35
|
+
"@vibe-forge/definition-core": "^2.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/js-yaml": "^4.0.9"
|
package/src/bundle-internal.ts
CHANGED
|
@@ -9,12 +9,7 @@ import {
|
|
|
9
9
|
resolveDefaultVibeForgeMcpServerConfig
|
|
10
10
|
} from '@vibe-forge/config'
|
|
11
11
|
import type { Config, Definition, Entity, PluginConfig, WorkspaceAsset, WorkspaceAssetKind } from '@vibe-forge/types'
|
|
12
|
-
import {
|
|
13
|
-
isLegacySkillsConfig,
|
|
14
|
-
resolveProjectAiBaseDir,
|
|
15
|
-
resolveProjectAiEntitiesDir,
|
|
16
|
-
resolveRelativePath
|
|
17
|
-
} from '@vibe-forge/utils'
|
|
12
|
+
import { resolveProjectAiBaseDir, resolveProjectAiEntitiesDir, resolveRelativePath } from '@vibe-forge/utils'
|
|
18
13
|
import { listManagedPluginInstalls, toManagedPluginConfig } from '@vibe-forge/utils/managed-plugin'
|
|
19
14
|
import {
|
|
20
15
|
flattenPluginInstances,
|
|
@@ -33,7 +28,6 @@ import {
|
|
|
33
28
|
resolveSkillIdentifier,
|
|
34
29
|
resolveSpecIdentifier
|
|
35
30
|
} from '@vibe-forge/definition-core'
|
|
36
|
-
import { ensureConfiguredProjectSkills } from './configured-skills'
|
|
37
31
|
import { HOME_BRIDGE_RESOLVED_BY } from './home-bridge'
|
|
38
32
|
import { resolveConfiguredWorkspaceAssets } from './workspaces'
|
|
39
33
|
|
|
@@ -159,8 +153,8 @@ const warnInvalidHomeSkillRoot = (root: string) => {
|
|
|
159
153
|
|
|
160
154
|
const resolveHomeBridgeConfig = (configs: [Config?, Config?]) => {
|
|
161
155
|
const [config, userConfig] = configs
|
|
162
|
-
const projectHomeBridge =
|
|
163
|
-
const userHomeBridge =
|
|
156
|
+
const projectHomeBridge = config?.skills?.homeBridge
|
|
157
|
+
const userHomeBridge = userConfig?.skills?.homeBridge
|
|
164
158
|
|
|
165
159
|
return {
|
|
166
160
|
enabled: userHomeBridge?.enabled ?? projectHomeBridge?.enabled ?? true,
|
|
@@ -532,8 +526,6 @@ export async function collectWorkspaceAssets(params: {
|
|
|
532
526
|
plugins?: PluginConfig
|
|
533
527
|
overlaySource?: string
|
|
534
528
|
includeManagedPlugins?: boolean
|
|
535
|
-
syncConfiguredSkills?: boolean
|
|
536
|
-
updateConfiguredSkills?: boolean
|
|
537
529
|
useDefaultVibeForgeMcpServer?: boolean
|
|
538
530
|
}): Promise<{
|
|
539
531
|
assets: WorkspaceAsset[]
|
|
@@ -552,13 +544,6 @@ export async function collectWorkspaceAssets(params: {
|
|
|
552
544
|
workspaces: Array<Extract<WorkspaceAsset, { kind: 'workspace' }>>
|
|
553
545
|
}> {
|
|
554
546
|
const [config, userConfig] = params.configs ?? await loadWorkspaceConfig(params.cwd)
|
|
555
|
-
if (params.syncConfiguredSkills === true) {
|
|
556
|
-
await ensureConfiguredProjectSkills({
|
|
557
|
-
configs: [config, userConfig],
|
|
558
|
-
updateInstalledSkills: params.updateConfiguredSkills,
|
|
559
|
-
workspaceFolder: params.cwd
|
|
560
|
-
})
|
|
561
|
-
}
|
|
562
547
|
const managedPluginConfigs = params.includeManagedPlugins === false
|
|
563
548
|
? undefined
|
|
564
549
|
: toManagedPluginConfig(await listManagedPluginInstalls(params.cwd))
|
package/src/bundle.ts
CHANGED
|
@@ -8,8 +8,6 @@ export async function resolveWorkspaceAssetBundle(params: {
|
|
|
8
8
|
plugins?: PluginConfig
|
|
9
9
|
overlaySource?: string
|
|
10
10
|
includeManagedPlugins?: boolean
|
|
11
|
-
syncConfiguredSkills?: boolean
|
|
12
|
-
updateConfiguredSkills?: boolean
|
|
13
11
|
useDefaultVibeForgeMcpServer?: boolean
|
|
14
12
|
}): Promise<WorkspaceAssetBundle> {
|
|
15
13
|
const collected = await collectWorkspaceAssets(params)
|
package/src/prompt-builders.ts
CHANGED
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
import type { Definition, Entity, Rule, Skill, Spec } from '@vibe-forge/types'
|
|
8
8
|
import { CANONICAL_VIBE_FORGE_MCP_SERVER_NAME, resolvePromptPath } from '@vibe-forge/utils'
|
|
9
9
|
|
|
10
|
+
import { buildManagedTaskToolGuidance } from './task-tool-guidance'
|
|
11
|
+
|
|
10
12
|
const toMarkdownBlockquote = (content: string) => (
|
|
11
13
|
content
|
|
12
14
|
.trim()
|
|
@@ -165,6 +167,7 @@ export const generateSpecRoutePrompt = (
|
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
export const generateEntitiesRoutePrompt = (entities: Definition<Entity>[]) => {
|
|
170
|
+
const taskToolGuidance = buildManagedTaskToolGuidance(CANONICAL_VIBE_FORGE_MCP_SERVER_NAME)
|
|
168
171
|
return (
|
|
169
172
|
'<system-prompt>\n' +
|
|
170
173
|
'The project includes the following entities:\n' +
|
|
@@ -179,6 +182,7 @@ export const generateEntitiesRoutePrompt = (entities: Definition<Entity>[]) => {
|
|
|
179
182
|
.join('')
|
|
180
183
|
}\n` +
|
|
181
184
|
`When solving user problems, you may specify entities through \`${CANONICAL_VIBE_FORGE_MCP_SERVER_NAME}.StartTasks\` as needed and have them coordinate multiple entity types to complete the work; use \`${CANONICAL_VIBE_FORGE_MCP_SERVER_NAME}.GetTaskInfo\` and \`wait\` to track progress.\n` +
|
|
185
|
+
`${taskToolGuidance}\n` +
|
|
182
186
|
'</system-prompt>\n'
|
|
183
187
|
)
|
|
184
188
|
}
|
package/src/prompt-selection.ts
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
resolveSelectedSkillAssetsWithDependencies,
|
|
36
36
|
toDocumentDefinitions
|
|
37
37
|
} from './selection-internal'
|
|
38
|
-
import {
|
|
38
|
+
import { expandSkillAssetDependenciesWithRegistry } from './skill-dependencies'
|
|
39
39
|
import { generateWorkspaceRoutePrompt } from './workspace-prompt'
|
|
40
40
|
|
|
41
41
|
export async function resolvePromptAssetSelection(params: {
|
|
@@ -164,7 +164,7 @@ export async function resolvePromptAssetSelection(params: {
|
|
|
164
164
|
resolveNamedAssets(effectiveBundle.skills, excludedRefs, targetInstancePath).map(asset => asset.id)
|
|
165
165
|
)
|
|
166
166
|
|
|
167
|
-
const expandedTargetSkills = await
|
|
167
|
+
const expandedTargetSkills = await expandSkillAssetDependenciesWithRegistry({
|
|
168
168
|
allAssets: effectiveBundle.assets,
|
|
169
169
|
configs: effectiveBundle.configs ?? [undefined, undefined],
|
|
170
170
|
cwd: effectiveBundle.cwd,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
isRemoteRuleReference,
|
|
27
27
|
parseScopedReference
|
|
28
28
|
} from '@vibe-forge/definition-core'
|
|
29
|
-
import { expandSkillAssetDependencies,
|
|
29
|
+
import { expandSkillAssetDependencies, expandSkillAssetDependenciesWithRegistry } from './skill-dependencies'
|
|
30
30
|
|
|
31
31
|
type DocumentAssetKind = Extract<WorkspaceAssetKind, 'rule' | 'spec' | 'entity' | 'skill'>
|
|
32
32
|
type DocumentAsset<TDefinition> = Extract<WorkspaceAsset, { kind: DocumentAssetKind }> & {
|
|
@@ -538,7 +538,7 @@ export const resolveSelectedSkillAssetsWithDependencies = async (
|
|
|
538
538
|
const excluded = new Set(
|
|
539
539
|
resolveNamedAssets(bundle.skills, selection?.exclude).map(asset => asset.id)
|
|
540
540
|
)
|
|
541
|
-
return await
|
|
541
|
+
return await expandSkillAssetDependenciesWithRegistry({
|
|
542
542
|
allAssets: bundle.assets,
|
|
543
543
|
configs: bundle.configs ?? [undefined, undefined],
|
|
544
544
|
cwd: bundle.cwd,
|
|
@@ -8,7 +8,7 @@ import type { Config, Definition, Skill, WorkspaceAsset } from '@vibe-forge/type
|
|
|
8
8
|
import { resolveRelativePath } from '@vibe-forge/utils'
|
|
9
9
|
|
|
10
10
|
import { HOME_BRIDGE_RESOLVED_BY } from './home-bridge'
|
|
11
|
-
import {
|
|
11
|
+
import { installRegistrySkillDependency } from './skill-registry'
|
|
12
12
|
|
|
13
13
|
type SkillAsset = Extract<WorkspaceAsset, { kind: 'skill' }>
|
|
14
14
|
|
|
@@ -16,6 +16,9 @@ export interface NormalizedSkillDependency {
|
|
|
16
16
|
ref: string
|
|
17
17
|
name: string
|
|
18
18
|
source?: string
|
|
19
|
+
registry?: string
|
|
20
|
+
version?: string
|
|
21
|
+
packageRegistry?: string
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
interface DependencyExpansionParams {
|
|
@@ -41,6 +44,29 @@ const toSkillSlug = (value: string) => (
|
|
|
41
44
|
.replace(/^-|-$/g, '')
|
|
42
45
|
)
|
|
43
46
|
|
|
47
|
+
const trimSlashes = (value: string) => value.replace(/^\/+|\/+$/g, '')
|
|
48
|
+
|
|
49
|
+
const normalizeLegacyUrl = (value: string) => {
|
|
50
|
+
const trimmed = value.trim()
|
|
51
|
+
if (trimmed === '') return undefined
|
|
52
|
+
const candidate = /^[a-z][a-z\d+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`
|
|
53
|
+
try {
|
|
54
|
+
return new URL(candidate)
|
|
55
|
+
} catch {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const buildDependencyRef = (params: {
|
|
61
|
+
name: string
|
|
62
|
+
source?: string
|
|
63
|
+
version?: string
|
|
64
|
+
}) => (
|
|
65
|
+
params.source == null
|
|
66
|
+
? (params.version == null ? params.name : `${params.name}@${params.version}`)
|
|
67
|
+
: `${params.source}@${params.name}${params.version == null ? '' : `@${params.version}`}`
|
|
68
|
+
)
|
|
69
|
+
|
|
44
70
|
const resolveUniqueSkillByName = (assets: SkillAsset[], name: string) => {
|
|
45
71
|
const nameSlug = toSkillSlug(name)
|
|
46
72
|
const matches = assets.filter(asset => asset.name === name || toSkillSlug(asset.name) === nameSlug)
|
|
@@ -118,7 +144,7 @@ const parseFrontmatterSkill = async (path: string): Promise<Definition<Skill>> =
|
|
|
118
144
|
}
|
|
119
145
|
}
|
|
120
146
|
|
|
121
|
-
const
|
|
147
|
+
const createRegistrySkillAsset = (params: {
|
|
122
148
|
cwd: string
|
|
123
149
|
definition: Definition<Skill>
|
|
124
150
|
}) => {
|
|
@@ -137,8 +163,38 @@ const createResolvedSkillAsset = (params: {
|
|
|
137
163
|
} satisfies SkillAsset
|
|
138
164
|
}
|
|
139
165
|
|
|
166
|
+
const parseLegacyRegistryDependency = (value: string): NormalizedSkillDependency | undefined => {
|
|
167
|
+
const ref = value.trim()
|
|
168
|
+
const segments = ref.split('@').map(segment => segment.trim())
|
|
169
|
+
if (segments.length < 3) return undefined
|
|
170
|
+
|
|
171
|
+
const hasVersion = segments.length >= 4
|
|
172
|
+
const nameIndex = hasVersion ? segments.length - 2 : segments.length - 1
|
|
173
|
+
const packageRegistry = normalizeLegacyUrl(segments[0] ?? '')
|
|
174
|
+
const sourceUrl = normalizeLegacyUrl(segments.slice(1, nameIndex).join('@'))
|
|
175
|
+
const name = asNonEmptyString(segments[nameIndex])
|
|
176
|
+
const version = hasVersion ? asNonEmptyString(segments[segments.length - 1]) : undefined
|
|
177
|
+
|
|
178
|
+
if (packageRegistry == null || sourceUrl == null || name == null) return undefined
|
|
179
|
+
|
|
180
|
+
const source = trimSlashes(sourceUrl.pathname)
|
|
181
|
+
if (source === '') return undefined
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
ref,
|
|
185
|
+
name,
|
|
186
|
+
source,
|
|
187
|
+
registry: sourceUrl.origin,
|
|
188
|
+
...(version == null ? {} : { version }),
|
|
189
|
+
packageRegistry: packageRegistry.toString().replace(/\/+$/, '')
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
140
193
|
const parseStringDependency = (value: string): NormalizedSkillDependency => {
|
|
141
194
|
const ref = value.trim()
|
|
195
|
+
const legacyRegistryDependency = parseLegacyRegistryDependency(ref)
|
|
196
|
+
if (legacyRegistryDependency != null) return legacyRegistryDependency
|
|
197
|
+
|
|
142
198
|
const atIndex = ref.lastIndexOf('@')
|
|
143
199
|
if (atIndex > 0 && atIndex < ref.length - 1) {
|
|
144
200
|
return {
|
|
@@ -148,15 +204,12 @@ const parseStringDependency = (value: string): NormalizedSkillDependency => {
|
|
|
148
204
|
}
|
|
149
205
|
}
|
|
150
206
|
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
sourcePathSegments.length >= 3 &&
|
|
154
|
-
sourcePathSegments.every(segment => !segment.includes(' '))
|
|
155
|
-
) {
|
|
207
|
+
const sourcePathMatch = ref.match(/^([^/\s]+\/[^/\s]+)\/([^/\s]+)$/)
|
|
208
|
+
if (sourcePathMatch != null) {
|
|
156
209
|
return {
|
|
157
210
|
ref,
|
|
158
|
-
source:
|
|
159
|
-
name:
|
|
211
|
+
source: sourcePathMatch[1],
|
|
212
|
+
name: sourcePathMatch[2]
|
|
160
213
|
}
|
|
161
214
|
}
|
|
162
215
|
|
|
@@ -176,10 +229,17 @@ export const normalizeSkillDependency = (value: unknown): NormalizedSkillDepende
|
|
|
176
229
|
if (name == null) return undefined
|
|
177
230
|
|
|
178
231
|
const source = asNonEmptyString(record.source)
|
|
232
|
+
const version = asNonEmptyString(record.version)
|
|
179
233
|
return {
|
|
180
|
-
ref:
|
|
234
|
+
ref: buildDependencyRef({
|
|
235
|
+
name,
|
|
236
|
+
...(source == null ? {} : { source }),
|
|
237
|
+
...(version == null ? {} : { version })
|
|
238
|
+
}),
|
|
181
239
|
name,
|
|
182
|
-
...(source == null ? {} : { source })
|
|
240
|
+
...(source == null ? {} : { source }),
|
|
241
|
+
...(asNonEmptyString(record.registry) == null ? {} : { registry: asNonEmptyString(record.registry) }),
|
|
242
|
+
...(version == null ? {} : { version })
|
|
183
243
|
}
|
|
184
244
|
}
|
|
185
245
|
|
|
@@ -243,7 +303,7 @@ export const expandSkillAssetDependencies = (
|
|
|
243
303
|
return selected
|
|
244
304
|
}
|
|
245
305
|
|
|
246
|
-
export const
|
|
306
|
+
export const expandSkillAssetDependenciesWithRegistry = async (
|
|
247
307
|
params: DependencyExpansionParams
|
|
248
308
|
) => {
|
|
249
309
|
const selected: SkillAsset[] = []
|
|
@@ -261,16 +321,16 @@ export const expandSkillAssetDependenciesWithRemoteResolution = async (
|
|
|
261
321
|
dependency: NormalizedSkillDependency,
|
|
262
322
|
currentInstancePath?: string
|
|
263
323
|
) => {
|
|
264
|
-
const fetchKey = dependency.ref
|
|
324
|
+
const fetchKey = `${dependency.registry ?? ''}:${dependency.ref}`
|
|
265
325
|
if (!fetchedDependencyRefs.has(fetchKey)) {
|
|
266
326
|
fetchedDependencyRefs.add(fetchKey)
|
|
267
|
-
const installed = await
|
|
327
|
+
const installed = await installRegistrySkillDependency({
|
|
268
328
|
cwd: params.cwd,
|
|
269
329
|
configs: params.configs,
|
|
270
330
|
dependency
|
|
271
331
|
})
|
|
272
332
|
const definition = await parseFrontmatterSkill(installed.skillPath)
|
|
273
|
-
const dependencyAsset =
|
|
333
|
+
const dependencyAsset = createRegistrySkillAsset({
|
|
274
334
|
cwd: params.cwd,
|
|
275
335
|
definition
|
|
276
336
|
})
|
|
@@ -335,13 +395,14 @@ export const expandSkillAssetDependenciesWithRemoteResolution = async (
|
|
|
335
395
|
const dependencyAsset = await installDependencyAsset(dependency, asset.instancePath).catch((error: unknown) => {
|
|
336
396
|
if (
|
|
337
397
|
localOrBridgedDependency != null &&
|
|
338
|
-
dependency.source == null
|
|
398
|
+
dependency.source == null &&
|
|
399
|
+
dependency.registry == null
|
|
339
400
|
) {
|
|
340
401
|
return localOrBridgedDependency
|
|
341
402
|
}
|
|
342
403
|
throw error
|
|
343
404
|
}) ?? (
|
|
344
|
-
dependency.source == null
|
|
405
|
+
dependency.source == null && dependency.registry == null
|
|
345
406
|
? localOrBridgedDependency
|
|
346
407
|
: undefined
|
|
347
408
|
)
|