@vibe-forge/workspace-assets 2.0.1 → 2.0.2
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/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 +16 -16
- package/src/skill-registry.ts +329 -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
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/* eslint-disable import/first -- hoisted vitest mocks must be declared before importing the bundle entrypoint */
|
|
2
|
-
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|
3
|
-
import os from 'node:os'
|
|
4
|
-
import path, { join } from 'node:path'
|
|
5
|
-
|
|
6
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
7
|
-
|
|
8
|
-
const mocks = vi.hoisted(() => ({
|
|
9
|
-
findSkillsCli: vi.fn(),
|
|
10
|
-
installSkillsCliRefToTemp: vi.fn(),
|
|
11
|
-
installSkillsCliSkillToTemp: vi.fn()
|
|
12
|
-
}))
|
|
13
|
-
|
|
14
|
-
vi.mock('@vibe-forge/utils/skills-cli', async () => {
|
|
15
|
-
const actual = await vi.importActual<typeof import('@vibe-forge/utils/skills-cli')>('@vibe-forge/utils/skills-cli')
|
|
16
|
-
return {
|
|
17
|
-
...actual,
|
|
18
|
-
findSkillsCli: mocks.findSkillsCli,
|
|
19
|
-
installSkillsCliRefToTemp: mocks.installSkillsCliRefToTemp,
|
|
20
|
-
installSkillsCliSkillToTemp: mocks.installSkillsCliSkillToTemp
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
import { buildAdapterAssetPlan, resolveWorkspaceAssetBundle } from '#~/index.js'
|
|
25
|
-
|
|
26
|
-
import { createWorkspace, writeDocument } from './test-helpers'
|
|
27
|
-
|
|
28
|
-
describe('skills CLI dependency resolution', () => {
|
|
29
|
-
let installWorkspace: string
|
|
30
|
-
|
|
31
|
-
beforeEach(async () => {
|
|
32
|
-
installWorkspace = await mkdtemp(path.join(os.tmpdir(), 'vf-skills-cli-dependency-'))
|
|
33
|
-
vi.clearAllMocks()
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
afterEach(async () => {
|
|
37
|
-
await rm(installWorkspace, { recursive: true, force: true })
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('installs missing bare-name dependencies through skills CLI by default', async () => {
|
|
41
|
-
const workspace = await createWorkspace()
|
|
42
|
-
const installedSkillDir = join(installWorkspace, '.agents', 'skills', 'frontend-design')
|
|
43
|
-
await mkdir(installedSkillDir, { recursive: true })
|
|
44
|
-
await writeFile(
|
|
45
|
-
join(installedSkillDir, 'SKILL.md'),
|
|
46
|
-
'---\nname: frontend-design\ndescription: UI design guidance\n---\nUse strong visual hierarchy.\n'
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
mocks.findSkillsCli.mockResolvedValue([
|
|
50
|
-
{
|
|
51
|
-
installRef: 'anthropics/skills@frontend-design',
|
|
52
|
-
source: 'anthropics/skills',
|
|
53
|
-
skill: 'frontend-design'
|
|
54
|
-
}
|
|
55
|
-
])
|
|
56
|
-
mocks.installSkillsCliRefToTemp.mockResolvedValue({
|
|
57
|
-
tempDir: installWorkspace,
|
|
58
|
-
installedSkill: {
|
|
59
|
-
dirName: 'frontend-design',
|
|
60
|
-
name: 'frontend-design',
|
|
61
|
-
sourcePath: installedSkillDir
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
await writeDocument(
|
|
66
|
-
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
67
|
-
[
|
|
68
|
-
'---',
|
|
69
|
-
'name: app-builder',
|
|
70
|
-
'description: Build apps',
|
|
71
|
-
'dependencies:',
|
|
72
|
-
' - frontend-design',
|
|
73
|
-
'---',
|
|
74
|
-
'Build the app.'
|
|
75
|
-
].join('\n')
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
const bundle = await resolveWorkspaceAssetBundle({
|
|
79
|
-
cwd: workspace,
|
|
80
|
-
configs: [undefined, undefined],
|
|
81
|
-
useDefaultVibeForgeMcpServer: false
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
await buildAdapterAssetPlan({
|
|
85
|
-
adapter: 'opencode',
|
|
86
|
-
bundle,
|
|
87
|
-
options: {
|
|
88
|
-
skills: {
|
|
89
|
-
include: ['app-builder']
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
const dependency = bundle.skills.find(asset => asset.name === 'frontend-design')
|
|
95
|
-
expect(bundle.skills.map(asset => asset.name).sort()).toEqual(['app-builder', 'frontend-design'])
|
|
96
|
-
expect(dependency?.sourcePath).toContain(
|
|
97
|
-
'/.ai/caches/skill-dependencies/skills-cli/skills/latest/default/anthropics/skills/frontend-design/'
|
|
98
|
-
)
|
|
99
|
-
expect(mocks.findSkillsCli).toHaveBeenCalledWith({
|
|
100
|
-
config: undefined,
|
|
101
|
-
query: 'frontend-design'
|
|
102
|
-
})
|
|
103
|
-
expect(mocks.installSkillsCliRefToTemp).toHaveBeenCalledWith({
|
|
104
|
-
config: undefined,
|
|
105
|
-
installRef: 'anthropics/skills@frontend-design'
|
|
106
|
-
})
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('merges top-level skillsCli config ahead of legacy skills.cli aliases', async () => {
|
|
110
|
-
const workspace = await createWorkspace()
|
|
111
|
-
const installedSkillDir = join(installWorkspace, '.agents', 'skills', 'frontend-design')
|
|
112
|
-
await mkdir(installedSkillDir, { recursive: true })
|
|
113
|
-
await writeFile(
|
|
114
|
-
join(installedSkillDir, 'SKILL.md'),
|
|
115
|
-
'---\nname: frontend-design\ndescription: UI design guidance\n---\nUse internal design system.\n'
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
mocks.installSkillsCliSkillToTemp.mockResolvedValue({
|
|
119
|
-
tempDir: installWorkspace,
|
|
120
|
-
installedSkill: {
|
|
121
|
-
dirName: 'frontend-design',
|
|
122
|
-
name: 'frontend-design',
|
|
123
|
-
sourcePath: installedSkillDir
|
|
124
|
-
}
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
await writeDocument(
|
|
128
|
-
join(workspace, '.ai/skills/app-builder/SKILL.md'),
|
|
129
|
-
[
|
|
130
|
-
'---',
|
|
131
|
-
'name: app-builder',
|
|
132
|
-
'description: Build apps',
|
|
133
|
-
'dependencies:',
|
|
134
|
-
' - example-source/default/public@frontend-design',
|
|
135
|
-
'---',
|
|
136
|
-
'Build the app.'
|
|
137
|
-
].join('\n')
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
const bundle = await resolveWorkspaceAssetBundle({
|
|
141
|
-
cwd: workspace,
|
|
142
|
-
configs: [{
|
|
143
|
-
skills: {
|
|
144
|
-
cli: {
|
|
145
|
-
package: 'legacy-skills'
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
skillsCli: {
|
|
149
|
-
package: '@byted/skills',
|
|
150
|
-
registry: 'https://registry.example.com'
|
|
151
|
-
}
|
|
152
|
-
}, undefined],
|
|
153
|
-
useDefaultVibeForgeMcpServer: false
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
await buildAdapterAssetPlan({
|
|
157
|
-
adapter: 'opencode',
|
|
158
|
-
bundle,
|
|
159
|
-
options: {
|
|
160
|
-
skills: {
|
|
161
|
-
include: ['app-builder']
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
expect(mocks.installSkillsCliSkillToTemp).toHaveBeenCalledWith({
|
|
167
|
-
config: {
|
|
168
|
-
package: '@byted/skills',
|
|
169
|
-
registry: 'https://registry.example.com'
|
|
170
|
-
},
|
|
171
|
-
skill: 'frontend-design',
|
|
172
|
-
source: 'example-source/default/public'
|
|
173
|
-
})
|
|
174
|
-
})
|
|
175
|
-
})
|
package/src/configured-skills.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { access } from 'node:fs/promises'
|
|
2
|
-
import process from 'node:process'
|
|
3
|
-
|
|
4
|
-
import type { Config, ConfiguredSkillInstallConfig, SkillsCliConfig } from '@vibe-forge/types'
|
|
5
|
-
import {
|
|
6
|
-
installProjectSkill,
|
|
7
|
-
normalizeProjectSkillInstall,
|
|
8
|
-
resolveConfiguredSkillInstalls as resolveDeclaredConfiguredSkillInstalls,
|
|
9
|
-
resolveProjectAiPath,
|
|
10
|
-
resolveSkillsCliRuntimeConfig
|
|
11
|
-
} from '@vibe-forge/utils'
|
|
12
|
-
import type { NormalizedProjectSkillInstall } from '@vibe-forge/utils'
|
|
13
|
-
|
|
14
|
-
const resolveConfiguredSkillsCliConfig = (configs: [Config?, Config?]) => {
|
|
15
|
-
const [projectConfig, userConfig] = configs
|
|
16
|
-
const merged = {
|
|
17
|
-
...(resolveSkillsCliRuntimeConfig(projectConfig) ?? {}),
|
|
18
|
-
...(resolveSkillsCliRuntimeConfig(userConfig) ?? {})
|
|
19
|
-
} satisfies SkillsCliConfig
|
|
20
|
-
|
|
21
|
-
return Object.keys(merged).length === 0 ? undefined : merged
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const resolveConfiguredSkillInstalls = (configs: [Config?, Config?]) => (
|
|
25
|
-
[
|
|
26
|
-
...resolveDeclaredConfiguredSkillInstalls(configs[0]?.skills),
|
|
27
|
-
...resolveDeclaredConfiguredSkillInstalls(configs[1]?.skills)
|
|
28
|
-
]
|
|
29
|
-
.map((item) => normalizeProjectSkillInstall(item as string | ConfiguredSkillInstallConfig))
|
|
30
|
-
.filter((item): item is NormalizedProjectSkillInstall => item != null)
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
const pathExists = async (targetPath: string) => {
|
|
34
|
-
try {
|
|
35
|
-
await access(targetPath)
|
|
36
|
-
return true
|
|
37
|
-
} catch {
|
|
38
|
-
return false
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const ensureUniqueTargets = (skills: NormalizedProjectSkillInstall[]) => {
|
|
43
|
-
const seen = new Map<string, string>()
|
|
44
|
-
|
|
45
|
-
for (const skill of skills) {
|
|
46
|
-
const previous = seen.get(skill.targetDirName)
|
|
47
|
-
if (previous != null) {
|
|
48
|
-
throw new Error(
|
|
49
|
-
`Configured skills "${previous}" and "${skill.ref}" resolve to the same target "${skill.targetDirName}"`
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
seen.set(skill.targetDirName, skill.ref)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export const ensureConfiguredProjectSkills = async (params: {
|
|
57
|
-
configs: [Config?, Config?]
|
|
58
|
-
updateInstalledSkills?: boolean
|
|
59
|
-
workspaceFolder: string
|
|
60
|
-
}) => {
|
|
61
|
-
const installs = resolveConfiguredSkillInstalls(params.configs)
|
|
62
|
-
if (installs.length === 0) {
|
|
63
|
-
return []
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
ensureUniqueTargets(installs)
|
|
67
|
-
|
|
68
|
-
const skillsCliConfig = resolveConfiguredSkillsCliConfig(params.configs)
|
|
69
|
-
const ensured: Array<{ dirName: string; skillPath: string }> = []
|
|
70
|
-
|
|
71
|
-
for (const skill of installs) {
|
|
72
|
-
const skillPath = resolveProjectAiPath(
|
|
73
|
-
params.workspaceFolder,
|
|
74
|
-
process.env,
|
|
75
|
-
'skills',
|
|
76
|
-
skill.targetDirName,
|
|
77
|
-
'SKILL.md'
|
|
78
|
-
)
|
|
79
|
-
if (params.updateInstalledSkills !== true && await pathExists(skillPath)) {
|
|
80
|
-
ensured.push({
|
|
81
|
-
dirName: skill.targetDirName,
|
|
82
|
-
skillPath
|
|
83
|
-
})
|
|
84
|
-
continue
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
ensured.push(
|
|
88
|
-
await installProjectSkill({
|
|
89
|
-
config: skillsCliConfig,
|
|
90
|
-
force: true,
|
|
91
|
-
registry: undefined,
|
|
92
|
-
skill,
|
|
93
|
-
workspaceFolder: params.workspaceFolder
|
|
94
|
-
})
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return ensured
|
|
99
|
-
}
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { access, copyFile, lstat, mkdir, readdir, rename, rm } from 'node:fs/promises'
|
|
2
|
-
import { dirname, resolve } from 'node:path'
|
|
3
|
-
import process from 'node:process'
|
|
4
|
-
import { setTimeout as delay } from 'node:timers/promises'
|
|
5
|
-
|
|
6
|
-
import type { Config, SkillsCliConfig } from '@vibe-forge/types'
|
|
7
|
-
import { resolveSkillsCliRuntimeConfig } from '@vibe-forge/utils'
|
|
8
|
-
import { resolveProjectSharedCachePath } from '@vibe-forge/utils/project-cache-path'
|
|
9
|
-
import {
|
|
10
|
-
findSkillsCli,
|
|
11
|
-
installSkillsCliRefToTemp,
|
|
12
|
-
installSkillsCliSkillToTemp,
|
|
13
|
-
resolveSkillsCliRegistry,
|
|
14
|
-
toSkillSlug
|
|
15
|
-
} from '@vibe-forge/utils/skills-cli'
|
|
16
|
-
|
|
17
|
-
import type { NormalizedSkillDependency } from './skill-dependencies'
|
|
18
|
-
|
|
19
|
-
const INSTALL_LOCK_TIMEOUT_MS = 30_000
|
|
20
|
-
const INSTALL_LOCK_RETRY_MS = 100
|
|
21
|
-
|
|
22
|
-
const toCacheSegment = (value: string) => (
|
|
23
|
-
value
|
|
24
|
-
.trim()
|
|
25
|
-
.toLowerCase()
|
|
26
|
-
.replace(/[^a-z0-9._-]+/g, '-')
|
|
27
|
-
.replace(/^-+|-+$/g, '') || 'default'
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
const pathExists = async (targetPath: string) => {
|
|
31
|
-
try {
|
|
32
|
-
await access(targetPath)
|
|
33
|
-
return true
|
|
34
|
-
} catch {
|
|
35
|
-
return false
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const withInstallLock = async <T>(lockDir: string, callback: () => Promise<T>) => {
|
|
40
|
-
const start = Date.now()
|
|
41
|
-
await mkdir(dirname(lockDir), { recursive: true })
|
|
42
|
-
|
|
43
|
-
while (true) {
|
|
44
|
-
try {
|
|
45
|
-
await mkdir(lockDir)
|
|
46
|
-
break
|
|
47
|
-
} catch (error) {
|
|
48
|
-
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error
|
|
49
|
-
if (Date.now() - start > INSTALL_LOCK_TIMEOUT_MS) {
|
|
50
|
-
throw new Error(`Timed out waiting for skill dependency install lock ${lockDir}`)
|
|
51
|
-
}
|
|
52
|
-
await delay(INSTALL_LOCK_RETRY_MS)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
return await callback()
|
|
58
|
-
} finally {
|
|
59
|
-
await rm(lockDir, { recursive: true, force: true })
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const copyRegularFiles = async (sourceDir: string, targetDir: string) => {
|
|
64
|
-
let fileCount = 0
|
|
65
|
-
const entries = await readdir(sourceDir, { withFileTypes: true })
|
|
66
|
-
|
|
67
|
-
await mkdir(targetDir, { recursive: true })
|
|
68
|
-
|
|
69
|
-
for (const entry of entries) {
|
|
70
|
-
const sourcePath = resolve(sourceDir, entry.name)
|
|
71
|
-
const targetPath = resolve(targetDir, entry.name)
|
|
72
|
-
const stat = await lstat(sourcePath)
|
|
73
|
-
|
|
74
|
-
if (stat.isDirectory()) {
|
|
75
|
-
fileCount += await copyRegularFiles(sourcePath, targetPath)
|
|
76
|
-
continue
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (!stat.isFile()) continue
|
|
80
|
-
|
|
81
|
-
await mkdir(dirname(targetPath), { recursive: true })
|
|
82
|
-
await copyFile(sourcePath, targetPath)
|
|
83
|
-
fileCount += 1
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return fileCount
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const pickSearchResult = (results: Awaited<ReturnType<typeof findSkillsCli>>, name: string) => {
|
|
90
|
-
const slug = toSkillSlug(name)
|
|
91
|
-
return results.find(result => (
|
|
92
|
-
result.skill === name ||
|
|
93
|
-
toSkillSlug(result.skill) === slug
|
|
94
|
-
)) ?? results[0]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const resolveConfiguredSkillsCliConfig = (configs: [Config?, Config?]) => {
|
|
98
|
-
const [projectConfig, userConfig] = configs
|
|
99
|
-
const merged = {
|
|
100
|
-
...(resolveSkillsCliRuntimeConfig(projectConfig) ?? {}),
|
|
101
|
-
...(resolveSkillsCliRuntimeConfig(userConfig) ?? {})
|
|
102
|
-
} satisfies SkillsCliConfig
|
|
103
|
-
|
|
104
|
-
return Object.keys(merged).length === 0 ? undefined : merged
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const buildInstallDir = (params: {
|
|
108
|
-
config?: SkillsCliConfig
|
|
109
|
-
cwd: string
|
|
110
|
-
skill: string
|
|
111
|
-
source: string
|
|
112
|
-
}) => {
|
|
113
|
-
const registry = resolveSkillsCliRegistry({
|
|
114
|
-
config: params.config
|
|
115
|
-
}) ?? 'default'
|
|
116
|
-
return resolveProjectSharedCachePath(
|
|
117
|
-
params.cwd,
|
|
118
|
-
process.env,
|
|
119
|
-
'skill-dependencies',
|
|
120
|
-
'skills-cli',
|
|
121
|
-
toCacheSegment(params.config?.package ?? 'skills'),
|
|
122
|
-
toCacheSegment(params.config?.version ?? 'latest'),
|
|
123
|
-
toCacheSegment(registry),
|
|
124
|
-
...params.source.split('/').map(toCacheSegment),
|
|
125
|
-
toCacheSegment(params.skill)
|
|
126
|
-
)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export const installSkillsCliDependency = async (params: {
|
|
130
|
-
cwd: string
|
|
131
|
-
configs: [Config?, Config?]
|
|
132
|
-
dependency: NormalizedSkillDependency
|
|
133
|
-
}) => {
|
|
134
|
-
const config = resolveConfiguredSkillsCliConfig(params.configs)
|
|
135
|
-
const resolvedTarget = params.dependency.source != null
|
|
136
|
-
? {
|
|
137
|
-
skill: params.dependency.name,
|
|
138
|
-
source: params.dependency.source
|
|
139
|
-
}
|
|
140
|
-
: await (async () => {
|
|
141
|
-
const searchResults = await findSkillsCli({
|
|
142
|
-
config,
|
|
143
|
-
query: params.dependency.name
|
|
144
|
-
})
|
|
145
|
-
const selected = pickSearchResult(searchResults, params.dependency.name)
|
|
146
|
-
if (selected == null) {
|
|
147
|
-
throw new Error(`Skill ${params.dependency.name} was not found by the skills CLI search.`)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
installRef: selected.installRef,
|
|
152
|
-
skill: selected.skill,
|
|
153
|
-
source: selected.source
|
|
154
|
-
}
|
|
155
|
-
})()
|
|
156
|
-
|
|
157
|
-
const installDir = buildInstallDir({
|
|
158
|
-
config,
|
|
159
|
-
cwd: params.cwd,
|
|
160
|
-
skill: resolvedTarget.skill,
|
|
161
|
-
source: resolvedTarget.source
|
|
162
|
-
})
|
|
163
|
-
const skillPath = resolve(installDir, 'SKILL.md')
|
|
164
|
-
|
|
165
|
-
return await withInstallLock(`${installDir}.lock`, async () => {
|
|
166
|
-
if (await pathExists(skillPath)) {
|
|
167
|
-
return {
|
|
168
|
-
installDir,
|
|
169
|
-
skillPath
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const tempInstallDir = `${installDir}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
174
|
-
await rm(tempInstallDir, { recursive: true, force: true })
|
|
175
|
-
await mkdir(tempInstallDir, { recursive: true })
|
|
176
|
-
|
|
177
|
-
const installResult = 'installRef' in resolvedTarget
|
|
178
|
-
? await installSkillsCliRefToTemp({
|
|
179
|
-
config,
|
|
180
|
-
installRef: resolvedTarget.installRef
|
|
181
|
-
})
|
|
182
|
-
: await installSkillsCliSkillToTemp({
|
|
183
|
-
config,
|
|
184
|
-
skill: resolvedTarget.skill,
|
|
185
|
-
source: resolvedTarget.source
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
try {
|
|
189
|
-
await copyRegularFiles(installResult.installedSkill.sourcePath, tempInstallDir)
|
|
190
|
-
if (!await pathExists(resolve(tempInstallDir, 'SKILL.md'))) {
|
|
191
|
-
throw new Error(`Skill dependency ${params.dependency.ref} did not include SKILL.md`)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
await rm(installDir, { recursive: true, force: true })
|
|
195
|
-
await rename(tempInstallDir, installDir)
|
|
196
|
-
} catch (error) {
|
|
197
|
-
await rm(tempInstallDir, { recursive: true, force: true })
|
|
198
|
-
throw error
|
|
199
|
-
} finally {
|
|
200
|
-
await rm(installResult.tempDir, { recursive: true, force: true })
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return {
|
|
204
|
-
installDir,
|
|
205
|
-
skillPath
|
|
206
|
-
}
|
|
207
|
-
})
|
|
208
|
-
}
|