@opendirectory.dev/skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/.claude/skills/claude-md-generator/.env.example +7 -0
  2. package/.claude/skills/claude-md-generator/README.md +78 -0
  3. package/.claude/skills/claude-md-generator/SKILL.md +248 -0
  4. package/.claude/skills/claude-md-generator/evals/evals.json +35 -0
  5. package/.claude/skills/claude-md-generator/references/section-guide.md +175 -0
  6. package/dist/e2e.test.d.ts +1 -0
  7. package/dist/e2e.test.js +62 -0
  8. package/dist/fs-adapters.d.ts +4 -0
  9. package/dist/fs-adapters.js +101 -0
  10. package/dist/fs-adapters.test.d.ts +1 -0
  11. package/dist/fs-adapters.test.js +108 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +211 -0
  14. package/dist/transformers.d.ts +6 -0
  15. package/dist/transformers.js +2 -0
  16. package/package.json +25 -0
  17. package/registry.json +226 -0
  18. package/skills/blog-cover-image-cli/.github/workflows/publish.yml +19 -0
  19. package/skills/blog-cover-image-cli/LICENSE +15 -0
  20. package/skills/blog-cover-image-cli/README.md +126 -0
  21. package/skills/blog-cover-image-cli/SKILL.md +7 -0
  22. package/skills/blog-cover-image-cli/agent-skill/blog-cover-generator/README.md +30 -0
  23. package/skills/blog-cover-image-cli/agent-skill/blog-cover-generator/SKILL.md +72 -0
  24. package/skills/blog-cover-image-cli/bin/cli.js +226 -0
  25. package/skills/blog-cover-image-cli/examples/100x_UX_Research_AI_Agent.png +0 -0
  26. package/skills/blog-cover-image-cli/examples/Firecrawl-supabase-bolt.png +0 -0
  27. package/skills/blog-cover-image-cli/examples/Git-City_Case_study_Cover_Image.jpg +0 -0
  28. package/skills/blog-cover-image-cli/examples/THE DISTRIBUTION LAYER (2).png +0 -0
  29. package/skills/blog-cover-image-cli/examples/canva-perplexity-duolingo-cover-image.png +0 -0
  30. package/skills/blog-cover-image-cli/examples/gamma-mistral-veed.png +0 -0
  31. package/skills/blog-cover-image-cli/examples/server-survival-case-study-cover-image(1).png +0 -0
  32. package/skills/blog-cover-image-cli/examples/viral-meme-automation.png +0 -0
  33. package/skills/blog-cover-image-cli/index.js +2 -0
  34. package/skills/blog-cover-image-cli/package-lock.json +2238 -0
  35. package/skills/blog-cover-image-cli/package.json +37 -0
  36. package/skills/blog-cover-image-cli/src/geminiGenerator.js +126 -0
  37. package/skills/blog-cover-image-cli/src/imageValidator.js +54 -0
  38. package/skills/blog-cover-image-cli/src/logoFetcher.js +86 -0
  39. package/skills/claude-md-generator/.env.example +7 -0
  40. package/skills/claude-md-generator/README.md +78 -0
  41. package/skills/claude-md-generator/SKILL.md +254 -0
  42. package/skills/claude-md-generator/evals/evals.json +35 -0
  43. package/skills/claude-md-generator/references/section-guide.md +175 -0
  44. package/skills/cook-the-blog/README.md +86 -0
  45. package/skills/cook-the-blog/SKILL.md +130 -0
  46. package/skills/dependency-update-bot/.env.example +13 -0
  47. package/skills/dependency-update-bot/README.md +101 -0
  48. package/skills/dependency-update-bot/SKILL.md +376 -0
  49. package/skills/dependency-update-bot/evals/evals.json +45 -0
  50. package/skills/dependency-update-bot/references/changelog-patterns.md +201 -0
  51. package/skills/docs-from-code/.env.example +13 -0
  52. package/skills/docs-from-code/README.md +97 -0
  53. package/skills/docs-from-code/SKILL.md +160 -0
  54. package/skills/docs-from-code/evals/evals.json +29 -0
  55. package/skills/docs-from-code/references/extraction-guide.md +174 -0
  56. package/skills/docs-from-code/references/output-template.md +135 -0
  57. package/skills/docs-from-code/scripts/extract_py.py +238 -0
  58. package/skills/docs-from-code/scripts/extract_ts.ts +284 -0
  59. package/skills/docs-from-code/scripts/package.json +18 -0
  60. package/skills/explain-this-pr/README.md +74 -0
  61. package/skills/explain-this-pr/SKILL.md +130 -0
  62. package/skills/explain-this-pr/evals/evals.json +35 -0
  63. package/skills/google-trends-api-skills/README.md +78 -0
  64. package/skills/google-trends-api-skills/SKILL.md +7 -0
  65. package/skills/google-trends-api-skills/google-trends-api/SKILL.md +163 -0
  66. package/skills/google-trends-api-skills/google-trends-api/references/api-responses.md +188 -0
  67. package/skills/google-trends-api-skills/google-trends-api/scripts/discover_keywords.py +344 -0
  68. package/skills/google-trends-api-skills/seo-keyword-research/SKILL.md +205 -0
  69. package/skills/google-trends-api-skills/seo-keyword-research/references/keyword-placement-guide.md +89 -0
  70. package/skills/google-trends-api-skills/seo-keyword-research/references/tech-blog-examples.md +207 -0
  71. package/skills/google-trends-api-skills/seo-keyword-research/scripts/blog_seo_research.py +373 -0
  72. package/skills/hackernews-intel/.env.example +33 -0
  73. package/skills/hackernews-intel/README.md +161 -0
  74. package/skills/hackernews-intel/SKILL.md +156 -0
  75. package/skills/hackernews-intel/evals/evals.json +35 -0
  76. package/skills/hackernews-intel/package.json +15 -0
  77. package/skills/hackernews-intel/scripts/monitor-hn.js +258 -0
  78. package/skills/kill-the-standup/.env.example +22 -0
  79. package/skills/kill-the-standup/README.md +84 -0
  80. package/skills/kill-the-standup/SKILL.md +169 -0
  81. package/skills/kill-the-standup/evals/evals.json +35 -0
  82. package/skills/kill-the-standup/references/standup-format.md +102 -0
  83. package/skills/linkedin-post-generator/.env.example +14 -0
  84. package/skills/linkedin-post-generator/README.md +107 -0
  85. package/skills/linkedin-post-generator/SKILL.md +228 -0
  86. package/skills/linkedin-post-generator/evals/evals.json +35 -0
  87. package/skills/linkedin-post-generator/references/linkedin-format.md +216 -0
  88. package/skills/linkedin-post-generator/references/output-template.md +154 -0
  89. package/skills/llms-txt-generator/.env.example +18 -0
  90. package/skills/llms-txt-generator/README.md +142 -0
  91. package/skills/llms-txt-generator/SKILL.md +176 -0
  92. package/skills/llms-txt-generator/evals/evals.json +35 -0
  93. package/skills/llms-txt-generator/references/llms-txt-spec.md +88 -0
  94. package/skills/llms-txt-generator/references/output-template.md +76 -0
  95. package/skills/llms-txt-generator/test-output/genzcareer.in/llms.txt +31 -0
  96. package/skills/luma-attendees-scraper/README.md +170 -0
  97. package/skills/luma-attendees-scraper/SKILL.md +7 -0
  98. package/skills/luma-attendees-scraper/luma_attendees_export.js +223 -0
  99. package/skills/meeting-brief-generator/.env.example +21 -0
  100. package/skills/meeting-brief-generator/README.md +90 -0
  101. package/skills/meeting-brief-generator/SKILL.md +275 -0
  102. package/skills/meeting-brief-generator/evals/evals.json +35 -0
  103. package/skills/meeting-brief-generator/references/brief-format.md +114 -0
  104. package/skills/meeting-brief-generator/references/output-template.md +150 -0
  105. package/skills/meta-ads-skill/README.md +100 -0
  106. package/skills/meta-ads-skill/SKILL.md +7 -0
  107. package/skills/meta-ads-skill/meta-ads-skill/SKILL.md +41 -0
  108. package/skills/meta-ads-skill/meta-ads-skill/references/report_templates.md +47 -0
  109. package/skills/meta-ads-skill/meta-ads-skill/references/workflows.md +51 -0
  110. package/skills/meta-ads-skill/meta-ads-skill/scripts/auth_check.py +22 -0
  111. package/skills/meta-ads-skill/meta-ads-skill/scripts/formatters.py +46 -0
  112. package/skills/newsletter-digest/.env.example +20 -0
  113. package/skills/newsletter-digest/README.md +147 -0
  114. package/skills/newsletter-digest/SKILL.md +221 -0
  115. package/skills/newsletter-digest/evals/evals.json +35 -0
  116. package/skills/newsletter-digest/feeds.json +7 -0
  117. package/skills/newsletter-digest/package.json +15 -0
  118. package/skills/newsletter-digest/references/digest-format.md +123 -0
  119. package/skills/newsletter-digest/references/output-template.md +136 -0
  120. package/skills/newsletter-digest/scripts/fetch-feeds.js +141 -0
  121. package/skills/newsletter-digest/scripts/ghost-publish.js +147 -0
  122. package/skills/noise2blog/.env.example +16 -0
  123. package/skills/noise2blog/README.md +107 -0
  124. package/skills/noise2blog/SKILL.md +229 -0
  125. package/skills/noise2blog/evals/evals.json +35 -0
  126. package/skills/noise2blog/references/blog-format.md +188 -0
  127. package/skills/noise2blog/references/output-template.md +184 -0
  128. package/skills/outreach-sequence-builder/.env.example +12 -0
  129. package/skills/outreach-sequence-builder/README.md +108 -0
  130. package/skills/outreach-sequence-builder/SKILL.md +248 -0
  131. package/skills/outreach-sequence-builder/evals/evals.json +36 -0
  132. package/skills/outreach-sequence-builder/references/output-template.md +171 -0
  133. package/skills/outreach-sequence-builder/references/sequence-format.md +167 -0
  134. package/skills/outreach-sequence-builder/references/signal-playbook.md +117 -0
  135. package/skills/position-me/README.md +71 -0
  136. package/skills/position-me/SKILL.md +7 -0
  137. package/skills/position-me/position-me/SKILL.md +50 -0
  138. package/skills/position-me/position-me/references/EVALUATION_SOP.md +40 -0
  139. package/skills/position-me/position-me/references/REPORT_TEMPLATE.md +58 -0
  140. package/skills/position-me/position-me/scripts/extract_links.py +49 -0
  141. package/skills/pr-description-writer/README.md +81 -0
  142. package/skills/pr-description-writer/SKILL.md +141 -0
  143. package/skills/pr-description-writer/evals/evals.json +35 -0
  144. package/skills/pr-description-writer/references/pr-format-guide.md +145 -0
  145. package/skills/producthunt-launch-kit/.env.example +7 -0
  146. package/skills/producthunt-launch-kit/README.md +95 -0
  147. package/skills/producthunt-launch-kit/SKILL.md +380 -0
  148. package/skills/producthunt-launch-kit/evals/evals.json +35 -0
  149. package/skills/producthunt-launch-kit/references/copy-rules.md +124 -0
  150. package/skills/reddit-icp-monitor/.env.example +16 -0
  151. package/skills/reddit-icp-monitor/README.md +117 -0
  152. package/skills/reddit-icp-monitor/SKILL.md +271 -0
  153. package/skills/reddit-icp-monitor/evals/evals.json +40 -0
  154. package/skills/reddit-icp-monitor/references/icp-format.md +131 -0
  155. package/skills/reddit-icp-monitor/references/reply-rules.md +110 -0
  156. package/skills/reddit-post-engine/.env.example +13 -0
  157. package/skills/reddit-post-engine/README.md +103 -0
  158. package/skills/reddit-post-engine/SKILL.md +303 -0
  159. package/skills/reddit-post-engine/evals/evals.json +35 -0
  160. package/skills/reddit-post-engine/references/subreddit-playbook.md +156 -0
  161. package/skills/schema-markup-generator/.env.example +19 -0
  162. package/skills/schema-markup-generator/README.md +114 -0
  163. package/skills/schema-markup-generator/SKILL.md +192 -0
  164. package/skills/schema-markup-generator/evals/evals.json +35 -0
  165. package/skills/schema-markup-generator/references/json-ld-spec.md +263 -0
  166. package/skills/schema-markup-generator/references/output-template.md +556 -0
  167. package/skills/show-hn-writer/.env.example +14 -0
  168. package/skills/show-hn-writer/README.md +88 -0
  169. package/skills/show-hn-writer/SKILL.md +303 -0
  170. package/skills/show-hn-writer/evals/evals.json +35 -0
  171. package/skills/show-hn-writer/references/hn-rules.md +74 -0
  172. package/skills/show-hn-writer/references/title-formulas.md +93 -0
  173. package/skills/stargazer/README.md +79 -0
  174. package/skills/stargazer/SKILL.md +7 -0
  175. package/skills/stargazer/stargazer-skill/SKILL.md +58 -0
  176. package/skills/stargazer/stargazer-skill/assets/.env.example +18 -0
  177. package/skills/stargazer/stargazer-skill/scripts/convert_to_csv.py +63 -0
  178. package/skills/stargazer/stargazer-skill/scripts/count_emails.py +52 -0
  179. package/skills/stargazer/stargazer-skill/scripts/stargazer_deep_extractor.py +450 -0
  180. package/skills/tweet-thread-from-blog/.env.example +14 -0
  181. package/skills/tweet-thread-from-blog/README.md +109 -0
  182. package/skills/tweet-thread-from-blog/SKILL.md +177 -0
  183. package/skills/tweet-thread-from-blog/evals/evals.json +35 -0
  184. package/skills/tweet-thread-from-blog/references/output-template.md +193 -0
  185. package/skills/tweet-thread-from-blog/references/thread-format.md +107 -0
  186. package/skills/twitter-GTM-find-skill/README.md +43 -0
  187. package/skills/twitter-GTM-find-skill/SKILL.md +7 -0
  188. package/skills/twitter-GTM-find-skill/twitter-GTM-find/SKILL.md +37 -0
  189. package/skills/twitter-GTM-find-skill/twitter-GTM-find/references/icp-checklist.md +35 -0
  190. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/package.json +23 -0
  191. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/run_pipeline.sh +8 -0
  192. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/debug.ts +23 -0
  193. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/extractor.ts +79 -0
  194. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/icp-filter.ts +87 -0
  195. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/index.ts +94 -0
  196. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/src/scraper.ts +41 -0
  197. package/skills/twitter-GTM-find-skill/twitter-GTM-find/scripts/tsconfig.json +13 -0
  198. package/skills/yc-intent-radar-skill/README.md +39 -0
  199. package/skills/yc-intent-radar-skill/SKILL.md +7 -0
  200. package/skills/yc-intent-radar-skill/yc-jobs-scraper/SKILL.md +59 -0
  201. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/auth.js +29 -0
  202. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/db.js +62 -0
  203. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/export_radar_candidates.js +40 -0
  204. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/package-lock.json +1525 -0
  205. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/package.json +12 -0
  206. package/skills/yc-intent-radar-skill/yc-jobs-scraper/scripts/scraper.js +217 -0
  207. package/src/e2e.test.ts +35 -0
  208. package/src/fs-adapters.test.ts +91 -0
  209. package/src/fs-adapters.ts +65 -0
  210. package/src/index.ts +182 -0
  211. package/src/transformers.ts +6 -0
  212. package/tsconfig.json +8 -0
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import gradient from 'gradient-string';
6
+ import figlet from 'figlet';
7
+ import Conf from 'conf';
8
+ import { password } from '@inquirer/prompts';
9
+ import { writeFile, mkdir } from 'node:fs/promises';
10
+ import path from 'node:path';
11
+ import { generateCoverImage } from '../src/geminiGenerator.js';
12
+ import { fetchLogo } from '../src/logoFetcher.js';
13
+ import { validateImage } from '../src/imageValidator.js';
14
+
15
+ const config = new Conf({ projectName: 'blog-cover-image-cli' });
16
+ const program = new Command();
17
+
18
+ // Display banner
19
+ console.log(
20
+ gradient(['#00ff00', '#00cc00', '#009900']).multiline(
21
+ figlet.textSync('Blog Cover CLI', { font: 'ANSI Shadow', horizontalLayout: 'full' })
22
+ )
23
+ );
24
+
25
+ async function getApiKey() {
26
+ let apiKey = config.get('GEMINI_API_KEY');
27
+ if (!apiKey) {
28
+ console.log(chalk.yellow('Gemini API Key not found.'));
29
+ try {
30
+ apiKey = await password({
31
+ message: 'Enter your Gemini API Key:',
32
+ validate: (value) => value.length > 0 || 'API Key cannot be empty',
33
+ });
34
+ config.set('GEMINI_API_KEY', apiKey);
35
+ console.log(chalk.green('API Key saved successfully.'));
36
+ } catch (error) {
37
+ if (error.name === 'ExitPromptError') {
38
+ console.log(chalk.red('\nOperation cancelled.'));
39
+ process.exit(0);
40
+ }
41
+ throw error;
42
+ }
43
+ }
44
+ return apiKey;
45
+ }
46
+ async function getBrandfetchId() {
47
+ let brandfetchId = config.get('BRANDFETCH_CLIENT_ID');
48
+ if (!brandfetchId) {
49
+ console.log(chalk.yellow('Brandfetch Client ID not found.'));
50
+ try {
51
+ brandfetchId = await password({
52
+ message: 'Enter your Brandfetch Client ID:',
53
+ validate: (value) => value.length > 0 || 'Client ID cannot be empty',
54
+ });
55
+ config.set('BRANDFETCH_CLIENT_ID', brandfetchId);
56
+ console.log(chalk.green('Brandfetch Client ID saved successfully.'));
57
+ } catch (error) {
58
+ if (error.name === 'ExitPromptError') {
59
+ console.log(chalk.red('\nOperation cancelled.'));
60
+ process.exit(0);
61
+ }
62
+ throw error;
63
+ }
64
+ }
65
+ return brandfetchId;
66
+ }
67
+
68
+
69
+ program
70
+ .name('blog-cover-cli')
71
+ .description('CLI to generate blog cover images using Gemini')
72
+ .version('1.0.0');
73
+
74
+ const configCmd = program.command('config').description('Manage configuration');
75
+
76
+ configCmd
77
+ .command('set-key')
78
+ .description('Set Gemini API Key')
79
+ .argument('<key>', 'Gemini API Key')
80
+ .action((key) => {
81
+ config.set('GEMINI_API_KEY', key);
82
+ console.log(chalk.green('Gemini API Key updated.'));
83
+ });
84
+
85
+ configCmd
86
+ .command('get-key')
87
+ .description('Get Gemini API Key (masked)')
88
+ .action(() => {
89
+ const key = config.get('GEMINI_API_KEY');
90
+ if (key) {
91
+ const masked = key.slice(0, 4) + '*'.repeat(key.length - 8) + key.slice(-4);
92
+ console.log(`GEMINI_API_KEY: ${chalk.blue(masked)}`);
93
+ } else {
94
+ console.log(chalk.yellow('No API Key set.'));
95
+ }
96
+ });
97
+
98
+ configCmd
99
+ .command('delete-key')
100
+ .description('Delete Gemini API Key')
101
+ .action(() => {
102
+ config.delete('GEMINI_API_KEY');
103
+ console.log(chalk.green('Gemini API Key deleted.'));
104
+ });
105
+ configCmd
106
+ .command('set-brandfetch-id')
107
+ .description('Set Brandfetch Client ID')
108
+ .argument('<id>', 'Brandfetch Client ID')
109
+ .action((id) => {
110
+ config.set('BRANDFETCH_CLIENT_ID', id);
111
+ console.log(chalk.green('Brandfetch Client ID updated.'));
112
+ });
113
+
114
+ configCmd
115
+ .command('get-brandfetch-id')
116
+ .description('Get Brandfetch Client ID (masked)')
117
+ .action(() => {
118
+ const id = config.get('BRANDFETCH_CLIENT_ID');
119
+ if (id) {
120
+ const masked = id.slice(0, 4) + '*'.repeat(Math.max(0, id.length - 8)) + id.slice(-4);
121
+ console.log(`BRANDFETCH_CLIENT_ID: ${chalk.blue(masked)}`);
122
+ } else {
123
+ console.log(chalk.yellow('No Brandfetch Client ID set.'));
124
+ }
125
+ });
126
+
127
+ configCmd
128
+ .command('delete-brandfetch-id')
129
+ .description('Delete Brandfetch Client ID')
130
+ .action(() => {
131
+ config.delete('BRANDFETCH_CLIENT_ID');
132
+ console.log(chalk.green('Brandfetch Client ID deleted.'));
133
+ });
134
+
135
+
136
+ program
137
+ .command('generate', { isDefault: true })
138
+ .description('Generate a blog cover image')
139
+ .option('-t, --title <title>', 'Blog post title')
140
+ .option('-l, --logo <logo>', 'Logo domain or URL')
141
+ .option('-o, --output <path>', 'Output file path')
142
+ .action(async (options) => {
143
+ try {
144
+ let { title, logo, output } = options;
145
+
146
+ if (!title) {
147
+ console.error(chalk.red('Error: Title is required. Use -t or --title.'));
148
+ process.exit(1);
149
+ }
150
+
151
+ const apiKey = await getApiKey();
152
+
153
+ console.log(chalk.blue('Fetching logo...'));
154
+ let logoData = null;
155
+ if (logo) {
156
+ const brandfetchId = await getBrandfetchId();
157
+ logoData = await fetchLogo(logo, brandfetchId);
158
+ if (!logoData) {
159
+ console.log(chalk.yellow(`Warning: Could not fetch logo for "${logo}". Proceeding without logo.`));
160
+ }
161
+ }
162
+
163
+ console.log(chalk.blue('Generating image...'));
164
+
165
+ const MAX_RETRIES = 3;
166
+ let attempt = 1;
167
+ let criticalFeedback = null;
168
+ let finalImage = null;
169
+ let finalOutput = null;
170
+ let validation = { isValid: false, issues: '' };
171
+
172
+ while (attempt <= MAX_RETRIES) {
173
+ const { base64Image, textOutput } = await generateCoverImage(title, logoData, apiKey, criticalFeedback);
174
+
175
+ console.log(chalk.blue(`Validating image (Attempt ${attempt}/${MAX_RETRIES})...`));
176
+ validation = await validateImage(base64Image, title, !!logoData, apiKey);
177
+
178
+ finalImage = base64Image;
179
+ finalOutput = textOutput;
180
+
181
+ if (validation.isValid) {
182
+ break;
183
+ } else if (attempt < MAX_RETRIES) {
184
+ console.log(chalk.yellow(`QA Failed: ${validation.issues}. Regenerating (Attempt ${attempt + 1}/${MAX_RETRIES})...`));
185
+ criticalFeedback = validation.issues;
186
+ }
187
+ attempt++;
188
+ }
189
+
190
+ if (!validation.isValid) {
191
+ console.log(chalk.red(`\nWarning: QA failed after ${MAX_RETRIES} attempts. Saving the last generated image anyway.`));
192
+ console.log(chalk.yellow(`Final issues: ${validation.issues}`));
193
+ }
194
+
195
+ if (!output) {
196
+ // Smart default filename inside an "output" directory
197
+ const namePart = logo ? logo.split('.')[0] : title.toLowerCase().replace(/[^a-z0-9]/g, '-').slice(0, 20);
198
+ output = path.join(process.cwd(), 'output', `${namePart}-cover.png`);
199
+ } else {
200
+ output = path.resolve(process.cwd(), output);
201
+ }
202
+
203
+ // Ensure directory exists
204
+ await mkdir(path.dirname(output), { recursive: true });
205
+
206
+ const buffer = Buffer.from(finalImage, 'base64');
207
+ await writeFile(output, buffer);
208
+
209
+ console.log(chalk.green(`\nSuccess! Image saved to: ${chalk.bold(output)}`));
210
+ if (finalOutput.trim()) {
211
+ console.log(chalk.gray('\nGemini Output:'));
212
+ console.log(finalOutput);
213
+ }
214
+ } catch (error) {
215
+ console.error(chalk.red('\nError:'), error.message);
216
+ process.exit(1);
217
+ }
218
+ });
219
+
220
+ // Handle Ctrl+C
221
+ process.on('SIGINT', () => {
222
+ console.log(chalk.red('\nProcess terminated.'));
223
+ process.exit(0);
224
+ });
225
+
226
+ program.parse();
@@ -0,0 +1,2 @@
1
+ export { generateCoverImage } from './src/geminiGenerator.js';
2
+ export { fetchLogo } from './src/logoFetcher.js';