clawbr 0.0.48 → 0.0.49
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/commands/analyze.command.js.map +1 -1
- package/dist/commands/config.command.js +0 -2
- package/dist/commands/config.command.js.map +1 -1
- package/dist/commands/generate.command.js +2 -51
- package/dist/commands/generate.command.js.map +1 -1
- package/dist/commands/models.command.js +1 -1
- package/dist/commands/models.command.js.map +1 -1
- package/dist/commands/onboard.command.js +26 -41
- package/dist/commands/onboard.command.js.map +1 -1
- package/dist/commands/tui.command.js +2 -63
- package/dist/commands/tui.command.js.map +1 -1
- package/dist/config/image-models.js +0 -44
- package/dist/config/image-models.js.map +1 -1
- package/dist/config.js +1 -8
- package/dist/config.js.map +1 -1
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/credentials.js +1 -3
- package/dist/utils/credentials.js.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/analyze.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport ora from \"ora\";\nimport { loadCredentials } from \"../utils/credentials.js\";\nimport { resolveImageToDataUri, validateImageInput } from \"../utils/image.js\";\nimport { analyzeImage } from \"../utils/vision.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface AnalyzeCommandOptions {\n image?: string;\n prompt?: string;\n json?: boolean;\n}\n\n@Command({\n name: \"analyze\",\n description: \"Analyze an image using AI vision models\",\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class AnalyzeCommand extends CommandRunner {\n async run(inputs: string[], options: AnalyzeCommandOptions): Promise<void> {\n await requireOnboarding();\n const { image, prompt, json = false } = options;\n\n // ─────────────────────────────────────────────────────────────────────\n // Validation\n // ─────────────────────────────────────────────────────────────────────\n if (!image) {\n throw new Error(\n '--image is required. Example: clawbr analyze --image \"./photo.jpg\" --prompt \"Describe this image\"'\n );\n }\n\n const validation = validateImageInput(image);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Load Credentials\n // ─────────────────────────────────────────────────────────────────────\n const credentials = loadCredentials();\n\n if (!credentials) {\n throw new Error(\"Credentials not found. Run 'clawbr onboard' first to set up your account.\");\n }\n\n const { aiProvider, apiKeys } = credentials;\n const apiKey = apiKeys[aiProvider as keyof typeof apiKeys];\n\n if (!apiKey) {\n throw new Error(\n `No API key found for provider '${aiProvider}'. Run 'clawbr onboard' to configure.`\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Prepare Image\n // ─────────────────────────────────────────────────────────────────────\n const imageData = await resolveImageToDataUri(image);\n\n // ─────────────────────────────────────────────────────────────────────\n // Analyze Image\n // ─────────────────────────────────────────────────────────────────────\n const spinner = json ? null : ora(\"Analyzing image...\").start();\n\n try {\n const analysis = await analyzeImage(\n {\n provider: aiProvider as \"openrouter\"
|
|
1
|
+
{"version":3,"sources":["../../src/commands/analyze.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport ora from \"ora\";\nimport { loadCredentials } from \"../utils/credentials.js\";\nimport { resolveImageToDataUri, validateImageInput } from \"../utils/image.js\";\nimport { analyzeImage } from \"../utils/vision.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface AnalyzeCommandOptions {\n image?: string;\n prompt?: string;\n json?: boolean;\n}\n\n@Command({\n name: \"analyze\",\n description: \"Analyze an image using AI vision models\",\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class AnalyzeCommand extends CommandRunner {\n async run(inputs: string[], options: AnalyzeCommandOptions): Promise<void> {\n await requireOnboarding();\n const { image, prompt, json = false } = options;\n\n // ─────────────────────────────────────────────────────────────────────\n // Validation\n // ─────────────────────────────────────────────────────────────────────\n if (!image) {\n throw new Error(\n '--image is required. Example: clawbr analyze --image \"./photo.jpg\" --prompt \"Describe this image\"'\n );\n }\n\n const validation = validateImageInput(image);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Load Credentials\n // ─────────────────────────────────────────────────────────────────────\n const credentials = loadCredentials();\n\n if (!credentials) {\n throw new Error(\"Credentials not found. Run 'clawbr onboard' first to set up your account.\");\n }\n\n const { aiProvider, apiKeys } = credentials;\n const apiKey = apiKeys[aiProvider as keyof typeof apiKeys];\n\n if (!apiKey) {\n throw new Error(\n `No API key found for provider '${aiProvider}'. Run 'clawbr onboard' to configure.`\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Prepare Image\n // ─────────────────────────────────────────────────────────────────────\n const imageData = await resolveImageToDataUri(image);\n\n // ─────────────────────────────────────────────────────────────────────\n // Analyze Image\n // ─────────────────────────────────────────────────────────────────────\n const spinner = json ? null : ora(\"Analyzing image...\").start();\n\n try {\n const analysis = await analyzeImage(\n {\n provider: aiProvider as \"openrouter\",\n apiKey,\n },\n imageData,\n prompt || \"Describe this image in detail.\"\n );\n\n if (spinner) {\n spinner.succeed(\"Image analyzed successfully!\");\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Output\n // ─────────────────────────────────────────────────────────────────────\n if (json) {\n console.log(\n JSON.stringify(\n {\n success: true,\n analysis,\n provider: aiProvider,\n },\n null,\n 2\n )\n );\n } else {\n console.log(\"\\n🔍 Image Analysis:\");\n console.log(\"═════════════════════════════════════\");\n console.log(analysis);\n console.log(\"─────────────────────────────────────\");\n console.log(`Provider: ${aiProvider}`);\n console.log(\"─────────────────────────────────────\\n\");\n }\n process.exit(0);\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Image analysis failed\");\n }\n throw error;\n }\n }\n\n @Option({\n flags: \"-i, --image <path>\",\n description: \"Path to the image file or URL\",\n })\n parseImage(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-p, --prompt <text>\",\n description: 'Custom prompt for analysis (default: \"Describe this image in detail.\")',\n })\n parsePrompt(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--json\",\n description: \"Output in JSON format\",\n })\n parseJson(): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","ora","loadCredentials","resolveImageToDataUri","validateImageInput","analyzeImage","requireOnboarding","AnalyzeCommand","run","inputs","options","image","prompt","json","Error","validation","valid","error","credentials","aiProvider","apiKeys","apiKey","imageData","spinner","start","analysis","provider","succeed","console","log","JSON","stringify","success","process","exit","isSpinning","fail","parseImage","val","parsePrompt","parseJson","flags","description","name","arguments","isDefault"],"mappings":";;;;;;;;;AAAA,SAASA,OAAO,EAAEC,aAAa,EAAEC,MAAM,QAAQ,iBAAiB;AAChE,OAAOC,SAAS,MAAM;AACtB,SAASC,eAAe,QAAQ,0BAA0B;AAC1D,SAASC,qBAAqB,EAAEC,kBAAkB,QAAQ,oBAAoB;AAC9E,SAASC,YAAY,QAAQ,qBAAqB;AAClD,SAASC,iBAAiB,QAAQ,qBAAqB;AAcvD,OAAO,MAAMC,uBAAuBR;IAClC,MAAMS,IAAIC,MAAgB,EAAEC,OAA8B,EAAiB;QACzE,MAAMJ;QACN,MAAM,EAAEK,KAAK,EAAEC,MAAM,EAAEC,OAAO,KAAK,EAAE,GAAGH;QAExC,wEAAwE;QACxE,aAAa;QACb,wEAAwE;QACxE,IAAI,CAACC,OAAO;YACV,MAAM,IAAIG,MACR;QAEJ;QAEA,MAAMC,aAAaX,mBAAmBO;QACtC,IAAI,CAACI,WAAWC,KAAK,EAAE;YACrB,MAAM,IAAIF,MAAMC,WAAWE,KAAK;QAClC;QAEA,wEAAwE;QACxE,mBAAmB;QACnB,wEAAwE;QACxE,MAAMC,cAAchB;QAEpB,IAAI,CAACgB,aAAa;YAChB,MAAM,IAAIJ,MAAM;QAClB;QAEA,MAAM,EAAEK,UAAU,EAAEC,OAAO,EAAE,GAAGF;QAChC,MAAMG,SAASD,OAAO,CAACD,WAAmC;QAE1D,IAAI,CAACE,QAAQ;YACX,MAAM,IAAIP,MACR,CAAC,+BAA+B,EAAEK,WAAW,qCAAqC,CAAC;QAEvF;QAEA,wEAAwE;QACxE,gBAAgB;QAChB,wEAAwE;QACxE,MAAMG,YAAY,MAAMnB,sBAAsBQ;QAE9C,wEAAwE;QACxE,gBAAgB;QAChB,wEAAwE;QACxE,MAAMY,UAAUV,OAAO,OAAOZ,IAAI,sBAAsBuB,KAAK;QAE7D,IAAI;YACF,MAAMC,WAAW,MAAMpB,aACrB;gBACEqB,UAAUP;gBACVE;YACF,GACAC,WACAV,UAAU;YAGZ,IAAIW,SAAS;gBACXA,QAAQI,OAAO,CAAC;YAClB;YAEA,wEAAwE;YACxE,SAAS;YACT,wEAAwE;YACxE,IAAId,MAAM;gBACRe,QAAQC,GAAG,CACTC,KAAKC,SAAS,CACZ;oBACEC,SAAS;oBACTP;oBACAC,UAAUP;gBACZ,GACA,MACA;YAGN,OAAO;gBACLS,QAAQC,GAAG,CAAC;gBACZD,QAAQC,GAAG,CAAC;gBACZD,QAAQC,GAAG,CAACJ;gBACZG,QAAQC,GAAG,CAAC;gBACZD,QAAQC,GAAG,CAAC,CAAC,UAAU,EAAEV,YAAY;gBACrCS,QAAQC,GAAG,CAAC;YACd;YACAI,QAAQC,IAAI,CAAC;QACf,EAAE,OAAOjB,OAAO;YACd,IAAIM,WAAWA,QAAQY,UAAU,EAAE;gBACjCZ,QAAQa,IAAI,CAAC;YACf;YACA,MAAMnB;QACR;IACF;IAMAoB,WAAWC,GAAW,EAAU;QAC9B,OAAOA;IACT;IAMAC,YAAYD,GAAW,EAAU;QAC/B,OAAOA;IACT;IAMAE,YAAqB;QACnB,OAAO;IACT;AACF;;;QAtBIC,OAAO;QACPC,aAAa;;;;;;;;;;QAObD,OAAO;QACPC,aAAa;;;;;;;;;;QAObD,OAAO;QACPC,aAAa;;;;;;;;QApHfC,MAAM;QACND,aAAa;QACbE,WAAW;QACXlC,SAAS;YAAEmC,WAAW;QAAM"}
|
|
@@ -50,8 +50,6 @@ export class ConfigCommand extends CommandRunner {
|
|
|
50
50
|
console.log(` API Key: ${chalk.green("✓ configured")}`);
|
|
51
51
|
} else {
|
|
52
52
|
console.log(` OpenRouter: ${parsedConfig.providers.openrouter ? chalk.green("✓ configured (env)") : chalk.gray("not set (env)")}`);
|
|
53
|
-
console.log(` Gemini: ${parsedConfig.providers.gemini ? chalk.green("✓ configured (env)") : chalk.gray("not set (env)")}`);
|
|
54
|
-
console.log(` OpenAI: ${parsedConfig.providers.openai ? chalk.green("✓ configured (env)") : chalk.gray("not set (env)")}`);
|
|
55
53
|
}
|
|
56
54
|
if (effectiveConfig) {
|
|
57
55
|
console.log(chalk.gray(` (Additional keys may be stored in credentials.json)`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/config.command.ts"],"sourcesContent":["import { Command, CommandRunner } from \"nest-commander\";\nimport { parsedConfig } from \"../config.js\";\nimport { getClawbrConfig } from \"../utils/config.js\";\nimport chalk from \"chalk\";\nimport { existsSync } from \"fs\";\n\n@Command({\n name: \"config\",\n description: \"Show configuration paths and settings\",\n})\nexport class ConfigCommand extends CommandRunner {\n async run(): Promise<void> {\n console.log(chalk.bold.cyan(\"\\n📁 Clawbr CLI Configuration\\n\"));\n\n // Config directory\n const configDirExists = existsSync(parsedConfig.paths.configDir);\n console.log(chalk.bold(\"Config Directory:\"));\n console.log(\n ` ${parsedConfig.paths.configDir} ${\n configDirExists ? chalk.green(\"✓\") : chalk.red(\"✗ (not found)\")\n }`\n );\n\n // Credentials file\n const credentialsPath = parsedConfig.paths.credentialsPath;\n const credentialsExists = existsSync(credentialsPath);\n console.log(chalk.bold(\"\\nCredentials File:\"));\n console.log(\n ` ${credentialsPath} ${credentialsExists ? chalk.green(\"✓\") : chalk.red(\"✗ (not found)\")}`\n );\n\n // Skills directory\n const skillsDirExists = existsSync(parsedConfig.paths.skillsDir);\n console.log(chalk.bold(\"\\nSkills Directory:\"));\n console.log(\n ` ${parsedConfig.paths.skillsDir} ${\n skillsDirExists ? chalk.green(\"✓\") : chalk.red(\"✗ (not found)\")\n }`\n );\n\n // Load effective configuration\n const effectiveConfig = await getClawbrConfig();\n const source = effectiveConfig ? \"credentials.json\" : \"none\";\n\n console.log(chalk.bold(\"\\nConfiguration Source:\"));\n if (!effectiveConfig) {\n console.log(chalk.red(\" No active configuration found\"));\n } else {\n console.log(chalk.green(` Active: ${source}`));\n }\n\n // API settings\n console.log(chalk.bold(\"\\nAPI Settings:\"));\n console.log(` Base URL: ${effectiveConfig?.url || parsedConfig.api.baseUrl}`);\n\n const hasToken = !!effectiveConfig?.apiKey || !!parsedConfig.api.token;\n console.log(` Token: ${hasToken ? chalk.green(\"✓ configured\") : chalk.yellow(\"⚠ not set\")}`);\n console.log(` Timeout: ${parsedConfig.api.timeout}ms`);\n\n // Environment (Internal)\n console.log(chalk.bold(\"\\nEnvironment:\"));\n console.log(\n ` Mode: ${\n parsedConfig.isDevelopment ? chalk.yellow(\"development\") : chalk.green(\"production\")\n }`\n );\n\n // AI Providers\n console.log(chalk.bold(\"\\nAI Providers:\"));\n\n if (effectiveConfig && effectiveConfig.generation) {\n console.log(` Active Provider: ${chalk.green(effectiveConfig.generation.provider)}`);\n console.log(` API Key: ${chalk.green(\"✓ configured\")}`);\n } else {\n console.log(\n ` OpenRouter: ${\n parsedConfig.providers.openrouter\n ? chalk.green(\"✓ configured (env)\")\n : chalk.gray(\"not set (env)\")\n }`\n );\n
|
|
1
|
+
{"version":3,"sources":["../../src/commands/config.command.ts"],"sourcesContent":["import { Command, CommandRunner } from \"nest-commander\";\nimport { parsedConfig } from \"../config.js\";\nimport { getClawbrConfig } from \"../utils/config.js\";\nimport chalk from \"chalk\";\nimport { existsSync } from \"fs\";\n\n@Command({\n name: \"config\",\n description: \"Show configuration paths and settings\",\n})\nexport class ConfigCommand extends CommandRunner {\n async run(): Promise<void> {\n console.log(chalk.bold.cyan(\"\\n📁 Clawbr CLI Configuration\\n\"));\n\n // Config directory\n const configDirExists = existsSync(parsedConfig.paths.configDir);\n console.log(chalk.bold(\"Config Directory:\"));\n console.log(\n ` ${parsedConfig.paths.configDir} ${\n configDirExists ? chalk.green(\"✓\") : chalk.red(\"✗ (not found)\")\n }`\n );\n\n // Credentials file\n const credentialsPath = parsedConfig.paths.credentialsPath;\n const credentialsExists = existsSync(credentialsPath);\n console.log(chalk.bold(\"\\nCredentials File:\"));\n console.log(\n ` ${credentialsPath} ${credentialsExists ? chalk.green(\"✓\") : chalk.red(\"✗ (not found)\")}`\n );\n\n // Skills directory\n const skillsDirExists = existsSync(parsedConfig.paths.skillsDir);\n console.log(chalk.bold(\"\\nSkills Directory:\"));\n console.log(\n ` ${parsedConfig.paths.skillsDir} ${\n skillsDirExists ? chalk.green(\"✓\") : chalk.red(\"✗ (not found)\")\n }`\n );\n\n // Load effective configuration\n const effectiveConfig = await getClawbrConfig();\n const source = effectiveConfig ? \"credentials.json\" : \"none\";\n\n console.log(chalk.bold(\"\\nConfiguration Source:\"));\n if (!effectiveConfig) {\n console.log(chalk.red(\" No active configuration found\"));\n } else {\n console.log(chalk.green(` Active: ${source}`));\n }\n\n // API settings\n console.log(chalk.bold(\"\\nAPI Settings:\"));\n console.log(` Base URL: ${effectiveConfig?.url || parsedConfig.api.baseUrl}`);\n\n const hasToken = !!effectiveConfig?.apiKey || !!parsedConfig.api.token;\n console.log(` Token: ${hasToken ? chalk.green(\"✓ configured\") : chalk.yellow(\"⚠ not set\")}`);\n console.log(` Timeout: ${parsedConfig.api.timeout}ms`);\n\n // Environment (Internal)\n console.log(chalk.bold(\"\\nEnvironment:\"));\n console.log(\n ` Mode: ${\n parsedConfig.isDevelopment ? chalk.yellow(\"development\") : chalk.green(\"production\")\n }`\n );\n\n // AI Providers\n console.log(chalk.bold(\"\\nAI Providers:\"));\n\n if (effectiveConfig && effectiveConfig.generation) {\n console.log(` Active Provider: ${chalk.green(effectiveConfig.generation.provider)}`);\n console.log(` API Key: ${chalk.green(\"✓ configured\")}`);\n } else {\n console.log(\n ` OpenRouter: ${\n parsedConfig.providers.openrouter\n ? chalk.green(\"✓ configured (env)\")\n : chalk.gray(\"not set (env)\")\n }`\n );\n }\n\n if (effectiveConfig) {\n console.log(chalk.gray(` (Additional keys may be stored in credentials.json)`));\n }\n\n console.log(); // Empty line at the end\n\n process.exit(0);\n }\n}\n"],"names":["Command","CommandRunner","parsedConfig","getClawbrConfig","chalk","existsSync","ConfigCommand","run","console","log","bold","cyan","configDirExists","paths","configDir","green","red","credentialsPath","credentialsExists","skillsDirExists","skillsDir","effectiveConfig","source","url","api","baseUrl","hasToken","apiKey","token","yellow","timeout","isDevelopment","generation","provider","providers","openrouter","gray","process","exit","name","description"],"mappings":";;;;;;AAAA,SAASA,OAAO,EAAEC,aAAa,QAAQ,iBAAiB;AACxD,SAASC,YAAY,QAAQ,eAAe;AAC5C,SAASC,eAAe,QAAQ,qBAAqB;AACrD,OAAOC,WAAW,QAAQ;AAC1B,SAASC,UAAU,QAAQ,KAAK;AAMhC,OAAO,MAAMC,sBAAsBL;IACjC,MAAMM,MAAqB;QACzBC,QAAQC,GAAG,CAACL,MAAMM,IAAI,CAACC,IAAI,CAAC;QAE5B,mBAAmB;QACnB,MAAMC,kBAAkBP,WAAWH,aAAaW,KAAK,CAACC,SAAS;QAC/DN,QAAQC,GAAG,CAACL,MAAMM,IAAI,CAAC;QACvBF,QAAQC,GAAG,CACT,CAAC,EAAE,EAAEP,aAAaW,KAAK,CAACC,SAAS,CAAC,CAAC,EACjCF,kBAAkBR,MAAMW,KAAK,CAAC,OAAOX,MAAMY,GAAG,CAAC,kBAC/C;QAGJ,mBAAmB;QACnB,MAAMC,kBAAkBf,aAAaW,KAAK,CAACI,eAAe;QAC1D,MAAMC,oBAAoBb,WAAWY;QACrCT,QAAQC,GAAG,CAACL,MAAMM,IAAI,CAAC;QACvBF,QAAQC,GAAG,CACT,CAAC,EAAE,EAAEQ,gBAAgB,CAAC,EAAEC,oBAAoBd,MAAMW,KAAK,CAAC,OAAOX,MAAMY,GAAG,CAAC,kBAAkB;QAG7F,mBAAmB;QACnB,MAAMG,kBAAkBd,WAAWH,aAAaW,KAAK,CAACO,SAAS;QAC/DZ,QAAQC,GAAG,CAACL,MAAMM,IAAI,CAAC;QACvBF,QAAQC,GAAG,CACT,CAAC,EAAE,EAAEP,aAAaW,KAAK,CAACO,SAAS,CAAC,CAAC,EACjCD,kBAAkBf,MAAMW,KAAK,CAAC,OAAOX,MAAMY,GAAG,CAAC,kBAC/C;QAGJ,+BAA+B;QAC/B,MAAMK,kBAAkB,MAAMlB;QAC9B,MAAMmB,SAASD,kBAAkB,qBAAqB;QAEtDb,QAAQC,GAAG,CAACL,MAAMM,IAAI,CAAC;QACvB,IAAI,CAACW,iBAAiB;YACpBb,QAAQC,GAAG,CAACL,MAAMY,GAAG,CAAC;QACxB,OAAO;YACLR,QAAQC,GAAG,CAACL,MAAMW,KAAK,CAAC,CAAC,UAAU,EAAEO,QAAQ;QAC/C;QAEA,eAAe;QACfd,QAAQC,GAAG,CAACL,MAAMM,IAAI,CAAC;QACvBF,QAAQC,GAAG,CAAC,CAAC,YAAY,EAAEY,iBAAiBE,OAAOrB,aAAasB,GAAG,CAACC,OAAO,EAAE;QAE7E,MAAMC,WAAW,CAAC,CAACL,iBAAiBM,UAAU,CAAC,CAACzB,aAAasB,GAAG,CAACI,KAAK;QACtEpB,QAAQC,GAAG,CAAC,CAAC,SAAS,EAAEiB,WAAWtB,MAAMW,KAAK,CAAC,kBAAkBX,MAAMyB,MAAM,CAAC,cAAc;QAC5FrB,QAAQC,GAAG,CAAC,CAAC,WAAW,EAAEP,aAAasB,GAAG,CAACM,OAAO,CAAC,EAAE,CAAC;QAEtD,yBAAyB;QACzBtB,QAAQC,GAAG,CAACL,MAAMM,IAAI,CAAC;QACvBF,QAAQC,GAAG,CACT,CAAC,QAAQ,EACPP,aAAa6B,aAAa,GAAG3B,MAAMyB,MAAM,CAAC,iBAAiBzB,MAAMW,KAAK,CAAC,eACvE;QAGJ,eAAe;QACfP,QAAQC,GAAG,CAACL,MAAMM,IAAI,CAAC;QAEvB,IAAIW,mBAAmBA,gBAAgBW,UAAU,EAAE;YACjDxB,QAAQC,GAAG,CAAC,CAAC,mBAAmB,EAAEL,MAAMW,KAAK,CAACM,gBAAgBW,UAAU,CAACC,QAAQ,GAAG;YACpFzB,QAAQC,GAAG,CAAC,CAAC,WAAW,EAAEL,MAAMW,KAAK,CAAC,iBAAiB;QACzD,OAAO;YACLP,QAAQC,GAAG,CACT,CAAC,cAAc,EACbP,aAAagC,SAAS,CAACC,UAAU,GAC7B/B,MAAMW,KAAK,CAAC,wBACZX,MAAMgC,IAAI,CAAC,kBACf;QAEN;QAEA,IAAIf,iBAAiB;YACnBb,QAAQC,GAAG,CAACL,MAAMgC,IAAI,CAAC,CAAC,qDAAqD,CAAC;QAChF;QAEA5B,QAAQC,GAAG,IAAI,wBAAwB;QAEvC4B,QAAQC,IAAI,CAAC;IACf;AACF;;;QApFEC,MAAM;QACNC,aAAa"}
|
|
@@ -12,9 +12,6 @@ import { writeFileSync } from "fs";
|
|
|
12
12
|
import ora from "ora";
|
|
13
13
|
import fetch from "node-fetch";
|
|
14
14
|
import { resolve } from "path";
|
|
15
|
-
import { generateImage } from "ai";
|
|
16
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
17
|
-
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
18
15
|
import { loadCredentials } from "../utils/credentials.js";
|
|
19
16
|
import { resolveImageToDataUri, validateImageInput } from "../utils/image.js";
|
|
20
17
|
import { requireOnboarding } from "../utils/config.js";
|
|
@@ -101,25 +98,9 @@ export class GenerateCommand extends CommandRunner {
|
|
|
101
98
|
primary: primaryModel,
|
|
102
99
|
fallbacks: fallbackModels
|
|
103
100
|
}, spinner, sourceImageData, imageConfig));
|
|
104
|
-
} else if (aiProvider === "openai") {
|
|
105
|
-
if (sourceImageData) {
|
|
106
|
-
throw new Error("OpenAI does not support image-to-image generation. Use OpenRouter with a model that supports reference images.");
|
|
107
|
-
}
|
|
108
|
-
({ buffer: imageBuffer, modelUsed } = await this.generateWithFallback(prompt, size, apiKey, "openai", {
|
|
109
|
-
primary: primaryModel,
|
|
110
|
-
fallbacks: fallbackModels
|
|
111
|
-
}, spinner));
|
|
112
|
-
} else if (aiProvider === "google") {
|
|
113
|
-
if (sourceImageData) {
|
|
114
|
-
throw new Error("Google Imagen does not support image-to-image generation. Use OpenRouter with a model that supports reference images.");
|
|
115
|
-
}
|
|
116
|
-
({ buffer: imageBuffer, modelUsed } = await this.generateWithFallback(prompt, size, apiKey, "google", {
|
|
117
|
-
primary: primaryModel,
|
|
118
|
-
fallbacks: fallbackModels
|
|
119
|
-
}, spinner));
|
|
120
101
|
} else {
|
|
121
102
|
if (spinner) spinner.fail();
|
|
122
|
-
throw new Error(`Unsupported AI provider: ${aiProvider}
|
|
103
|
+
throw new Error(`Unsupported AI provider: ${aiProvider}. Only 'openrouter' is supported.`);
|
|
123
104
|
}
|
|
124
105
|
// ─────────────────────────────────────────────────────────────────────
|
|
125
106
|
// Save Image
|
|
@@ -206,22 +187,6 @@ export class GenerateCommand extends CommandRunner {
|
|
|
206
187
|
throw new Error(`All models failed to generate image. Last error: ${lastError?.message || "Unknown error"}`);
|
|
207
188
|
}
|
|
208
189
|
/**
|
|
209
|
-
* get the model configuration for the AI SDK
|
|
210
|
-
*/ getImageModel(provider, apiKey, model) {
|
|
211
|
-
if (provider === "openai") {
|
|
212
|
-
const openai = createOpenAI({
|
|
213
|
-
apiKey
|
|
214
|
-
});
|
|
215
|
-
return openai.image(model);
|
|
216
|
-
} else if (provider === "google") {
|
|
217
|
-
const google = createGoogleGenerativeAI({
|
|
218
|
-
apiKey
|
|
219
|
-
});
|
|
220
|
-
return google.image(model);
|
|
221
|
-
}
|
|
222
|
-
throw new Error(`Provider ${provider} not supported via AI SDK`);
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
190
|
* Generate image using a specific model
|
|
226
191
|
*/ async generateWithModel(prompt, size, apiKey, provider, model, sourceImageData, imageConfig) {
|
|
227
192
|
// ─────────────────────────────────────────────────────────────────────
|
|
@@ -335,21 +300,7 @@ export class GenerateCommand extends CommandRunner {
|
|
|
335
300
|
}
|
|
336
301
|
throw new Error("No image generated from OpenRouter response");
|
|
337
302
|
}
|
|
338
|
-
|
|
339
|
-
// OPENAI / GOOGLE (Via AI SDK)
|
|
340
|
-
// ─────────────────────────────────────────────────────────────────────
|
|
341
|
-
const imageModel = this.getImageModel(provider, apiKey, model);
|
|
342
|
-
// Pass size as string directly as per SDK requirements.
|
|
343
|
-
// We cast to 'any' to avoid strict template literal validation errors
|
|
344
|
-
// since we know validSizes allows specifically "1024x1024" etc.
|
|
345
|
-
const { image } = await generateImage({
|
|
346
|
-
model: imageModel,
|
|
347
|
-
prompt,
|
|
348
|
-
n: 1,
|
|
349
|
-
size: size
|
|
350
|
-
});
|
|
351
|
-
// The image object from 'ai' SDK contains the base64 string
|
|
352
|
-
return Buffer.from(image.base64, "base64");
|
|
303
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
353
304
|
}
|
|
354
305
|
parsePrompt(val) {
|
|
355
306
|
return val;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/generate.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport { writeFileSync } from \"fs\";\nimport ora from \"ora\";\nimport fetch from \"node-fetch\";\nimport { resolve } from \"path\";\nimport { generateImage } from \"ai\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\nimport { loadCredentials } from \"../utils/credentials.js\";\nimport { resolveImageToDataUri, validateImageInput } from \"../utils/image.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\nimport {\n getProviderModels,\n getModelById,\n isValidModel,\n getPrimaryModel,\n getFallbackModels,\n supportsReferenceImage,\n formatModelList,\n} from \"../config/image-models.js\";\n\ninterface GenerateCommandOptions {\n prompt?: string;\n output?: string;\n size?: string;\n sourceImage?: string;\n model?: string;\n aspectRatio?: string;\n imageSize?: string;\n json?: boolean;\n}\n\n@Command({\n name: \"generate\",\n description: \"Generate an image using AI with smart model fallback\",\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class GenerateCommand extends CommandRunner {\n async run(inputs: string[], options: GenerateCommandOptions): Promise<void> {\n await requireOnboarding();\n const {\n prompt,\n output,\n size = \"1024x1024\",\n sourceImage,\n model,\n aspectRatio,\n imageSize,\n json = false,\n } = options;\n\n // ─────────────────────────────────────────────────────────────────────\n // Validation\n // ─────────────────────────────────────────────────────────────────────\n if (!prompt) {\n throw new Error(\n '--prompt is required. Example: clawbr generate --prompt \"a robot building software\" --output \"./robot.png\"'\n );\n }\n\n if (!output) {\n throw new Error(\n '--output is required. Example: clawbr generate --prompt \"...\" --output \"./image.png\"'\n );\n }\n\n // Validate source image if provided\n if (sourceImage) {\n const validation = validateImageInput(sourceImage);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n }\n\n // Validate size\n const validSizes = [\"256x256\", \"512x512\", \"1024x1024\", \"1792x1024\", \"1024x1792\"];\n if (!validSizes.includes(size)) {\n throw new Error(`Invalid size. Must be one of: ${validSizes.join(\", \")}`);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Load Credentials\n // ─────────────────────────────────────────────────────────────────────\n const credentials = loadCredentials();\n\n if (!credentials) {\n throw new Error(\"Credentials not found. Run 'clawbr onboard' first to set up your account.\");\n }\n\n const { aiProvider, apiKeys } = credentials;\n const apiKey = apiKeys[aiProvider as keyof typeof apiKeys];\n\n if (!apiKey) {\n throw new Error(\n `No API key found for provider '${aiProvider}'. Run 'clawbr onboard' to configure.`\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Validate model if provided\n // ─────────────────────────────────────────────────────────────────────\n if (model && !isValidModel(aiProvider, model)) {\n const availableModels = formatModelList(aiProvider);\n throw new Error(\n `Invalid model '${model}' for provider '${aiProvider}'.\\n\\nAvailable models:\\n${availableModels}`\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Check reference image support\n // ─────────────────────────────────────────────────────────────────────\n if (sourceImage && model && !supportsReferenceImage(aiProvider, model)) {\n const modelInfo = getModelById(aiProvider, model);\n throw new Error(\n `Model '${modelInfo?.name || model}' does not support reference images.\\n\\n` +\n `For reference image support with ${aiProvider}, use one of:\\n` +\n getProviderModels(aiProvider)\n .filter((m) => m.supportsReferenceImage)\n .map((m) => ` • ${m.id}`)\n .join(\"\\n\")\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Prepare source image if provided\n // ─────────────────────────────────────────────────────────────────────\n const sourceImageData = sourceImage ? await resolveImageToDataUri(sourceImage) : undefined;\n\n // ─────────────────────────────────────────────────────────────────────\n // Generate Image with Smart Fallback\n // ─────────────────────────────────────────────────────────────────────\n const spinner = json\n ? null\n : ora(sourceImageData ? \"Generating image from source...\" : \"Generating image...\").start();\n\n try {\n let imageBuffer: Buffer;\n let modelUsed: string;\n\n // Determine models to try\n const primaryModel = model || getPrimaryModel(aiProvider);\n // If the user explicitly specified a model, disable fallbacks so we\n // honour their choice strictly and fail fast if it doesn't work.\n const fallbackModels = model ? [] : getFallbackModels(aiProvider);\n\n // Pass aspect ratio and image size to generation\n const imageConfig: { aspectRatio?: string; imageSize?: string } = {};\n if (aspectRatio) imageConfig.aspectRatio = aspectRatio;\n if (imageSize) imageConfig.imageSize = imageSize;\n\n if (aiProvider === \"openrouter\") {\n ({ buffer: imageBuffer, modelUsed } = await this.generateWithFallback(\n prompt,\n size,\n apiKey,\n \"openrouter\",\n { primary: primaryModel, fallbacks: fallbackModels },\n spinner,\n sourceImageData,\n imageConfig\n ));\n } else if (aiProvider === \"openai\") {\n if (sourceImageData) {\n throw new Error(\n \"OpenAI does not support image-to-image generation. Use OpenRouter with a model that supports reference images.\"\n );\n }\n ({ buffer: imageBuffer, modelUsed } = await this.generateWithFallback(\n prompt,\n size,\n apiKey,\n \"openai\",\n { primary: primaryModel, fallbacks: fallbackModels },\n spinner\n ));\n } else if (aiProvider === \"google\") {\n if (sourceImageData) {\n throw new Error(\n \"Google Imagen does not support image-to-image generation. Use OpenRouter with a model that supports reference images.\"\n );\n }\n ({ buffer: imageBuffer, modelUsed } = await this.generateWithFallback(\n prompt,\n size,\n apiKey,\n \"google\",\n { primary: primaryModel, fallbacks: fallbackModels },\n spinner\n ));\n } else {\n if (spinner) spinner.fail();\n throw new Error(`Unsupported AI provider: ${aiProvider}`);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Save Image\n // ─────────────────────────────────────────────────────────────────────\n const outputPath = resolve(output);\n writeFileSync(outputPath, imageBuffer);\n\n if (spinner) {\n spinner.succeed(`Image generated and saved to: ${outputPath}`);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Output\n // ─────────────────────────────────────────────────────────────────────\n if (json) {\n console.log(\n JSON.stringify(\n {\n success: true,\n prompt,\n output: outputPath,\n size,\n provider: aiProvider,\n modelUsed,\n },\n null,\n 2\n )\n );\n } else {\n console.log(\"\\n🎨 Image Generation Complete!\");\n console.log(\"─────────────────────────────────────\");\n console.log(`Prompt: ${prompt}`);\n console.log(`Size: ${size}`);\n if (sourceImageData) {\n console.log(`Source Image: ${sourceImage}`);\n }\n console.log(`Output: ${outputPath}`);\n console.log(`Provider: ${aiProvider}`);\n if (model) {\n console.log(`Model: ${model}`);\n }\n console.log(\"─────────────────────────────────────\\n\");\n }\n process.exit(0);\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Image generation failed\");\n }\n throw error;\n }\n }\n\n /**\n * Generate image with smart fallback chain\n * Tries primary model first, then falls back to alternatives if it fails\n */\n private async generateWithFallback(\n prompt: string,\n size: string,\n apiKey: string,\n provider: \"openrouter\" | \"openai\" | \"google\",\n config: { primary: string | null; fallbacks: string[] },\n spinner: {\n text: string;\n info: (msg: string) => void;\n warn: (msg: string) => void;\n isSpinning?: boolean;\n } | null,\n sourceImageData?: string,\n imageConfig?: { aspectRatio?: string; imageSize?: string }\n ): Promise<{ buffer: Buffer; modelUsed: string }> {\n const modelsToTry = [config.primary, ...config.fallbacks].filter(\n (model): model is string => model !== null\n );\n\n let lastError: Error | null = null;\n\n for (let i = 0; i < modelsToTry.length; i++) {\n const model = modelsToTry[i];\n\n try {\n if (spinner) {\n const modelName = model.split(\"/\").pop() || model;\n spinner.text = `Generating image with ${modelName}... (attempt ${i + 1}/${modelsToTry.length})`;\n }\n\n const imageBuffer = await this.generateWithModel(\n prompt,\n size,\n apiKey,\n provider,\n model,\n sourceImageData,\n imageConfig\n );\n\n if (spinner && i > 0) {\n // Only show fallback message if we had to fall back\n spinner.info(`Successfully generated with fallback model: ${model}`);\n }\n\n return { buffer: imageBuffer, modelUsed: model };\n } catch (error) {\n lastError = error as Error;\n\n // If this wasn't the last model, log the failure and try the next one\n if (i < modelsToTry.length - 1) {\n if (spinner) {\n spinner.warn(`Model ${model} failed, trying fallback...`);\n } else {\n console.warn(`Model ${model} failed: ${lastError.message}`);\n }\n continue;\n }\n }\n }\n\n // If we get here, all models failed\n throw new Error(\n `All models failed to generate image. Last error: ${lastError?.message || \"Unknown error\"}`\n );\n }\n\n /**\n * get the model configuration for the AI SDK\n */\n private getImageModel(provider: string, apiKey: string, model: string) {\n if (provider === \"openai\") {\n const openai = createOpenAI({ apiKey });\n return openai.image(model);\n } else if (provider === \"google\") {\n const google = createGoogleGenerativeAI({ apiKey });\n return google.image(model);\n }\n throw new Error(`Provider ${provider} not supported via AI SDK`);\n }\n\n /**\n * Generate image using a specific model\n */\n private async generateWithModel(\n prompt: string,\n size: string,\n apiKey: string,\n provider: \"openrouter\" | \"openai\" | \"google\",\n model: string,\n sourceImageData?: string,\n imageConfig?: { aspectRatio?: string; imageSize?: string }\n ): Promise<Buffer> {\n // ─────────────────────────────────────────────────────────────────────\n // OPENROUTER (Via Fetch / Chat Completions)\n // ─────────────────────────────────────────────────────────────────────\n if (provider === \"openrouter\") {\n // Calculate aspect ratio from size if not provided\n let aspectRatio = imageConfig?.aspectRatio || \"1:1\";\n if (!imageConfig?.aspectRatio) {\n const [width, height] = size.split(\"x\").map(Number);\n if (width && height) {\n const gcd = (a: number, b: number): number => (b === 0 ? a : gcd(b, a % b));\n const divisor = gcd(width, height);\n const calculated = `${width / divisor}:${height / divisor}`;\n\n // Map calculated ratio to supported OpenRouter ratios\n const supportedRatios: Record<string, string> = {\n \"1:1\": \"1:1\",\n \"2:3\": \"2:3\",\n \"3:2\": \"3:2\",\n \"3:4\": \"3:4\",\n \"4:3\": \"4:3\",\n \"4:5\": \"4:5\",\n \"5:4\": \"5:4\",\n \"9:16\": \"9:16\",\n \"16:9\": \"16:9\",\n \"21:9\": \"21:9\",\n // Common unsupported ratios mapped to closest supported\n \"7:4\": \"16:9\", // 1792x1024\n \"4:7\": \"9:16\", // 1024x1792\n \"64:27\": \"21:9\", // ultrawide variants\n };\n\n aspectRatio = supportedRatios[calculated] || \"1:1\";\n }\n }\n\n // Build messages array\n let content: Array<{ type: string; text?: string; image_url?: { url: string } }> | string;\n if (sourceImageData) {\n // Image-to-image generation: include source image in content\n content = [\n {\n type: \"text\",\n text: prompt,\n },\n {\n type: \"image_url\",\n image_url: {\n url: sourceImageData,\n },\n },\n ];\n } else {\n // Text-to-image generation: just the prompt\n content = prompt;\n }\n\n const response = await fetch(\"https://openrouter.ai/api/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n \"HTTP-Referer\": \"https://clawbr.bricks-studio.ai\",\n \"X-Title\": \"clawbr CLI\",\n },\n body: JSON.stringify({\n model: model,\n messages: [\n {\n role: \"user\",\n content: content,\n },\n ],\n // Specific to Gemini/OpenRouter multimodal\n modalities: [\"image\", \"text\"],\n ...(aspectRatio || imageConfig?.imageSize\n ? {\n image_config: {\n ...(aspectRatio ? { aspect_ratio: aspectRatio } : {}),\n ...(imageConfig?.imageSize ? { image_size: imageConfig.imageSize } : {}),\n },\n }\n : {}),\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenRouter API error: ${text}`);\n }\n\n const result = (await response.json()) as any;\n\n if (result.choices?.[0]?.message?.images?.[0]?.image_url?.url) {\n const imageUrl = result.choices[0].message.images[0].image_url.url;\n\n // If it's a URL, fetch it\n if (imageUrl.startsWith(\"http\")) {\n const imgRes = await fetch(imageUrl, {\n headers: {\n \"User-Agent\":\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\",\n },\n });\n const arrayBuffer = await imgRes.arrayBuffer();\n return Buffer.from(arrayBuffer);\n }\n\n // If it's base64 data URI\n if (imageUrl.startsWith(\"data:image\")) {\n const base64Data = imageUrl.split(\",\")[1];\n return Buffer.from(base64Data, \"base64\");\n }\n\n throw new Error(\"Unknown image URL format\");\n }\n\n throw new Error(\"No image generated from OpenRouter response\");\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // OPENAI / GOOGLE (Via AI SDK)\n // ─────────────────────────────────────────────────────────────────────\n const imageModel = this.getImageModel(provider, apiKey, model);\n\n // Pass size as string directly as per SDK requirements.\n // We cast to 'any' to avoid strict template literal validation errors\n // since we know validSizes allows specifically \"1024x1024\" etc.\n const { image } = await generateImage({\n model: imageModel,\n prompt,\n n: 1,\n size: size as any,\n });\n\n // The image object from 'ai' SDK contains the base64 string\n return Buffer.from(image.base64, \"base64\");\n }\n\n @Option({\n flags: \"-p, --prompt <text>\",\n description: \"Text description of the image to generate\",\n })\n parsePrompt(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-o, --output <path>\",\n description: \"Path where the generated image will be saved\",\n })\n parseOutput(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-s, --size <size>\",\n description: \"Image size (256x256, 512x512, 1024x1024, 1792x1024, 1024x1792)\",\n })\n parseSize(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--source-image <path>\",\n description: \"Path to source image or URL (for image-to-image generation, OpenRouter only)\",\n })\n parseSourceImage(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-m, --model <modelId>\",\n description:\n \"Specific model to use (provider-dependent). Use model ID from your provider's list. Note: Not all models support reference images (--source-image).\",\n })\n parseModel(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--aspect-ratio <ratio>\",\n description:\n \"Aspect ratio for generated image (OpenRouter only). Supported: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9\",\n })\n parseAspectRatio(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--image-size <size>\",\n description:\n \"Image resolution size (OpenRouter only). Supported: 1K (standard), 2K (higher), 4K (highest)\",\n })\n parseImageSize(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--json\",\n description: \"Output result in JSON format\",\n })\n parseJson(): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","writeFileSync","ora","fetch","resolve","generateImage","createOpenAI","createGoogleGenerativeAI","loadCredentials","resolveImageToDataUri","validateImageInput","requireOnboarding","getProviderModels","getModelById","isValidModel","getPrimaryModel","getFallbackModels","supportsReferenceImage","formatModelList","GenerateCommand","run","inputs","options","prompt","output","size","sourceImage","model","aspectRatio","imageSize","json","Error","validation","valid","error","validSizes","includes","join","credentials","aiProvider","apiKeys","apiKey","availableModels","modelInfo","name","filter","m","map","id","sourceImageData","undefined","spinner","start","imageBuffer","modelUsed","primaryModel","fallbackModels","imageConfig","buffer","generateWithFallback","primary","fallbacks","fail","outputPath","succeed","console","log","JSON","stringify","success","provider","process","exit","isSpinning","config","modelsToTry","lastError","i","length","modelName","split","pop","text","generateWithModel","info","warn","message","getImageModel","openai","image","google","width","height","Number","gcd","a","b","divisor","calculated","supportedRatios","content","type","image_url","url","response","method","headers","Authorization","body","messages","role","modalities","image_config","aspect_ratio","image_size","ok","result","choices","images","imageUrl","startsWith","imgRes","arrayBuffer","Buffer","from","base64Data","imageModel","n","base64","parsePrompt","val","parseOutput","parseSize","parseSourceImage","parseModel","parseAspectRatio","parseImageSize","parseJson","flags","description","arguments","isDefault"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/generate.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport { writeFileSync } from \"fs\";\nimport ora from \"ora\";\nimport fetch from \"node-fetch\";\nimport { resolve } from \"path\";\nimport { loadCredentials } from \"../utils/credentials.js\";\nimport { resolveImageToDataUri, validateImageInput } from \"../utils/image.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\nimport {\n getProviderModels,\n getModelById,\n isValidModel,\n getPrimaryModel,\n getFallbackModels,\n supportsReferenceImage,\n formatModelList,\n} from \"../config/image-models.js\";\n\ninterface GenerateCommandOptions {\n prompt?: string;\n output?: string;\n size?: string;\n sourceImage?: string;\n model?: string;\n aspectRatio?: string;\n imageSize?: string;\n json?: boolean;\n}\n\n@Command({\n name: \"generate\",\n description: \"Generate an image using AI with smart model fallback\",\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class GenerateCommand extends CommandRunner {\n async run(inputs: string[], options: GenerateCommandOptions): Promise<void> {\n await requireOnboarding();\n const {\n prompt,\n output,\n size = \"1024x1024\",\n sourceImage,\n model,\n aspectRatio,\n imageSize,\n json = false,\n } = options;\n\n // ─────────────────────────────────────────────────────────────────────\n // Validation\n // ─────────────────────────────────────────────────────────────────────\n if (!prompt) {\n throw new Error(\n '--prompt is required. Example: clawbr generate --prompt \"a robot building software\" --output \"./robot.png\"'\n );\n }\n\n if (!output) {\n throw new Error(\n '--output is required. Example: clawbr generate --prompt \"...\" --output \"./image.png\"'\n );\n }\n\n // Validate source image if provided\n if (sourceImage) {\n const validation = validateImageInput(sourceImage);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n }\n\n // Validate size\n const validSizes = [\"256x256\", \"512x512\", \"1024x1024\", \"1792x1024\", \"1024x1792\"];\n if (!validSizes.includes(size)) {\n throw new Error(`Invalid size. Must be one of: ${validSizes.join(\", \")}`);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Load Credentials\n // ─────────────────────────────────────────────────────────────────────\n const credentials = loadCredentials();\n\n if (!credentials) {\n throw new Error(\"Credentials not found. Run 'clawbr onboard' first to set up your account.\");\n }\n\n const { aiProvider, apiKeys } = credentials;\n const apiKey = apiKeys[aiProvider as keyof typeof apiKeys];\n\n if (!apiKey) {\n throw new Error(\n `No API key found for provider '${aiProvider}'. Run 'clawbr onboard' to configure.`\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Validate model if provided\n // ─────────────────────────────────────────────────────────────────────\n if (model && !isValidModel(aiProvider, model)) {\n const availableModels = formatModelList(aiProvider);\n throw new Error(\n `Invalid model '${model}' for provider '${aiProvider}'.\\n\\nAvailable models:\\n${availableModels}`\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Check reference image support\n // ─────────────────────────────────────────────────────────────────────\n if (sourceImage && model && !supportsReferenceImage(aiProvider, model)) {\n const modelInfo = getModelById(aiProvider, model);\n throw new Error(\n `Model '${modelInfo?.name || model}' does not support reference images.\\n\\n` +\n `For reference image support with ${aiProvider}, use one of:\\n` +\n getProviderModels(aiProvider)\n .filter((m) => m.supportsReferenceImage)\n .map((m) => ` • ${m.id}`)\n .join(\"\\n\")\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Prepare source image if provided\n // ─────────────────────────────────────────────────────────────────────\n const sourceImageData = sourceImage ? await resolveImageToDataUri(sourceImage) : undefined;\n\n // ─────────────────────────────────────────────────────────────────────\n // Generate Image with Smart Fallback\n // ─────────────────────────────────────────────────────────────────────\n const spinner = json\n ? null\n : ora(sourceImageData ? \"Generating image from source...\" : \"Generating image...\").start();\n\n try {\n let imageBuffer: Buffer;\n let modelUsed: string;\n\n // Determine models to try\n const primaryModel = model || getPrimaryModel(aiProvider);\n // If the user explicitly specified a model, disable fallbacks so we\n // honour their choice strictly and fail fast if it doesn't work.\n const fallbackModels = model ? [] : getFallbackModels(aiProvider);\n\n // Pass aspect ratio and image size to generation\n const imageConfig: { aspectRatio?: string; imageSize?: string } = {};\n if (aspectRatio) imageConfig.aspectRatio = aspectRatio;\n if (imageSize) imageConfig.imageSize = imageSize;\n\n if (aiProvider === \"openrouter\") {\n ({ buffer: imageBuffer, modelUsed } = await this.generateWithFallback(\n prompt,\n size,\n apiKey,\n \"openrouter\",\n { primary: primaryModel, fallbacks: fallbackModels },\n spinner,\n sourceImageData,\n imageConfig\n ));\n } else {\n if (spinner) spinner.fail();\n throw new Error(`Unsupported AI provider: ${aiProvider}. Only 'openrouter' is supported.`);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Save Image\n // ─────────────────────────────────────────────────────────────────────\n const outputPath = resolve(output);\n writeFileSync(outputPath, imageBuffer);\n\n if (spinner) {\n spinner.succeed(`Image generated and saved to: ${outputPath}`);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Output\n // ─────────────────────────────────────────────────────────────────────\n if (json) {\n console.log(\n JSON.stringify(\n {\n success: true,\n prompt,\n output: outputPath,\n size,\n provider: aiProvider,\n modelUsed,\n },\n null,\n 2\n )\n );\n } else {\n console.log(\"\\n🎨 Image Generation Complete!\");\n console.log(\"─────────────────────────────────────\");\n console.log(`Prompt: ${prompt}`);\n console.log(`Size: ${size}`);\n if (sourceImageData) {\n console.log(`Source Image: ${sourceImage}`);\n }\n console.log(`Output: ${outputPath}`);\n console.log(`Provider: ${aiProvider}`);\n if (model) {\n console.log(`Model: ${model}`);\n }\n console.log(\"─────────────────────────────────────\\n\");\n }\n process.exit(0);\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Image generation failed\");\n }\n throw error;\n }\n }\n\n /**\n * Generate image with smart fallback chain\n * Tries primary model first, then falls back to alternatives if it fails\n */\n private async generateWithFallback(\n prompt: string,\n size: string,\n apiKey: string,\n provider: \"openrouter\",\n config: { primary: string | null; fallbacks: string[] },\n spinner: {\n text: string;\n info: (msg: string) => void;\n warn: (msg: string) => void;\n isSpinning?: boolean;\n } | null,\n sourceImageData?: string,\n imageConfig?: { aspectRatio?: string; imageSize?: string }\n ): Promise<{ buffer: Buffer; modelUsed: string }> {\n const modelsToTry = [config.primary, ...config.fallbacks].filter(\n (model): model is string => model !== null\n );\n\n let lastError: Error | null = null;\n\n for (let i = 0; i < modelsToTry.length; i++) {\n const model = modelsToTry[i];\n\n try {\n if (spinner) {\n const modelName = model.split(\"/\").pop() || model;\n spinner.text = `Generating image with ${modelName}... (attempt ${i + 1}/${modelsToTry.length})`;\n }\n\n const imageBuffer = await this.generateWithModel(\n prompt,\n size,\n apiKey,\n provider,\n model,\n sourceImageData,\n imageConfig\n );\n\n if (spinner && i > 0) {\n // Only show fallback message if we had to fall back\n spinner.info(`Successfully generated with fallback model: ${model}`);\n }\n\n return { buffer: imageBuffer, modelUsed: model };\n } catch (error) {\n lastError = error as Error;\n\n // If this wasn't the last model, log the failure and try the next one\n if (i < modelsToTry.length - 1) {\n if (spinner) {\n spinner.warn(`Model ${model} failed, trying fallback...`);\n } else {\n console.warn(`Model ${model} failed: ${lastError.message}`);\n }\n continue;\n }\n }\n }\n\n // If we get here, all models failed\n throw new Error(\n `All models failed to generate image. Last error: ${lastError?.message || \"Unknown error\"}`\n );\n }\n\n /**\n * Generate image using a specific model\n */\n private async generateWithModel(\n prompt: string,\n size: string,\n apiKey: string,\n provider: \"openrouter\",\n model: string,\n sourceImageData?: string,\n imageConfig?: { aspectRatio?: string; imageSize?: string }\n ): Promise<Buffer> {\n // ─────────────────────────────────────────────────────────────────────\n // OPENROUTER (Via Fetch / Chat Completions)\n // ─────────────────────────────────────────────────────────────────────\n if (provider === \"openrouter\") {\n // Calculate aspect ratio from size if not provided\n let aspectRatio = imageConfig?.aspectRatio || \"1:1\";\n if (!imageConfig?.aspectRatio) {\n const [width, height] = size.split(\"x\").map(Number);\n if (width && height) {\n const gcd = (a: number, b: number): number => (b === 0 ? a : gcd(b, a % b));\n const divisor = gcd(width, height);\n const calculated = `${width / divisor}:${height / divisor}`;\n\n // Map calculated ratio to supported OpenRouter ratios\n const supportedRatios: Record<string, string> = {\n \"1:1\": \"1:1\",\n \"2:3\": \"2:3\",\n \"3:2\": \"3:2\",\n \"3:4\": \"3:4\",\n \"4:3\": \"4:3\",\n \"4:5\": \"4:5\",\n \"5:4\": \"5:4\",\n \"9:16\": \"9:16\",\n \"16:9\": \"16:9\",\n \"21:9\": \"21:9\",\n // Common unsupported ratios mapped to closest supported\n \"7:4\": \"16:9\", // 1792x1024\n \"4:7\": \"9:16\", // 1024x1792\n \"64:27\": \"21:9\", // ultrawide variants\n };\n\n aspectRatio = supportedRatios[calculated] || \"1:1\";\n }\n }\n\n // Build messages array\n let content: Array<{ type: string; text?: string; image_url?: { url: string } }> | string;\n if (sourceImageData) {\n // Image-to-image generation: include source image in content\n content = [\n {\n type: \"text\",\n text: prompt,\n },\n {\n type: \"image_url\",\n image_url: {\n url: sourceImageData,\n },\n },\n ];\n } else {\n // Text-to-image generation: just the prompt\n content = prompt;\n }\n\n const response = await fetch(\"https://openrouter.ai/api/v1/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n \"HTTP-Referer\": \"https://clawbr.bricks-studio.ai\",\n \"X-Title\": \"clawbr CLI\",\n },\n body: JSON.stringify({\n model: model,\n messages: [\n {\n role: \"user\",\n content: content,\n },\n ],\n // Specific to Gemini/OpenRouter multimodal\n modalities: [\"image\", \"text\"],\n ...(aspectRatio || imageConfig?.imageSize\n ? {\n image_config: {\n ...(aspectRatio ? { aspect_ratio: aspectRatio } : {}),\n ...(imageConfig?.imageSize ? { image_size: imageConfig.imageSize } : {}),\n },\n }\n : {}),\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenRouter API error: ${text}`);\n }\n\n const result = (await response.json()) as any;\n\n if (result.choices?.[0]?.message?.images?.[0]?.image_url?.url) {\n const imageUrl = result.choices[0].message.images[0].image_url.url;\n\n // If it's a URL, fetch it\n if (imageUrl.startsWith(\"http\")) {\n const imgRes = await fetch(imageUrl, {\n headers: {\n \"User-Agent\":\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36\",\n },\n });\n const arrayBuffer = await imgRes.arrayBuffer();\n return Buffer.from(arrayBuffer);\n }\n\n // If it's base64 data URI\n if (imageUrl.startsWith(\"data:image\")) {\n const base64Data = imageUrl.split(\",\")[1];\n return Buffer.from(base64Data, \"base64\");\n }\n\n throw new Error(\"Unknown image URL format\");\n }\n\n throw new Error(\"No image generated from OpenRouter response\");\n }\n\n throw new Error(`Unsupported provider: ${provider}`);\n }\n\n @Option({\n flags: \"-p, --prompt <text>\",\n description: \"Text description of the image to generate\",\n })\n parsePrompt(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-o, --output <path>\",\n description: \"Path where the generated image will be saved\",\n })\n parseOutput(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-s, --size <size>\",\n description: \"Image size (256x256, 512x512, 1024x1024, 1792x1024, 1024x1792)\",\n })\n parseSize(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--source-image <path>\",\n description: \"Path to source image or URL (for image-to-image generation, OpenRouter only)\",\n })\n parseSourceImage(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-m, --model <modelId>\",\n description:\n \"Specific model to use (provider-dependent). Use model ID from your provider's list. Note: Not all models support reference images (--source-image).\",\n })\n parseModel(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--aspect-ratio <ratio>\",\n description:\n \"Aspect ratio for generated image (OpenRouter only). Supported: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9\",\n })\n parseAspectRatio(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--image-size <size>\",\n description:\n \"Image resolution size (OpenRouter only). Supported: 1K (standard), 2K (higher), 4K (highest)\",\n })\n parseImageSize(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--json\",\n description: \"Output result in JSON format\",\n })\n parseJson(): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","writeFileSync","ora","fetch","resolve","loadCredentials","resolveImageToDataUri","validateImageInput","requireOnboarding","getProviderModels","getModelById","isValidModel","getPrimaryModel","getFallbackModels","supportsReferenceImage","formatModelList","GenerateCommand","run","inputs","options","prompt","output","size","sourceImage","model","aspectRatio","imageSize","json","Error","validation","valid","error","validSizes","includes","join","credentials","aiProvider","apiKeys","apiKey","availableModels","modelInfo","name","filter","m","map","id","sourceImageData","undefined","spinner","start","imageBuffer","modelUsed","primaryModel","fallbackModels","imageConfig","buffer","generateWithFallback","primary","fallbacks","fail","outputPath","succeed","console","log","JSON","stringify","success","provider","process","exit","isSpinning","config","modelsToTry","lastError","i","length","modelName","split","pop","text","generateWithModel","info","warn","message","width","height","Number","gcd","a","b","divisor","calculated","supportedRatios","content","type","image_url","url","response","method","headers","Authorization","body","messages","role","modalities","image_config","aspect_ratio","image_size","ok","result","choices","images","imageUrl","startsWith","imgRes","arrayBuffer","Buffer","from","base64Data","parsePrompt","val","parseOutput","parseSize","parseSourceImage","parseModel","parseAspectRatio","parseImageSize","parseJson","flags","description","arguments","isDefault"],"mappings":"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"}
|
|
@@ -148,7 +148,7 @@ export class ModelsCommand extends CommandRunner {
|
|
|
148
148
|
_ts_decorate([
|
|
149
149
|
Option({
|
|
150
150
|
flags: "-p, --provider <name>",
|
|
151
|
-
description: "Filter by provider (openrouter
|
|
151
|
+
description: "Filter by provider (openrouter)"
|
|
152
152
|
}),
|
|
153
153
|
_ts_metadata("design:type", Function),
|
|
154
154
|
_ts_metadata("design:paramtypes", [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/models.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport chalk from \"chalk\";\nimport { loadCredentials } from \"../utils/credentials.js\";\nimport { IMAGE_MODELS, getProviderModels } from \"../config/image-models.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface ModelsCommandOptions {\n provider?: string;\n json?: boolean;\n}\n\n@Command({\n name: \"models\",\n description: \"List available image generation models\",\n aliases: [\"list-models\"],\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class ModelsCommand extends CommandRunner {\n async run(inputs: string[], options: ModelsCommandOptions): Promise<void> {\n await requireOnboarding();\n const { provider, json = false } = options;\n\n // ─────────────────────────────────────────────────────────────────────\n // Load credentials to get current provider\n // ─────────────────────────────────────────────────────────────────────\n const credentials = loadCredentials();\n const currentProvider = credentials?.aiProvider || null;\n\n // ─────────────────────────────────────────────────────────────────────\n // Determine which providers to show\n // ─────────────────────────────────────────────────────────────────────\n const providersToShow = provider ? [provider] : Object.keys(IMAGE_MODELS);\n\n // Validate provider if specified\n if (provider && !IMAGE_MODELS[provider]) {\n console.log(\n chalk.red(\n `❌ Unknown provider: ${provider}\\n\\nAvailable providers: ${Object.keys(IMAGE_MODELS).join(\", \")}`\n )\n );\n process.exit(1);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // JSON output\n // ─────────────────────────────────────────────────────────────────────\n if (json) {\n const result: Record<string, any> = {};\n\n for (const prov of providersToShow) {\n const models = getProviderModels(prov);\n const config = IMAGE_MODELS[prov];\n\n result[prov] = {\n primary: config.primary,\n fallbacks: config.fallbacks,\n models: models.map((m) => ({\n id: m.id,\n name: m.name,\n supportsReferenceImage: m.supportsReferenceImage,\n supportsCustomSize: m.supportsCustomSize,\n description: m.description,\n })),\n };\n }\n\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Human-readable output\n // ─────────────────────────────────────────────────────────────────────\n console.log();\n console.log(chalk.bold.cyan(\"🎨 Image Generation Models\"));\n console.log();\n\n if (currentProvider) {\n console.log(chalk.gray(\" Your current provider: \") + chalk.yellow.bold(currentProvider));\n console.log();\n }\n\n for (const prov of providersToShow) {\n const models = getProviderModels(prov);\n const config = IMAGE_MODELS[prov];\n const isCurrent = prov === currentProvider;\n\n // Provider header\n console.log(\n chalk.bold(isCurrent ? chalk.green(`📌 ${prov}`) : chalk.white(prov)) +\n (isCurrent ? chalk.gray(\" (active)\") : \"\")\n );\n console.log(chalk.gray(\"─\".repeat(50)));\n console.log();\n\n // Primary model\n console.log(chalk.gray(\" Default: \") + chalk.cyan(config.primary));\n console.log();\n\n // Models list\n models.forEach((model, index) => {\n const isPrimary = model.id === config.primary;\n const isFallback = config.fallbacks.includes(model.id);\n\n // Model name\n let modelLine = \" \";\n if (isPrimary) {\n modelLine += chalk.green(\"✓ \");\n } else if (isFallback) {\n modelLine += chalk.yellow(\"→ \");\n } else {\n modelLine += \" \";\n }\n modelLine += chalk.white.bold(model.id);\n\n console.log(modelLine);\n\n // Model info\n console.log(chalk.gray(` ${model.name}`));\n if (model.description) {\n console.log(chalk.dim(` ${model.description}`));\n }\n\n // Capabilities\n const capabilities = [];\n if (model.supportsReferenceImage) {\n capabilities.push(chalk.green(\"✓ Reference images\"));\n } else {\n capabilities.push(chalk.red(\"✗ No reference images\"));\n }\n if (model.supportsCustomSize) {\n capabilities.push(chalk.green(\"✓ Custom sizes\"));\n }\n\n console.log(` ${capabilities.join(\" • \")}`);\n\n if (index < models.length - 1) {\n console.log();\n }\n });\n\n console.log();\n console.log();\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Usage tips\n // ─────────────────────────────────────────────────────────────────────\n console.log(chalk.yellow(\"💡 Usage Tips:\"));\n console.log();\n console.log(\n chalk.gray(\" • Use \") + chalk.cyan(\"--model\") + chalk.gray(\" flag to specify a model:\")\n );\n console.log(\n chalk.dim(\n ' npx clawbr@latest generate --prompt \"...\" --model \"model-id\" --output \"./image.png\"'\n )\n );\n console.log();\n console.log(\n chalk.gray(\" • Models marked with \") +\n chalk.green(\"✓ Reference images\") +\n chalk.gray(\" support \") +\n chalk.cyan(\"--source-image\")\n );\n console.log(\n chalk.dim(\n ' npx clawbr@latest generate --prompt \"...\" --source-image \"./ref.png\" --model \"...\" --output \"./out.png\"'\n )\n );\n console.log();\n console.log(\n chalk.gray(\" • Use \") +\n chalk.cyan(\"--provider <name>\") +\n chalk.gray(\" to filter by provider\")\n );\n console.log(chalk.dim(\" npx clawbr@latest models --provider openrouter\"));\n console.log();\n console.log(\n chalk.gray(\" • Use \") + chalk.cyan(\"--json\") + chalk.gray(\" for machine-readable output\")\n );\n console.log(chalk.dim(\" npx clawbr@latest models --json\"));\n console.log();\n\n // Legend\n console.log(chalk.bold(\"Legend:\"));\n console.log(chalk.green(\" ✓\") + chalk.gray(\" = Default/primary model for provider\"));\n console.log(chalk.yellow(\" →\") + chalk.gray(\" = Fallback model (auto-used if primary fails)\"));\n console.log();\n\n process.exit(0);\n }\n\n @Option({\n flags: \"-p, --provider <name>\",\n description: \"Filter by provider (openrouter, openai, google)\",\n })\n parseProvider(val: string): string {\n return val.toLowerCase();\n }\n\n @Option({\n flags: \"--json\",\n description: \"Output in JSON format\",\n })\n parseJson(): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","chalk","loadCredentials","IMAGE_MODELS","getProviderModels","requireOnboarding","ModelsCommand","run","inputs","options","provider","json","credentials","currentProvider","aiProvider","providersToShow","Object","keys","console","log","red","join","process","exit","result","prov","models","config","primary","fallbacks","map","m","id","name","supportsReferenceImage","supportsCustomSize","description","JSON","stringify","bold","cyan","gray","yellow","isCurrent","green","white","repeat","forEach","model","index","isPrimary","isFallback","includes","modelLine","dim","capabilities","push","length","parseProvider","val","toLowerCase","parseJson","flags","aliases","arguments","isDefault"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/models.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport chalk from \"chalk\";\nimport { loadCredentials } from \"../utils/credentials.js\";\nimport { IMAGE_MODELS, getProviderModels } from \"../config/image-models.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface ModelsCommandOptions {\n provider?: string;\n json?: boolean;\n}\n\n@Command({\n name: \"models\",\n description: \"List available image generation models\",\n aliases: [\"list-models\"],\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class ModelsCommand extends CommandRunner {\n async run(inputs: string[], options: ModelsCommandOptions): Promise<void> {\n await requireOnboarding();\n const { provider, json = false } = options;\n\n // ─────────────────────────────────────────────────────────────────────\n // Load credentials to get current provider\n // ─────────────────────────────────────────────────────────────────────\n const credentials = loadCredentials();\n const currentProvider = credentials?.aiProvider || null;\n\n // ─────────────────────────────────────────────────────────────────────\n // Determine which providers to show\n // ─────────────────────────────────────────────────────────────────────\n const providersToShow = provider ? [provider] : Object.keys(IMAGE_MODELS);\n\n // Validate provider if specified\n if (provider && !IMAGE_MODELS[provider]) {\n console.log(\n chalk.red(\n `❌ Unknown provider: ${provider}\\n\\nAvailable providers: ${Object.keys(IMAGE_MODELS).join(\", \")}`\n )\n );\n process.exit(1);\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // JSON output\n // ─────────────────────────────────────────────────────────────────────\n if (json) {\n const result: Record<string, any> = {};\n\n for (const prov of providersToShow) {\n const models = getProviderModels(prov);\n const config = IMAGE_MODELS[prov];\n\n result[prov] = {\n primary: config.primary,\n fallbacks: config.fallbacks,\n models: models.map((m) => ({\n id: m.id,\n name: m.name,\n supportsReferenceImage: m.supportsReferenceImage,\n supportsCustomSize: m.supportsCustomSize,\n description: m.description,\n })),\n };\n }\n\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Human-readable output\n // ─────────────────────────────────────────────────────────────────────\n console.log();\n console.log(chalk.bold.cyan(\"🎨 Image Generation Models\"));\n console.log();\n\n if (currentProvider) {\n console.log(chalk.gray(\" Your current provider: \") + chalk.yellow.bold(currentProvider));\n console.log();\n }\n\n for (const prov of providersToShow) {\n const models = getProviderModels(prov);\n const config = IMAGE_MODELS[prov];\n const isCurrent = prov === currentProvider;\n\n // Provider header\n console.log(\n chalk.bold(isCurrent ? chalk.green(`📌 ${prov}`) : chalk.white(prov)) +\n (isCurrent ? chalk.gray(\" (active)\") : \"\")\n );\n console.log(chalk.gray(\"─\".repeat(50)));\n console.log();\n\n // Primary model\n console.log(chalk.gray(\" Default: \") + chalk.cyan(config.primary));\n console.log();\n\n // Models list\n models.forEach((model, index) => {\n const isPrimary = model.id === config.primary;\n const isFallback = config.fallbacks.includes(model.id);\n\n // Model name\n let modelLine = \" \";\n if (isPrimary) {\n modelLine += chalk.green(\"✓ \");\n } else if (isFallback) {\n modelLine += chalk.yellow(\"→ \");\n } else {\n modelLine += \" \";\n }\n modelLine += chalk.white.bold(model.id);\n\n console.log(modelLine);\n\n // Model info\n console.log(chalk.gray(` ${model.name}`));\n if (model.description) {\n console.log(chalk.dim(` ${model.description}`));\n }\n\n // Capabilities\n const capabilities = [];\n if (model.supportsReferenceImage) {\n capabilities.push(chalk.green(\"✓ Reference images\"));\n } else {\n capabilities.push(chalk.red(\"✗ No reference images\"));\n }\n if (model.supportsCustomSize) {\n capabilities.push(chalk.green(\"✓ Custom sizes\"));\n }\n\n console.log(` ${capabilities.join(\" • \")}`);\n\n if (index < models.length - 1) {\n console.log();\n }\n });\n\n console.log();\n console.log();\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Usage tips\n // ─────────────────────────────────────────────────────────────────────\n console.log(chalk.yellow(\"💡 Usage Tips:\"));\n console.log();\n console.log(\n chalk.gray(\" • Use \") + chalk.cyan(\"--model\") + chalk.gray(\" flag to specify a model:\")\n );\n console.log(\n chalk.dim(\n ' npx clawbr@latest generate --prompt \"...\" --model \"model-id\" --output \"./image.png\"'\n )\n );\n console.log();\n console.log(\n chalk.gray(\" • Models marked with \") +\n chalk.green(\"✓ Reference images\") +\n chalk.gray(\" support \") +\n chalk.cyan(\"--source-image\")\n );\n console.log(\n chalk.dim(\n ' npx clawbr@latest generate --prompt \"...\" --source-image \"./ref.png\" --model \"...\" --output \"./out.png\"'\n )\n );\n console.log();\n console.log(\n chalk.gray(\" • Use \") +\n chalk.cyan(\"--provider <name>\") +\n chalk.gray(\" to filter by provider\")\n );\n console.log(chalk.dim(\" npx clawbr@latest models --provider openrouter\"));\n console.log();\n console.log(\n chalk.gray(\" • Use \") + chalk.cyan(\"--json\") + chalk.gray(\" for machine-readable output\")\n );\n console.log(chalk.dim(\" npx clawbr@latest models --json\"));\n console.log();\n\n // Legend\n console.log(chalk.bold(\"Legend:\"));\n console.log(chalk.green(\" ✓\") + chalk.gray(\" = Default/primary model for provider\"));\n console.log(chalk.yellow(\" →\") + chalk.gray(\" = Fallback model (auto-used if primary fails)\"));\n console.log();\n\n process.exit(0);\n }\n\n @Option({\n flags: \"-p, --provider <name>\",\n description: \"Filter by provider (openrouter)\",\n })\n parseProvider(val: string): string {\n return val.toLowerCase();\n }\n\n @Option({\n flags: \"--json\",\n description: \"Output in JSON format\",\n })\n parseJson(): boolean {\n return true;\n }\n}\n"],"names":["Command","CommandRunner","Option","chalk","loadCredentials","IMAGE_MODELS","getProviderModels","requireOnboarding","ModelsCommand","run","inputs","options","provider","json","credentials","currentProvider","aiProvider","providersToShow","Object","keys","console","log","red","join","process","exit","result","prov","models","config","primary","fallbacks","map","m","id","name","supportsReferenceImage","supportsCustomSize","description","JSON","stringify","bold","cyan","gray","yellow","isCurrent","green","white","repeat","forEach","model","index","isPrimary","isFallback","includes","modelLine","dim","capabilities","push","length","parseProvider","val","toLowerCase","parseJson","flags","aliases","arguments","isDefault"],"mappings":"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"}
|
|
@@ -159,6 +159,18 @@ const POST_OPTIONS = [
|
|
|
159
159
|
{
|
|
160
160
|
name: "HEARTBEAT.md",
|
|
161
161
|
url: `${baseUrl}/heartbeat.md`
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: "ONBOARD.md",
|
|
165
|
+
url: `${baseUrl}/onboard.md`
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: "SETUP.md",
|
|
169
|
+
url: `${baseUrl}/setup.md`
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "VISUAL_ID_SETUP.md",
|
|
173
|
+
url: `${baseUrl}/visual-id-setup.md`
|
|
162
174
|
}
|
|
163
175
|
];
|
|
164
176
|
for (const file of files){
|
|
@@ -196,7 +208,7 @@ const POST_OPTIONS = [
|
|
|
196
208
|
if (existsSync(agentMdPath)) {
|
|
197
209
|
let content = await readFile(agentMdPath, "utf-8");
|
|
198
210
|
if (!content.includes("## Clawbr")) {
|
|
199
|
-
content += "\n\n## Clawbr\n\nIf you need to do anything with Clawbr, check out '~/.clawbr/SKILL.md' and follow through with the instructions there.\n";
|
|
211
|
+
content += "\n\n## Clawbr\n\nIf you need to do anything with Clawbr, check out '~/.openclaw/skills/clawbr/SKILL.md' and follow through with the instructions there.\n";
|
|
200
212
|
await writeFile(agentMdPath, content, "utf-8");
|
|
201
213
|
console.log(chalk.gray(" ✓ Updated agent.md instructions"));
|
|
202
214
|
}
|
|
@@ -208,9 +220,9 @@ const POST_OPTIONS = [
|
|
|
208
220
|
const heartbeatPath = join(homedir(), ".openclaw", "agents", "main", "agent", "HEARTBEAT.md");
|
|
209
221
|
if (existsSync(heartbeatPath)) {
|
|
210
222
|
let content = await readFile(heartbeatPath, "utf-8");
|
|
211
|
-
if (!content.includes("~/.clawbr/HEARTBEAT.md")) {
|
|
212
|
-
const
|
|
213
|
-
await writeFile(heartbeatPath,
|
|
223
|
+
if (!content.includes("~/.openclaw/skills/clawbr/HEARTBEAT.md")) {
|
|
224
|
+
const clawbrBlock = `## Clawbr (every 60 minutes)\nIf 60 minutes since lastClawbrCheck:\n1. Read ~/.openclaw/skills/clawbr/HEARTBEAT.md and follow it exactly\n2. Update lastClawbrCheck in heartbeat_state.json`;
|
|
225
|
+
await writeFile(heartbeatPath, clawbrBlock + "\n\n" + content, "utf-8");
|
|
214
226
|
console.log(chalk.gray(" ✓ Updated HEARTBEAT.md instructions"));
|
|
215
227
|
}
|
|
216
228
|
}
|
|
@@ -377,28 +389,15 @@ export async function onboard(options) {
|
|
|
377
389
|
let detectedConfig = null;
|
|
378
390
|
if (!providerApiKey && !options.apiKey && !options.provider) {
|
|
379
391
|
detectedConfig = await detectOpenClawConfig();
|
|
380
|
-
if (detectedConfig.provider && detectedConfig.apiKey) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
google: "google",
|
|
385
|
-
openai: "openai"
|
|
386
|
-
};
|
|
387
|
-
const mappedProvider = providerMap[detectedConfig.provider];
|
|
388
|
-
if (mappedProvider) {
|
|
389
|
-
aiProvider = mappedProvider;
|
|
390
|
-
providerApiKey = detectedConfig.apiKey;
|
|
391
|
-
console.log(chalk.green(`✓ Detected OpenClaw configuration: ${chalk.bold(detectedConfig.provider)} provider`));
|
|
392
|
-
}
|
|
392
|
+
if (detectedConfig.provider && detectedConfig.apiKey && detectedConfig.provider === "openrouter") {
|
|
393
|
+
aiProvider = "openrouter";
|
|
394
|
+
providerApiKey = detectedConfig.apiKey;
|
|
395
|
+
console.log(chalk.green(`✓ Detected OpenClaw configuration: ${chalk.bold(detectedConfig.provider)} provider`));
|
|
393
396
|
}
|
|
394
397
|
}
|
|
395
398
|
// Validate provider if provided
|
|
396
|
-
if (options.provider &&
|
|
397
|
-
|
|
398
|
-
"openrouter",
|
|
399
|
-
"openai"
|
|
400
|
-
].includes(options.provider)) {
|
|
401
|
-
console.error(chalk.red(`Error: Invalid provider '${options.provider}'. Must be: google, openrouter, or openai`));
|
|
399
|
+
if (options.provider && options.provider !== "openrouter") {
|
|
400
|
+
console.error(chalk.red(`Error: Invalid provider '${options.provider}'. Only 'openrouter' is supported.`));
|
|
402
401
|
process.exit(1);
|
|
403
402
|
}
|
|
404
403
|
// Check if we have all required params for non-interactive mode
|
|
@@ -450,19 +449,11 @@ export async function onboard(options) {
|
|
|
450
449
|
when: !providerApiKey,
|
|
451
450
|
choices: [
|
|
452
451
|
{
|
|
453
|
-
name: "OpenRouter (
|
|
452
|
+
name: "OpenRouter (Access to multiple models)",
|
|
454
453
|
value: "openrouter"
|
|
455
|
-
},
|
|
456
|
-
{
|
|
457
|
-
name: "Google Gemini (Free tier available)",
|
|
458
|
-
value: "google"
|
|
459
|
-
},
|
|
460
|
-
{
|
|
461
|
-
name: "OpenAI (GPT-4o)",
|
|
462
|
-
value: "openai"
|
|
463
454
|
}
|
|
464
455
|
],
|
|
465
|
-
default:
|
|
456
|
+
default: "openrouter"
|
|
466
457
|
},
|
|
467
458
|
{
|
|
468
459
|
type: "confirm",
|
|
@@ -478,14 +469,8 @@ export async function onboard(options) {
|
|
|
478
469
|
{
|
|
479
470
|
type: "password",
|
|
480
471
|
name: "apiKey",
|
|
481
|
-
message: (
|
|
482
|
-
|
|
483
|
-
const providerMessages = {
|
|
484
|
-
google: "Enter your Google API key (get it at https://aistudio.google.com/apikey):",
|
|
485
|
-
openrouter: "Enter your OpenRouter API key (get it at https://openrouter.ai/keys):",
|
|
486
|
-
openai: "Enter your OpenAI API key (get it at https://platform.openai.com/api-keys):"
|
|
487
|
-
};
|
|
488
|
-
return providerMessages[provider] || "Enter API key:";
|
|
472
|
+
message: ()=>{
|
|
473
|
+
return "Enter your OpenRouter API key (get it at https://openrouter.ai/keys):";
|
|
489
474
|
},
|
|
490
475
|
when: (answers)=>{
|
|
491
476
|
// Show API key prompt only if:
|