@drawcall/market 0.1.34 → 0.1.36
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 +2 -2
- package/dist/asset-implementation.d.ts +10 -7
- package/dist/asset-implementation.d.ts.map +1 -1
- package/dist/asset-implementation.js +8 -1
- package/dist/asset-implementation.js.map +1 -1
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/install.d.ts +3 -4
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +57 -11
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/upload.d.ts.map +1 -1
- package/dist/commands/upload.js +64 -2
- package/dist/commands/upload.js.map +1 -1
- package/dist/contract.d.ts +7 -1
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +1 -1
- package/dist/contract.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +14 -0
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +133 -23
- package/dist/install.js.map +1 -1
- package/dist/market-lock.d.ts +17 -0
- package/dist/market-lock.d.ts.map +1 -0
- package/dist/market-lock.js +44 -0
- package/dist/market-lock.js.map +1 -0
- package/dist/output.d.ts +2 -2
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +5 -2
- package/dist/output.js.map +1 -1
- package/dist/package-json.d.ts +11 -0
- package/dist/package-json.d.ts.map +1 -0
- package/dist/package-json.js +23 -0
- package/dist/package-json.js.map +1 -0
- package/dist/skill.d.ts +1 -1
- package/dist/skill.d.ts.map +1 -1
- package/dist/skill.js +5 -3
- package/dist/skill.js.map +1 -1
- package/package.json +1 -1
- package/src/asset-implementation.ts +18 -6
- package/src/cli.ts +16 -9
- package/src/commands/install.ts +76 -16
- package/src/commands/upload.ts +84 -2
- package/src/contract.ts +8 -1
- package/src/index.ts +9 -0
- package/src/install.ts +197 -35
- package/src/market-lock.ts +65 -0
- package/src/output.ts +7 -3
- package/src/package-json.ts +37 -0
- package/src/skill.ts +5 -3
- package/tests/install-command.test.ts +23 -1
- package/tests/install-layout.test.ts +117 -0
- package/tests/output.test.ts +19 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createHash } from 'crypto'
|
|
2
|
+
import * as fs from 'fs/promises'
|
|
3
|
+
import * as path from 'path'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
|
|
6
|
+
export const MARKET_LOCK_PATH = '.drawcall/market-lock.json'
|
|
7
|
+
|
|
8
|
+
export interface MarketLockAsset {
|
|
9
|
+
version: string
|
|
10
|
+
type: string
|
|
11
|
+
files: Record<string, { sha256: string }>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface MarketLock {
|
|
15
|
+
version: 1
|
|
16
|
+
assets: Record<string, MarketLockAsset>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const marketLockSchema = z.object({
|
|
20
|
+
version: z.literal(1),
|
|
21
|
+
assets: z.record(
|
|
22
|
+
z.string(),
|
|
23
|
+
z.object({
|
|
24
|
+
version: z.string(),
|
|
25
|
+
type: z.string(),
|
|
26
|
+
files: z.record(
|
|
27
|
+
z.string(),
|
|
28
|
+
z.object({
|
|
29
|
+
sha256: z.string(),
|
|
30
|
+
}),
|
|
31
|
+
),
|
|
32
|
+
}),
|
|
33
|
+
),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
export async function readMarketLock(projectRoot: string): Promise<MarketLock> {
|
|
37
|
+
const lockPath = path.join(projectRoot, MARKET_LOCK_PATH)
|
|
38
|
+
try {
|
|
39
|
+
return marketLockSchema.parse(JSON.parse(await fs.readFile(lockPath, 'utf-8')))
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (isMissingFile(error)) return emptyMarketLock()
|
|
42
|
+
throw error
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function writeMarketLock(projectRoot: string, lock: MarketLock): Promise<void> {
|
|
47
|
+
const lockPath = path.join(projectRoot, MARKET_LOCK_PATH)
|
|
48
|
+
await fs.mkdir(path.dirname(lockPath), { recursive: true })
|
|
49
|
+
await fs.writeFile(lockPath, JSON.stringify(lock, null, 2) + '\n')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function emptyMarketLock(): MarketLock {
|
|
53
|
+
return {
|
|
54
|
+
version: 1,
|
|
55
|
+
assets: {},
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function sha256(bytes: Uint8Array): string {
|
|
60
|
+
return createHash('sha256').update(bytes).digest('hex')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isMissingFile(error: unknown): boolean {
|
|
64
|
+
return error instanceof Error && 'code' in error && error.code === 'ENOENT'
|
|
65
|
+
}
|
package/src/output.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssetSearchResult } from './contract.js'
|
|
1
|
+
import type { AssetInstallMetadata, AssetSearchResult } from './contract.js'
|
|
2
2
|
import type { InstallResult } from './install.js'
|
|
3
3
|
|
|
4
4
|
export function assetVersionRef(name: string, version?: string): string {
|
|
@@ -33,7 +33,7 @@ export function assetSearchResultLine(item: AssetSearchResult): string {
|
|
|
33
33
|
|
|
34
34
|
export function installResult(
|
|
35
35
|
result: InstallResult,
|
|
36
|
-
|
|
36
|
+
installMetadata: Record<string, AssetInstallMetadata> = {},
|
|
37
37
|
): string {
|
|
38
38
|
const npmDependencies = Object.entries(result.npmDependencies)
|
|
39
39
|
|
|
@@ -48,7 +48,7 @@ export function installResult(
|
|
|
48
48
|
if (files.length > 0) {
|
|
49
49
|
lines.push(' files:', ...indent(fileTree(files), ' '))
|
|
50
50
|
}
|
|
51
|
-
const message =
|
|
51
|
+
const message = installMetadata[asset.type]?.installMessage
|
|
52
52
|
if (message) {
|
|
53
53
|
lines.push(...block(' note: ', message))
|
|
54
54
|
}
|
|
@@ -71,6 +71,10 @@ export function installResult(
|
|
|
71
71
|
)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
if (result.warnings.length > 0) {
|
|
75
|
+
lines.push('Warnings:', ...result.warnings.map((warning) => `- ${warning}`))
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
return lines.join('\n')
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
export interface PackageJson {
|
|
4
|
+
name?: string
|
|
5
|
+
private?: boolean
|
|
6
|
+
dependencies?: Record<string, string>
|
|
7
|
+
assetDependencies?: Record<string, string>
|
|
8
|
+
[key: string]: unknown
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const stringRecordSchema = z.record(z.string(), z.string())
|
|
12
|
+
|
|
13
|
+
export function packageJsonAssetDependenciesFromFiles(
|
|
14
|
+
files: Record<string, Uint8Array>,
|
|
15
|
+
): Record<string, string> {
|
|
16
|
+
const bytes = files['package.json']
|
|
17
|
+
if (!bytes) return {}
|
|
18
|
+
|
|
19
|
+
return packageJsonAssetDependencies(new TextDecoder().decode(bytes), 'package.json')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function packageJsonAssetDependencies(json: string, source: string): Record<string, string> {
|
|
23
|
+
const parsed = parsePackageJson(json, source)
|
|
24
|
+
const dependencies = parsed.assetDependencies
|
|
25
|
+
if (dependencies === undefined) return {}
|
|
26
|
+
|
|
27
|
+
return stringRecordSchema.parse(dependencies)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function parsePackageJson(json: string, source: string): PackageJson {
|
|
31
|
+
const parsed = JSON.parse(json) as unknown
|
|
32
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
33
|
+
throw new Error(`${source} must contain a JSON object`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return parsed as PackageJson
|
|
37
|
+
}
|
package/src/skill.ts
CHANGED
|
@@ -19,13 +19,13 @@ market preview wooden-chair --out /tmp/wooden-chair.png
|
|
|
19
19
|
|
|
20
20
|
1. Search first unless the user already gave an exact asset name. \`search\` requires \`--type\`; use \`model\` unless the user names another supported type: \`humanoid-model\`, \`texture\`, \`humanoid-animation\`, \`template\`, \`sound-effect\`, \`background-music\`, \`environment\`, or \`flipbook\`.
|
|
21
21
|
2. Use \`--limit 1\` for lookup, \`--limit 3\` for choice. Search caps at 5 and prints full descriptions.
|
|
22
|
-
3. \`install\` takes
|
|
22
|
+
3. \`install\` takes zero or more exact asset names (optionally \`name@range\`). With names, it installs those assets; with no names, it installs \`assetDependencies\` from the nearest \`package.json\`. It does not search or generate. Find names with \`search\` first. No \`--type\` is needed — asset names are unique. Use \`--force\` only when the user agrees to overwrite changed local files.
|
|
23
23
|
4. \`preview <name>\` saves the preview image; no \`--type\` is needed. Not every type has previews (e.g. \`humanoid-animation\`, \`template\`, \`sound-effect\`, \`background-music\`); the CLI reports when one is unavailable.
|
|
24
24
|
5. Use \`--unapproved\` only when the user asks for unapproved/private/admin assets. Do not install unapproved assets without explicit acceptance.
|
|
25
25
|
6. \`generate --type <type> "<prompt>"\` creates a new asset; it requires login and a type that supports generation. No asset type currently supports generation.
|
|
26
|
-
7. Upload only when publishing is requested: \`market upload <name> <zip> "<description>" --type <type>\`. Declare dependencies with repeatable flags: \`--npm name@range\`, \`--asset name@range\`, \`--skill label=source\`. A skill source is a \`skills add\` argument: a whole repo (\`owner/repo\` or a git URL), a single skill via the full URL form \`https://github.com/owner/repo/tree/<branch>/<subpath>\` (the \`tree/<branch>/<subpath>\` shorthand needs the full URL, not \`owner/repo\`), or a local path to a skill directory inside the zip. Example: \`market upload my-scene scene.zip "A scene" --type model --npm three@^0.178.0 --skill web-design=https://github.com/vercel-labs/agent-skills/tree/main/skills/web-design-guidelines\`.
|
|
26
|
+
7. Upload only when publishing is requested: \`market upload <name> <zip> "<description>" --type <type>\`. Declare dependencies with repeatable flags: \`--npm name@range\`, \`--asset name@range\`, \`--skill label=source\`. Template uploads also read root \`package.json.assetDependencies\`; \`--asset\` flags are additive and must not conflict. Template upload omits installed dependency files whose hashes still match \`.drawcall/market-lock.json\`, so edited local files stay in the template. A skill source is a \`skills add\` argument: a whole repo (\`owner/repo\` or a git URL), a single skill via the full URL form \`https://github.com/owner/repo/tree/<branch>/<subpath>\` (the \`tree/<branch>/<subpath>\` shorthand needs the full URL, not \`owner/repo\`), or a local path to a skill directory inside the zip. Example: \`market upload my-scene scene.zip "A scene" --type model --npm three@^0.178.0 --skill web-design=https://github.com/vercel-labs/agent-skills/tree/main/skills/web-design-guidelines\`.
|
|
27
27
|
8. Installed \`environment\` assets contain \`public/environment/<name>.hdr\` for Three.js IBL lighting and \`public/environment/<name>-background.webp\` for the visible equirectangular background. Use \`market preview\` to fetch the preview image separately.
|
|
28
|
-
9. Installed \`flipbook\` assets contain \`public/flipbook/<name>.ktx2\`. Render them with \`@drawcall/flipbook\`'s \`Flipbook\` class; \`market preview\` fetches the middle frame from the flipbook.
|
|
28
|
+
9. Installed \`flipbook\` assets contain \`public/flipbook/<name>.ktx2\`. Render them with \`@drawcall/flipbook\`'s \`Flipbook\` class and Three.js \`KTX2Loader\` for Basis-compressed files; \`market preview\` fetches the middle frame from the flipbook.
|
|
29
29
|
|
|
30
30
|
## Humanoid animations
|
|
31
31
|
|
|
@@ -53,5 +53,7 @@ Saved preview for wooden-chair@1.0.0: /tmp/wooden-chair.png
|
|
|
53
53
|
|
|
54
54
|
Assets may also declare \`skill\` dependencies, installed for you via the \`skills\` CLI (\`skills add\`) during \`install\`. Sources are either a GitHub/git ref or a local path to a skill directory shipped inside the asset. This requires \`npx\` to be available.
|
|
55
55
|
|
|
56
|
+
Installed non-template assets are saved to \`package.json.assetDependencies\`; templates are scaffolds and are not saved as project asset dependencies. Exact installed versions and file hashes are recorded in \`.drawcall/market-lock.json\`.
|
|
57
|
+
|
|
56
58
|
If search returns no results, try one broader noun phrase. If a command returns \`Error: Not logged in...\`, ask before running \`market login\`.
|
|
57
59
|
`
|
|
@@ -31,7 +31,29 @@ test('resolveArg keeps explicit versioned refs exact when the asset exists', asy
|
|
|
31
31
|
|
|
32
32
|
const request = await resolveArg(client, 'fresh-sky@1.2.3', false)
|
|
33
33
|
|
|
34
|
-
assert.deepEqual(request, {
|
|
34
|
+
assert.deepEqual(request, {
|
|
35
|
+
name: 'fresh-sky',
|
|
36
|
+
range: '1.2.3',
|
|
37
|
+
saveRange: '1.2.3',
|
|
38
|
+
save: true,
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('resolveArg saves an implicit range from the selected latest version', async () => {
|
|
43
|
+
const client = {
|
|
44
|
+
asset: {
|
|
45
|
+
exact: async () => ({ name: 'fresh-sky', latestVersion: '1.2.3', approved: true }),
|
|
46
|
+
},
|
|
47
|
+
} as never
|
|
48
|
+
|
|
49
|
+
const request = await resolveArg(client, 'fresh-sky', false)
|
|
50
|
+
|
|
51
|
+
assert.deepEqual(request, {
|
|
52
|
+
name: 'fresh-sky',
|
|
53
|
+
range: '*',
|
|
54
|
+
saveRange: '^1.2.3',
|
|
55
|
+
save: true,
|
|
56
|
+
})
|
|
35
57
|
})
|
|
36
58
|
|
|
37
59
|
test('resolveArg errors when the asset does not exist instead of deferring', async () => {
|
|
@@ -5,6 +5,7 @@ import * as path from 'node:path'
|
|
|
5
5
|
import test from 'node:test'
|
|
6
6
|
import { zipSync } from 'fflate'
|
|
7
7
|
import { findInstallRoot, install } from '../src/install.js'
|
|
8
|
+
import { MARKET_LOCK_PATH } from '../src/market-lock.js'
|
|
8
9
|
|
|
9
10
|
const textEncoder = new TextEncoder()
|
|
10
11
|
|
|
@@ -53,6 +54,7 @@ test('install writes zip files into the package root', async () => {
|
|
|
53
54
|
],
|
|
54
55
|
npmDependencies: {},
|
|
55
56
|
skillDependencies: {},
|
|
57
|
+
warnings: [],
|
|
56
58
|
})
|
|
57
59
|
assert.equal(
|
|
58
60
|
await fs.readFile(path.join(appRoot, 'public', 'humanoid-animation', 'idle-loop.glb'), 'utf-8'),
|
|
@@ -64,6 +66,15 @@ test('install writes zip files into the package root', async () => {
|
|
|
64
66
|
)
|
|
65
67
|
assert.equal(await fs.readFile(path.join(appRoot, 'README.md'), 'utf-8'), 'project readme\n')
|
|
66
68
|
assert.equal(await exists(path.join(cwd, 'src', 'idle-loop', 'public')), false)
|
|
69
|
+
|
|
70
|
+
const lock = JSON.parse(await fs.readFile(path.join(appRoot, MARKET_LOCK_PATH), 'utf-8')) as {
|
|
71
|
+
assets: Record<string, { version: string; files: Record<string, { sha256: string }> }>
|
|
72
|
+
}
|
|
73
|
+
assert.equal(lock.assets['idle-loop'].version, '1.0.0')
|
|
74
|
+
assert.equal(
|
|
75
|
+
typeof lock.assets['idle-loop'].files['public/humanoid-animation/idle-loop.glb'].sha256,
|
|
76
|
+
'string',
|
|
77
|
+
)
|
|
67
78
|
})
|
|
68
79
|
|
|
69
80
|
test('install rejects zip paths that escape through parent segments', async () => {
|
|
@@ -149,6 +160,112 @@ test('install runs the skills runner per dependency, resolving local paths again
|
|
|
149
160
|
'web-design-guidelines': 'vercel-labs/agent-skills/tree/main/skills/web-design-guidelines',
|
|
150
161
|
'local-skill': './public/skills/local-skill',
|
|
151
162
|
})
|
|
163
|
+
assert.deepEqual(result.warnings, [])
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
test('install saves top-level assets according to provider policy', async () => {
|
|
167
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'market-save-policy-'))
|
|
168
|
+
await fs.writeFile(path.join(tempDir, 'package.json'), '{}\n')
|
|
169
|
+
|
|
170
|
+
await install(
|
|
171
|
+
clientWithZip({
|
|
172
|
+
'public/model/chair.glb': textEncoder.encode('chair'),
|
|
173
|
+
'src/template.ts': textEncoder.encode('export {}\n'),
|
|
174
|
+
}),
|
|
175
|
+
{
|
|
176
|
+
assets: [
|
|
177
|
+
{
|
|
178
|
+
name: 'chair',
|
|
179
|
+
type: 'model',
|
|
180
|
+
version: '1.2.0',
|
|
181
|
+
description: null,
|
|
182
|
+
npmDependencies: {},
|
|
183
|
+
assetDependencies: {},
|
|
184
|
+
skillDependencies: {},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: 'starter-template',
|
|
188
|
+
type: 'template',
|
|
189
|
+
version: '2.0.0',
|
|
190
|
+
description: null,
|
|
191
|
+
npmDependencies: {},
|
|
192
|
+
assetDependencies: {},
|
|
193
|
+
skillDependencies: {},
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
npmDependencies: {},
|
|
197
|
+
skillDependencies: {},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
cwd: tempDir,
|
|
201
|
+
rootRequests: [
|
|
202
|
+
{ name: 'chair', range: '*', saveRange: '^1.2.0', save: true },
|
|
203
|
+
{ name: 'starter-template', range: '*', saveRange: '^2.0.0', save: true },
|
|
204
|
+
],
|
|
205
|
+
installMetadata: {
|
|
206
|
+
template: {
|
|
207
|
+
saveOnInstall: false,
|
|
208
|
+
readAssetDependenciesFromPackageJson: true,
|
|
209
|
+
omitUnchangedInstalledFilesOnUpload: true,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
const pkg = JSON.parse(await fs.readFile(path.join(tempDir, 'package.json'), 'utf-8')) as {
|
|
216
|
+
assetDependencies: Record<string, string>
|
|
217
|
+
}
|
|
218
|
+
assert.deepEqual(pkg.assetDependencies, { chair: '^1.2.0' })
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
test('install skips existing changed files unless force is set', async () => {
|
|
222
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'market-conflict-'))
|
|
223
|
+
await fs.mkdir(path.join(tempDir, 'public', 'model'), { recursive: true })
|
|
224
|
+
await fs.writeFile(path.join(tempDir, 'package.json'), '{}\n')
|
|
225
|
+
await fs.writeFile(path.join(tempDir, 'public', 'model', 'chair.glb'), 'local edit')
|
|
226
|
+
|
|
227
|
+
const resolution = {
|
|
228
|
+
assets: [
|
|
229
|
+
{
|
|
230
|
+
name: 'chair',
|
|
231
|
+
type: 'model',
|
|
232
|
+
version: '1.0.0',
|
|
233
|
+
description: null,
|
|
234
|
+
npmDependencies: {},
|
|
235
|
+
assetDependencies: {},
|
|
236
|
+
skillDependencies: {},
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
npmDependencies: {},
|
|
240
|
+
skillDependencies: {},
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const skipped = await install(
|
|
244
|
+
clientWithZip({
|
|
245
|
+
'public/model/chair.glb': textEncoder.encode('market bytes'),
|
|
246
|
+
}),
|
|
247
|
+
resolution,
|
|
248
|
+
{ cwd: tempDir },
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
assert.equal(await fs.readFile(path.join(tempDir, 'public', 'model', 'chair.glb'), 'utf-8'), 'local edit')
|
|
252
|
+
assert.match(skipped.warnings[0], /Skipped public\/model\/chair\.glb/u)
|
|
253
|
+
assert.deepEqual(skipped.assets[0].files, [])
|
|
254
|
+
|
|
255
|
+
const forced = await install(
|
|
256
|
+
clientWithZip({
|
|
257
|
+
'public/model/chair.glb': textEncoder.encode('market bytes'),
|
|
258
|
+
}),
|
|
259
|
+
resolution,
|
|
260
|
+
{ cwd: tempDir, force: true },
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
assert.equal(
|
|
264
|
+
await fs.readFile(path.join(tempDir, 'public', 'model', 'chair.glb'), 'utf-8'),
|
|
265
|
+
'market bytes',
|
|
266
|
+
)
|
|
267
|
+
assert.deepEqual(forced.warnings, [])
|
|
268
|
+
assert.deepEqual(forced.assets[0].files, ['public/model/chair.glb'])
|
|
152
269
|
})
|
|
153
270
|
|
|
154
271
|
test('findInstallRoot uses the nearest package.json, not the monorepo root', async () => {
|
package/tests/output.test.ts
CHANGED
|
@@ -47,6 +47,7 @@ test('installResult prints asset type, file tree, and npm list', () => {
|
|
|
47
47
|
],
|
|
48
48
|
npmDependencies: { '@react-three/drei': 'latest' },
|
|
49
49
|
skillDependencies: {},
|
|
50
|
+
warnings: [],
|
|
50
51
|
}),
|
|
51
52
|
`Installed:
|
|
52
53
|
- wooden-chair@1.2.0 (model)
|
|
@@ -87,9 +88,15 @@ test('installResult attaches each post-install note under its asset', () => {
|
|
|
87
88
|
],
|
|
88
89
|
npmDependencies: {},
|
|
89
90
|
skillDependencies: {},
|
|
91
|
+
warnings: [],
|
|
90
92
|
},
|
|
91
93
|
{
|
|
92
|
-
model:
|
|
94
|
+
model: {
|
|
95
|
+
installMessage: 'Load the model.',
|
|
96
|
+
saveOnInstall: true,
|
|
97
|
+
readAssetDependenciesFromPackageJson: false,
|
|
98
|
+
omitUnchangedInstalledFilesOnUpload: false,
|
|
99
|
+
},
|
|
93
100
|
// sound-effect intentionally omitted -> no note for `beep`.
|
|
94
101
|
},
|
|
95
102
|
),
|
|
@@ -107,8 +114,16 @@ test('installResult word-wraps a long note with a hanging indent', () => {
|
|
|
107
114
|
assets: [{ name: 'thing', type: 'model', version: '1.0.0', description: null, files: [] }],
|
|
108
115
|
npmDependencies: {},
|
|
109
116
|
skillDependencies: {},
|
|
117
|
+
warnings: [],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
model: {
|
|
121
|
+
installMessage: message,
|
|
122
|
+
saveOnInstall: true,
|
|
123
|
+
readAssetDependenciesFromPackageJson: false,
|
|
124
|
+
omitUnchangedInstalledFilesOnUpload: false,
|
|
125
|
+
},
|
|
110
126
|
},
|
|
111
|
-
{ model: message },
|
|
112
127
|
)
|
|
113
128
|
|
|
114
129
|
assert.equal(
|
|
@@ -137,6 +152,7 @@ test('installResult lists installed skills with their source', () => {
|
|
|
137
152
|
'web-design-guidelines': 'vercel-labs/agent-skills/tree/main/skills/web-design-guidelines',
|
|
138
153
|
'local-skill': '/abs/public/skills/local-skill',
|
|
139
154
|
},
|
|
155
|
+
warnings: [],
|
|
140
156
|
}),
|
|
141
157
|
`Installed:
|
|
142
158
|
- wooden-chair@1.2.0 (model)
|
|
@@ -160,6 +176,7 @@ test('installResult shows each installed asset description', () => {
|
|
|
160
176
|
],
|
|
161
177
|
npmDependencies: {},
|
|
162
178
|
skillDependencies: {},
|
|
179
|
+
warnings: [],
|
|
163
180
|
}),
|
|
164
181
|
`Installed:
|
|
165
182
|
- wooden-chair@1.2.0 (model)
|