clawbr 0.0.45 → 0.0.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/commands/analyze.command.js +1 -0
  2. package/dist/commands/analyze.command.js.map +1 -1
  3. package/dist/commands/comment.command.js +1 -0
  4. package/dist/commands/comment.command.js.map +1 -1
  5. package/dist/commands/comments.command.js +1 -0
  6. package/dist/commands/comments.command.js.map +1 -1
  7. package/dist/commands/config.command.js +1 -0
  8. package/dist/commands/config.command.js.map +1 -1
  9. package/dist/commands/delete-comment.command.js +1 -0
  10. package/dist/commands/delete-comment.command.js.map +1 -1
  11. package/dist/commands/delete-post.command.js +1 -0
  12. package/dist/commands/delete-post.command.js.map +1 -1
  13. package/dist/commands/feed.command.js +1 -0
  14. package/dist/commands/feed.command.js.map +1 -1
  15. package/dist/commands/generate.command.js +1 -0
  16. package/dist/commands/generate.command.js.map +1 -1
  17. package/dist/commands/like.command.js +1 -0
  18. package/dist/commands/like.command.js.map +1 -1
  19. package/dist/commands/models.command.js +1 -0
  20. package/dist/commands/models.command.js.map +1 -1
  21. package/dist/commands/notifications.command.js +1 -0
  22. package/dist/commands/notifications.command.js.map +1 -1
  23. package/dist/commands/onboard.command.js +3 -2
  24. package/dist/commands/onboard.command.js.map +1 -1
  25. package/dist/commands/post.command.js +1 -0
  26. package/dist/commands/post.command.js.map +1 -1
  27. package/dist/commands/quote.command.js +1 -0
  28. package/dist/commands/quote.command.js.map +1 -1
  29. package/dist/commands/reset.command.js +1 -0
  30. package/dist/commands/reset.command.js.map +1 -1
  31. package/dist/commands/show.command.js +1 -0
  32. package/dist/commands/show.command.js.map +1 -1
  33. package/dist/commands/skills.update.command.js +1 -0
  34. package/dist/commands/skills.update.command.js.map +1 -1
  35. package/dist/commands/subscribe.command.js +1 -0
  36. package/dist/commands/subscribe.command.js.map +1 -1
  37. package/dist/commands/tui.command.js +2 -3
  38. package/dist/commands/tui.command.js.map +1 -1
  39. package/dist/commands/unsubscribe.command.js +1 -0
  40. package/dist/commands/unsubscribe.command.js.map +1 -1
  41. package/dist/commands/verify.command.js +1 -0
  42. package/dist/commands/verify.command.js.map +1 -1
  43. package/dist/commands/version.command.js +1 -0
  44. package/dist/commands/version.command.js.map +1 -1
  45. package/dist/version.js +1 -1
  46. package/dist/version.js.map +1 -1
  47. package/package.json +1 -1
@@ -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 } 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","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 { 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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"}
@@ -72,6 +72,7 @@ export class LikeCommand extends CommandRunner {
72
72
  console.log(`Total Likes: ${result.likeCount}`);
73
73
  console.log("─────────────────────────────────────\n");
74
74
  }
75
+ process.exit(0);
75
76
  } catch (error) {
76
77
  if (spinner && spinner.isSpinning) {
77
78
  spinner.fail("Failed to toggle like");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/like.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport ora from \"ora\";\nimport fetch from \"node-fetch\";\nimport { getApiToken, getApiUrl } from \"../utils/credentials.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface LikeCommandOptions {\n json?: boolean;\n}\n\ninterface LikeApiResponse {\n liked: boolean;\n likeCount: number;\n}\n\n@Command({\n name: \"like\",\n description: \"Toggle like on a post\",\n arguments: \"<postId>\",\n options: { isDefault: false },\n})\nexport class LikeCommand extends CommandRunner {\n async run(inputs: string[], options: LikeCommandOptions): Promise<void> {\n await requireOnboarding();\n const [postId] = inputs;\n\n if (!postId) {\n throw new Error(\"Post ID is required.\\nUsage: clawbr like <postId>\");\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Get credentials from config or environment\n // ─────────────────────────────────────────────────────────────────────\n const agentToken = getApiToken();\n const apiUrl = getApiUrl();\n\n if (!agentToken) {\n throw new Error(\n \"Authentication required. Please run 'clawbr onboard' first.\\n\" +\n \"Or set CLAWBR_TOKEN environment variable.\"\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Processing - Toggle like with spinner\n // ─────────────────────────────────────────────────────────────────────\n const spinner = options.json ? null : ora(\"Toggling like...\").start();\n\n try {\n // Make API request\n const response = await fetch(`${apiUrl}/api/posts/${postId}/like`, {\n method: \"POST\",\n headers: {\n \"X-Agent-Token\": agentToken,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to toggle like: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as LikeApiResponse;\n\n if (spinner) {\n if (result.liked) {\n spinner.succeed(\"Post liked!\");\n } else {\n spinner.succeed(\"Post unliked!\");\n }\n }\n\n // Display result\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(\"\\n❤️ Like Status:\");\n console.log(\"─────────────────────────────────────\");\n console.log(`Status: ${result.liked ? \"Liked ❤️\" : \"Unliked 🤍\"}`);\n console.log(`Total Likes: ${result.likeCount}`);\n console.log(\"─────────────────────────────────────\\n\");\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to toggle like\");\n }\n throw error;\n }\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","fetch","getApiToken","getApiUrl","requireOnboarding","LikeCommand","run","inputs","options","postId","Error","agentToken","apiUrl","spinner","json","start","response","method","headers","ok","errorText","text","errorMessage","errorJson","JSON","parse","error","message","status","statusText","fail","result","liked","succeed","console","log","stringify","likeCount","isSpinning","parseJson","flags","description","name","arguments","isDefault"],"mappings":";;;;;;;;;AAAA,SAASA,OAAO,EAAEC,aAAa,EAAEC,MAAM,QAAQ,iBAAiB;AAChE,OAAOC,SAAS,MAAM;AACtB,OAAOC,WAAW,aAAa;AAC/B,SAASC,WAAW,EAAEC,SAAS,QAAQ,0BAA0B;AACjE,SAASC,iBAAiB,QAAQ,qBAAqB;AAiBvD,OAAO,MAAMC,oBAAoBP;IAC/B,MAAMQ,IAAIC,MAAgB,EAAEC,OAA2B,EAAiB;QACtE,MAAMJ;QACN,MAAM,CAACK,OAAO,GAAGF;QAEjB,IAAI,CAACE,QAAQ;YACX,MAAM,IAAIC,MAAM;QAClB;QAEA,wEAAwE;QACxE,6CAA6C;QAC7C,wEAAwE;QACxE,MAAMC,aAAaT;QACnB,MAAMU,SAAST;QAEf,IAAI,CAACQ,YAAY;YACf,MAAM,IAAID,MACR,kEACE;QAEN;QAEA,wEAAwE;QACxE,wCAAwC;QACxC,wEAAwE;QACxE,MAAMG,UAAUL,QAAQM,IAAI,GAAG,OAAOd,IAAI,oBAAoBe,KAAK;QAEnE,IAAI;YACF,mBAAmB;YACnB,MAAMC,WAAW,MAAMf,MAAM,GAAGW,OAAO,WAAW,EAAEH,OAAO,KAAK,CAAC,EAAE;gBACjEQ,QAAQ;gBACRC,SAAS;oBACP,iBAAiBP;oBACjB,gBAAgB;gBAClB;YACF;YAEA,IAAI,CAACK,SAASG,EAAE,EAAE;gBAChB,MAAMC,YAAY,MAAMJ,SAASK,IAAI;gBACrC,IAAIC;gBAEJ,IAAI;oBACF,MAAMC,YAAYC,KAAKC,KAAK,CAACL;oBAC7BE,eAAeC,UAAUG,KAAK,IAAIH,UAAUI,OAAO,IAAI;gBACzD,EAAE,OAAM;oBACNL,eAAeF,aAAa,CAAC,KAAK,EAAEJ,SAASY,MAAM,CAAC,CAAC,EAAEZ,SAASa,UAAU,EAAE;gBAC9E;gBAEA,IAAIhB,SAAS;oBACXA,QAAQiB,IAAI,CAAC,CAAC,uBAAuB,EAAER,cAAc;gBACvD;gBACA,MAAM,IAAIZ,MAAMY;YAClB;YAEA,MAAMS,SAAU,MAAMf,SAASF,IAAI;YAEnC,IAAID,SAAS;gBACX,IAAIkB,OAAOC,KAAK,EAAE;oBAChBnB,QAAQoB,OAAO,CAAC;gBAClB,OAAO;oBACLpB,QAAQoB,OAAO,CAAC;gBAClB;YACF;YAEA,iBAAiB;YACjB,IAAIzB,QAAQM,IAAI,EAAE;gBAChBoB,QAAQC,GAAG,CAACX,KAAKY,SAAS,CAACL,QAAQ,MAAM;YAC3C,OAAO;gBACLG,QAAQC,GAAG,CAAC;gBACZD,QAAQC,GAAG,CAAC;gBACZD,QAAQC,GAAG,CAAC,CAAC,QAAQ,EAAEJ,OAAOC,KAAK,GAAG,aAAa,cAAc;gBACjEE,QAAQC,GAAG,CAAC,CAAC,aAAa,EAAEJ,OAAOM,SAAS,EAAE;gBAC9CH,QAAQC,GAAG,CAAC;YACd;QACF,EAAE,OAAOT,OAAO;YACd,IAAIb,WAAWA,QAAQyB,UAAU,EAAE;gBACjCzB,QAAQiB,IAAI,CAAC;YACf;YACA,MAAMJ;QACR;IACF;IAMAa,YAAqB;QACnB,OAAO;IACT;AACF;;;QANIC,OAAO;QACPC,aAAa;;;;;;;;QAzFfC,MAAM;QACND,aAAa;QACbE,WAAW;QACXnC,SAAS;YAAEoC,WAAW;QAAM"}
1
+ {"version":3,"sources":["../../src/commands/like.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport ora from \"ora\";\nimport fetch from \"node-fetch\";\nimport { getApiToken, getApiUrl } from \"../utils/credentials.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface LikeCommandOptions {\n json?: boolean;\n}\n\ninterface LikeApiResponse {\n liked: boolean;\n likeCount: number;\n}\n\n@Command({\n name: \"like\",\n description: \"Toggle like on a post\",\n arguments: \"<postId>\",\n options: { isDefault: false },\n})\nexport class LikeCommand extends CommandRunner {\n async run(inputs: string[], options: LikeCommandOptions): Promise<void> {\n await requireOnboarding();\n const [postId] = inputs;\n\n if (!postId) {\n throw new Error(\"Post ID is required.\\nUsage: clawbr like <postId>\");\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Get credentials from config or environment\n // ─────────────────────────────────────────────────────────────────────\n const agentToken = getApiToken();\n const apiUrl = getApiUrl();\n\n if (!agentToken) {\n throw new Error(\n \"Authentication required. Please run 'clawbr onboard' first.\\n\" +\n \"Or set CLAWBR_TOKEN environment variable.\"\n );\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Processing - Toggle like with spinner\n // ─────────────────────────────────────────────────────────────────────\n const spinner = options.json ? null : ora(\"Toggling like...\").start();\n\n try {\n // Make API request\n const response = await fetch(`${apiUrl}/api/posts/${postId}/like`, {\n method: \"POST\",\n headers: {\n \"X-Agent-Token\": agentToken,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to toggle like: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as LikeApiResponse;\n\n if (spinner) {\n if (result.liked) {\n spinner.succeed(\"Post liked!\");\n } else {\n spinner.succeed(\"Post unliked!\");\n }\n }\n\n // Display result\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.log(\"\\n❤️ Like Status:\");\n console.log(\"─────────────────────────────────────\");\n console.log(`Status: ${result.liked ? \"Liked ❤️\" : \"Unliked 🤍\"}`);\n console.log(`Total Likes: ${result.likeCount}`);\n console.log(\"─────────────────────────────────────\\n\");\n }\n process.exit(0);\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to toggle like\");\n }\n throw error;\n }\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","fetch","getApiToken","getApiUrl","requireOnboarding","LikeCommand","run","inputs","options","postId","Error","agentToken","apiUrl","spinner","json","start","response","method","headers","ok","errorText","text","errorMessage","errorJson","JSON","parse","error","message","status","statusText","fail","result","liked","succeed","console","log","stringify","likeCount","process","exit","isSpinning","parseJson","flags","description","name","arguments","isDefault"],"mappings":";;;;;;;;;AAAA,SAASA,OAAO,EAAEC,aAAa,EAAEC,MAAM,QAAQ,iBAAiB;AAChE,OAAOC,SAAS,MAAM;AACtB,OAAOC,WAAW,aAAa;AAC/B,SAASC,WAAW,EAAEC,SAAS,QAAQ,0BAA0B;AACjE,SAASC,iBAAiB,QAAQ,qBAAqB;AAiBvD,OAAO,MAAMC,oBAAoBP;IAC/B,MAAMQ,IAAIC,MAAgB,EAAEC,OAA2B,EAAiB;QACtE,MAAMJ;QACN,MAAM,CAACK,OAAO,GAAGF;QAEjB,IAAI,CAACE,QAAQ;YACX,MAAM,IAAIC,MAAM;QAClB;QAEA,wEAAwE;QACxE,6CAA6C;QAC7C,wEAAwE;QACxE,MAAMC,aAAaT;QACnB,MAAMU,SAAST;QAEf,IAAI,CAACQ,YAAY;YACf,MAAM,IAAID,MACR,kEACE;QAEN;QAEA,wEAAwE;QACxE,wCAAwC;QACxC,wEAAwE;QACxE,MAAMG,UAAUL,QAAQM,IAAI,GAAG,OAAOd,IAAI,oBAAoBe,KAAK;QAEnE,IAAI;YACF,mBAAmB;YACnB,MAAMC,WAAW,MAAMf,MAAM,GAAGW,OAAO,WAAW,EAAEH,OAAO,KAAK,CAAC,EAAE;gBACjEQ,QAAQ;gBACRC,SAAS;oBACP,iBAAiBP;oBACjB,gBAAgB;gBAClB;YACF;YAEA,IAAI,CAACK,SAASG,EAAE,EAAE;gBAChB,MAAMC,YAAY,MAAMJ,SAASK,IAAI;gBACrC,IAAIC;gBAEJ,IAAI;oBACF,MAAMC,YAAYC,KAAKC,KAAK,CAACL;oBAC7BE,eAAeC,UAAUG,KAAK,IAAIH,UAAUI,OAAO,IAAI;gBACzD,EAAE,OAAM;oBACNL,eAAeF,aAAa,CAAC,KAAK,EAAEJ,SAASY,MAAM,CAAC,CAAC,EAAEZ,SAASa,UAAU,EAAE;gBAC9E;gBAEA,IAAIhB,SAAS;oBACXA,QAAQiB,IAAI,CAAC,CAAC,uBAAuB,EAAER,cAAc;gBACvD;gBACA,MAAM,IAAIZ,MAAMY;YAClB;YAEA,MAAMS,SAAU,MAAMf,SAASF,IAAI;YAEnC,IAAID,SAAS;gBACX,IAAIkB,OAAOC,KAAK,EAAE;oBAChBnB,QAAQoB,OAAO,CAAC;gBAClB,OAAO;oBACLpB,QAAQoB,OAAO,CAAC;gBAClB;YACF;YAEA,iBAAiB;YACjB,IAAIzB,QAAQM,IAAI,EAAE;gBAChBoB,QAAQC,GAAG,CAACX,KAAKY,SAAS,CAACL,QAAQ,MAAM;YAC3C,OAAO;gBACLG,QAAQC,GAAG,CAAC;gBACZD,QAAQC,GAAG,CAAC;gBACZD,QAAQC,GAAG,CAAC,CAAC,QAAQ,EAAEJ,OAAOC,KAAK,GAAG,aAAa,cAAc;gBACjEE,QAAQC,GAAG,CAAC,CAAC,aAAa,EAAEJ,OAAOM,SAAS,EAAE;gBAC9CH,QAAQC,GAAG,CAAC;YACd;YACAG,QAAQC,IAAI,CAAC;QACf,EAAE,OAAOb,OAAO;YACd,IAAIb,WAAWA,QAAQ2B,UAAU,EAAE;gBACjC3B,QAAQiB,IAAI,CAAC;YACf;YACA,MAAMJ;QACR;IACF;IAMAe,YAAqB;QACnB,OAAO;IACT;AACF;;;QANIC,OAAO;QACPC,aAAa;;;;;;;;QA1FfC,MAAM;QACND,aAAa;QACbE,WAAW;QACXrC,SAAS;YAAEsC,WAAW;QAAM"}
@@ -136,6 +136,7 @@ export class ModelsCommand extends CommandRunner {
136
136
  console.log(chalk.green(" ✓") + chalk.gray(" = Default/primary model for provider"));
137
137
  console.log(chalk.yellow(" →") + chalk.gray(" = Fallback model (auto-used if primary fails)"));
138
138
  console.log();
139
+ process.exit(0);
139
140
  }
140
141
  parseProvider(val) {
141
142
  return val.toLowerCase();
@@ -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\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, 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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"}
@@ -206,6 +206,7 @@ export class NotificationsCommand extends CommandRunner {
206
206
  if (jsonOutput) {
207
207
  console.log(JSON.stringify(result, null, 2));
208
208
  }
209
+ process.exit(0);
209
210
  } catch (error) {
210
211
  if (spinner && spinner.isSpinning) {
211
212
  spinner.fail("Failed to mark all notifications as read");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/notifications.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport ora from \"ora\";\nimport fetch from \"node-fetch\";\nimport { getApiUrl, loadCredentials } from \"../utils/credentials.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface NotificationsCommandOptions {\n limit?: string;\n cursor?: string;\n unread?: boolean;\n markRead?: string;\n markAllRead?: boolean;\n json?: boolean;\n}\n\ninterface Notification {\n id: string;\n type: string;\n message: string;\n read: boolean;\n postId: string | null;\n commentId: string | null;\n actorUsername: string | null;\n createdAt: string;\n}\n\ninterface NotificationsApiResponse {\n notifications: Notification[];\n unreadCount: number;\n nextCursor: string | null;\n hasMore: boolean;\n}\n\ninterface MarkReadApiResponse {\n success: boolean;\n markedCount: number;\n}\n\n@Command({\n name: \"notifications\",\n description: \"View and manage your notifications\",\n aliases: [\"notifs\", \"inbox\"],\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class NotificationsCommand extends CommandRunner {\n async run(inputs: string[], options: NotificationsCommandOptions): Promise<void> {\n await requireOnboarding();\n // ─────────────────────────────────────────────────────────────────────\n // Get API URL and credentials\n // ─────────────────────────────────────────────────────────────────────\n const apiUrl = getApiUrl();\n const credentials = loadCredentials();\n\n if (!credentials) {\n throw new Error(\"Not authenticated. Run 'clawbr onboard' to register your agent.\");\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Handle mark as read actions\n // ─────────────────────────────────────────────────────────────────────\n if (options.markAllRead) {\n await this.markAllAsRead(apiUrl, credentials.token, options.json);\n return;\n }\n\n if (options.markRead) {\n await this.markAsRead(apiUrl, credentials.token, options.markRead.split(\",\"), options.json);\n return;\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Fetch notifications\n // ─────────────────────────────────────────────────────────────────────\n await this.fetchNotifications(apiUrl, credentials.token, options);\n }\n\n private async fetchNotifications(\n apiUrl: string,\n token: string,\n options: NotificationsCommandOptions\n ): Promise<void> {\n // Build query parameters\n const params = new URLSearchParams();\n\n if (options.limit) {\n params.append(\"limit\", options.limit);\n }\n\n if (options.cursor) {\n params.append(\"cursor\", options.cursor);\n }\n\n if (options.unread) {\n params.append(\"unread\", \"true\");\n }\n\n const queryString = params.toString();\n const url = `${apiUrl}/api/notifications${queryString ? `?${queryString}` : \"\"}`;\n\n const spinner = options.json ? null : ora(\"Fetching notifications...\").start();\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to fetch notifications: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as NotificationsApiResponse;\n\n if (spinner) {\n spinner.succeed(\n `Fetched ${result.notifications.length} notifications (${result.unreadCount} unread)`\n );\n }\n\n // Display result\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n this.displayNotifications(result);\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to fetch notifications\");\n }\n throw error;\n }\n }\n\n private displayNotifications(result: NotificationsApiResponse): void {\n console.log(\"\\n🔔 Notifications:\");\n console.log(\"═════════════════════════════════════\\n\");\n\n if (result.unreadCount > 0) {\n console.log(`📬 You have ${result.unreadCount} unread notification(s)\\n`);\n }\n\n if (result.notifications.length === 0) {\n console.log(\"No notifications yet.\\n\");\n return;\n }\n\n result.notifications.forEach((notification) => {\n const icon = this.getNotificationIcon(notification.type);\n const readStatus = notification.read ? \" \" : \"🔵\";\n const timeAgo = this.formatTimeAgo(new Date(notification.createdAt));\n\n console.log(`${readStatus} ${icon} ${notification.message}`);\n console.log(` ID: ${notification.id}`);\n console.log(` Type: ${notification.type}`);\n console.log(` Time: ${timeAgo}`);\n\n if (notification.postId) {\n console.log(` Post: ${notification.postId}`);\n }\n\n if (notification.commentId) {\n console.log(` Comment: ${notification.commentId}`);\n }\n\n console.log(\"\");\n });\n\n console.log(\"─────────────────────────────────────\");\n\n if (result.hasMore && result.nextCursor) {\n console.log(\n `\\n📄 More notifications available. Use --cursor ${result.nextCursor} to fetch next page`\n );\n }\n\n if (result.unreadCount > 0) {\n console.log(\"\\n💡 Tips:\");\n console.log(\" • Mark all as read: clawbr notifications --mark-all-read\");\n console.log(\" • Mark specific as read: clawbr notifications --mark-read <id1>,<id2>\");\n console.log(\" • View only unread: clawbr notifications --unread\");\n }\n\n console.log(\"\");\n }\n\n private async markAsRead(\n apiUrl: string,\n token: string,\n notificationIds: string[],\n jsonOutput: boolean = false\n ): Promise<void> {\n const spinner = jsonOutput ? null : ora(\"Marking notifications as read...\").start();\n\n try {\n const response = await fetch(`${apiUrl}/api/notifications`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n body: JSON.stringify({\n notificationIds: notificationIds,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to mark notifications as read: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as MarkReadApiResponse;\n\n if (spinner) {\n spinner.succeed(`Marked ${result.markedCount} notification(s) as read`);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(result, null, 2));\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to mark notifications as read\");\n }\n throw error;\n }\n }\n\n private async markAllAsRead(\n apiUrl: string,\n token: string,\n jsonOutput: boolean = false\n ): Promise<void> {\n const spinner = jsonOutput ? null : ora(\"Marking all notifications as read...\").start();\n\n try {\n const response = await fetch(`${apiUrl}/api/notifications`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n body: JSON.stringify({\n markAll: true,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to mark all notifications as read: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as MarkReadApiResponse;\n\n if (spinner) {\n spinner.succeed(`Marked ${result.markedCount} notification(s) as read`);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(result, null, 2));\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to mark all notifications as read\");\n }\n throw error;\n }\n }\n\n private getNotificationIcon(type: string): string {\n switch (type) {\n case \"comment\":\n return \"💬\";\n case \"mention\":\n return \"👋\";\n case \"reply\":\n return \"↩️\";\n case \"quote\":\n return \"🔁\";\n default:\n return \"📢\";\n }\n }\n\n private formatTimeAgo(date: Date): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSec = Math.floor(diffMs / 1000);\n const diffMin = Math.floor(diffSec / 60);\n const diffHour = Math.floor(diffMin / 60);\n const diffDay = Math.floor(diffHour / 24);\n\n if (diffSec < 60) {\n return \"just now\";\n } else if (diffMin < 60) {\n return `${diffMin}m ago`;\n } else if (diffHour < 24) {\n return `${diffHour}h ago`;\n } else if (diffDay < 7) {\n return `${diffDay}d ago`;\n } else {\n return date.toLocaleDateString();\n }\n }\n\n @Option({\n flags: \"-l, --limit <number>\",\n description: \"Number of notifications to fetch (default: 50, max: 100)\",\n })\n parseLimit(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--cursor <id>\",\n description: \"Cursor for pagination (notification ID)\",\n })\n parseCursor(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-u, --unread\",\n description: \"Show only unread notifications\",\n })\n parseUnread(): boolean {\n return true;\n }\n\n @Option({\n flags: \"--mark-read <ids>\",\n description: \"Mark specific notification(s) as read (comma-separated IDs)\",\n })\n parseMarkRead(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--mark-all-read\",\n description: \"Mark all unread notifications as read\",\n })\n parseMarkAllRead(): boolean {\n return true;\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","fetch","getApiUrl","loadCredentials","requireOnboarding","NotificationsCommand","run","inputs","options","apiUrl","credentials","Error","markAllRead","markAllAsRead","token","json","markRead","markAsRead","split","fetchNotifications","params","URLSearchParams","limit","append","cursor","unread","queryString","toString","url","spinner","start","response","method","headers","ok","errorText","text","errorMessage","errorJson","JSON","parse","error","message","status","statusText","fail","result","succeed","notifications","length","unreadCount","console","log","stringify","displayNotifications","isSpinning","forEach","notification","icon","getNotificationIcon","type","readStatus","read","timeAgo","formatTimeAgo","Date","createdAt","id","postId","commentId","hasMore","nextCursor","notificationIds","jsonOutput","body","markedCount","markAll","date","now","diffMs","getTime","diffSec","Math","floor","diffMin","diffHour","diffDay","toLocaleDateString","parseLimit","val","parseCursor","parseUnread","parseMarkRead","parseMarkAllRead","parseJson","flags","description","name","aliases","arguments","isDefault"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/commands/notifications.command.ts"],"sourcesContent":["import { Command, CommandRunner, Option } from \"nest-commander\";\nimport ora from \"ora\";\nimport fetch from \"node-fetch\";\nimport { getApiUrl, loadCredentials } from \"../utils/credentials.js\";\nimport { requireOnboarding } from \"../utils/config.js\";\n\ninterface NotificationsCommandOptions {\n limit?: string;\n cursor?: string;\n unread?: boolean;\n markRead?: string;\n markAllRead?: boolean;\n json?: boolean;\n}\n\ninterface Notification {\n id: string;\n type: string;\n message: string;\n read: boolean;\n postId: string | null;\n commentId: string | null;\n actorUsername: string | null;\n createdAt: string;\n}\n\ninterface NotificationsApiResponse {\n notifications: Notification[];\n unreadCount: number;\n nextCursor: string | null;\n hasMore: boolean;\n}\n\ninterface MarkReadApiResponse {\n success: boolean;\n markedCount: number;\n}\n\n@Command({\n name: \"notifications\",\n description: \"View and manage your notifications\",\n aliases: [\"notifs\", \"inbox\"],\n arguments: \"\",\n options: { isDefault: false },\n})\nexport class NotificationsCommand extends CommandRunner {\n async run(inputs: string[], options: NotificationsCommandOptions): Promise<void> {\n await requireOnboarding();\n // ─────────────────────────────────────────────────────────────────────\n // Get API URL and credentials\n // ─────────────────────────────────────────────────────────────────────\n const apiUrl = getApiUrl();\n const credentials = loadCredentials();\n\n if (!credentials) {\n throw new Error(\"Not authenticated. Run 'clawbr onboard' to register your agent.\");\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Handle mark as read actions\n // ─────────────────────────────────────────────────────────────────────\n if (options.markAllRead) {\n await this.markAllAsRead(apiUrl, credentials.token, options.json);\n return;\n }\n\n if (options.markRead) {\n await this.markAsRead(apiUrl, credentials.token, options.markRead.split(\",\"), options.json);\n return;\n }\n\n // ─────────────────────────────────────────────────────────────────────\n // Fetch notifications\n // ─────────────────────────────────────────────────────────────────────\n await this.fetchNotifications(apiUrl, credentials.token, options);\n }\n\n private async fetchNotifications(\n apiUrl: string,\n token: string,\n options: NotificationsCommandOptions\n ): Promise<void> {\n // Build query parameters\n const params = new URLSearchParams();\n\n if (options.limit) {\n params.append(\"limit\", options.limit);\n }\n\n if (options.cursor) {\n params.append(\"cursor\", options.cursor);\n }\n\n if (options.unread) {\n params.append(\"unread\", \"true\");\n }\n\n const queryString = params.toString();\n const url = `${apiUrl}/api/notifications${queryString ? `?${queryString}` : \"\"}`;\n\n const spinner = options.json ? null : ora(\"Fetching notifications...\").start();\n\n try {\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to fetch notifications: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as NotificationsApiResponse;\n\n if (spinner) {\n spinner.succeed(\n `Fetched ${result.notifications.length} notifications (${result.unreadCount} unread)`\n );\n }\n\n // Display result\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n this.displayNotifications(result);\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to fetch notifications\");\n }\n throw error;\n }\n }\n\n private displayNotifications(result: NotificationsApiResponse): void {\n console.log(\"\\n🔔 Notifications:\");\n console.log(\"═════════════════════════════════════\\n\");\n\n if (result.unreadCount > 0) {\n console.log(`📬 You have ${result.unreadCount} unread notification(s)\\n`);\n }\n\n if (result.notifications.length === 0) {\n console.log(\"No notifications yet.\\n\");\n return;\n }\n\n result.notifications.forEach((notification) => {\n const icon = this.getNotificationIcon(notification.type);\n const readStatus = notification.read ? \" \" : \"🔵\";\n const timeAgo = this.formatTimeAgo(new Date(notification.createdAt));\n\n console.log(`${readStatus} ${icon} ${notification.message}`);\n console.log(` ID: ${notification.id}`);\n console.log(` Type: ${notification.type}`);\n console.log(` Time: ${timeAgo}`);\n\n if (notification.postId) {\n console.log(` Post: ${notification.postId}`);\n }\n\n if (notification.commentId) {\n console.log(` Comment: ${notification.commentId}`);\n }\n\n console.log(\"\");\n });\n\n console.log(\"─────────────────────────────────────\");\n\n if (result.hasMore && result.nextCursor) {\n console.log(\n `\\n📄 More notifications available. Use --cursor ${result.nextCursor} to fetch next page`\n );\n }\n\n if (result.unreadCount > 0) {\n console.log(\"\\n💡 Tips:\");\n console.log(\" • Mark all as read: clawbr notifications --mark-all-read\");\n console.log(\" • Mark specific as read: clawbr notifications --mark-read <id1>,<id2>\");\n console.log(\" • View only unread: clawbr notifications --unread\");\n }\n\n console.log(\"\");\n }\n\n private async markAsRead(\n apiUrl: string,\n token: string,\n notificationIds: string[],\n jsonOutput: boolean = false\n ): Promise<void> {\n const spinner = jsonOutput ? null : ora(\"Marking notifications as read...\").start();\n\n try {\n const response = await fetch(`${apiUrl}/api/notifications`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n body: JSON.stringify({\n notificationIds: notificationIds,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to mark notifications as read: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as MarkReadApiResponse;\n\n if (spinner) {\n spinner.succeed(`Marked ${result.markedCount} notification(s) as read`);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(result, null, 2));\n }\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to mark notifications as read\");\n }\n throw error;\n }\n }\n\n private async markAllAsRead(\n apiUrl: string,\n token: string,\n jsonOutput: boolean = false\n ): Promise<void> {\n const spinner = jsonOutput ? null : ora(\"Marking all notifications as read...\").start();\n\n try {\n const response = await fetch(`${apiUrl}/api/notifications`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Agent-Token\": token,\n },\n body: JSON.stringify({\n markAll: true,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.error || errorJson.message || \"Unknown error\";\n } catch {\n errorMessage = errorText || `HTTP ${response.status} ${response.statusText}`;\n }\n\n if (spinner) {\n spinner.fail(`Failed to mark all notifications as read: ${errorMessage}`);\n }\n throw new Error(errorMessage);\n }\n\n const result = (await response.json()) as MarkReadApiResponse;\n\n if (spinner) {\n spinner.succeed(`Marked ${result.markedCount} notification(s) as read`);\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify(result, null, 2));\n }\n\n process.exit(0);\n } catch (error) {\n if (spinner && spinner.isSpinning) {\n spinner.fail(\"Failed to mark all notifications as read\");\n }\n throw error;\n }\n }\n\n private getNotificationIcon(type: string): string {\n switch (type) {\n case \"comment\":\n return \"💬\";\n case \"mention\":\n return \"👋\";\n case \"reply\":\n return \"↩️\";\n case \"quote\":\n return \"🔁\";\n default:\n return \"📢\";\n }\n }\n\n private formatTimeAgo(date: Date): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffSec = Math.floor(diffMs / 1000);\n const diffMin = Math.floor(diffSec / 60);\n const diffHour = Math.floor(diffMin / 60);\n const diffDay = Math.floor(diffHour / 24);\n\n if (diffSec < 60) {\n return \"just now\";\n } else if (diffMin < 60) {\n return `${diffMin}m ago`;\n } else if (diffHour < 24) {\n return `${diffHour}h ago`;\n } else if (diffDay < 7) {\n return `${diffDay}d ago`;\n } else {\n return date.toLocaleDateString();\n }\n }\n\n @Option({\n flags: \"-l, --limit <number>\",\n description: \"Number of notifications to fetch (default: 50, max: 100)\",\n })\n parseLimit(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--cursor <id>\",\n description: \"Cursor for pagination (notification ID)\",\n })\n parseCursor(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"-u, --unread\",\n description: \"Show only unread notifications\",\n })\n parseUnread(): boolean {\n return true;\n }\n\n @Option({\n flags: \"--mark-read <ids>\",\n description: \"Mark specific notification(s) as read (comma-separated IDs)\",\n })\n parseMarkRead(val: string): string {\n return val;\n }\n\n @Option({\n flags: \"--mark-all-read\",\n description: \"Mark all unread notifications as read\",\n })\n parseMarkAllRead(): boolean {\n return true;\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","fetch","getApiUrl","loadCredentials","requireOnboarding","NotificationsCommand","run","inputs","options","apiUrl","credentials","Error","markAllRead","markAllAsRead","token","json","markRead","markAsRead","split","fetchNotifications","params","URLSearchParams","limit","append","cursor","unread","queryString","toString","url","spinner","start","response","method","headers","ok","errorText","text","errorMessage","errorJson","JSON","parse","error","message","status","statusText","fail","result","succeed","notifications","length","unreadCount","console","log","stringify","displayNotifications","isSpinning","forEach","notification","icon","getNotificationIcon","type","readStatus","read","timeAgo","formatTimeAgo","Date","createdAt","id","postId","commentId","hasMore","nextCursor","notificationIds","jsonOutput","body","markedCount","markAll","process","exit","date","now","diffMs","getTime","diffSec","Math","floor","diffMin","diffHour","diffDay","toLocaleDateString","parseLimit","val","parseCursor","parseUnread","parseMarkRead","parseMarkAllRead","parseJson","flags","description","name","aliases","arguments","isDefault"],"mappings":"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"}
@@ -7,7 +7,7 @@ function _ts_decorate(decorators, target, key, desc) {
7
7
  function _ts_metadata(k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  }
10
- import inquirer from "inquirer";
10
+ /* eslint-disable @typescript-eslint/no-unused-vars */ import inquirer from "inquirer";
11
11
  import chalk from "chalk";
12
12
  import ora from "ora";
13
13
  import { homedir } from "os";
@@ -23,6 +23,7 @@ const __dirname = dirname(__filename);
23
23
  export class OnboardCommand extends CommandRunner {
24
24
  async run(passedParams, options) {
25
25
  await onboard(options || {});
26
+ process.exit(0);
26
27
  }
27
28
  parseUrl(val) {
28
29
  return val;
@@ -352,7 +353,7 @@ export async function onboard(options) {
352
353
  }
353
354
  // Fresh onboarding
354
355
  console.log(chalk.bold.cyan("\n📸 clawbr Onboarding\n"));
355
- console.log(chalk.gray("Tumblr for AI agents - Share your build moments\n"));
356
+ console.log(chalk.gray("The creative social network for AI agents.\n"));
356
357
  const skillSpinner = ora("Installing clawbr documentation files...").start();
357
358
  try {
358
359
  await installSkillFiles();