gunni 0.3.6 → 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.
- package/dist/index.js +95 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -69400,7 +69400,8 @@ async function downloadImage(url2, outputPath, onProgress) {
|
|
|
69400
69400
|
const correctExt = await detectImageFormat(outputPath);
|
|
69401
69401
|
const currentExt = extname(outputPath).toLowerCase();
|
|
69402
69402
|
if (correctExt && correctExt !== currentExt) {
|
|
69403
|
-
const
|
|
69403
|
+
const basePath = currentExt ? outputPath.slice(0, -currentExt.length) : outputPath;
|
|
69404
|
+
const fixedPath = basePath + correctExt;
|
|
69404
69405
|
await rename(outputPath, fixedPath);
|
|
69405
69406
|
return fixedPath;
|
|
69406
69407
|
}
|
|
@@ -69431,7 +69432,8 @@ async function saveImageData(data, outputPath, onProgress) {
|
|
|
69431
69432
|
const correctExt = await detectImageFormat(outputPath);
|
|
69432
69433
|
const currentExt = extname(outputPath).toLowerCase();
|
|
69433
69434
|
if (correctExt && correctExt !== currentExt) {
|
|
69434
|
-
const
|
|
69435
|
+
const basePath = currentExt ? outputPath.slice(0, -currentExt.length) : outputPath;
|
|
69436
|
+
const fixedPath = basePath + correctExt;
|
|
69435
69437
|
await rename(outputPath, fixedPath);
|
|
69436
69438
|
return fixedPath;
|
|
69437
69439
|
}
|
|
@@ -86261,7 +86263,7 @@ var RemoteClient = class {
|
|
|
86261
86263
|
}
|
|
86262
86264
|
}
|
|
86263
86265
|
);
|
|
86264
|
-
this.client = new Client({ name: "gunni-cli", version: "0.3.
|
|
86266
|
+
this.client = new Client({ name: "gunni-cli", version: "0.3.8" });
|
|
86265
86267
|
await this.client.connect(transport);
|
|
86266
86268
|
}
|
|
86267
86269
|
async callTool(name, args) {
|
|
@@ -86435,40 +86437,58 @@ var DEFAULT_MODELS = {
|
|
|
86435
86437
|
"remove-bg": "bria-bg-remove"
|
|
86436
86438
|
};
|
|
86437
86439
|
function registerImageCommand(program3) {
|
|
86438
|
-
program3.command("image").description("Unified image command: generate, edit, describe, upscale, or remove background").argument("[
|
|
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(
|
|
86439
86441
|
"after",
|
|
86440
86442
|
`
|
|
86441
86443
|
Examples:
|
|
86442
86444
|
|
|
86443
86445
|
Generate an image:
|
|
86444
|
-
$ gunni image "a cat on a beach" -o cat
|
|
86445
|
-
$ gunni image "product photo" --model nano-banana -o product
|
|
86446
|
+
$ gunni image "a cat on a beach" -o cat
|
|
86447
|
+
$ gunni image "product photo" --model nano-banana -o product
|
|
86446
86448
|
|
|
86447
86449
|
Edit an image:
|
|
86448
|
-
$ gunni image photo.jpg "make the lighting warmer" -o photo-warm
|
|
86449
|
-
$ gunni image logo.png "place on a coffee cup mockup" -o mockup
|
|
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"
|
|
86450
86456
|
|
|
86451
86457
|
Describe an image:
|
|
86452
86458
|
$ gunni image photo.jpg
|
|
86453
86459
|
|
|
86454
|
-
Upscale
|
|
86455
|
-
$ gunni image photo.jpg --upscale -o photo-hires
|
|
86456
|
-
$ gunni image
|
|
86457
|
-
|
|
86458
|
-
Remove background:
|
|
86459
|
-
$ 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
|
|
86460
86463
|
|
|
86461
86464
|
Explore with variants:
|
|
86462
|
-
$ gunni image "logo concepts" --variants 4 -o concepts/logo-{n}
|
|
86465
|
+
$ gunni image "logo concepts" --variants 4 -o concepts/logo-{n}
|
|
86463
86466
|
|
|
86464
86467
|
Agent usage:
|
|
86465
86468
|
$ gunni --json image "product photo" --variants 3
|
|
86466
|
-
|
|
86467
|
-
Returns: { operation, results: [{ image: { path, url, width, height }, seed }], model, prompt }
|
|
86468
86469
|
`
|
|
86469
|
-
).action(async (
|
|
86470
|
+
).action(async (inputs, opts) => {
|
|
86470
86471
|
const json2 = program3.opts().json ?? false;
|
|
86471
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;
|
|
86472
86492
|
if (!input) {
|
|
86473
86493
|
throw new GunniError(
|
|
86474
86494
|
"No input provided. Pass an image path or text prompt.",
|
|
@@ -86476,13 +86496,13 @@ Examples:
|
|
|
86476
86496
|
"Run `gunni image --help` for usage examples."
|
|
86477
86497
|
);
|
|
86478
86498
|
}
|
|
86479
|
-
const isFile =
|
|
86499
|
+
const isFile = imagePaths.length > 0;
|
|
86480
86500
|
const operation = routeOperation(isFile, prompt, opts);
|
|
86481
86501
|
const config2 = new ConfigManager();
|
|
86482
86502
|
const gunniKey = await config2.getGunniApiKey();
|
|
86483
86503
|
if (gunniKey) {
|
|
86484
86504
|
const serverUrl = await config2.getServerUrl();
|
|
86485
|
-
return handleRemote(input, prompt, operation, opts, json2, gunniKey, serverUrl);
|
|
86505
|
+
return handleRemote(imagePaths.length > 1 ? imagePaths : input, prompt, operation, opts, json2, gunniKey, serverUrl);
|
|
86486
86506
|
}
|
|
86487
86507
|
throw new GunniError(
|
|
86488
86508
|
"No API key configured",
|
|
@@ -86553,9 +86573,10 @@ function resolveVariantPath(template, index) {
|
|
|
86553
86573
|
return `${base}-${index}${ext}`;
|
|
86554
86574
|
}
|
|
86555
86575
|
async function handleRemote(input, prompt, operation, opts, json2, apiKey, serverUrl) {
|
|
86576
|
+
const isMultiImage = Array.isArray(input);
|
|
86556
86577
|
const spinnerLabels = {
|
|
86557
86578
|
generate: "Painting pixels\u2026",
|
|
86558
|
-
edit: "Reworking the canvas\u2026",
|
|
86579
|
+
edit: isMultiImage ? `Combining ${input.length} images\u2026` : "Reworking the canvas\u2026",
|
|
86559
86580
|
describe: "Studying the image\u2026",
|
|
86560
86581
|
upscale: "Enhancing resolution\u2026",
|
|
86561
86582
|
"remove-bg": "Cutting out the background\u2026"
|
|
@@ -86567,8 +86588,17 @@ async function handleRemote(input, prompt, operation, opts, json2, apiKey, serve
|
|
|
86567
86588
|
try {
|
|
86568
86589
|
let imageUrl;
|
|
86569
86590
|
if (operation !== "generate") {
|
|
86570
|
-
|
|
86571
|
-
|
|
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
|
+
}
|
|
86572
86602
|
}
|
|
86573
86603
|
let effectiveModel = opts.model ?? DEFAULT_MODELS[operation];
|
|
86574
86604
|
let effectivePrompt = operation === "generate" ? input : prompt;
|
|
@@ -87891,7 +87921,7 @@ KEY PRINCIPLES
|
|
|
87891
87921
|
}
|
|
87892
87922
|
},
|
|
87893
87923
|
latest: {
|
|
87894
|
-
version: "0.3.
|
|
87924
|
+
version: "0.3.7",
|
|
87895
87925
|
date: "2026-03-29",
|
|
87896
87926
|
updates: [
|
|
87897
87927
|
"Production system: templates (proven prompts with variables), styles (visual direction), presets (platform rules), pipelines (multi-step workflows).",
|
|
@@ -87969,9 +87999,27 @@ ${import_picocolors8.default.dim("Run: gunni learn <topic>")}
|
|
|
87969
87999
|
`);
|
|
87970
88000
|
} else {
|
|
87971
88001
|
console.log(`
|
|
87972
|
-
${import_picocolors8.default.bold(result.title)}
|
|
88002
|
+
${import_picocolors8.default.bold(import_picocolors8.default.cyan(result.title))}
|
|
87973
88003
|
`);
|
|
87974
|
-
|
|
88004
|
+
const lines = result.content.split("\n");
|
|
88005
|
+
for (const line of lines) {
|
|
88006
|
+
if (/^[A-Z][A-Z _/()]+:/.test(line)) {
|
|
88007
|
+
const colonIdx = line.indexOf(":");
|
|
88008
|
+
console.log(`${import_picocolors8.default.bold(line.slice(0, colonIdx + 1))}${import_picocolors8.default.dim(line.slice(colonIdx + 1))}`);
|
|
88009
|
+
} else if (line.startsWith("- ")) {
|
|
88010
|
+
const dashEnd = line.indexOf(" ", 2);
|
|
88011
|
+
const toolMatch = line.match(/^- (\w+\(\)[^ ]*)(.*)/);
|
|
88012
|
+
if (toolMatch) {
|
|
88013
|
+
console.log(` ${import_picocolors8.default.green("\u2022")} ${import_picocolors8.default.cyan(toolMatch[1])}${import_picocolors8.default.dim(toolMatch[2])}`);
|
|
88014
|
+
} else {
|
|
88015
|
+
console.log(` ${import_picocolors8.default.green("\u2022")} ${line.slice(2)}`);
|
|
88016
|
+
}
|
|
88017
|
+
} else if (/^\d+\./.test(line)) {
|
|
88018
|
+
console.log(` ${import_picocolors8.default.dim(line)}`);
|
|
88019
|
+
} else {
|
|
88020
|
+
console.log(line);
|
|
88021
|
+
}
|
|
88022
|
+
}
|
|
87975
88023
|
console.log();
|
|
87976
88024
|
}
|
|
87977
88025
|
} catch (err) {
|
|
@@ -89391,7 +89439,8 @@ Examples:
|
|
|
89391
89439
|
console.log(`
|
|
89392
89440
|
${import_picocolors14.default.bold(import_picocolors14.default.cyan(category.toUpperCase()))}`);
|
|
89393
89441
|
for (const m2 of catModels) {
|
|
89394
|
-
|
|
89442
|
+
const tag = m2.isDefault ? import_picocolors14.default.green(" \u2605") : "";
|
|
89443
|
+
console.log(` ${import_picocolors14.default.bold(m2.id)}${tag} ${import_picocolors14.default.dim(m2.description)}`);
|
|
89395
89444
|
}
|
|
89396
89445
|
}
|
|
89397
89446
|
console.log();
|
|
@@ -90896,7 +90945,7 @@ async function runOnboarding() {
|
|
|
90896
90945
|
|
|
90897
90946
|
// src/index.ts
|
|
90898
90947
|
var program2 = new Command();
|
|
90899
|
-
program2.name("gunni").description("AI media toolkit \u2014 give any agent the ability to create professional media").version("0.3.
|
|
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(
|
|
90900
90949
|
"after",
|
|
90901
90950
|
`
|
|
90902
90951
|
Examples:
|
|
@@ -90906,18 +90955,18 @@ Examples:
|
|
|
90906
90955
|
$ gunni init --template brand # Start a brand project
|
|
90907
90956
|
|
|
90908
90957
|
Image (generate, edit, describe, upscale, remove-bg):
|
|
90909
|
-
$ gunni image "a coffee bag on white background" -o bag
|
|
90910
|
-
$ gunni image bag.
|
|
90911
|
-
$ gunni image bag-clean.png "place on marble counter" -o hero
|
|
90912
|
-
$ gunni image hero.
|
|
90913
|
-
$ gunni image hero-final.
|
|
90958
|
+
$ gunni image "a coffee bag on white background" -o bag
|
|
90959
|
+
$ gunni image bag.jpg --remove-bg -o bag-clean
|
|
90960
|
+
$ gunni image bag-clean.png "place on marble counter" -o hero
|
|
90961
|
+
$ gunni image hero.jpg --upscale -o hero-final
|
|
90962
|
+
$ gunni image hero-final.jpg # describe
|
|
90914
90963
|
|
|
90915
90964
|
Video & audio:
|
|
90916
|
-
$ gunni video hero.
|
|
90965
|
+
$ gunni video hero.jpg -p "slow cinematic zoom in" -o hero.mp4
|
|
90917
90966
|
$ gunni audio "Welcome to our roastery" -o intro.mp3
|
|
90918
90967
|
|
|
90919
90968
|
Explore with variants:
|
|
90920
|
-
$ gunni image "logo concepts" --variants 4 -o logo-{n}
|
|
90969
|
+
$ gunni image "logo concepts" --variants 4 -o logo-{n}
|
|
90921
90970
|
|
|
90922
90971
|
Creative expertise:
|
|
90923
90972
|
$ gunni learn exploration # How to explore creatively
|
|
@@ -90926,8 +90975,8 @@ Examples:
|
|
|
90926
90975
|
Agent workflow (structured JSON):
|
|
90927
90976
|
$ gunni --json learn overview # Load capabilities
|
|
90928
90977
|
$ gunni --json image "product photo" --variants 3 # Explore
|
|
90929
|
-
$ gunni --json image best.
|
|
90930
|
-
$ gunni --json image final.
|
|
90978
|
+
$ gunni --json image best.jpg "refine the lighting" # Iterate
|
|
90979
|
+
$ gunni --json image final.jpg --upscale # Polish
|
|
90931
90980
|
`
|
|
90932
90981
|
);
|
|
90933
90982
|
registerImageCommand(program2);
|
|
@@ -90948,7 +90997,7 @@ program2.command("models").description("List available models (alias for: gunni
|
|
|
90948
90997
|
return;
|
|
90949
90998
|
}
|
|
90950
90999
|
if (models.length === 0) {
|
|
90951
|
-
console.log(`No models found${opts.type ? ` for category "${opts.type}"` : ""}.`);
|
|
91000
|
+
console.log(import_picocolors23.default.dim(`No models found${opts.type ? ` for category "${opts.type}"` : ""}.`));
|
|
90952
91001
|
return;
|
|
90953
91002
|
}
|
|
90954
91003
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -90959,9 +91008,10 @@ program2.command("models").description("List available models (alias for: gunni
|
|
|
90959
91008
|
}
|
|
90960
91009
|
for (const [category, catModels] of grouped) {
|
|
90961
91010
|
console.log(`
|
|
90962
|
-
${category.toUpperCase()}`);
|
|
91011
|
+
${import_picocolors23.default.bold(import_picocolors23.default.cyan(category.toUpperCase()))}`);
|
|
90963
91012
|
for (const m2 of catModels) {
|
|
90964
|
-
|
|
91013
|
+
const tag = m2.isDefault ? import_picocolors23.default.green(" \u2605") : "";
|
|
91014
|
+
console.log(` ${import_picocolors23.default.bold(m2.id)}${tag} ${import_picocolors23.default.dim(m2.description)}`);
|
|
90965
91015
|
}
|
|
90966
91016
|
}
|
|
90967
91017
|
console.log();
|
|
@@ -90995,7 +91045,7 @@ program2.action(async () => {
|
|
|
90995
91045
|
{ name: "models", usage: "gunni models [--type <category>]", description: "List available models" },
|
|
90996
91046
|
{ name: "config", usage: "gunni config", description: "Manage API keys" }
|
|
90997
91047
|
];
|
|
90998
|
-
console.log(JSON.stringify({ version: "0.3.
|
|
91048
|
+
console.log(JSON.stringify({ version: "0.3.8", commands, categories, models }, null, 2));
|
|
90999
91049
|
return;
|
|
91000
91050
|
}
|
|
91001
91051
|
const configured = await hasGunniKey();
|
|
@@ -91051,10 +91101,10 @@ ${import_picocolors23.default.bold("Models:")} ${import_picocolors23.default.dim
|
|
|
91051
91101
|
}
|
|
91052
91102
|
console.log(`
|
|
91053
91103
|
${import_picocolors23.default.bold("Quick start:")}
|
|
91054
|
-
${import_picocolors23.default.dim("$")} gunni image "coffee bag product shot" -o bag
|
|
91055
|
-
${import_picocolors23.default.dim("$")} gunni image bag.
|
|
91056
|
-
${import_picocolors23.default.dim("$")} gunni image bag-clean.png "on marble counter" -o hero
|
|
91057
|
-
${import_picocolors23.default.dim("$")} gunni image hero.
|
|
91104
|
+
${import_picocolors23.default.dim("$")} gunni image "coffee bag product shot" -o bag
|
|
91105
|
+
${import_picocolors23.default.dim("$")} gunni image bag.jpg --remove-bg -o bag-clean
|
|
91106
|
+
${import_picocolors23.default.dim("$")} gunni image bag-clean.png "on marble counter" -o hero
|
|
91107
|
+
${import_picocolors23.default.dim("$")} gunni image hero.jpg --upscale -o hero-final
|
|
91058
91108
|
|
|
91059
91109
|
${import_picocolors23.default.dim("Add --json to any command for structured output.")}
|
|
91060
91110
|
${import_picocolors23.default.dim("Run gunni learn to load creative expertise.")}
|