@drawcall/market 0.1.74 → 0.1.76

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.
Files changed (58) hide show
  1. package/dist/agent.d.ts +2 -2
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +15 -3
  4. package/dist/agent.js.map +1 -1
  5. package/dist/asset-implementation.d.ts +7 -0
  6. package/dist/asset-implementation.d.ts.map +1 -1
  7. package/dist/asset-implementation.js +1 -0
  8. package/dist/asset-implementation.js.map +1 -1
  9. package/dist/cli.js +8 -21
  10. package/dist/cli.js.map +1 -1
  11. package/dist/commands/agent.d.ts +2 -42
  12. package/dist/commands/agent.d.ts.map +1 -1
  13. package/dist/commands/agent.js +8 -382
  14. package/dist/commands/agent.js.map +1 -1
  15. package/dist/commands/generate.d.ts +2 -0
  16. package/dist/commands/generate.d.ts.map +1 -1
  17. package/dist/commands/generate.js +3 -0
  18. package/dist/commands/generate.js.map +1 -1
  19. package/dist/commands/reference-images.d.ts +6 -0
  20. package/dist/commands/reference-images.d.ts.map +1 -0
  21. package/dist/commands/reference-images.js +28 -0
  22. package/dist/commands/reference-images.js.map +1 -0
  23. package/dist/contract.d.ts +4 -46
  24. package/dist/contract.d.ts.map +1 -1
  25. package/dist/contract.js +2 -8
  26. package/dist/contract.js.map +1 -1
  27. package/dist/generate.d.ts +2 -0
  28. package/dist/generate.d.ts.map +1 -1
  29. package/dist/generate.js.map +1 -1
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/output.d.ts.map +1 -1
  35. package/dist/output.js +18 -48
  36. package/dist/output.js.map +1 -1
  37. package/dist/schemas.d.ts +3 -46
  38. package/dist/schemas.d.ts.map +1 -1
  39. package/dist/schemas.js +20 -46
  40. package/dist/schemas.js.map +1 -1
  41. package/dist/skill.d.ts +1 -1
  42. package/dist/skill.d.ts.map +1 -1
  43. package/dist/skill.js +2 -0
  44. package/dist/skill.js.map +1 -1
  45. package/package.json +1 -1
  46. package/skills/market/SKILL.md +2 -0
  47. package/src/agent.ts +17 -4
  48. package/src/asset-implementation.ts +8 -0
  49. package/src/cli.ts +19 -33
  50. package/src/commands/agent.ts +11 -474
  51. package/src/commands/generate.ts +5 -0
  52. package/src/commands/reference-images.ts +25 -0
  53. package/src/contract.ts +3 -9
  54. package/src/generate.ts +2 -0
  55. package/src/index.ts +0 -7
  56. package/src/output.ts +18 -56
  57. package/src/schemas.ts +24 -53
  58. package/src/skill.ts +2 -0
package/src/contract.ts CHANGED
@@ -3,8 +3,6 @@ import { z } from 'zod'
3
3
  import type { AssetFileManifest } from './schemas.js'
4
4
  import {
5
5
  MAX_UPLOAD_ZIP_SIZE_BYTES,
6
- agentControlResultSchema,
7
- agentDeferredStartSchema,
8
6
  agentRunStatusSchema,
9
7
  agentStartSchema,
10
8
  agentStatusSchema,
@@ -104,6 +102,8 @@ export interface AssetInstallMetadata {
104
102
  installMessage?: string
105
103
  /** Omitted by Market APIs released before capability discovery. */
106
104
  canGenerate?: boolean
105
+ /** Whether `generate` takes reference images for this type. */
106
+ acceptsReferenceImages?: boolean
107
107
  saveOnInstall: boolean
108
108
  readAssetDependenciesFromPackageJson: boolean
109
109
  omitUnchangedInstalledFilesOnUpload: boolean
@@ -149,16 +149,10 @@ export const contract = {
149
149
  // The agent plans, searches, judges and (where supported) generates a set of
150
150
  // assets from a goal. `start` kicks off an async run; `status` long-polls it
151
151
  // (blocks until the run settles or a heartbeat window elapses). The
152
- // `agentAndWait` drives ordinary runs. A safety-critical deferred caller
153
- // uses fail-closed `startDeferred`, observes `status`, then calls `approve`
154
- // or `cancel`. Deferred semantics deliberately do not exist on `start`:
155
- // an older worker could strip an unknown optional flag and spend immediately.
152
+ // `agentAndWait` client helper drives both.
156
153
  agent: {
157
154
  start: oc.input(agentStartSchema).output(z.object({ runId: z.string() })),
158
- startDeferred: oc.input(agentDeferredStartSchema).output(z.object({ runId: z.string() })),
159
155
  status: oc.input(agentStatusSchema).output(agentRunStatusSchema),
160
- approve: oc.input(agentStatusSchema).output(agentControlResultSchema),
161
- cancel: oc.input(agentStatusSchema).output(agentControlResultSchema),
162
156
  },
163
157
  },
164
158
 
package/src/generate.ts CHANGED
@@ -11,6 +11,8 @@ export class GenerateError extends Error {
11
11
  export interface GenerateInput {
12
12
  description: string
13
13
  type?: AssetType
14
+ /** Reference images (https URL or data URI) the result should match. */
15
+ referenceImages?: string[]
14
16
  /** Requested visibility; omitted lets the server resolve it from entitlement. */
15
17
  access?: AssetAccess
16
18
  }
package/src/index.ts CHANGED
@@ -67,11 +67,7 @@ export {
67
67
  updateProfileSchema,
68
68
  listAssetsSchema,
69
69
  agentStartSchema,
70
- agentDeferredStartSchema,
71
70
  agentStatusSchema,
72
- agentGenerationStateSchema,
73
- agentControlStateSchema,
74
- agentControlResultSchema,
75
71
  agentResultAssetSchema,
76
72
  agentResultSchema,
77
73
  agentRunStatusSchema,
@@ -87,9 +83,6 @@ export type {
87
83
  AgentResultAsset,
88
84
  AgentResult,
89
85
  AgentRunStatus,
90
- AgentGenerationState,
91
- AgentControlState,
92
- AgentControlResult,
93
86
  GenerateResponse,
94
87
  GenerateJobStatus,
95
88
  } from './schemas.js'
package/src/output.ts CHANGED
@@ -103,7 +103,7 @@ export function assetTypesResult(metadata: Record<string, AssetInstallMetadata>)
103
103
 
104
104
  const lines = ['Asset types:']
105
105
  for (const [type, details] of types) {
106
- lines.push(`- ${type} (${assetCapabilities(details.canGenerate)})`)
106
+ lines.push(`- ${type} (${assetCapabilities(details)})`)
107
107
  if (details.searchMessage) {
108
108
  lines.push(...block(' search: ', details.searchMessage))
109
109
  }
@@ -111,10 +111,10 @@ export function assetTypesResult(metadata: Record<string, AssetInstallMetadata>)
111
111
  return lines.join('\n')
112
112
  }
113
113
 
114
- function assetCapabilities(canGenerate: boolean | undefined): string {
115
- if (canGenerate === true) return 'search, generate'
116
- if (canGenerate === false) return 'search only'
117
- return 'search, generation unknown'
114
+ function assetCapabilities(details: AssetInstallMetadata): string {
115
+ if (details.canGenerate === undefined) return 'search, generation unknown'
116
+ if (!details.canGenerate) return 'search only'
117
+ return details.acceptsReferenceImages ? 'search, generate (reference images)' : 'search, generate'
118
118
  }
119
119
 
120
120
  function assetLine(asset: { name: string; version: string; type: string }): string {
@@ -122,12 +122,13 @@ function assetLine(asset: { name: string; version: string; type: string }): stri
122
122
  }
123
123
 
124
124
  function assetFileLines(paths: string[]): string[] {
125
- const lines: string[] = []
126
- const files = unique(paths)
127
- if (files.length > 0) {
128
- lines.push(' files:', ...indent(fileTree(files), ' '))
129
- }
130
- return lines
125
+ const files = unique(paths).sort((a, b) => a.localeCompare(b))
126
+ if (files.length === 0) return []
127
+ return [' files:', ...files.map((file) => ` ${installedFileLine(file)}`)]
128
+ }
129
+
130
+ function installedFileLine(file: string): string {
131
+ return file.startsWith('public/') ? `${file} -> browser: /${file.slice('public/'.length)}` : file
131
132
  }
132
133
 
133
134
  function block(label: string, message: string, width = 68): string[] {
@@ -161,13 +162,17 @@ export function generatedInstallResult(
161
162
  export function generationStartedResult(jobId: string): string {
162
163
  return [
163
164
  'Still generating after the normal wait — it continues in the background.',
164
- `Run this to pick up where it left off and install when ready: market generate install ${jobId}`,
165
+ `Resume this same job and install when ready: ${generationInstallCommand(jobId)}`,
165
166
  ].join('\n')
166
167
  }
167
168
 
168
169
  // Printed by `generate install` when the job is still running after its wait window.
169
170
  export function generationRunningResult(jobId: string): string {
170
- return `Still generating. Run again to continue: market generate install ${jobId}`
171
+ return `Still generating. Resume this same job: ${generationInstallCommand(jobId)}`
172
+ }
173
+
174
+ function generationInstallCommand(jobId: string): string {
175
+ return `npx @drawcall/market@latest generate install ${jobId} --cwd "$PWD"`
171
176
  }
172
177
 
173
178
  export function uploadResult(name: string, version: string): string {
@@ -217,53 +222,10 @@ function normalizeInline(value: string): string {
217
222
  return value.replace(/\s+/g, ' ').trim()
218
223
  }
219
224
 
220
- interface FileTreeNode {
221
- children: Map<string, FileTreeNode>
222
- }
223
-
224
- function fileTree(paths: string[]): string[] {
225
- const root: FileTreeNode = { children: new Map() }
226
-
227
- for (const filePath of paths) {
228
- const parts = filePath.split('/').filter(Boolean)
229
- let node = root
230
- for (const part of parts) {
231
- let child = node.children.get(part)
232
- if (!child) {
233
- child = { children: new Map() }
234
- node.children.set(part, child)
235
- }
236
- node = child
237
- }
238
- }
239
-
240
- return renderFileTree(root)
241
- }
242
-
243
- function renderFileTree(node: FileTreeNode, prefix = '', showConnector = false): string[] {
244
- const entries = [...node.children.entries()].sort(([aName, aNode], [bName, bNode]) => {
245
- const aIsDir = aNode.children.size > 0
246
- const bIsDir = bNode.children.size > 0
247
- if (aIsDir !== bIsDir) return aIsDir ? -1 : 1
248
- return aName.localeCompare(bName)
249
- })
250
-
251
- return entries.flatMap(([name, child], index) => {
252
- const isLast = index === entries.length - 1
253
- const connector = showConnector ? (isLast ? '└─ ' : '├─ ') : ''
254
- const childPrefix = showConnector ? prefix + (isLast ? ' ' : '│ ') : ''
255
- return [`${prefix}${connector}${name}`, ...renderFileTree(child, childPrefix, true)]
256
- })
257
- }
258
-
259
225
  function unique<T>(values: T[]): T[] {
260
226
  return [...new Set(values)]
261
227
  }
262
228
 
263
- function indent(lines: string[], prefix: string): string[] {
264
- return lines.map((line) => `${prefix}${line}`)
265
- }
266
-
267
229
  function dependencyLines(label: string, deps: Record<string, string>): string[] {
268
230
  const entries = Object.entries(deps)
269
231
  if (entries.length === 0) return []
package/src/schemas.ts CHANGED
@@ -106,9 +106,26 @@ export const fileManifestSchema = z.object({
106
106
  */
107
107
  export type AssetFileManifest = Record<string, string>
108
108
 
109
+ // A phone-photo data URI is a few MB; this bounds worker and model payloads while staying far
110
+ // above what providers keep (images are downscaled upstream).
111
+ const MAX_REFERENCE_IMAGE_CHARS = 10_000_000
112
+
113
+ // Reference images the generated asset should match, each an http(s) URL or a
114
+ // `data:image/<type>;base64,<data>` URI. Only providers that declare
115
+ // `acceptsReferenceImages` take them, and none takes more than two.
116
+ export const referenceImagesSchema = z
117
+ .array(
118
+ z
119
+ .string()
120
+ .max(MAX_REFERENCE_IMAGE_CHARS)
121
+ .regex(/^(https?:\/\/|data:image\/)/, 'Must be an http(s) URL or a data:image URI'),
122
+ )
123
+ .max(2)
124
+
109
125
  export const generateAssetSchema = z.object({
110
126
  description: assetDescriptionSchema.min(3),
111
127
  type: assetTypeSchema.optional(),
128
+ referenceImages: referenceImagesSchema.optional(),
112
129
  // Requested visibility of the generated asset (same resolution as upload).
113
130
  access: assetAccessSchema.optional(),
114
131
  })
@@ -143,47 +160,16 @@ export type GenerateJobStatus = z.infer<typeof generateJobStatusSchema>
143
160
 
144
161
  // The agent takes a natural-language goal (which carries the count and kinds,
145
162
  // e.g. "3 low poly stones" or "a template for a zombie game, none if no fit")
146
- // and optional reference images as base64 (raw or data URLs).
163
+ // and optional reference images (http(s) URL or data URI).
147
164
  export const agentStartSchema = z.strictObject({
148
165
  goal: z.string().min(3).max(1000),
149
- images: z.array(z.string()).optional(),
150
- })
151
-
152
- // A distinct procedure lets safety-critical callers fail closed against an
153
- // older worker: an unknown `startDeferred` starts nothing. Deferred runs are
154
- // goal-only because their restart input is persisted until the wall deadline;
155
- // accepting unbounded base64 reference images would make that unsafe.
156
- export const agentDeferredStartSchema = z.strictObject({
157
- goal: agentStartSchema.shape.goal,
158
- runId: z.string().uuid(),
166
+ referenceImages: referenceImagesSchema.optional(),
159
167
  })
160
168
 
161
169
  export const agentStatusSchema = z.object({
162
170
  runId: z.string().min(1),
163
171
  })
164
172
 
165
- export const agentGenerationStateSchema = z.enum([
166
- 'deferred',
167
- 'awaiting-approval',
168
- 'approved',
169
- 'generation-started',
170
- ])
171
- export type AgentGenerationState = z.infer<typeof agentGenerationStateSchema>
172
-
173
- export const agentControlStateSchema = z.enum([
174
- ...agentGenerationStateSchema.options,
175
- 'completed',
176
- 'failed',
177
- 'cancelled',
178
- ])
179
- export type AgentControlState = z.infer<typeof agentControlStateSchema>
180
-
181
- export const agentControlResultSchema = z.object({
182
- accepted: z.boolean(),
183
- state: agentControlStateSchema,
184
- })
185
- export type AgentControlResult = z.infer<typeof agentControlResultSchema>
186
-
187
173
  // One chosen asset: a verified, installable `name@version` (the agent only
188
174
  // returns names the catalog resolved) plus a note on what it contributes.
189
175
  export const agentResultAssetSchema = z.object({
@@ -203,27 +189,12 @@ export const agentResultSchema = z.object({
203
189
  })
204
190
  export type AgentResult = z.infer<typeof agentResultSchema>
205
191
 
206
- // An agent run is an async job: it is running (with optional generation-gate
207
- // progress), completed, failed, or explicitly cancelled. A discriminated union
208
- // keeps "completed without a result" and "failed without an error"
192
+ // An agent run is an async job: running, completed, or failed. A discriminated
193
+ // union keeps "completed without a result" and "failed without an error"
209
194
  // unrepresentable.
210
195
  export const agentRunStatusSchema = z.discriminatedUnion('status', [
211
- z.object({
212
- status: z.literal('running'),
213
- // Optional so a new client can still read a running response from an older
214
- // worker during a rolling deploy.
215
- generation: agentGenerationStateSchema.optional(),
216
- }),
217
- z.object({
218
- status: z.literal('completed'),
219
- result: agentResultSchema,
220
- generationStarted: z.boolean().optional(),
221
- }),
222
- z.object({
223
- status: z.literal('failed'),
224
- error: z.string(),
225
- generationStarted: z.boolean().optional(),
226
- }),
227
- z.object({ status: z.literal('cancelled'), generationStarted: z.boolean().optional() }),
196
+ z.object({ status: z.literal('running') }),
197
+ z.object({ status: z.literal('completed'), result: agentResultSchema }),
198
+ z.object({ status: z.literal('failed'), error: z.string() }),
228
199
  ])
229
200
  export type AgentRunStatus = z.infer<typeof agentRunStatusSchema>
package/src/skill.ts CHANGED
@@ -33,6 +33,8 @@ Install prints the exact files it wrote. It never searches or generates. With no
33
33
 
34
34
  \`npx @drawcall/market generate --type <type> "<description>"\` creates and installs one provider-supported asset. It requires login and normally waits through provider generation before printing exact installed paths and type-specific usage guidance. Unsupported types report an error. If an unusually long job returns a continuation, run the printed \`generate install <jobId>\`; it resumes the same server-side job rather than generating again.
35
35
 
36
+ Add repeatable \`--reference-image <file-or-url>\` when the result should match given images; \`types\` shows which asset types accept reference images. A humanoid-model keeps the face and distinctive features of the person shown (at most 2 images). Types without reference image support reject them.
37
+
36
38
  Add \`--access public\` or \`--access private\` when visibility matters. Omitted access follows the account entitlement; private generation requires \`market:private\`.
37
39
 
38
40
  ## Publish only when asked