gunni 0.3.7 → 0.3.8

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 (2) hide show
  1. package/dist/index.js +51 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -86263,7 +86263,7 @@ var RemoteClient = class {
86263
86263
  }
86264
86264
  }
86265
86265
  );
86266
- this.client = new Client({ name: "gunni-cli", version: "0.3.7" });
86266
+ this.client = new Client({ name: "gunni-cli", version: "0.3.8" });
86267
86267
  await this.client.connect(transport);
86268
86268
  }
86269
86269
  async callTool(name, args) {
@@ -86437,40 +86437,58 @@ var DEFAULT_MODELS = {
86437
86437
  "remove-bg": "bria-bg-remove"
86438
86438
  };
86439
86439
  function registerImageCommand(program3) {
86440
- program3.command("image").description("Unified image command: generate, edit, describe, upscale, or remove background").argument("[input]", "Image path or text prompt").argument("[prompt]", "Edit instructions (when input is an image)").option("-m, --model <model>", "Model to use (auto-selected by operation if omitted)").option("-o, --output <path>", "Output file path (default: auto-generated)").option("--width <pixels>", "Image width in pixels", parseInt).option("--height <pixels>", "Image height in pixels", parseInt).option("--seed <number>", "Random seed for reproducibility", parseInt).option("--upscale", "Upscale the input image").option("--remove-bg", "Remove background from the input image").option("--scale <factor>", "Scale factor for upscale (default: 2)", parseInt, 2).option("--variants <count>", "Number of variants to generate", parseInt).option("--style <name>", "Apply a saved visual style").addHelpText(
86440
+ program3.command("image").description("Unified image command: generate, edit, describe, upscale, or remove background").argument("[inputs...]", "Image path(s) or text prompt. Multiple images for multi-ref editing.").option("-m, --model <model>", "Model to use (auto-selected by operation if omitted)").option("-o, --output <path>", "Output file path (default: auto-generated)").option("--width <pixels>", "Image width in pixels", parseInt).option("--height <pixels>", "Image height in pixels", parseInt).option("--seed <number>", "Random seed for reproducibility", parseInt).option("--upscale", "Upscale the input image").option("--remove-bg", "Remove background from the input image").option("--scale <factor>", "Scale factor for upscale (default: 2)", parseInt, 2).option("--variants <count>", "Number of variants to generate", parseInt).option("--style <name>", "Apply a saved visual style").addHelpText(
86441
86441
  "after",
86442
86442
  `
86443
86443
  Examples:
86444
86444
 
86445
86445
  Generate an image:
86446
- $ gunni image "a cat on a beach" -o cat.png
86447
- $ gunni image "product photo" --model nano-banana -o product.png
86446
+ $ gunni image "a cat on a beach" -o cat
86447
+ $ gunni image "product photo" --model nano-banana -o product
86448
86448
 
86449
86449
  Edit an image:
86450
- $ gunni image photo.jpg "make the lighting warmer" -o photo-warm.jpg
86451
- $ gunni image logo.png "place on a coffee cup mockup" -o mockup.png
86450
+ $ gunni image photo.jpg "make the lighting warmer" -o photo-warm
86451
+ $ gunni image logo.png "place on a coffee cup mockup" -o mockup
86452
+
86453
+ Multi-image edit (combine references):
86454
+ $ gunni image fox.jpg forest.jpg "place the fox from @image1 on the path in @image2"
86455
+ $ gunni image character.png style-ref.png "redraw @image1 in the style of @image2"
86452
86456
 
86453
86457
  Describe an image:
86454
86458
  $ gunni image photo.jpg
86455
86459
 
86456
- Upscale an image:
86457
- $ gunni image photo.jpg --upscale -o photo-hires.jpg
86458
- $ gunni image photo.jpg --upscale --scale 4 -o photo-4x.jpg
86459
-
86460
- Remove background:
86461
- $ gunni image product.png --remove-bg -o product-clean.png
86460
+ Upscale / remove background:
86461
+ $ gunni image photo.jpg --upscale -o photo-hires
86462
+ $ gunni image product.png --remove-bg -o product-clean
86462
86463
 
86463
86464
  Explore with variants:
86464
- $ gunni image "logo concepts" --variants 4 -o concepts/logo-{n}.png
86465
+ $ gunni image "logo concepts" --variants 4 -o concepts/logo-{n}
86465
86466
 
86466
86467
  Agent usage:
86467
86468
  $ gunni --json image "product photo" --variants 3
86468
-
86469
- Returns: { operation, results: [{ image: { path, url, width, height }, seed }], model, prompt }
86470
86469
  `
86471
- ).action(async (input, prompt, opts) => {
86470
+ ).action(async (inputs, opts) => {
86472
86471
  const json2 = program3.opts().json ?? false;
86473
86472
  try {
86473
+ if (!inputs || inputs.length === 0) {
86474
+ throw new GunniError(
86475
+ "No input provided. Pass an image path or text prompt.",
86476
+ "MISSING_INPUT",
86477
+ "Run `gunni image --help` for usage examples."
86478
+ );
86479
+ }
86480
+ const imagePaths = [];
86481
+ let prompt;
86482
+ for (const arg of inputs) {
86483
+ if (existsSync(arg)) {
86484
+ imagePaths.push(arg);
86485
+ } else if (!prompt) {
86486
+ prompt = arg;
86487
+ } else {
86488
+ prompt += " " + arg;
86489
+ }
86490
+ }
86491
+ const input = imagePaths.length > 0 ? imagePaths[0] : prompt;
86474
86492
  if (!input) {
86475
86493
  throw new GunniError(
86476
86494
  "No input provided. Pass an image path or text prompt.",
@@ -86478,13 +86496,13 @@ Examples:
86478
86496
  "Run `gunni image --help` for usage examples."
86479
86497
  );
86480
86498
  }
86481
- const isFile = existsSync(input);
86499
+ const isFile = imagePaths.length > 0;
86482
86500
  const operation = routeOperation(isFile, prompt, opts);
86483
86501
  const config2 = new ConfigManager();
86484
86502
  const gunniKey = await config2.getGunniApiKey();
86485
86503
  if (gunniKey) {
86486
86504
  const serverUrl = await config2.getServerUrl();
86487
- return handleRemote(input, prompt, operation, opts, json2, gunniKey, serverUrl);
86505
+ return handleRemote(imagePaths.length > 1 ? imagePaths : input, prompt, operation, opts, json2, gunniKey, serverUrl);
86488
86506
  }
86489
86507
  throw new GunniError(
86490
86508
  "No API key configured",
@@ -86555,9 +86573,10 @@ function resolveVariantPath(template, index) {
86555
86573
  return `${base}-${index}${ext}`;
86556
86574
  }
86557
86575
  async function handleRemote(input, prompt, operation, opts, json2, apiKey, serverUrl) {
86576
+ const isMultiImage = Array.isArray(input);
86558
86577
  const spinnerLabels = {
86559
86578
  generate: "Painting pixels\u2026",
86560
- edit: "Reworking the canvas\u2026",
86579
+ edit: isMultiImage ? `Combining ${input.length} images\u2026` : "Reworking the canvas\u2026",
86561
86580
  describe: "Studying the image\u2026",
86562
86581
  upscale: "Enhancing resolution\u2026",
86563
86582
  "remove-bg": "Cutting out the background\u2026"
@@ -86569,8 +86588,17 @@ async function handleRemote(input, prompt, operation, opts, json2, apiKey, serve
86569
86588
  try {
86570
86589
  let imageUrl;
86571
86590
  if (operation !== "generate") {
86572
- update("Uploading image\u2026");
86573
- imageUrl = await uploadLocalFile(input, apiKey, serverUrl);
86591
+ if (isMultiImage) {
86592
+ const urls = [];
86593
+ for (let i2 = 0; i2 < input.length; i2++) {
86594
+ update(`Uploading image ${i2 + 1} of ${input.length}\u2026`);
86595
+ urls.push(await uploadLocalFile(input[i2], apiKey, serverUrl));
86596
+ }
86597
+ imageUrl = urls;
86598
+ } else {
86599
+ update("Uploading image\u2026");
86600
+ imageUrl = await uploadLocalFile(input, apiKey, serverUrl);
86601
+ }
86574
86602
  }
86575
86603
  let effectiveModel = opts.model ?? DEFAULT_MODELS[operation];
86576
86604
  let effectivePrompt = operation === "generate" ? input : prompt;
@@ -90917,7 +90945,7 @@ async function runOnboarding() {
90917
90945
 
90918
90946
  // src/index.ts
90919
90947
  var program2 = new Command();
90920
- program2.name("gunni").description("AI media toolkit \u2014 give any agent the ability to create professional media").version("0.3.7").option("--json", "Output results as JSON").addHelpText(
90948
+ program2.name("gunni").description("AI media toolkit \u2014 give any agent the ability to create professional media").version("0.3.8").option("--json", "Output results as JSON").addHelpText(
90921
90949
  "after",
90922
90950
  `
90923
90951
  Examples:
@@ -91017,7 +91045,7 @@ program2.action(async () => {
91017
91045
  { name: "models", usage: "gunni models [--type <category>]", description: "List available models" },
91018
91046
  { name: "config", usage: "gunni config", description: "Manage API keys" }
91019
91047
  ];
91020
- console.log(JSON.stringify({ version: "0.3.7", commands, categories, models }, null, 2));
91048
+ console.log(JSON.stringify({ version: "0.3.8", commands, categories, models }, null, 2));
91021
91049
  return;
91022
91050
  }
91023
91051
  const configured = await hasGunniKey();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gunni",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "AI media toolkit — give any agent the ability to create professional media",
5
5
  "type": "module",
6
6
  "bin": {