sintetica-cli 0.2.0 → 0.4.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.
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const brandCommand: Command;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.brandCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const api_js_1 = require("../lib/api.js");
6
+ const getCommand = new commander_1.Command('get')
7
+ .description('View current brand settings')
8
+ .action(async () => {
9
+ try {
10
+ const data = await (0, api_js_1.api)('/api/cli/brand');
11
+ console.log(JSON.stringify(data));
12
+ }
13
+ catch (err) {
14
+ console.error(JSON.stringify({ error: err instanceof Error ? err.message : 'Failed' }));
15
+ process.exit(1);
16
+ }
17
+ });
18
+ const setCommand = new commander_1.Command('set')
19
+ .description('Update brand settings')
20
+ .option('--name <name>', 'Brand/company name')
21
+ .option('--website <url>', 'Brand website')
22
+ .option('--industry <industry>', 'Industry (e.g. wellness, beauty, fitness, fashion, food, tech)')
23
+ .option('--colors <colors>', 'Brand colors, comma-separated hex (e.g. "#1a1a1a,#d4af37,#ffffff")')
24
+ .option('--voice <voice>', 'Brand voice (e.g. premium, playful, clinical, bold, professional, eco-conscious)')
25
+ .option('--archetype <archetype>', 'Brand archetype (e.g. hero, sage, rebel, lover, creator, explorer, ruler, magician, caregiver, everyman, jester, innocent)')
26
+ .option('--target-audience <audience>', 'Target audience description')
27
+ .option('--tagline <tagline>', 'Brand tagline')
28
+ .option('--keywords <words>', 'Brand keywords, comma-separated')
29
+ .option('--logo-url <url>', 'Logo URL')
30
+ .option('--background-style <style>', 'Default background style (e.g. "clean white", "dark moody", "natural outdoor")')
31
+ .action(async (opts) => {
32
+ const body = {};
33
+ if (opts.name)
34
+ body.name = opts.name;
35
+ if (opts.website)
36
+ body.website = opts.website;
37
+ if (opts.industry)
38
+ body.industry = opts.industry;
39
+ if (opts.colors)
40
+ body.colors = opts.colors.split(',').map(c => c.trim());
41
+ if (opts.voice)
42
+ body.voice = opts.voice;
43
+ if (opts.archetype)
44
+ body.archetype = opts.archetype;
45
+ if (opts.targetAudience)
46
+ body.targetAudience = opts.targetAudience;
47
+ if (opts.tagline)
48
+ body.tagline = opts.tagline;
49
+ if (opts.keywords)
50
+ body.keywords = opts.keywords.split(',').map(k => k.trim());
51
+ if (opts.logoUrl)
52
+ body.logoUrl = opts.logoUrl;
53
+ if (opts.backgroundStyle)
54
+ body.backgroundStyle = opts.backgroundStyle;
55
+ if (Object.keys(body).length === 0) {
56
+ console.error(JSON.stringify({ error: 'Provide at least one setting to update' }));
57
+ process.exit(1);
58
+ }
59
+ try {
60
+ const data = await (0, api_js_1.api)('/api/cli/brand', { method: 'PATCH', body });
61
+ console.log(JSON.stringify(data));
62
+ }
63
+ catch (err) {
64
+ console.error(JSON.stringify({ error: err instanceof Error ? err.message : 'Failed' }));
65
+ process.exit(1);
66
+ }
67
+ });
68
+ const analyzeCommand = new commander_1.Command('analyze')
69
+ .description('Analyze a website to auto-detect brand identity (colors, voice, industry)')
70
+ .requiredOption('--url <url>', 'Website URL to analyze')
71
+ .option('--apply', 'Automatically apply detected settings to your profile')
72
+ .action(async (opts) => {
73
+ try {
74
+ const data = await (0, api_js_1.api)('/api/cli/brand/analyze', {
75
+ body: { url: opts.url },
76
+ });
77
+ console.log(JSON.stringify(data));
78
+ // Auto-apply if flag is set
79
+ if (opts.apply) {
80
+ const applyBody = {};
81
+ if (data.name)
82
+ applyBody.name = data.name;
83
+ if (data.colors && data.colors.length > 0)
84
+ applyBody.colors = data.colors;
85
+ if (data.voice)
86
+ applyBody.voice = data.voice;
87
+ if (data.industry)
88
+ applyBody.industry = data.industry;
89
+ if (data.logoUrl)
90
+ applyBody.logoUrl = data.logoUrl;
91
+ if (data.keywords && data.keywords.length > 0)
92
+ applyBody.keywords = data.keywords;
93
+ if (Object.keys(applyBody).length > 0) {
94
+ const result = await (0, api_js_1.api)('/api/cli/brand', { method: 'PATCH', body: applyBody });
95
+ process.stderr.write(' Brand settings applied from analysis\n');
96
+ console.log(JSON.stringify(result));
97
+ }
98
+ }
99
+ }
100
+ catch (err) {
101
+ console.error(JSON.stringify({ error: err instanceof Error ? err.message : 'Analysis failed' }));
102
+ process.exit(1);
103
+ }
104
+ });
105
+ exports.brandCommand = new commander_1.Command('brand')
106
+ .description('Manage brand identity (colors, voice, audience, style)')
107
+ .addCommand(getCommand)
108
+ .addCommand(setCommand)
109
+ .addCommand(analyzeCommand);
@@ -84,14 +84,89 @@ 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')
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('--brand-colors <colors>', 'Brand colors, comma-separated')
91
+ .option('--brand-voice <voice>', 'Brand voice')
92
+ .option('--target-audience <audience>', 'Target audience')
93
+ .option('--background <bg>', 'Background style')
94
+ .option('--keywords <words>', 'Brand keywords, comma-separated')
88
95
  .option('--wait', 'Wait for completion')
89
96
  .action(async (opts) => {
90
- if (opts.product) {
91
- await generateAction.parseAsync(['', '', '--product', opts.product, '--style', opts.style, '--format', opts.format, '--count', opts.count, ...(opts.wait ? ['--wait'] : [])]);
92
- }
93
- else {
97
+ if (!opts.product) {
94
98
  exports.generateCommand.help();
99
+ return;
100
+ }
101
+ try {
102
+ const baseBody = {
103
+ productId: opts.product,
104
+ style: opts.style,
105
+ format: opts.format,
106
+ brandColors: opts.brandColors?.split(',').map(c => c.trim()),
107
+ brandVoice: opts.brandVoice,
108
+ targetAudience: opts.targetAudience,
109
+ background: opts.background,
110
+ keywords: opts.keywords?.split(',').map(k => k.trim()),
111
+ };
112
+ // Multi-shot mode: separate jobs with different prompts
113
+ if (opts.shots) {
114
+ let shotPrompts;
115
+ try {
116
+ shotPrompts = JSON.parse(opts.shots);
117
+ if (!Array.isArray(shotPrompts))
118
+ throw new Error('not an array');
119
+ }
120
+ catch {
121
+ console.error(JSON.stringify({ error: '--shots must be a JSON array of strings, e.g. \'["prompt 1","prompt 2"]\'' }));
122
+ process.exit(1);
123
+ return;
124
+ }
125
+ const allAssets = [];
126
+ const jobs = [];
127
+ for (let i = 0; i < shotPrompts.length; i++) {
128
+ const shotPrompt = shotPrompts[i];
129
+ process.stderr.write(` Shot ${i + 1}/${shotPrompts.length}: submitting...\n`);
130
+ const result = await (0, api_js_1.api)('/api/cli/generate', {
131
+ body: { ...baseBody, count: 1, prompt: shotPrompt },
132
+ });
133
+ jobs.push({ jobId: result.jobId, prompt: shotPrompt });
134
+ process.stderr.write(` Shot ${i + 1}: job ${result.jobId} (${result.creditsCost} credits)\n`);
135
+ }
136
+ if (opts.wait) {
137
+ for (let i = 0; i < jobs.length; i++) {
138
+ process.stderr.write(` Waiting for shot ${i + 1}/${jobs.length}...`);
139
+ const status = await pollUntilDone(jobs[i].jobId);
140
+ process.stderr.write('\n');
141
+ allAssets.push(...status.assets);
142
+ }
143
+ console.log(JSON.stringify({
144
+ shots: jobs.length,
145
+ assets: allAssets,
146
+ jobIds: jobs.map(j => j.jobId),
147
+ }));
148
+ }
149
+ else {
150
+ console.log(JSON.stringify({ jobs }));
151
+ }
152
+ return;
153
+ }
154
+ // Single shot mode
155
+ const result = await (0, api_js_1.api)('/api/cli/generate', {
156
+ body: { ...baseBody, count: parseInt(opts.count), prompt: opts.prompt },
157
+ });
158
+ if (!opts.wait) {
159
+ console.log(JSON.stringify(result));
160
+ return;
161
+ }
162
+ process.stderr.write(` Job ${result.jobId} started (${result.creditsCost} credits)\n`);
163
+ const finalStatus = await pollUntilDone(result.jobId);
164
+ process.stderr.write('\n');
165
+ console.log(JSON.stringify(finalStatus));
166
+ }
167
+ catch (err) {
168
+ console.error(JSON.stringify({ error: err instanceof Error ? err.message : 'Generation failed' }));
169
+ process.exit(1);
95
170
  }
96
171
  });
97
172
  exports.generateCommand.addCommand(statusCommand);
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ const commander_1 = require("commander");
5
5
  const login_js_1 = require("./commands/login.js");
6
6
  const credits_js_1 = require("./commands/credits.js");
7
7
  const topup_js_1 = require("./commands/topup.js");
8
+ const brand_js_1 = require("./commands/brand.js");
8
9
  const products_js_1 = require("./commands/products.js");
9
10
  const generate_js_1 = require("./commands/generate.js");
10
11
  const assets_js_1 = require("./commands/assets.js");
@@ -17,6 +18,7 @@ program
17
18
  program.addCommand(login_js_1.loginCommand);
18
19
  program.addCommand(credits_js_1.creditsCommand);
19
20
  program.addCommand(topup_js_1.topupCommand);
21
+ program.addCommand(brand_js_1.brandCommand);
20
22
  program.addCommand(products_js_1.productsCommand);
21
23
  program.addCommand(generate_js_1.generateCommand);
22
24
  program.addCommand(assets_js_1.assetsCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sintetica-cli",
3
- "version": "0.2.0",
3
+ "version": "0.4.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>",