@hasna/skills 0.1.26 ā 0.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -10
- package/README.md +141 -39
- package/bin/index.js +30122 -27575
- package/bin/mcp.js +22112 -18593
- package/dist/cli/cli.test-utils.d.ts +15 -0
- package/dist/cli/commands/auth.d.ts +2 -0
- package/dist/cli/commands/install.d.ts +1 -1
- package/dist/cli/commands/runtime-mcp.d.ts +4 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +11607 -597
- package/dist/lib/auth-store.d.ts +13 -0
- package/dist/lib/installer.d.ts +58 -55
- package/dist/lib/mcp-contracts.d.ts +86 -0
- package/dist/lib/project-state.d.ts +43 -0
- package/dist/lib/registry-data/business-marketing.d.ts +2 -0
- package/dist/lib/registry-data/communication.d.ts +2 -0
- package/dist/lib/registry-data/content-generation.d.ts +2 -0
- package/dist/lib/registry-data/data-analysis.d.ts +2 -0
- package/dist/lib/registry-data/design-branding.d.ts +2 -0
- package/dist/lib/registry-data/development-tools.d.ts +2 -0
- package/dist/lib/registry-data/education-learning.d.ts +2 -0
- package/dist/lib/registry-data/event-management.d.ts +2 -0
- package/dist/lib/registry-data/finance-compliance.d.ts +2 -0
- package/dist/lib/registry-data/health-wellness.d.ts +2 -0
- package/dist/lib/registry-data/index.d.ts +2 -0
- package/dist/lib/registry-data/media-processing.d.ts +2 -0
- package/dist/lib/registry-data/productivity-organization.d.ts +2 -0
- package/dist/lib/registry-data/project-management.d.ts +2 -0
- package/dist/lib/registry-data/research-writing.d.ts +2 -0
- package/dist/lib/registry-data/science-academic.d.ts +2 -0
- package/dist/lib/registry-data/travel-lifestyle.d.ts +2 -0
- package/dist/lib/registry-data/web-browser.d.ts +2 -0
- package/dist/lib/registry-types.d.ts +27 -0
- package/dist/lib/registry.d.ts +6 -18
- package/dist/lib/remote-registry.d.ts +3 -0
- package/dist/lib/run-state.d.ts +60 -0
- package/dist/lib/skill-aliases.d.ts +17 -0
- package/dist/lib/skillinfo.d.ts +5 -1
- package/dist/mcp/discovery-tools.d.ts +2 -0
- package/dist/mcp/helpers.d.ts +26 -0
- package/dist/mcp/http.d.ts +10 -0
- package/dist/mcp/index.d.ts +3 -2
- package/dist/mcp/operation-tools.d.ts +2 -0
- package/dist/mcp/resource-meta-tools.d.ts +2 -0
- package/dist/mcp/schedule-tools.d.ts +2 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/types/api.d.ts +7 -4
- package/package.json +23 -10
- package/skills/_common/http-client.ts +1 -1
- package/skills/_common/index.ts +2 -3
- package/skills/_common/install.sh +5 -110
- package/skills/_common/installer.ts +31 -282
- package/skills/_common/skill-install.ts +14 -181
- package/skills/ad-creative-pack/SKILL.md +45 -0
- package/skills/ad-creative-pack/package.json +14 -0
- package/skills/advanced-math/package.json +3 -1
- package/skills/advanced-math/src/calculators.ts +118 -0
- package/skills/advanced-math/src/cli.ts +130 -0
- package/skills/advanced-math/src/conversion.ts +90 -0
- package/skills/advanced-math/src/finance.ts +75 -0
- package/skills/advanced-math/src/formatting.ts +95 -0
- package/skills/advanced-math/src/index.ts +24 -702
- package/skills/advanced-math/src/runtime.ts +49 -0
- package/skills/advanced-math/src/symbolic.ts +110 -0
- package/skills/advanced-math/src/types.ts +36 -0
- package/skills/analyze-data/SKILL.md +2 -2
- package/skills/analyze-data/src/analysis.ts +401 -0
- package/skills/analyze-data/src/cli.ts +66 -0
- package/skills/analyze-data/src/formatters.ts +235 -0
- package/skills/analyze-data/src/index.ts +6 -1027
- package/skills/analyze-data/src/logger.ts +36 -0
- package/skills/analyze-data/src/parsers.ts +57 -0
- package/skills/analyze-data/src/stats.ts +151 -0
- package/skills/analyze-data/src/types.ts +85 -0
- package/skills/api-docs-portal/SKILL.md +46 -0
- package/skills/api-docs-portal/package.json +9 -0
- package/skills/api-test-suite/src/index.ts +13 -0
- package/skills/apidocs/package.json +1 -1
- package/skills/apidocs/src/index.ts +3 -0
- package/skills/audio/package.json +2 -3
- package/skills/audio-cleanup-lab/SKILL.md +2 -2
- package/skills/audio-extract/CLAUDE.md +1 -1
- package/skills/audio-transcript-pack/SKILL.md +43 -0
- package/skills/audio-transcript-pack/package.json +10 -0
- package/skills/blog-article/CLAUDE.md +12 -0
- package/skills/blog-article/SKILL.md +45 -0
- package/skills/{create-blog-article ā blog-article}/package.json +3 -3
- package/skills/brand-kit/SKILL.md +45 -0
- package/skills/brand-kit/package.json +14 -0
- package/skills/brand-photo-shoot/SKILL.md +28 -0
- package/skills/brand-photo-shoot/package.json +10 -0
- package/skills/brand-style-guide/SKILL.md +2 -2
- package/skills/brand-style-guide/src/index.ts +0 -0
- package/skills/budget-variance-analyzer/SKILL.md +2 -2
- package/skills/businessactivity/package.json +1 -1
- package/skills/businessactivity/src/index.ts +3 -0
- package/skills/calendar-events/src/ai-parser.ts +103 -0
- package/skills/calendar-events/src/api.ts +157 -0
- package/skills/calendar-events/src/auth.ts +22 -0
- package/skills/calendar-events/src/config.ts +6 -0
- package/skills/calendar-events/src/format.ts +96 -0
- package/skills/calendar-events/src/help.ts +54 -0
- package/skills/calendar-events/src/index.ts +21 -524
- package/skills/calendar-events/src/logger.ts +34 -0
- package/skills/calendar-events/src/types.ts +67 -0
- package/skills/compress-video/SKILL.md +2 -2
- package/skills/consolelog/package.json +1 -1
- package/skills/consolelog/src/index.ts +3 -0
- package/skills/contract-review-report/SKILL.md +43 -0
- package/skills/contract-review-report/package.json +10 -0
- package/skills/convert/SKILL.md +2 -3
- package/skills/customer-feedback-report/SKILL.md +44 -0
- package/skills/customer-feedback-report/package.json +10 -0
- package/skills/dashboard-builder/package.json +3 -1
- package/skills/database-explorer/package.json +3 -1
- package/skills/deepresearch/README.md +4 -13
- package/skills/deploy/src/http-client.ts +1 -1
- package/skills/diff-viewer/package.json +4 -1
- package/skills/doc-generate/package.json +0 -1
- package/skills/doc-generate/src/ai.ts +50 -0
- package/skills/doc-generate/src/cli.ts +203 -0
- package/skills/doc-generate/src/dependencies.ts +44 -0
- package/skills/doc-generate/src/document-builder.ts +299 -0
- package/skills/doc-generate/src/index.ts +40 -764
- package/skills/doc-generate/src/markdown-parser.ts +125 -0
- package/skills/doc-generate/src/types.ts +68 -0
- package/skills/domainpurchase/SKILL.md +1 -1
- package/skills/domainpurchase/package.json +1 -1
- package/skills/domainpurchase/src/index.ts +3 -0
- package/skills/domainsearch/SKILL.md +1 -1
- package/skills/domainsearch/package.json +1 -1
- package/skills/domainsearch/src/index.ts +3 -0
- package/skills/email-sequence/SKILL.md +44 -0
- package/skills/email-sequence/package.json +14 -0
- package/skills/excel/CLAUDE.md +2 -2
- package/skills/experiment-power-calculator/package.json +3 -1
- package/skills/extract-invoice/src/cli.ts +97 -0
- package/skills/extract-invoice/src/extractor.ts +170 -0
- package/skills/extract-invoice/src/file-utils.ts +46 -0
- package/skills/extract-invoice/src/formatters.ts +144 -0
- package/skills/extract-invoice/src/index.ts +44 -629
- package/skills/extract-invoice/src/runtime.ts +46 -0
- package/skills/extract-invoice/src/types.ts +88 -0
- package/skills/folder-tree/package.json +3 -1
- package/skills/form-filler/package.json +3 -1
- package/skills/generate-api-client/package.json +3 -1
- package/skills/generate-api-client/src/generator.ts +47 -0
- package/skills/generate-api-client/src/index.ts +3 -777
- package/skills/generate-api-client/src/logger.ts +34 -0
- package/skills/generate-api-client/src/python-generator.ts +245 -0
- package/skills/generate-api-client/src/spec-loader.ts +48 -0
- package/skills/generate-api-client/src/type-mappers.ts +79 -0
- package/skills/generate-api-client/src/types.ts +76 -0
- package/skills/generate-api-client/src/typescript-generator.ts +247 -0
- package/skills/generate-book-cover/package.json +3 -1
- package/skills/generate-dockerfile/src/cli.ts +78 -0
- package/skills/generate-dockerfile/src/dockerfile-templates.ts +392 -0
- package/skills/generate-dockerfile/src/index.ts +12 -790
- package/skills/generate-dockerfile/src/logger.ts +30 -0
- package/skills/generate-dockerfile/src/project-detection.ts +68 -0
- package/skills/generate-dockerfile/src/support-files.ts +171 -0
- package/skills/generate-dockerfile/src/types.ts +29 -0
- package/skills/generate-documentation/src/ai.ts +131 -0
- package/skills/generate-documentation/src/cli.ts +71 -0
- package/skills/generate-documentation/src/code-parser.ts +300 -0
- package/skills/generate-documentation/src/file-processing.ts +182 -0
- package/skills/generate-documentation/src/index.ts +13 -753
- package/skills/generate-documentation/src/runtime.ts +35 -0
- package/skills/generate-documentation/src/types.ts +30 -0
- package/skills/generate-env/package.json +3 -1
- package/skills/generate-env/src/cli.ts +85 -0
- package/skills/generate-env/src/detection.ts +161 -0
- package/skills/generate-env/src/env-data.ts +66 -0
- package/skills/generate-env/src/generators.ts +240 -0
- package/skills/generate-env/src/index.ts +76 -676
- package/skills/generate-env/src/runtime.ts +30 -0
- package/skills/generate-env/src/types.ts +32 -0
- package/skills/generate-favicon/package.json +3 -1
- package/skills/generate-mock-data/package.json +3 -1
- package/skills/generate-mock-data/src/ai.ts +102 -0
- package/skills/generate-mock-data/src/formatters.ts +84 -0
- package/skills/generate-mock-data/src/generator.ts +377 -0
- package/skills/generate-mock-data/src/index.ts +15 -716
- package/skills/generate-mock-data/src/logger.ts +37 -0
- package/skills/generate-mock-data/src/presets.ts +110 -0
- package/skills/generate-mock-data/src/types.ts +21 -0
- package/skills/generate-pr-description/src/ai.ts +144 -0
- package/skills/generate-pr-description/src/cli.ts +80 -0
- package/skills/generate-pr-description/src/clipboard.ts +30 -0
- package/skills/generate-pr-description/src/formatters.ts +231 -0
- package/skills/generate-pr-description/src/git.ts +153 -0
- package/skills/generate-pr-description/src/index.ts +21 -714
- package/skills/generate-pr-description/src/types.ts +49 -0
- package/skills/generate-presentation/src/ai-clients.ts +61 -0
- package/skills/generate-presentation/src/cli.ts +126 -0
- package/skills/generate-presentation/src/index.ts +3 -751
- package/skills/generate-presentation/src/logger.ts +67 -0
- package/skills/generate-presentation/src/presentation-generator.ts +425 -0
- package/skills/generate-presentation/src/runtime.ts +6 -0
- package/skills/generate-presentation/src/security.ts +12 -0
- package/skills/generate-presentation/src/types.ts +28 -0
- package/skills/generate-qrcode/package.json +4 -1
- package/skills/generate-regex/package.json +3 -1
- package/skills/generate-resume/src/cli.ts +157 -0
- package/skills/generate-resume/src/index.ts +13 -917
- package/skills/generate-resume/src/parsers.ts +95 -0
- package/skills/generate-resume/src/renderers.ts +538 -0
- package/skills/generate-resume/src/security.ts +39 -0
- package/skills/generate-resume/src/types.ts +86 -0
- package/skills/generate-social-posts/src/ai.ts +88 -0
- package/skills/generate-social-posts/src/cli.ts +118 -0
- package/skills/generate-social-posts/src/exporters.ts +126 -0
- package/skills/generate-social-posts/src/generator.ts +130 -0
- package/skills/generate-social-posts/src/index.ts +19 -709
- package/skills/generate-social-posts/src/platforms.ts +39 -0
- package/skills/generate-social-posts/src/runtime.ts +34 -0
- package/skills/generate-social-posts/src/source.ts +116 -0
- package/skills/generate-social-posts/src/types.ts +58 -0
- package/skills/gif-maker/package.json +4 -1
- package/skills/github-manager/package.json +3 -1
- package/skills/gmail/CLAUDE.md +1 -1
- package/skills/highlight-reel-generator/src/index.ts +19 -0
- package/skills/hook/src/commands/create.ts +20 -845
- package/skills/hook/src/templates/root.ts +196 -0
- package/skills/hook/src/templates/source.ts +647 -0
- package/skills/http-server/package.json +3 -1
- package/skills/icon-pack/README.md +28 -0
- package/skills/icon-pack/SKILL.md +23 -0
- package/skills/icon-pack/package.json +29 -0
- package/skills/{audio ā icon-pack}/tsconfig.json +10 -12
- package/skills/image/package.json +1 -2
- package/skills/implementation-agent/package.json +3 -1
- package/skills/implementation-agent/src/ai-generation.ts +225 -0
- package/skills/implementation-agent/src/index.ts +3 -960
- package/skills/implementation-agent/src/minimist.d.ts +15 -0
- package/skills/implementation-agent/src/templates.ts +686 -0
- package/skills/implementation-agent/src/types.ts +53 -0
- package/skills/implementation-plan/package.json +3 -1
- package/skills/implementation-todo/package.json +3 -1
- package/skills/invoice/package.json +1 -1
- package/skills/invoice/src/index.ts +3 -0
- package/skills/invoice-reconciliation/SKILL.md +42 -0
- package/skills/invoice-reconciliation/package.json +10 -0
- package/skills/landing-page-pack/SKILL.md +47 -0
- package/skills/landing-page-pack/package.json +14 -0
- package/skills/latex-table-generator/package.json +3 -1
- package/skills/logo-design/SKILL.md +25 -44
- package/skills/logo-design/package.json +3 -15
- package/skills/lorem-generator/package.json +3 -1
- package/skills/lorem-generator/src/index.ts +13 -0
- package/skills/managehook/package.json +1 -1
- package/skills/managehook/src/index.ts +3 -0
- package/skills/managemcp/package.json +1 -1
- package/skills/managemcp/src/index.ts +3 -0
- package/skills/manageskill/package.json +1 -1
- package/skills/manageskill/src/index.ts +3 -0
- package/skills/markdown-validator/package.json +3 -1
- package/skills/markdown-validator/src/index.ts +1 -4
- package/skills/market-research-report/SKILL.md +41 -0
- package/skills/market-research-report/package.json +10 -0
- package/skills/mcp-builder/package.json +4 -1
- package/skills/mcp-builder/src/ai-descriptions.ts +37 -0
- package/skills/mcp-builder/src/generators.ts +513 -0
- package/skills/mcp-builder/src/index.ts +7 -908
- package/skills/mcp-builder/src/minimist.d.ts +15 -0
- package/skills/mcp-builder/src/naming.ts +12 -0
- package/skills/mcp-builder/src/options.ts +170 -0
- package/skills/mcp-builder/src/templates.ts +149 -0
- package/skills/mcp-builder/src/types.ts +42 -0
- package/skills/meeting-pack/SKILL.md +43 -0
- package/skills/meeting-pack/package.json +10 -0
- package/skills/merge-pdfs/package.json +5 -1
- package/skills/migration-plan-pack/SKILL.md +45 -0
- package/skills/migration-plan-pack/package.json +10 -0
- package/skills/music/package.json +2 -3
- package/skills/music-album/SKILL.md +37 -0
- package/skills/music-album/package.json +10 -0
- package/skills/notion-manager/package.json +3 -1
- package/skills/npmpublish/CLAUDE.md +5 -8
- package/skills/npmpublish/README.md +5 -26
- package/skills/npmpublish/src/index.ts +9 -147
- package/skills/one-page-website/SKILL.md +46 -0
- package/skills/one-page-website/package.json +10 -0
- package/skills/one-page-website/tsconfig.json +8 -0
- package/skills/pdf-generate/src/cli.ts +162 -0
- package/skills/pdf-generate/src/html.ts +84 -0
- package/skills/pdf-generate/src/index.ts +11 -800
- package/skills/pdf-generate/src/markdown.ts +27 -0
- package/skills/pdf-generate/src/pdf-writer.ts +78 -0
- package/skills/pdf-generate/src/runtime.ts +34 -0
- package/skills/pdf-generate/src/security.ts +37 -0
- package/skills/pdf-generate/src/templates.ts +311 -0
- package/skills/pdf-generate/src/types.ts +28 -0
- package/skills/pdf-read/SKILL.md +10 -10
- package/skills/pdf-to-dataset/SKILL.md +45 -0
- package/skills/pdf-to-dataset/package.json +10 -0
- package/skills/pdf-to-markdown/SKILL.md +49 -0
- package/skills/pdf-to-markdown/package.json +10 -0
- package/skills/pdf-to-markdown/tsconfig.json +10 -0
- package/skills/performance-audit-report/SKILL.md +42 -0
- package/skills/performance-audit-report/package.json +10 -0
- package/skills/persona-based-adwriter/src/index.ts +19 -0
- package/skills/photo-album/SKILL.md +29 -0
- package/skills/photo-album/package.json +9 -0
- package/skills/photo-album/tsconfig.json +4 -0
- package/skills/pitch-deck/SKILL.md +43 -0
- package/skills/pitch-deck/package.json +9 -0
- package/skills/playlist-maker/SKILL.md +33 -0
- package/skills/playlist-maker/package.json +9 -0
- package/skills/playlist-maker/tsconfig.json +4 -0
- package/skills/product-mockup/SKILL.md +45 -0
- package/skills/product-mockup/package.json +3 -20
- package/skills/product-mockup/tsconfig.json +3 -5
- package/skills/project-retro-companion/src/index.ts +19 -0
- package/skills/proposal-pack/SKILL.md +45 -0
- package/skills/proposal-pack/package.json +10 -0
- package/skills/read-pdf/SKILL.md +5 -4
- package/skills/repo-onboarding-report/SKILL.md +42 -0
- package/skills/repo-onboarding-report/package.json +10 -0
- package/skills/sales-call-recapper/src/index.ts +20 -0
- package/skills/salescopy/package.json +1 -1
- package/skills/salescopy/src/index.ts +3 -0
- package/skills/scaffold-project/src/ai-detect.ts +136 -0
- package/skills/scaffold-project/src/file-generators.ts +292 -0
- package/skills/scaffold-project/src/index.ts +8 -991
- package/skills/scaffold-project/src/project-config.ts +338 -0
- package/skills/scaffold-project/src/templates.ts +173 -0
- package/skills/scaffold-project/src/types.ts +58 -0
- package/skills/scientific-figure-check/package.json +3 -1
- package/skills/sdk-generator/SKILL.md +45 -0
- package/skills/sdk-generator/package.json +10 -0
- package/skills/sdk-generator/tsconfig.json +8 -0
- package/skills/security-audit/src/index.ts +25 -6
- package/skills/security-audit-report/SKILL.md +40 -0
- package/skills/security-audit-report/package.json +10 -0
- package/skills/seo-content-pack/SKILL.md +44 -0
- package/skills/seo-content-pack/package.json +9 -0
- package/skills/short-video-pack/SKILL.md +30 -0
- package/skills/short-video-pack/package.json +10 -0
- package/skills/slack-assistant/package.json +3 -1
- package/skills/slide-deck-generator/SKILL.md +44 -0
- package/skills/slide-deck-generator/package.json +10 -0
- package/skills/sms/package.json +1 -1
- package/skills/sms/src/index.ts +15 -0
- package/skills/social-content-calendar/SKILL.md +45 -0
- package/skills/social-content-calendar/package.json +14 -0
- package/skills/split-pdf/package.json +4 -1
- package/skills/subtitle/package.json +2 -1
- package/skills/subtitle/src/index.ts +3 -0
- package/skills/terraform-generator/package.json +3 -1
- package/skills/test-suite-generator/SKILL.md +41 -0
- package/skills/test-suite-generator/package.json +10 -0
- package/skills/timesheet/package.json +1 -1
- package/skills/timesheet/src/index.ts +3 -0
- package/skills/transcript/SKILL.md +1 -8
- package/skills/validate-config/package.json +3 -1
- package/skills/video/package.json +6 -4
- package/skills/video-downloader/package.json +3 -1
- package/skills/video-highlight-pack/SKILL.md +44 -0
- package/skills/video-highlight-pack/package.json +10 -0
- package/skills/voiceover-jingle-pack/SKILL.md +28 -0
- package/skills/voiceover-jingle-pack/package.json +10 -0
- package/skills/watermark/package.json +6 -1
- package/skills/webcrawling/package.json +2 -1
- package/skills/write/SKILL.md +6 -6
- package/dist/server/serve.d.ts +0 -11
- package/skills/apidocs/.claude/settings.json +0 -5
- package/skills/audio/.env.example +0 -14
- package/skills/audio/QUICKSTART.md +0 -158
- package/skills/audio/README.md +0 -256
- package/skills/audio/src/index-local.ts +0 -206
- package/skills/audio/src/index.ts +0 -95
- package/skills/audio/src/providers/elevenlabs.ts +0 -115
- package/skills/audio/src/providers/google.ts +0 -116
- package/skills/audio/src/providers/minimax.ts +0 -83
- package/skills/audio/src/providers/openai.ts +0 -115
- package/skills/audio/src/types.ts +0 -79
- package/skills/audiobook-chapter-proofer/CLAUDE.md +0 -19
- package/skills/audiobook-chapter-proofer/package.json +0 -27
- package/skills/audiobook-chapter-proofer/src/index.ts +0 -285
- package/skills/browse/src/client.ts +0 -373
- package/skills/browse/src/index-local.ts +0 -430
- package/skills/browse/src/index.ts +0 -110
- package/skills/browse/src/sse-server.ts +0 -919
- package/skills/browse/src/types.ts +0 -104
- package/skills/consolelog/src/server/index.ts +0 -508
- package/skills/create-blog-article/CLAUDE.md +0 -19
- package/skills/create-blog-article/src/index.ts +0 -745
- package/skills/create-blog-article/tsconfig.json +0 -10
- package/skills/deepresearch/src/agents/query-generator.ts +0 -91
- package/skills/deepresearch/src/agents/synthesizer.ts +0 -111
- package/skills/deepresearch/src/index.ts +0 -224
- package/skills/deepresearch/src/research.ts +0 -166
- package/skills/deepresearch/src/services/anthropic.ts +0 -69
- package/skills/deepresearch/src/services/exa.ts +0 -108
- package/skills/deepresearch/src/services/firecrawl.ts +0 -88
- package/skills/deepresearch/src/services/openai.ts +0 -81
- package/skills/deepresearch/src/types.ts +0 -76
- package/skills/deepresearch/src/utils/file.ts +0 -111
- package/skills/deepresearch/src/utils/logger.ts +0 -84
- package/skills/domainpurchase/src/server/index.ts +0 -332
- package/skills/domainsearch/src/server/index.ts +0 -229
- package/skills/e2bswarm/README.md +0 -135
- package/skills/e2bswarm/SKILL.md +0 -118
- package/skills/e2bswarm/examples/tasks-example.json +0 -38
- package/skills/e2bswarm/package.json +0 -59
- package/skills/e2bswarm/src/commands/collect.ts +0 -135
- package/skills/e2bswarm/src/commands/install.ts +0 -164
- package/skills/e2bswarm/src/commands/kill.ts +0 -62
- package/skills/e2bswarm/src/commands/spawn.ts +0 -134
- package/skills/e2bswarm/src/commands/status.ts +0 -90
- package/skills/e2bswarm/src/commands/sync.ts +0 -208
- package/skills/e2bswarm/src/index.ts +0 -121
- package/skills/e2bswarm/src/lib/config.ts +0 -75
- package/skills/e2bswarm/src/lib/e2b.ts +0 -490
- package/skills/e2bswarm/src/lib/github.ts +0 -253
- package/skills/e2bswarm/src/lib/logger.ts +0 -41
- package/skills/e2bswarm/src/lib/paths.ts +0 -75
- package/skills/e2bswarm/src/lib/tasks.ts +0 -320
- package/skills/e2bswarm/src/types/index.ts +0 -107
- package/skills/e2bswarm/templates/codebox/e2b.Dockerfile +0 -38
- package/skills/e2bswarm/templates/codebox/e2b.toml +0 -3
- package/skills/e2bswarm/templates/setup.sh +0 -21
- package/skills/e2bswarm/tsconfig.json +0 -19
- package/skills/generate-book-cover/src/index.ts +0 -694
- package/skills/image/src/index-local.ts +0 -206
- package/skills/image/src/index.ts +0 -96
- package/skills/image/src/providers/google.ts +0 -79
- package/skills/image/src/providers/minimax.ts +0 -94
- package/skills/image/src/providers/openai.ts +0 -80
- package/skills/image/src/providers/xai.ts +0 -73
- package/skills/image/src/types.ts +0 -37
- package/skills/logo-design/CLAUDE.md +0 -30
- package/skills/logo-design/src/index.ts +0 -322
- package/skills/managehook/src/server/index.ts +0 -108
- package/skills/managemcp/src/server/index.ts +0 -108
- package/skills/manageskill/src/server/index.ts +0 -108
- package/skills/music/CLAUDE.md +0 -9
- package/skills/music/src/index.ts +0 -94
- package/skills/music/tsconfig.json +0 -10
- package/skills/pdf-read/src/index.ts +0 -320
- package/skills/product-mockup/CLAUDE.md +0 -19
- package/skills/product-mockup/src/index.ts +0 -290
- package/skills/read-pdf/src/index.ts +0 -388
- package/skills/remove-background/src/index.ts +0 -405
- package/skills/scaffold-project/my-app/.env.example +0 -2
- package/skills/scaffold-project/my-app/README.md +0 -72
- package/skills/scaffold-project/my-app/package.json +0 -29
- package/skills/scaffold-project/my-app/src/index.ts +0 -23
- package/skills/scaffold-project/my-app/tsconfig.json +0 -33
- package/skills/sound-effects/SKILL.md +0 -34
- package/skills/sound-effects/package.json +0 -21
- package/skills/sound-effects/src/index.ts +0 -172
- package/skills/sound-effects/tsconfig.json +0 -8
- package/skills/transcript/src/chunker.ts +0 -215
- package/skills/transcript/src/formatter.ts +0 -134
- package/skills/transcript/src/index-local.ts +0 -226
- package/skills/transcript/src/index.ts +0 -110
- package/skills/transcript/src/providers/elevenlabs.ts +0 -133
- package/skills/transcript/src/providers/gemini.ts +0 -192
- package/skills/transcript/src/providers/index.ts +0 -54
- package/skills/transcript/src/providers/openai.ts +0 -203
- package/skills/transcript/src/types.ts +0 -106
- package/skills/video/.env.example +0 -14
- package/skills/video/EXAMPLES.md +0 -266
- package/skills/video/LICENSE +0 -192
- package/skills/video/README.md +0 -174
- package/skills/video/src/cli.ts +0 -155
- package/skills/video/src/index-local.ts +0 -148
- package/skills/video/src/index.ts +0 -96
- package/skills/video/src/providers/google-veo.ts +0 -126
- package/skills/video/src/providers/index.ts +0 -22
- package/skills/video/src/providers/minimax.ts +0 -100
- package/skills/video/src/providers/openai-sora.ts +0 -164
- package/skills/video/src/providers/runway.ts +0 -159
- package/skills/video/src/types.ts +0 -35
- package/skills/video/tsconfig.json +0 -22
- package/skills/voiceover-casting-assistant/CLAUDE.md +0 -19
- package/skills/voiceover-casting-assistant/package.json +0 -27
- package/skills/voiceover-casting-assistant/src/index.ts +0 -255
- package/skills/voiceover-casting-assistant/tsconfig.json +0 -10
- package/skills/webcrawling/src/commands/config.ts +0 -34
- package/skills/webcrawling/src/commands/crawl.ts +0 -33
- package/skills/webcrawling/src/commands/scrape.ts +0 -32
- package/skills/webcrawling/src/commands/sessions.ts +0 -42
- package/skills/webcrawling/src/lib/crawler.ts +0 -174
- package/skills/webcrawling/src/lib/storage.ts +0 -130
- package/skills/webcrawling/src/types/index.ts +0 -45
- package/skills/webcrawling/src/utils/logger.ts +0 -30
- package/skills/webcrawling/src/utils/paths.ts +0 -28
- /package/skills/{audiobook-chapter-proofer ā blog-article}/tsconfig.json +0 -0
|
@@ -1,745 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* Create Blog Article Skill
|
|
4
|
-
* Generates complete blog articles with AI-generated images
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { parseArgs } from "util";
|
|
8
|
-
import { mkdirSync, writeFileSync, appendFileSync, existsSync } from "fs";
|
|
9
|
-
import { join, dirname } from "path";
|
|
10
|
-
import { randomUUID } from "crypto";
|
|
11
|
-
|
|
12
|
-
// Types
|
|
13
|
-
interface ArticleOptions {
|
|
14
|
-
topic: string;
|
|
15
|
-
tone: "professional" | "casual" | "technical" | "friendly";
|
|
16
|
-
length: "short" | "medium" | "long";
|
|
17
|
-
images: number;
|
|
18
|
-
style: "photorealistic" | "illustration" | "minimalist";
|
|
19
|
-
seo: boolean;
|
|
20
|
-
outlineOnly: boolean;
|
|
21
|
-
output?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface ArticleOutline {
|
|
25
|
-
title: string;
|
|
26
|
-
metaDescription: string;
|
|
27
|
-
introduction: string;
|
|
28
|
-
sections: Array<{
|
|
29
|
-
heading: string;
|
|
30
|
-
subheadings?: string[];
|
|
31
|
-
imagePrompt?: string;
|
|
32
|
-
}>;
|
|
33
|
-
conclusion: string;
|
|
34
|
-
keywords: string[];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
interface ArticleContent {
|
|
38
|
-
title: string;
|
|
39
|
-
metaDescription: string;
|
|
40
|
-
featuredImageUrl?: string;
|
|
41
|
-
introduction: string;
|
|
42
|
-
sections: Array<{
|
|
43
|
-
heading: string;
|
|
44
|
-
content: string;
|
|
45
|
-
imageUrl?: string;
|
|
46
|
-
}>;
|
|
47
|
-
conclusion: string;
|
|
48
|
-
keywords: string[];
|
|
49
|
-
tags: string[];
|
|
50
|
-
wordCount: number;
|
|
51
|
-
readingTime: number;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
interface OpenAIChatResponse {
|
|
55
|
-
choices: Array<{
|
|
56
|
-
message: {
|
|
57
|
-
content: string;
|
|
58
|
-
};
|
|
59
|
-
}>;
|
|
60
|
-
usage?: {
|
|
61
|
-
total_tokens: number;
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface OpenAIImageResponse {
|
|
66
|
-
data: Array<{
|
|
67
|
-
url?: string;
|
|
68
|
-
revised_prompt?: string;
|
|
69
|
-
}>;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// =============================================================================
|
|
73
|
-
// Security: HTML Escaping to prevent XSS
|
|
74
|
-
// =============================================================================
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Escape HTML special characters to prevent XSS attacks
|
|
78
|
-
*/
|
|
79
|
-
function escapeHtml(str: string | undefined | null): string {
|
|
80
|
-
if (str === undefined || str === null) return "";
|
|
81
|
-
return String(str)
|
|
82
|
-
.replace(/&/g, "&")
|
|
83
|
-
.replace(/</g, "<")
|
|
84
|
-
.replace(/>/g, ">")
|
|
85
|
-
.replace(/"/g, """)
|
|
86
|
-
.replace(/'/g, "'");
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Constants
|
|
90
|
-
const SKILL_NAME = "create-blog-article";
|
|
91
|
-
const SESSION_ID = randomUUID().slice(0, 8);
|
|
92
|
-
|
|
93
|
-
// Use SKILLS_OUTPUT_DIR from CLI if available, otherwise fall back to cwd
|
|
94
|
-
const SKILLS_OUTPUT_DIR = process.env.SKILLS_OUTPUT_DIR || join(process.cwd(), ".skills");
|
|
95
|
-
const EXPORTS_DIR = join(SKILLS_OUTPUT_DIR, "exports", SKILL_NAME);
|
|
96
|
-
const LOGS_DIR = join(SKILLS_OUTPUT_DIR, "logs", SKILL_NAME);
|
|
97
|
-
|
|
98
|
-
// Ensure directories exist
|
|
99
|
-
function ensureDir(dir: string) {
|
|
100
|
-
if (!existsSync(dir)) {
|
|
101
|
-
mkdirSync(dir, { recursive: true });
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Session timestamp for log filename
|
|
106
|
-
const SESSION_TIMESTAMP = new Date().toISOString().replace(/[:.]/g, "_").replace(/-/g, "_").slice(0, 19).toLowerCase();
|
|
107
|
-
|
|
108
|
-
// Logger
|
|
109
|
-
function log(message: string, level: "info" | "error" | "success" = "info") {
|
|
110
|
-
const timestamp = new Date().toISOString();
|
|
111
|
-
const logFile = join(LOGS_DIR, `log_${SESSION_TIMESTAMP}_${SESSION_ID}.log`);
|
|
112
|
-
|
|
113
|
-
ensureDir(LOGS_DIR);
|
|
114
|
-
|
|
115
|
-
const logEntry = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
|
|
116
|
-
appendFileSync(logFile, logEntry);
|
|
117
|
-
|
|
118
|
-
const prefix = level === "error" ? "ā" : level === "success" ? "ā
" : "ā¹ļø";
|
|
119
|
-
if (level === "error") {
|
|
120
|
-
console.error(`${prefix} ${message}`);
|
|
121
|
-
} else {
|
|
122
|
-
console.log(`${prefix} ${message}`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Generate slug from text
|
|
127
|
-
function slugify(text: string): string {
|
|
128
|
-
return text
|
|
129
|
-
.toLowerCase()
|
|
130
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
131
|
-
.replace(/^-|-$/g, "")
|
|
132
|
-
.slice(0, 60);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Calculate reading time (assuming 200 words per minute)
|
|
136
|
-
function calculateReadingTime(wordCount: number): number {
|
|
137
|
-
return Math.ceil(wordCount / 200);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Count words in text
|
|
141
|
-
function countWords(text: string): number {
|
|
142
|
-
return text.split(/\s+/).filter(word => word.length > 0).length;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Call OpenAI Chat API
|
|
146
|
-
async function callOpenAI(prompt: string, systemPrompt: string): Promise<string> {
|
|
147
|
-
const apiKey = process.env.OPENAI_API_KEY;
|
|
148
|
-
|
|
149
|
-
if (!apiKey) {
|
|
150
|
-
throw new Error("OPENAI_API_KEY environment variable is not set");
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
154
|
-
method: "POST",
|
|
155
|
-
headers: {
|
|
156
|
-
"Content-Type": "application/json",
|
|
157
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
158
|
-
},
|
|
159
|
-
body: JSON.stringify({
|
|
160
|
-
model: "gpt-4o-mini",
|
|
161
|
-
messages: [
|
|
162
|
-
{ role: "system", content: systemPrompt },
|
|
163
|
-
{ role: "user", content: prompt },
|
|
164
|
-
],
|
|
165
|
-
temperature: 0.7,
|
|
166
|
-
max_tokens: 4000,
|
|
167
|
-
}),
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
if (!response.ok) {
|
|
171
|
-
const error = await response.json();
|
|
172
|
-
throw new Error(`OpenAI API error: ${error.error?.message || response.statusText}`);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const data: OpenAIChatResponse = await response.json();
|
|
176
|
-
|
|
177
|
-
if (!data.choices?.[0]?.message?.content) {
|
|
178
|
-
throw new Error("No content returned from OpenAI");
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return data.choices[0].message.content;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Generate article outline
|
|
185
|
-
async function generateOutline(options: ArticleOptions): Promise<ArticleOutline> {
|
|
186
|
-
log(`Generating article outline for: "${options.topic}"`);
|
|
187
|
-
|
|
188
|
-
const lengthGuide = {
|
|
189
|
-
short: "3-4 sections, ~500 words total",
|
|
190
|
-
medium: "5-6 sections, ~1000 words total",
|
|
191
|
-
long: "7-9 sections, ~2000 words total",
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
const systemPrompt = `You are an expert content writer and SEO specialist. Generate a detailed article outline in JSON format. The outline should be engaging, well-structured, and optimized for readability.`;
|
|
195
|
-
|
|
196
|
-
const userPrompt = `Create a detailed outline for a blog article with the following requirements:
|
|
197
|
-
|
|
198
|
-
Topic: ${options.topic}
|
|
199
|
-
Tone: ${options.tone}
|
|
200
|
-
Length: ${options.length} (${lengthGuide[options.length]})
|
|
201
|
-
Images: ${options.images} images will be generated
|
|
202
|
-
${options.seo ? "SEO: Include keywords and meta description optimized for search engines" : ""}
|
|
203
|
-
|
|
204
|
-
Return a JSON object with this exact structure:
|
|
205
|
-
{
|
|
206
|
-
"title": "Compelling article title",
|
|
207
|
-
"metaDescription": "SEO-optimized meta description (150-160 characters)",
|
|
208
|
-
"introduction": "Brief outline of introduction paragraph",
|
|
209
|
-
"sections": [
|
|
210
|
-
{
|
|
211
|
-
"heading": "Section heading",
|
|
212
|
-
"subheadings": ["Optional subheading 1", "Optional subheading 2"],
|
|
213
|
-
"imagePrompt": "Optional DALL-E prompt for section image"
|
|
214
|
-
}
|
|
215
|
-
],
|
|
216
|
-
"conclusion": "Brief outline of conclusion",
|
|
217
|
-
"keywords": ["keyword1", "keyword2", "keyword3"]
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
Make the outline engaging and informative. ${options.images > 1 ? `Include imagePrompt for ${options.images - 1} sections (featured image will be generated separately).` : "No section images needed."}`;
|
|
221
|
-
|
|
222
|
-
const response = await callOpenAI(userPrompt, systemPrompt);
|
|
223
|
-
|
|
224
|
-
// Parse JSON response
|
|
225
|
-
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
226
|
-
if (!jsonMatch) {
|
|
227
|
-
throw new Error("Could not parse outline JSON from response");
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const outline = JSON.parse(jsonMatch[0]);
|
|
231
|
-
log(`Outline generated with ${outline.sections.length} sections`, "success");
|
|
232
|
-
|
|
233
|
-
return outline;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Generate full article content from outline
|
|
237
|
-
async function generateArticleContent(outline: ArticleOutline, options: ArticleOptions): Promise<ArticleContent> {
|
|
238
|
-
log(`Generating full article content`);
|
|
239
|
-
|
|
240
|
-
const lengthGuide = {
|
|
241
|
-
short: "500 words",
|
|
242
|
-
medium: "1000 words",
|
|
243
|
-
long: "2000 words",
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const systemPrompt = `You are an expert content writer. Write engaging, informative blog articles with a ${options.tone} tone. Focus on providing value to readers with clear, well-structured content.`;
|
|
247
|
-
|
|
248
|
-
const userPrompt = `Write a complete blog article based on this outline:
|
|
249
|
-
|
|
250
|
-
Title: ${outline.title}
|
|
251
|
-
Topic: ${options.topic}
|
|
252
|
-
Tone: ${options.tone}
|
|
253
|
-
Target Length: ${lengthGuide[options.length]}
|
|
254
|
-
|
|
255
|
-
Introduction: ${outline.introduction}
|
|
256
|
-
|
|
257
|
-
Sections:
|
|
258
|
-
${outline.sections.map((s, i) => `${i + 1}. ${s.heading}${s.subheadings ? "\n - " + s.subheadings.join("\n - ") : ""}`).join("\n")}
|
|
259
|
-
|
|
260
|
-
Conclusion: ${outline.conclusion}
|
|
261
|
-
|
|
262
|
-
Return a JSON object with this structure:
|
|
263
|
-
{
|
|
264
|
-
"introduction": "Full introduction paragraph(s)",
|
|
265
|
-
"sections": [
|
|
266
|
-
{
|
|
267
|
-
"heading": "Section heading",
|
|
268
|
-
"content": "Full section content with multiple paragraphs"
|
|
269
|
-
}
|
|
270
|
-
],
|
|
271
|
-
"conclusion": "Full conclusion paragraph(s)",
|
|
272
|
-
"tags": ["tag1", "tag2", "tag3"]
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
Write naturally and engagingly. Each section should be substantial and informative.`;
|
|
276
|
-
|
|
277
|
-
const response = await callOpenAI(userPrompt, systemPrompt);
|
|
278
|
-
|
|
279
|
-
// Parse JSON response
|
|
280
|
-
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
281
|
-
if (!jsonMatch) {
|
|
282
|
-
throw new Error("Could not parse article JSON from response");
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const content = JSON.parse(jsonMatch[0]);
|
|
286
|
-
|
|
287
|
-
// Calculate word count
|
|
288
|
-
const allText = [
|
|
289
|
-
content.introduction,
|
|
290
|
-
...content.sections.map((s: { content: string }) => s.content),
|
|
291
|
-
content.conclusion,
|
|
292
|
-
].join(" ");
|
|
293
|
-
|
|
294
|
-
const wordCount = countWords(allText);
|
|
295
|
-
const readingTime = calculateReadingTime(wordCount);
|
|
296
|
-
|
|
297
|
-
log(`Article generated: ${wordCount} words, ${readingTime} min read`, "success");
|
|
298
|
-
|
|
299
|
-
return {
|
|
300
|
-
title: outline.title,
|
|
301
|
-
metaDescription: outline.metaDescription,
|
|
302
|
-
introduction: content.introduction,
|
|
303
|
-
sections: content.sections.map((s: { heading: string; content: string }, i: number) => ({
|
|
304
|
-
heading: s.heading,
|
|
305
|
-
content: s.content,
|
|
306
|
-
imageUrl: outline.sections[i]?.imagePrompt ? undefined : undefined, // Will be filled later
|
|
307
|
-
})),
|
|
308
|
-
conclusion: content.conclusion,
|
|
309
|
-
keywords: outline.keywords,
|
|
310
|
-
tags: content.tags || [],
|
|
311
|
-
wordCount,
|
|
312
|
-
readingTime,
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Generate image using DALL-E
|
|
317
|
-
async function generateImage(prompt: string, style: string): Promise<string> {
|
|
318
|
-
const apiKey = process.env.OPENAI_API_KEY;
|
|
319
|
-
|
|
320
|
-
if (!apiKey) {
|
|
321
|
-
throw new Error("OPENAI_API_KEY environment variable is not set");
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
log(`Generating image: "${prompt.slice(0, 50)}..."`);
|
|
325
|
-
|
|
326
|
-
const styleMap: Record<string, string> = {
|
|
327
|
-
photorealistic: "photorealistic, professional photography, high quality",
|
|
328
|
-
illustration: "digital illustration, clean lines, artistic",
|
|
329
|
-
minimalist: "minimalist design, simple, clean, modern",
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
const enhancedPrompt = `${prompt}, ${styleMap[style] || styleMap.photorealistic}`;
|
|
333
|
-
|
|
334
|
-
const response = await fetch("https://api.openai.com/v1/images/generations", {
|
|
335
|
-
method: "POST",
|
|
336
|
-
headers: {
|
|
337
|
-
"Content-Type": "application/json",
|
|
338
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
339
|
-
},
|
|
340
|
-
body: JSON.stringify({
|
|
341
|
-
model: "dall-e-3",
|
|
342
|
-
prompt: enhancedPrompt,
|
|
343
|
-
n: 1,
|
|
344
|
-
size: "1792x1024",
|
|
345
|
-
quality: "standard",
|
|
346
|
-
response_format: "url",
|
|
347
|
-
}),
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
if (!response.ok) {
|
|
351
|
-
const error = await response.json();
|
|
352
|
-
throw new Error(`OpenAI API error: ${error.error?.message || response.statusText}`);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
const data: OpenAIImageResponse = await response.json();
|
|
356
|
-
|
|
357
|
-
if (!data.data?.[0]?.url) {
|
|
358
|
-
throw new Error("No image URL returned from OpenAI");
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
log(`Image generated successfully`, "success");
|
|
362
|
-
|
|
363
|
-
return data.data[0].url;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Download image from URL
|
|
367
|
-
async function downloadImage(url: string, outputPath: string): Promise<void> {
|
|
368
|
-
const response = await fetch(url);
|
|
369
|
-
|
|
370
|
-
if (!response.ok) {
|
|
371
|
-
throw new Error(`Failed to download image: ${response.statusText}`);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const buffer = await response.arrayBuffer();
|
|
375
|
-
const dir = dirname(outputPath);
|
|
376
|
-
|
|
377
|
-
ensureDir(dir);
|
|
378
|
-
writeFileSync(outputPath, Buffer.from(buffer));
|
|
379
|
-
|
|
380
|
-
log(`Image saved to: ${outputPath}`);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// Generate all images for article
|
|
384
|
-
async function generateArticleImages(
|
|
385
|
-
outline: ArticleOutline,
|
|
386
|
-
content: ArticleContent,
|
|
387
|
-
options: ArticleOptions,
|
|
388
|
-
outputDir: string
|
|
389
|
-
): Promise<ArticleContent> {
|
|
390
|
-
if (options.images === 0) {
|
|
391
|
-
log("Skipping image generation (--images 0)");
|
|
392
|
-
return content;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const imagesDir = join(outputDir, "images");
|
|
396
|
-
ensureDir(imagesDir);
|
|
397
|
-
|
|
398
|
-
// Generate featured image
|
|
399
|
-
log("Generating featured image...");
|
|
400
|
-
const featuredPrompt = `Blog article featured image for: ${content.title}`;
|
|
401
|
-
const featuredUrl = await generateImage(featuredPrompt, options.style);
|
|
402
|
-
const featuredPath = join(imagesDir, "featured.png");
|
|
403
|
-
await downloadImage(featuredUrl, featuredPath);
|
|
404
|
-
content.featuredImageUrl = featuredPath;
|
|
405
|
-
|
|
406
|
-
// Generate section images if requested
|
|
407
|
-
if (options.images > 1) {
|
|
408
|
-
log(`Generating ${options.images - 1} section images...`);
|
|
409
|
-
|
|
410
|
-
let imageCount = 0;
|
|
411
|
-
for (let i = 0; i < outline.sections.length && imageCount < options.images - 1; i++) {
|
|
412
|
-
const section = outline.sections[i];
|
|
413
|
-
if (section.imagePrompt) {
|
|
414
|
-
try {
|
|
415
|
-
const imageUrl = await generateImage(section.imagePrompt, options.style);
|
|
416
|
-
const imagePath = join(imagesDir, `section-${i + 1}.png`);
|
|
417
|
-
await downloadImage(imageUrl, imagePath);
|
|
418
|
-
content.sections[i].imageUrl = imagePath;
|
|
419
|
-
imageCount++;
|
|
420
|
-
} catch (error) {
|
|
421
|
-
log(`Failed to generate image for section ${i + 1}: ${error}`, "error");
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
log(`Generated ${options.images} image(s) successfully`, "success");
|
|
428
|
-
return content;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Export article as Markdown
|
|
432
|
-
function exportMarkdown(content: ArticleContent, outputPath: string): void {
|
|
433
|
-
let markdown = `---
|
|
434
|
-
title: ${content.title}
|
|
435
|
-
description: ${content.metaDescription}
|
|
436
|
-
keywords: ${content.keywords.join(", ")}
|
|
437
|
-
tags: ${content.tags.join(", ")}
|
|
438
|
-
readingTime: ${content.readingTime} min
|
|
439
|
-
wordCount: ${content.wordCount}
|
|
440
|
-
---
|
|
441
|
-
|
|
442
|
-
# ${content.title}
|
|
443
|
-
|
|
444
|
-
`;
|
|
445
|
-
|
|
446
|
-
if (content.featuredImageUrl) {
|
|
447
|
-
markdown += `\n\n`;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
markdown += `${content.introduction}\n\n`;
|
|
451
|
-
|
|
452
|
-
for (const section of content.sections) {
|
|
453
|
-
markdown += `## ${section.heading}\n\n`;
|
|
454
|
-
markdown += `${section.content}\n\n`;
|
|
455
|
-
if (section.imageUrl) {
|
|
456
|
-
const imageName = section.imageUrl.split("/").pop();
|
|
457
|
-
markdown += `\n\n`;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
markdown += `## Conclusion\n\n${content.conclusion}\n\n`;
|
|
462
|
-
|
|
463
|
-
markdown += `---\n\n`;
|
|
464
|
-
markdown += `**Keywords:** ${content.keywords.join(", ")}\n\n`;
|
|
465
|
-
markdown += `**Tags:** ${content.tags.join(", ")}\n`;
|
|
466
|
-
|
|
467
|
-
writeFileSync(outputPath, markdown);
|
|
468
|
-
log(`Markdown exported to: ${outputPath}`);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Export article as HTML
|
|
472
|
-
function exportHTML(content: ArticleContent, outputPath: string): void {
|
|
473
|
-
let html = `<!DOCTYPE html>
|
|
474
|
-
<html lang="en">
|
|
475
|
-
<head>
|
|
476
|
-
<meta charset="UTF-8">
|
|
477
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
478
|
-
<meta name="description" content="${escapeHtml(content.metaDescription)}">
|
|
479
|
-
<meta name="keywords" content="${escapeHtml(content.keywords.join(", "))}">
|
|
480
|
-
<title>${escapeHtml(content.title)}</title>
|
|
481
|
-
<style>
|
|
482
|
-
body {
|
|
483
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
484
|
-
line-height: 1.6;
|
|
485
|
-
max-width: 800px;
|
|
486
|
-
margin: 0 auto;
|
|
487
|
-
padding: 2rem;
|
|
488
|
-
color: #333;
|
|
489
|
-
}
|
|
490
|
-
img {
|
|
491
|
-
max-width: 100%;
|
|
492
|
-
height: auto;
|
|
493
|
-
border-radius: 8px;
|
|
494
|
-
margin: 2rem 0;
|
|
495
|
-
}
|
|
496
|
-
h1 {
|
|
497
|
-
font-size: 2.5rem;
|
|
498
|
-
margin-bottom: 1rem;
|
|
499
|
-
}
|
|
500
|
-
h2 {
|
|
501
|
-
font-size: 1.75rem;
|
|
502
|
-
margin-top: 2rem;
|
|
503
|
-
margin-bottom: 1rem;
|
|
504
|
-
}
|
|
505
|
-
.meta {
|
|
506
|
-
color: #666;
|
|
507
|
-
font-size: 0.9rem;
|
|
508
|
-
margin-bottom: 2rem;
|
|
509
|
-
}
|
|
510
|
-
.tags {
|
|
511
|
-
margin-top: 3rem;
|
|
512
|
-
padding-top: 2rem;
|
|
513
|
-
border-top: 1px solid #eee;
|
|
514
|
-
}
|
|
515
|
-
.tags span {
|
|
516
|
-
display: inline-block;
|
|
517
|
-
background: #f0f0f0;
|
|
518
|
-
padding: 0.25rem 0.75rem;
|
|
519
|
-
margin: 0.25rem;
|
|
520
|
-
border-radius: 4px;
|
|
521
|
-
font-size: 0.9rem;
|
|
522
|
-
}
|
|
523
|
-
</style>
|
|
524
|
-
</head>
|
|
525
|
-
<body>
|
|
526
|
-
<article>
|
|
527
|
-
<header>
|
|
528
|
-
<h1>${escapeHtml(content.title)}</h1>
|
|
529
|
-
<div class="meta">
|
|
530
|
-
${content.readingTime} min read ⢠${content.wordCount} words
|
|
531
|
-
</div>
|
|
532
|
-
</header>
|
|
533
|
-
|
|
534
|
-
`;
|
|
535
|
-
|
|
536
|
-
if (content.featuredImageUrl) {
|
|
537
|
-
html += ` <img src="./images/featured.png" alt="Featured Image">\n\n`;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
html += ` <p>${escapeHtml(content.introduction).replace(/\n/g, "</p>\n <p>")}</p>\n\n`;
|
|
541
|
-
|
|
542
|
-
for (const section of content.sections) {
|
|
543
|
-
html += ` <section>
|
|
544
|
-
<h2>${escapeHtml(section.heading)}</h2>
|
|
545
|
-
<p>${escapeHtml(section.content).replace(/\n/g, "</p>\n <p>")}</p>
|
|
546
|
-
`;
|
|
547
|
-
if (section.imageUrl) {
|
|
548
|
-
const imageName = section.imageUrl.split("/").pop();
|
|
549
|
-
html += ` <img src="./images/${imageName}" alt="${escapeHtml(section.heading)}">\n`;
|
|
550
|
-
}
|
|
551
|
-
html += ` </section>\n\n`;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
html += ` <section>
|
|
555
|
-
<h2>Conclusion</h2>
|
|
556
|
-
<p>${escapeHtml(content.conclusion).replace(/\n/g, "</p>\n <p>")}</p>
|
|
557
|
-
</section>
|
|
558
|
-
|
|
559
|
-
<div class="tags">
|
|
560
|
-
<strong>Tags:</strong>
|
|
561
|
-
`;
|
|
562
|
-
|
|
563
|
-
for (const tag of content.tags) {
|
|
564
|
-
html += ` <span>${escapeHtml(tag)}</span>\n`;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
html += ` </div>
|
|
568
|
-
</article>
|
|
569
|
-
</body>
|
|
570
|
-
</html>`;
|
|
571
|
-
|
|
572
|
-
writeFileSync(outputPath, html);
|
|
573
|
-
log(`HTML exported to: ${outputPath}`);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
// Export article as JSON
|
|
577
|
-
function exportJSON(content: ArticleContent, outputPath: string): void {
|
|
578
|
-
const json = JSON.stringify(content, null, 2);
|
|
579
|
-
writeFileSync(outputPath, json);
|
|
580
|
-
log(`JSON exported to: ${outputPath}`);
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// Main function
|
|
584
|
-
async function main() {
|
|
585
|
-
const { values, positionals } = parseArgs({
|
|
586
|
-
args: Bun.argv.slice(2),
|
|
587
|
-
options: {
|
|
588
|
-
tone: { type: "string", default: "professional" },
|
|
589
|
-
length: { type: "string", default: "medium" },
|
|
590
|
-
images: { type: "string", default: "1" },
|
|
591
|
-
style: { type: "string", default: "photorealistic" },
|
|
592
|
-
seo: { type: "boolean", default: false },
|
|
593
|
-
"outline-only": { type: "boolean", default: false },
|
|
594
|
-
output: { type: "string", short: "o" },
|
|
595
|
-
help: { type: "boolean", short: "h" },
|
|
596
|
-
},
|
|
597
|
-
allowPositionals: true,
|
|
598
|
-
});
|
|
599
|
-
|
|
600
|
-
// Show help
|
|
601
|
-
if (values.help || positionals.length === 0) {
|
|
602
|
-
console.log(`
|
|
603
|
-
Create Blog Article - Generate complete blog articles with AI-generated images
|
|
604
|
-
|
|
605
|
-
Usage:
|
|
606
|
-
bun run src/index.ts <topic> [options]
|
|
607
|
-
|
|
608
|
-
Options:
|
|
609
|
-
--tone <tone> Writing tone (professional, casual, technical, friendly) [default: professional]
|
|
610
|
-
--length <length> Article length (short ~500w, medium ~1000w, long ~2000w) [default: medium]
|
|
611
|
-
--images <number> Number of images (0, 1, 3, 5) [default: 1]
|
|
612
|
-
--style <style> Image style (photorealistic, illustration, minimalist) [default: photorealistic]
|
|
613
|
-
--seo Include SEO metadata and keywords [default: false]
|
|
614
|
-
--outline-only Generate outline only, no full article [default: false]
|
|
615
|
-
--output, -o <path> Custom output path
|
|
616
|
-
--help, -h Show this help
|
|
617
|
-
|
|
618
|
-
Examples:
|
|
619
|
-
bun run src/index.ts "The Future of AI Development"
|
|
620
|
-
bun run src/index.ts "How to Build REST APIs" --tone technical --length long
|
|
621
|
-
bun run src/index.ts "Travel Tips" --seo --images 3 --style photorealistic
|
|
622
|
-
bun run src/index.ts "Code Reviews" --outline-only
|
|
623
|
-
`);
|
|
624
|
-
process.exit(0);
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
const topic = positionals.join(" ");
|
|
628
|
-
|
|
629
|
-
if (!topic) {
|
|
630
|
-
log("Please provide a topic/title for the article", "error");
|
|
631
|
-
process.exit(1);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
// Validate options
|
|
635
|
-
const validTones = ["professional", "casual", "technical", "friendly"];
|
|
636
|
-
const validLengths = ["short", "medium", "long"];
|
|
637
|
-
const validStyles = ["photorealistic", "illustration", "minimalist"];
|
|
638
|
-
const validImageCounts = [0, 1, 3, 5];
|
|
639
|
-
|
|
640
|
-
const tone = values.tone as string;
|
|
641
|
-
const length = values.length as string;
|
|
642
|
-
const style = values.style as string;
|
|
643
|
-
const images = parseInt(values.images as string);
|
|
644
|
-
|
|
645
|
-
if (!validTones.includes(tone)) {
|
|
646
|
-
log(`Invalid tone: ${tone}. Must be one of: ${validTones.join(", ")}`, "error");
|
|
647
|
-
process.exit(1);
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
if (!validLengths.includes(length)) {
|
|
651
|
-
log(`Invalid length: ${length}. Must be one of: ${validLengths.join(", ")}`, "error");
|
|
652
|
-
process.exit(1);
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
if (!validStyles.includes(style)) {
|
|
656
|
-
log(`Invalid style: ${style}. Must be one of: ${validStyles.join(", ")}`, "error");
|
|
657
|
-
process.exit(1);
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
if (!validImageCounts.includes(images)) {
|
|
661
|
-
log(`Invalid images count: ${images}. Must be one of: ${validImageCounts.join(", ")}`, "error");
|
|
662
|
-
process.exit(1);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
const options: ArticleOptions = {
|
|
666
|
-
topic,
|
|
667
|
-
tone: tone as ArticleOptions["tone"],
|
|
668
|
-
length: length as ArticleOptions["length"],
|
|
669
|
-
images,
|
|
670
|
-
style: style as ArticleOptions["style"],
|
|
671
|
-
seo: values.seo as boolean,
|
|
672
|
-
outlineOnly: values["outline-only"] as boolean,
|
|
673
|
-
output: values.output as string | undefined,
|
|
674
|
-
};
|
|
675
|
-
|
|
676
|
-
try {
|
|
677
|
-
log(`Session ID: ${SESSION_ID}`);
|
|
678
|
-
log(`Topic: "${topic}"`);
|
|
679
|
-
log(`Options: ${tone} tone, ${length} length, ${images} images, ${style} style`);
|
|
680
|
-
|
|
681
|
-
// Determine output directory
|
|
682
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "_").replace(/-/g, "_").slice(0, 19).toLowerCase();
|
|
683
|
-
const titleSlug = slugify(topic);
|
|
684
|
-
const outputDir = options.output || join(EXPORTS_DIR, `export_${timestamp}_${titleSlug}`);
|
|
685
|
-
ensureDir(outputDir);
|
|
686
|
-
|
|
687
|
-
log(`Output directory: ${outputDir}`);
|
|
688
|
-
|
|
689
|
-
// Step 1: Generate outline
|
|
690
|
-
const outline = await generateOutline(options);
|
|
691
|
-
|
|
692
|
-
if (options.outlineOnly) {
|
|
693
|
-
// Export outline only
|
|
694
|
-
const outlineJson = JSON.stringify(outline, null, 2);
|
|
695
|
-
const outlinePath = join(outputDir, "outline.json");
|
|
696
|
-
writeFileSync(outlinePath, outlineJson);
|
|
697
|
-
|
|
698
|
-
console.log(`\n⨠Outline generated successfully!`);
|
|
699
|
-
console.log(` š Output: ${outlinePath}`);
|
|
700
|
-
console.log(` š Log: ${join(LOGS_DIR, `log_${SESSION_TIMESTAMP}_${SESSION_ID}.log`)}`);
|
|
701
|
-
console.log(`\nš Outline:`);
|
|
702
|
-
console.log(` Title: ${outline.title}`);
|
|
703
|
-
console.log(` Sections: ${outline.sections.length}`);
|
|
704
|
-
console.log(` Keywords: ${outline.keywords.join(", ")}`);
|
|
705
|
-
|
|
706
|
-
return;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
// Step 2: Generate full article content
|
|
710
|
-
let content = await generateArticleContent(outline, options);
|
|
711
|
-
|
|
712
|
-
// Step 3: Generate images
|
|
713
|
-
content = await generateArticleImages(outline, content, options, outputDir);
|
|
714
|
-
|
|
715
|
-
// Step 4: Export in all formats
|
|
716
|
-
log("Exporting article in multiple formats...");
|
|
717
|
-
|
|
718
|
-
exportMarkdown(content, join(outputDir, "article.md"));
|
|
719
|
-
exportHTML(content, join(outputDir, "article.html"));
|
|
720
|
-
exportJSON(content, join(outputDir, "article.json"));
|
|
721
|
-
|
|
722
|
-
console.log(`\n⨠Blog article generated successfully!`);
|
|
723
|
-
console.log(` š Output: ${outputDir}`);
|
|
724
|
-
console.log(` š Formats: article.md, article.html, article.json`);
|
|
725
|
-
if (options.images > 0) {
|
|
726
|
-
console.log(` š¼ļø Images: ${options.images} image(s) in images/`);
|
|
727
|
-
}
|
|
728
|
-
console.log(` š Log: ${join(LOGS_DIR, `log_${SESSION_TIMESTAMP}_${SESSION_ID}.log`)}`);
|
|
729
|
-
console.log(`\nš Article Stats:`);
|
|
730
|
-
console.log(` Title: ${content.title}`);
|
|
731
|
-
console.log(` Words: ${content.wordCount}`);
|
|
732
|
-
console.log(` Reading Time: ${content.readingTime} min`);
|
|
733
|
-
console.log(` Sections: ${content.sections.length}`);
|
|
734
|
-
console.log(` Tags: ${content.tags.join(", ")}`);
|
|
735
|
-
|
|
736
|
-
} catch (error) {
|
|
737
|
-
log(`Error: ${error instanceof Error ? error.message : "Unknown error"}`, "error");
|
|
738
|
-
if (error instanceof Error && error.stack) {
|
|
739
|
-
log(`Stack trace: ${error.stack}`, "error");
|
|
740
|
-
}
|
|
741
|
-
process.exit(1);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
main();
|