sintetica-cli 0.3.0 → 0.5.0

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.
@@ -84,47 +84,91 @@ exports.generateCommand
84
84
  .option('--product <id>', 'Product ID')
85
85
  .option('--style <style>', 'Style preset', 'minimal')
86
86
  .option('--format <format>', 'Image format', 'instagram_square')
87
- .option('--count <n>', 'Number of variations', '4')
88
- .option('--prompt <text>', 'Custom creative direction (e.g. "zen spa setting with candles")')
89
- .option('--brand-colors <colors>', 'Brand colors, comma-separated (e.g. "#1a1a1a,#d4af37")')
90
- .option('--brand-voice <voice>', 'Brand voice (e.g. "premium", "playful", "clinical")')
91
- .option('--target-audience <audience>', 'Target audience (e.g. "health-conscious millennials")')
92
- .option('--background <bg>', 'Background style (e.g. "marble surface", "gym setting", "kitchen counter")')
87
+ .option('--count <n>', 'Number of images per job', '1')
88
+ .option('--prompt <text>', 'Custom creative direction')
89
+ .option('--shots <json>', 'Multiple shots with different prompts (JSON array of strings)')
90
+ .option('--model-url <url>', 'URL of a person/model reference image to include in the shot')
91
+ .option('--brand-colors <colors>', 'Brand colors, comma-separated')
92
+ .option('--brand-voice <voice>', 'Brand voice')
93
+ .option('--target-audience <audience>', 'Target audience')
94
+ .option('--background <bg>', 'Background style')
93
95
  .option('--keywords <words>', 'Brand keywords, comma-separated')
94
96
  .option('--wait', 'Wait for completion')
95
97
  .action(async (opts) => {
96
- if (opts.product) {
97
- try {
98
- const result = await (0, api_js_1.api)('/api/cli/generate', {
99
- body: {
100
- productId: opts.product,
101
- style: opts.style,
102
- format: opts.format,
103
- count: parseInt(opts.count),
104
- prompt: opts.prompt,
105
- brandColors: opts.brandColors?.split(',').map(c => c.trim()),
106
- brandVoice: opts.brandVoice,
107
- targetAudience: opts.targetAudience,
108
- background: opts.background,
109
- keywords: opts.keywords?.split(',').map(k => k.trim()),
110
- },
111
- });
112
- if (!opts.wait) {
113
- console.log(JSON.stringify(result));
98
+ if (!opts.product) {
99
+ exports.generateCommand.help();
100
+ return;
101
+ }
102
+ try {
103
+ const baseBody = {
104
+ productId: opts.product,
105
+ style: opts.style,
106
+ format: opts.format,
107
+ modelUrl: opts.modelUrl,
108
+ brandColors: opts.brandColors?.split(',').map(c => c.trim()),
109
+ brandVoice: opts.brandVoice,
110
+ targetAudience: opts.targetAudience,
111
+ background: opts.background,
112
+ keywords: opts.keywords?.split(',').map(k => k.trim()),
113
+ };
114
+ // Multi-shot mode: separate jobs with different prompts
115
+ if (opts.shots) {
116
+ let shotPrompts;
117
+ try {
118
+ shotPrompts = JSON.parse(opts.shots);
119
+ if (!Array.isArray(shotPrompts))
120
+ throw new Error('not an array');
121
+ }
122
+ catch {
123
+ console.error(JSON.stringify({ error: '--shots must be a JSON array of strings, e.g. \'["prompt 1","prompt 2"]\'' }));
124
+ process.exit(1);
114
125
  return;
115
126
  }
116
- process.stderr.write(` Job ${result.jobId} started (${result.creditsCost} credits)\n`);
117
- const finalStatus = await pollUntilDone(result.jobId);
118
- process.stderr.write('\n');
119
- console.log(JSON.stringify(finalStatus));
127
+ const allAssets = [];
128
+ const jobs = [];
129
+ for (let i = 0; i < shotPrompts.length; i++) {
130
+ const shotPrompt = shotPrompts[i];
131
+ process.stderr.write(` Shot ${i + 1}/${shotPrompts.length}: submitting...\n`);
132
+ const result = await (0, api_js_1.api)('/api/cli/generate', {
133
+ body: { ...baseBody, count: 1, prompt: shotPrompt },
134
+ });
135
+ jobs.push({ jobId: result.jobId, prompt: shotPrompt });
136
+ process.stderr.write(` Shot ${i + 1}: job ${result.jobId} (${result.creditsCost} credits)\n`);
137
+ }
138
+ if (opts.wait) {
139
+ for (let i = 0; i < jobs.length; i++) {
140
+ process.stderr.write(` Waiting for shot ${i + 1}/${jobs.length}...`);
141
+ const status = await pollUntilDone(jobs[i].jobId);
142
+ process.stderr.write('\n');
143
+ allAssets.push(...status.assets);
144
+ }
145
+ console.log(JSON.stringify({
146
+ shots: jobs.length,
147
+ assets: allAssets,
148
+ jobIds: jobs.map(j => j.jobId),
149
+ }));
150
+ }
151
+ else {
152
+ console.log(JSON.stringify({ jobs }));
153
+ }
154
+ return;
120
155
  }
121
- catch (err) {
122
- console.error(JSON.stringify({ error: err instanceof Error ? err.message : 'Generation failed' }));
123
- process.exit(1);
156
+ // Single shot mode
157
+ const result = await (0, api_js_1.api)('/api/cli/generate', {
158
+ body: { ...baseBody, count: parseInt(opts.count), prompt: opts.prompt },
159
+ });
160
+ if (!opts.wait) {
161
+ console.log(JSON.stringify(result));
162
+ return;
124
163
  }
164
+ process.stderr.write(` Job ${result.jobId} started (${result.creditsCost} credits)\n`);
165
+ const finalStatus = await pollUntilDone(result.jobId);
166
+ process.stderr.write('\n');
167
+ console.log(JSON.stringify(finalStatus));
125
168
  }
126
- else {
127
- exports.generateCommand.help();
169
+ catch (err) {
170
+ console.error(JSON.stringify({ error: err instanceof Error ? err.message : 'Generation failed' }));
171
+ process.exit(1);
128
172
  }
129
173
  });
130
174
  exports.generateCommand.addCommand(statusCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sintetica-cli",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Sintetica CLI — AI product photography from your terminal. Generate professional product photos with one command.",
5
5
  "keywords": ["sintetica", "ai", "product-photography", "ecommerce", "shopify", "cli", "claude-code"],
6
6
  "author": "Sintetica <hello@sintetica.ro>",