@hasna/skills 0.1.27 ā 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 +30121 -27576
- package/bin/mcp.js +22073 -18556
- 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 +11606 -598
- 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 +22 -11
- 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/exports/products-2025-12-14T13-50-53-041Z.csv +16 -0
- package/skills/consolelog/exports/products-2025-12-14T13-50-53-041Z.json +227 -0
- 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/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,709 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
/**
|
|
3
3
|
* Generate Social Posts Skill
|
|
4
|
-
* Transform blog posts and articles into engaging social media content
|
|
4
|
+
* Transform blog posts and articles into engaging social media content.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { parseArgs } from "util";
|
|
8
|
-
import { mkdirSync, writeFileSync, appendFileSync, existsSync, readFileSync } from "fs";
|
|
9
7
|
import { join } from "path";
|
|
10
|
-
import {
|
|
8
|
+
import { parseGenerateOptions } from "./cli";
|
|
9
|
+
import { exportJSON, exportMarkdown, exportText } from "./exporters";
|
|
10
|
+
import { generateAllPosts } from "./generator";
|
|
11
|
+
import { PLATFORM_CONFIGS } from "./platforms";
|
|
12
|
+
import { getContent, slugify } from "./source";
|
|
13
|
+
import { EXPORTS_DIR, LOGS_DIR, SESSION_ID, SESSION_TIMESTAMP, ensureDir, log } from "./runtime";
|
|
11
14
|
|
|
12
|
-
// Types
|
|
13
|
-
type Platform = "twitter" | "linkedin" | "facebook" | "instagram" | "threads";
|
|
14
|
-
type Tone = "professional" | "casual" | "witty" | "inspiring" | "educational";
|
|
15
|
-
type OutputFormat = "json" | "markdown" | "text";
|
|
16
|
-
|
|
17
|
-
interface GenerateOptions {
|
|
18
|
-
source: string; // URL, file path, or direct text
|
|
19
|
-
sourceType: "url" | "file" | "text";
|
|
20
|
-
platforms: Platform[];
|
|
21
|
-
count: number;
|
|
22
|
-
tone: Tone;
|
|
23
|
-
includeHashtags: boolean;
|
|
24
|
-
threads: boolean;
|
|
25
|
-
maxLength: number;
|
|
26
|
-
output?: string;
|
|
27
|
-
format: OutputFormat;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface PlatformConfig {
|
|
31
|
-
name: string;
|
|
32
|
-
charLimit: number;
|
|
33
|
-
hashtagLimit: number;
|
|
34
|
-
emojiUsage: "minimal" | "moderate" | "heavy";
|
|
35
|
-
style: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
interface SocialPost {
|
|
39
|
-
platform: Platform;
|
|
40
|
-
content: string;
|
|
41
|
-
hashtags: string[];
|
|
42
|
-
hooks: string[];
|
|
43
|
-
cta?: string;
|
|
44
|
-
threadPosts?: string[];
|
|
45
|
-
bestTime?: string;
|
|
46
|
-
characterCount: number;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
interface GeneratedContent {
|
|
50
|
-
sourceTitle: string;
|
|
51
|
-
sourceSummary: string;
|
|
52
|
-
platforms: Platform[];
|
|
53
|
-
posts: SocialPost[];
|
|
54
|
-
generatedAt: string;
|
|
55
|
-
options: GenerateOptions;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
interface OpenAIChatResponse {
|
|
59
|
-
choices: Array<{
|
|
60
|
-
message: {
|
|
61
|
-
content: string;
|
|
62
|
-
};
|
|
63
|
-
}>;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
interface AnthropicResponse {
|
|
67
|
-
content: Array<{
|
|
68
|
-
text: string;
|
|
69
|
-
}>;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Constants
|
|
73
|
-
const SKILL_NAME = "generate-social-posts";
|
|
74
|
-
const SESSION_ID = randomUUID().slice(0, 8);
|
|
75
|
-
|
|
76
|
-
const SKILLS_OUTPUT_DIR = process.env.SKILLS_OUTPUT_DIR || join(process.cwd(), ".skills");
|
|
77
|
-
const EXPORTS_DIR = join(SKILLS_OUTPUT_DIR, "exports", SKILL_NAME);
|
|
78
|
-
const LOGS_DIR = join(SKILLS_OUTPUT_DIR, "logs", SKILL_NAME);
|
|
79
|
-
|
|
80
|
-
const PLATFORM_CONFIGS: Record<Platform, PlatformConfig> = {
|
|
81
|
-
twitter: {
|
|
82
|
-
name: "Twitter/X",
|
|
83
|
-
charLimit: 280,
|
|
84
|
-
hashtagLimit: 3,
|
|
85
|
-
emojiUsage: "moderate",
|
|
86
|
-
style: "Concise, punchy, attention-grabbing. Use strategic line breaks. Include hooks that stop the scroll.",
|
|
87
|
-
},
|
|
88
|
-
linkedin: {
|
|
89
|
-
name: "LinkedIn",
|
|
90
|
-
charLimit: 3000,
|
|
91
|
-
hashtagLimit: 5,
|
|
92
|
-
emojiUsage: "minimal",
|
|
93
|
-
style: "Professional, value-driven, business-focused. Multi-paragraph format. Start with a strong hook.",
|
|
94
|
-
},
|
|
95
|
-
facebook: {
|
|
96
|
-
name: "Facebook",
|
|
97
|
-
charLimit: 63206,
|
|
98
|
-
hashtagLimit: 3,
|
|
99
|
-
emojiUsage: "moderate",
|
|
100
|
-
style: "Conversational, story-driven, community-oriented. Personal and relatable.",
|
|
101
|
-
},
|
|
102
|
-
instagram: {
|
|
103
|
-
name: "Instagram",
|
|
104
|
-
charLimit: 2200,
|
|
105
|
-
hashtagLimit: 30,
|
|
106
|
-
emojiUsage: "heavy",
|
|
107
|
-
style: "Visual-first descriptions, emoji-rich, inspirational. Hashtag-heavy at the end.",
|
|
108
|
-
},
|
|
109
|
-
threads: {
|
|
110
|
-
name: "Threads",
|
|
111
|
-
charLimit: 500,
|
|
112
|
-
hashtagLimit: 2,
|
|
113
|
-
emojiUsage: "moderate",
|
|
114
|
-
style: "Brief, authentic, conversational. Similar to Twitter but more personal.",
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
// Session timestamp for log filename
|
|
119
|
-
const SESSION_TIMESTAMP = new Date().toISOString().replace(/[:.]/g, "_").replace(/-/g, "_").slice(0, 19).toLowerCase();
|
|
120
|
-
|
|
121
|
-
// Ensure directories exist
|
|
122
|
-
function ensureDir(dir: string) {
|
|
123
|
-
if (!existsSync(dir)) {
|
|
124
|
-
mkdirSync(dir, { recursive: true });
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Logger
|
|
129
|
-
function log(message: string, level: "info" | "error" | "success" = "info") {
|
|
130
|
-
const timestamp = new Date().toISOString();
|
|
131
|
-
const logFile = join(LOGS_DIR, `log_${SESSION_TIMESTAMP}_${SESSION_ID}.log`);
|
|
132
|
-
|
|
133
|
-
ensureDir(LOGS_DIR);
|
|
134
|
-
|
|
135
|
-
const logEntry = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
|
|
136
|
-
appendFileSync(logFile, logEntry);
|
|
137
|
-
|
|
138
|
-
const prefix = level === "error" ? "ā" : level === "success" ? "ā
" : "ā¹ļø";
|
|
139
|
-
console.log(`${prefix} ${message}`);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Generate slug from text
|
|
143
|
-
function slugify(text: string): string {
|
|
144
|
-
return text
|
|
145
|
-
.toLowerCase()
|
|
146
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
147
|
-
.replace(/^-|-$/g, "")
|
|
148
|
-
.slice(0, 60);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Detect source type
|
|
152
|
-
function detectSourceType(source: string): "url" | "file" | "text" {
|
|
153
|
-
// Check if it's a URL
|
|
154
|
-
if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
155
|
-
return "url";
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Check if it's a file path
|
|
159
|
-
if (existsSync(source)) {
|
|
160
|
-
return "file";
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Otherwise it's direct text
|
|
164
|
-
return "text";
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Extract content from URL
|
|
168
|
-
async function extractFromURL(url: string): Promise<string> {
|
|
169
|
-
log(`Fetching content from URL: ${url}`);
|
|
170
|
-
|
|
171
|
-
try {
|
|
172
|
-
const response = await fetch(url);
|
|
173
|
-
|
|
174
|
-
if (!response.ok) {
|
|
175
|
-
throw new Error(`Failed to fetch URL: ${response.statusText}`);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const html = await response.text();
|
|
179
|
-
|
|
180
|
-
// Basic HTML to text conversion
|
|
181
|
-
// Remove script and style tags
|
|
182
|
-
let text = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "");
|
|
183
|
-
text = text.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, "");
|
|
184
|
-
|
|
185
|
-
// Remove HTML tags
|
|
186
|
-
text = text.replace(/<[^>]+>/g, " ");
|
|
187
|
-
|
|
188
|
-
// Decode HTML entities
|
|
189
|
-
text = text.replace(/ /g, " ");
|
|
190
|
-
text = text.replace(/"/g, '"');
|
|
191
|
-
text = text.replace(/'/g, "'");
|
|
192
|
-
text = text.replace(/&/g, "&");
|
|
193
|
-
text = text.replace(/</g, "<");
|
|
194
|
-
text = text.replace(/>/g, ">");
|
|
195
|
-
|
|
196
|
-
// Clean up whitespace
|
|
197
|
-
text = text.replace(/\s+/g, " ").trim();
|
|
198
|
-
|
|
199
|
-
log(`Extracted ${text.length} characters from URL`, "success");
|
|
200
|
-
return text;
|
|
201
|
-
} catch (error) {
|
|
202
|
-
throw new Error(`Failed to extract content from URL: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Extract content from file
|
|
207
|
-
function extractFromFile(filePath: string): string {
|
|
208
|
-
log(`Reading content from file: ${filePath}`);
|
|
209
|
-
|
|
210
|
-
try {
|
|
211
|
-
const content = readFileSync(filePath, "utf-8");
|
|
212
|
-
|
|
213
|
-
// If it's markdown, do some basic cleanup
|
|
214
|
-
let text = content;
|
|
215
|
-
|
|
216
|
-
if (filePath.endsWith(".md") || filePath.endsWith(".markdown")) {
|
|
217
|
-
// Remove markdown syntax for cleaner processing
|
|
218
|
-
text = text.replace(/^#{1,6}\s+/gm, ""); // Headers
|
|
219
|
-
text = text.replace(/\*\*(.+?)\*\*/g, "$1"); // Bold
|
|
220
|
-
text = text.replace(/\*(.+?)\*/g, "$1"); // Italic
|
|
221
|
-
text = text.replace(/\[(.+?)\]\(.+?\)/g, "$1"); // Links
|
|
222
|
-
text = text.replace(/`{1,3}[^`]+`{1,3}/g, ""); // Code blocks
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Clean up whitespace
|
|
226
|
-
text = text.replace(/\s+/g, " ").trim();
|
|
227
|
-
|
|
228
|
-
log(`Extracted ${text.length} characters from file`, "success");
|
|
229
|
-
return text;
|
|
230
|
-
} catch (error) {
|
|
231
|
-
throw new Error(`Failed to read file: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Get content based on source type
|
|
236
|
-
async function getContent(source: string, sourceType: "url" | "file" | "text", maxLength: number): Promise<string> {
|
|
237
|
-
let content: string;
|
|
238
|
-
|
|
239
|
-
if (sourceType === "url") {
|
|
240
|
-
content = await extractFromURL(source);
|
|
241
|
-
} else if (sourceType === "file") {
|
|
242
|
-
content = extractFromFile(source);
|
|
243
|
-
} else {
|
|
244
|
-
content = source;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Truncate if too long
|
|
248
|
-
if (content.length > maxLength) {
|
|
249
|
-
log(`Content truncated from ${content.length} to ${maxLength} characters`);
|
|
250
|
-
content = content.slice(0, maxLength);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return content;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Call AI API
|
|
257
|
-
async function callAI(prompt: string, systemPrompt: string): Promise<string> {
|
|
258
|
-
// Try OpenAI first
|
|
259
|
-
const openaiKey = process.env.OPENAI_API_KEY;
|
|
260
|
-
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
261
|
-
|
|
262
|
-
if (openaiKey) {
|
|
263
|
-
return await callOpenAI(prompt, systemPrompt, openaiKey);
|
|
264
|
-
} else if (anthropicKey) {
|
|
265
|
-
return await callAnthropic(prompt, systemPrompt, anthropicKey);
|
|
266
|
-
} else {
|
|
267
|
-
throw new Error("No AI API key found. Please set OPENAI_API_KEY or ANTHROPIC_API_KEY environment variable");
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Call OpenAI API
|
|
272
|
-
async function callOpenAI(prompt: string, systemPrompt: string, apiKey: string): Promise<string> {
|
|
273
|
-
log("Using OpenAI API...");
|
|
274
|
-
|
|
275
|
-
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
276
|
-
method: "POST",
|
|
277
|
-
headers: {
|
|
278
|
-
"Content-Type": "application/json",
|
|
279
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
280
|
-
},
|
|
281
|
-
body: JSON.stringify({
|
|
282
|
-
model: "gpt-4o-mini",
|
|
283
|
-
messages: [
|
|
284
|
-
{ role: "system", content: systemPrompt },
|
|
285
|
-
{ role: "user", content: prompt },
|
|
286
|
-
],
|
|
287
|
-
temperature: 0.8,
|
|
288
|
-
max_tokens: 4000,
|
|
289
|
-
}),
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
if (!response.ok) {
|
|
293
|
-
const error = await response.json();
|
|
294
|
-
throw new Error(`OpenAI API error: ${error.error?.message || response.statusText}`);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const data: OpenAIChatResponse = await response.json();
|
|
298
|
-
|
|
299
|
-
if (!data.choices?.[0]?.message?.content) {
|
|
300
|
-
throw new Error("No content returned from OpenAI");
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return data.choices[0].message.content;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Call Anthropic API
|
|
307
|
-
async function callAnthropic(prompt: string, systemPrompt: string, apiKey: string): Promise<string> {
|
|
308
|
-
log("Using Anthropic Claude API...");
|
|
309
|
-
|
|
310
|
-
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
311
|
-
method: "POST",
|
|
312
|
-
headers: {
|
|
313
|
-
"Content-Type": "application/json",
|
|
314
|
-
"x-api-key": apiKey,
|
|
315
|
-
"anthropic-version": "2023-06-01",
|
|
316
|
-
},
|
|
317
|
-
body: JSON.stringify({
|
|
318
|
-
model: "claude-3-5-sonnet-20241022",
|
|
319
|
-
max_tokens: 4000,
|
|
320
|
-
system: systemPrompt,
|
|
321
|
-
messages: [
|
|
322
|
-
{ role: "user", content: prompt },
|
|
323
|
-
],
|
|
324
|
-
temperature: 0.8,
|
|
325
|
-
}),
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
if (!response.ok) {
|
|
329
|
-
const error = await response.json();
|
|
330
|
-
throw new Error(`Anthropic API error: ${error.error?.message || response.statusText}`);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const data: AnthropicResponse = await response.json();
|
|
334
|
-
|
|
335
|
-
if (!data.content?.[0]?.text) {
|
|
336
|
-
throw new Error("No content returned from Anthropic");
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return data.content[0].text;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Generate posts for a specific platform
|
|
343
|
-
async function generatePlatformPosts(
|
|
344
|
-
content: string,
|
|
345
|
-
platform: Platform,
|
|
346
|
-
options: GenerateOptions
|
|
347
|
-
): Promise<SocialPost[]> {
|
|
348
|
-
const config = PLATFORM_CONFIGS[platform];
|
|
349
|
-
|
|
350
|
-
log(`Generating ${options.count} post(s) for ${config.name}...`);
|
|
351
|
-
|
|
352
|
-
const systemPrompt = `You are an expert social media content creator specializing in ${config.name}. Create engaging, platform-optimized posts that drive engagement and conversions.`;
|
|
353
|
-
|
|
354
|
-
const toneDescriptions = {
|
|
355
|
-
professional: "formal, authoritative, business-appropriate",
|
|
356
|
-
casual: "friendly, approachable, conversational",
|
|
357
|
-
witty: "clever, humorous, attention-grabbing",
|
|
358
|
-
inspiring: "motivational, uplifting, aspirational",
|
|
359
|
-
educational: "informative, clear, teaching-focused",
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
const userPrompt = `Transform the following content into ${options.count} engaging ${config.name} post(s).
|
|
363
|
-
|
|
364
|
-
CONTENT:
|
|
365
|
-
${content.slice(0, 3000)}...
|
|
366
|
-
|
|
367
|
-
REQUIREMENTS:
|
|
368
|
-
- Platform: ${config.name}
|
|
369
|
-
- Character limit: ${config.charLimit}
|
|
370
|
-
- Tone: ${toneDescriptions[options.tone]}
|
|
371
|
-
- Style: ${config.style}
|
|
372
|
-
- Emoji usage: ${config.emojiUsage}
|
|
373
|
-
${options.includeHashtags ? `- Include ${config.hashtagLimit} relevant hashtags` : "- No hashtags"}
|
|
374
|
-
${options.threads ? "- Create thread version if content is long" : ""}
|
|
375
|
-
|
|
376
|
-
Return a JSON array with ${options.count} post objects in this format:
|
|
377
|
-
[
|
|
378
|
-
{
|
|
379
|
-
"content": "The post content (respecting character limit)",
|
|
380
|
-
"hashtags": ["hashtag1", "hashtag2"],
|
|
381
|
-
"hook": "Attention-grabbing opening line",
|
|
382
|
-
"cta": "Call to action",
|
|
383
|
-
${options.threads ? '"threadPosts": ["post 1/5", "post 2/5", ...],' : ""}
|
|
384
|
-
"bestTime": "Optimal posting time (e.g., 'Weekday mornings 9-11am')"
|
|
385
|
-
}
|
|
386
|
-
]
|
|
387
|
-
|
|
388
|
-
Make each post variant unique and engaging. Ensure character counts are within limits.`;
|
|
389
|
-
|
|
390
|
-
const response = await callAI(userPrompt, systemPrompt);
|
|
391
|
-
|
|
392
|
-
// Parse JSON response
|
|
393
|
-
const jsonMatch = response.match(/\[[\s\S]*\]/);
|
|
394
|
-
if (!jsonMatch) {
|
|
395
|
-
throw new Error(`Could not parse ${platform} posts JSON from response`);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
const postsData = JSON.parse(jsonMatch[0]);
|
|
399
|
-
|
|
400
|
-
const posts: SocialPost[] = postsData.map((post: any) => ({
|
|
401
|
-
platform,
|
|
402
|
-
content: post.content,
|
|
403
|
-
hashtags: post.hashtags || [],
|
|
404
|
-
hooks: [post.hook].filter(Boolean),
|
|
405
|
-
cta: post.cta,
|
|
406
|
-
threadPosts: post.threadPosts,
|
|
407
|
-
bestTime: post.bestTime,
|
|
408
|
-
characterCount: post.content.length,
|
|
409
|
-
}));
|
|
410
|
-
|
|
411
|
-
log(`Generated ${posts.length} ${config.name} post(s)`, "success");
|
|
412
|
-
|
|
413
|
-
return posts;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// Generate all posts
|
|
417
|
-
async function generateAllPosts(
|
|
418
|
-
content: string,
|
|
419
|
-
options: GenerateOptions
|
|
420
|
-
): Promise<GeneratedContent> {
|
|
421
|
-
log(`Generating posts for ${options.platforms.length} platform(s)...`);
|
|
422
|
-
|
|
423
|
-
// First, get a summary and title from the content
|
|
424
|
-
const summaryPrompt = `Analyze this content and provide a title and brief summary.
|
|
425
|
-
|
|
426
|
-
CONTENT:
|
|
427
|
-
${content.slice(0, 2000)}...
|
|
428
|
-
|
|
429
|
-
Return JSON:
|
|
430
|
-
{
|
|
431
|
-
"title": "Content title or main topic",
|
|
432
|
-
"summary": "2-3 sentence summary"
|
|
433
|
-
}`;
|
|
434
|
-
|
|
435
|
-
const summaryResponse = await callAI(
|
|
436
|
-
summaryPrompt,
|
|
437
|
-
"You are a content analyst. Provide concise, accurate summaries."
|
|
438
|
-
);
|
|
439
|
-
|
|
440
|
-
const summaryMatch = summaryResponse.match(/\{[\s\S]*\}/);
|
|
441
|
-
const summaryData = summaryMatch ? JSON.parse(summaryMatch[0]) : {
|
|
442
|
-
title: "Generated Content",
|
|
443
|
-
summary: "Social media posts generated from content",
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
// Generate posts for each platform
|
|
447
|
-
const allPosts: SocialPost[] = [];
|
|
448
|
-
|
|
449
|
-
for (const platform of options.platforms) {
|
|
450
|
-
const posts = await generatePlatformPosts(content, platform, options);
|
|
451
|
-
allPosts.push(...posts);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
const result: GeneratedContent = {
|
|
455
|
-
sourceTitle: summaryData.title,
|
|
456
|
-
sourceSummary: summaryData.summary,
|
|
457
|
-
platforms: options.platforms,
|
|
458
|
-
posts: allPosts,
|
|
459
|
-
generatedAt: new Date().toISOString(),
|
|
460
|
-
options,
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
log(`Generated ${allPosts.length} total posts across all platforms`, "success");
|
|
464
|
-
|
|
465
|
-
return result;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
// Export as JSON
|
|
469
|
-
function exportJSON(content: GeneratedContent, outputPath: string): void {
|
|
470
|
-
const json = JSON.stringify(content, null, 2);
|
|
471
|
-
writeFileSync(outputPath, json);
|
|
472
|
-
log(`JSON exported to: ${outputPath}`);
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Export as Markdown
|
|
476
|
-
function exportMarkdown(content: GeneratedContent, outputPath: string): void {
|
|
477
|
-
let markdown = `# Social Media Posts\n\n`;
|
|
478
|
-
markdown += `**Source:** ${content.sourceTitle}\n\n`;
|
|
479
|
-
markdown += `**Summary:** ${content.sourceSummary}\n\n`;
|
|
480
|
-
markdown += `**Generated:** ${new Date(content.generatedAt).toLocaleString()}\n\n`;
|
|
481
|
-
markdown += `**Platforms:** ${content.platforms.join(", ")}\n\n`;
|
|
482
|
-
markdown += `---\n\n`;
|
|
483
|
-
|
|
484
|
-
// Group posts by platform
|
|
485
|
-
const postsByPlatform: Record<Platform, SocialPost[]> = {
|
|
486
|
-
twitter: [],
|
|
487
|
-
linkedin: [],
|
|
488
|
-
facebook: [],
|
|
489
|
-
instagram: [],
|
|
490
|
-
threads: [],
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
content.posts.forEach(post => {
|
|
494
|
-
postsByPlatform[post.platform].push(post);
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
// Write posts for each platform
|
|
498
|
-
for (const platform of content.platforms) {
|
|
499
|
-
const posts = postsByPlatform[platform];
|
|
500
|
-
if (posts.length === 0) continue;
|
|
501
|
-
|
|
502
|
-
const config = PLATFORM_CONFIGS[platform];
|
|
503
|
-
markdown += `## ${config.name}\n\n`;
|
|
504
|
-
|
|
505
|
-
posts.forEach((post, index) => {
|
|
506
|
-
markdown += `### Variant ${index + 1}\n\n`;
|
|
507
|
-
markdown += `${post.content}\n\n`;
|
|
508
|
-
|
|
509
|
-
if (post.hashtags.length > 0) {
|
|
510
|
-
markdown += `**Hashtags:** ${post.hashtags.join(" ")}\n\n`;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
if (post.hooks.length > 0) {
|
|
514
|
-
markdown += `**Hook:** ${post.hooks[0]}\n\n`;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
if (post.cta) {
|
|
518
|
-
markdown += `**CTA:** ${post.cta}\n\n`;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
if (post.threadPosts && post.threadPosts.length > 0) {
|
|
522
|
-
markdown += `**Thread Version:**\n\n`;
|
|
523
|
-
post.threadPosts.forEach((threadPost, i) => {
|
|
524
|
-
markdown += `${i + 1}. ${threadPost}\n\n`;
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
if (post.bestTime) {
|
|
529
|
-
markdown += `**Best Time:** ${post.bestTime}\n\n`;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
markdown += `**Character Count:** ${post.characterCount}\n\n`;
|
|
533
|
-
markdown += `---\n\n`;
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
writeFileSync(outputPath, markdown);
|
|
538
|
-
log(`Markdown exported to: ${outputPath}`);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// Export as text files per platform
|
|
542
|
-
function exportText(content: GeneratedContent, outputDir: string): void {
|
|
543
|
-
const postsByPlatform: Record<Platform, SocialPost[]> = {
|
|
544
|
-
twitter: [],
|
|
545
|
-
linkedin: [],
|
|
546
|
-
facebook: [],
|
|
547
|
-
instagram: [],
|
|
548
|
-
threads: [],
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
content.posts.forEach(post => {
|
|
552
|
-
postsByPlatform[post.platform].push(post);
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
for (const platform of content.platforms) {
|
|
556
|
-
const posts = postsByPlatform[platform];
|
|
557
|
-
if (posts.length === 0) continue;
|
|
558
|
-
|
|
559
|
-
let text = `${PLATFORM_CONFIGS[platform].name} Posts\n`;
|
|
560
|
-
text += `${"=".repeat(50)}\n\n`;
|
|
561
|
-
|
|
562
|
-
posts.forEach((post, index) => {
|
|
563
|
-
text += `--- Variant ${index + 1} ---\n\n`;
|
|
564
|
-
text += `${post.content}\n\n`;
|
|
565
|
-
|
|
566
|
-
if (post.hashtags.length > 0) {
|
|
567
|
-
text += `Hashtags: ${post.hashtags.join(" ")}\n\n`;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
if (post.threadPosts && post.threadPosts.length > 0) {
|
|
571
|
-
text += `Thread Version:\n`;
|
|
572
|
-
post.threadPosts.forEach((threadPost, i) => {
|
|
573
|
-
text += `${i + 1}. ${threadPost}\n`;
|
|
574
|
-
});
|
|
575
|
-
text += `\n`;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
text += `Character Count: ${post.characterCount}\n`;
|
|
579
|
-
text += `Best Time: ${post.bestTime || "N/A"}\n\n`;
|
|
580
|
-
text += `${"=".repeat(50)}\n\n`;
|
|
581
|
-
});
|
|
582
|
-
|
|
583
|
-
const outputPath = join(outputDir, `${platform}.txt`);
|
|
584
|
-
writeFileSync(outputPath, text);
|
|
585
|
-
log(`${PLATFORM_CONFIGS[platform].name} posts exported to: ${outputPath}`);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// Main function
|
|
590
15
|
async function main() {
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
options: {
|
|
594
|
-
input: { type: "string" },
|
|
595
|
-
platforms: { type: "string", default: "all" },
|
|
596
|
-
count: { type: "string", default: "3" },
|
|
597
|
-
tone: { type: "string", default: "professional" },
|
|
598
|
-
"include-hashtags": { type: "boolean", default: true },
|
|
599
|
-
threads: { type: "boolean", default: false },
|
|
600
|
-
"max-length": { type: "string", default: "10000" },
|
|
601
|
-
output: { type: "string", short: "o" },
|
|
602
|
-
format: { type: "string", default: "json" },
|
|
603
|
-
help: { type: "boolean", short: "h" },
|
|
604
|
-
},
|
|
605
|
-
allowPositionals: true,
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
// Show help
|
|
609
|
-
if (values.help) {
|
|
610
|
-
console.log(`
|
|
611
|
-
Generate Social Posts - Transform content into platform-optimized social media posts
|
|
612
|
-
|
|
613
|
-
Usage:
|
|
614
|
-
bun run src/index.ts <url|file> [options]
|
|
615
|
-
bun run src/index.ts --input "text" [options]
|
|
616
|
-
|
|
617
|
-
Options:
|
|
618
|
-
--input <text> Direct text input (alternative to URL/file)
|
|
619
|
-
--platforms <list> Comma-separated platforms (twitter,linkedin,facebook,instagram,threads,all) [default: all]
|
|
620
|
-
--count <number> Number of post variants per platform [default: 3]
|
|
621
|
-
--tone <tone> Writing tone (professional,casual,witty,inspiring,educational) [default: professional]
|
|
622
|
-
--include-hashtags Include hashtag suggestions [default: true]
|
|
623
|
-
--threads Generate thread/carousel versions [default: false]
|
|
624
|
-
--max-length <chars> Maximum content length to process [default: 10000]
|
|
625
|
-
--output, -o <path> Custom output path
|
|
626
|
-
--format <format> Output format (json,markdown,text) [default: json]
|
|
627
|
-
--help, -h Show this help
|
|
628
|
-
|
|
629
|
-
Examples:
|
|
630
|
-
bun run src/index.ts "https://blog.com/article"
|
|
631
|
-
bun run src/index.ts ./article.md --platforms twitter,linkedin
|
|
632
|
-
bun run src/index.ts --input "Launch announcement" --tone witty
|
|
633
|
-
bun run src/index.ts ./post.md --threads --count 5
|
|
634
|
-
`);
|
|
635
|
-
process.exit(0);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
// Determine source
|
|
639
|
-
let source: string;
|
|
640
|
-
let sourceType: "url" | "file" | "text";
|
|
641
|
-
|
|
642
|
-
if (values.input) {
|
|
643
|
-
source = values.input as string;
|
|
644
|
-
sourceType = "text";
|
|
645
|
-
} else if (positionals.length > 0) {
|
|
646
|
-
source = positionals.join(" ");
|
|
647
|
-
sourceType = detectSourceType(source);
|
|
648
|
-
} else {
|
|
649
|
-
log("Please provide a URL, file path, or use --input for direct text", "error");
|
|
650
|
-
process.exit(1);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// Parse platforms
|
|
654
|
-
let platforms: Platform[];
|
|
655
|
-
const platformsInput = (values.platforms as string).toLowerCase();
|
|
656
|
-
|
|
657
|
-
if (platformsInput === "all") {
|
|
658
|
-
platforms = ["twitter", "linkedin", "facebook", "instagram", "threads"];
|
|
659
|
-
} else {
|
|
660
|
-
const platformList = platformsInput.split(",").map(p => p.trim());
|
|
661
|
-
const validPlatforms: Platform[] = ["twitter", "linkedin", "facebook", "instagram", "threads"];
|
|
662
|
-
|
|
663
|
-
platforms = platformList.filter(p => validPlatforms.includes(p as Platform)) as Platform[];
|
|
664
|
-
|
|
665
|
-
if (platforms.length === 0) {
|
|
666
|
-
log("No valid platforms specified. Use: twitter, linkedin, facebook, instagram, threads, or all", "error");
|
|
667
|
-
process.exit(1);
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// Validate options
|
|
672
|
-
const count = parseInt(values.count as string);
|
|
673
|
-
const maxLength = parseInt(values["max-length"] as string);
|
|
674
|
-
const tone = values.tone as Tone;
|
|
675
|
-
const format = values.format as OutputFormat;
|
|
676
|
-
|
|
677
|
-
const validTones: Tone[] = ["professional", "casual", "witty", "inspiring", "educational"];
|
|
678
|
-
const validFormats: OutputFormat[] = ["json", "markdown", "text"];
|
|
679
|
-
|
|
680
|
-
if (!validTones.includes(tone)) {
|
|
681
|
-
log(`Invalid tone: ${tone}. Must be one of: ${validTones.join(", ")}`, "error");
|
|
682
|
-
process.exit(1);
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
if (!validFormats.includes(format)) {
|
|
686
|
-
log(`Invalid format: ${format}. Must be one of: ${validFormats.join(", ")}`, "error");
|
|
687
|
-
process.exit(1);
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
if (count < 1 || count > 20) {
|
|
691
|
-
log("Count must be between 1 and 20", "error");
|
|
692
|
-
process.exit(1);
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
const options: GenerateOptions = {
|
|
696
|
-
source,
|
|
697
|
-
sourceType,
|
|
698
|
-
platforms,
|
|
699
|
-
count,
|
|
700
|
-
tone,
|
|
701
|
-
includeHashtags: values["include-hashtags"] as boolean,
|
|
702
|
-
threads: values.threads as boolean,
|
|
703
|
-
maxLength,
|
|
704
|
-
output: values.output as string | undefined,
|
|
705
|
-
format,
|
|
706
|
-
};
|
|
16
|
+
const options = parseGenerateOptions();
|
|
17
|
+
const { source, sourceType, platforms, count, tone, maxLength, format } = options;
|
|
707
18
|
|
|
708
19
|
try {
|
|
709
20
|
log(`Session ID: ${SESSION_ID}`);
|
|
@@ -711,7 +22,6 @@ Examples:
|
|
|
711
22
|
log(`Platforms: ${platforms.join(", ")}`);
|
|
712
23
|
log(`Options: ${tone} tone, ${count} variants per platform, hashtags: ${options.includeHashtags}, threads: ${options.threads}`);
|
|
713
24
|
|
|
714
|
-
// Get content
|
|
715
25
|
const content = await getContent(source, sourceType, maxLength);
|
|
716
26
|
|
|
717
27
|
if (content.length < 50) {
|
|
@@ -719,18 +29,20 @@ Examples:
|
|
|
719
29
|
process.exit(1);
|
|
720
30
|
}
|
|
721
31
|
|
|
722
|
-
|
|
723
|
-
|
|
32
|
+
const timestamp = new Date()
|
|
33
|
+
.toISOString()
|
|
34
|
+
.replace(/[:.]/g, "_")
|
|
35
|
+
.replace(/-/g, "_")
|
|
36
|
+
.slice(0, 19)
|
|
37
|
+
.toLowerCase();
|
|
724
38
|
const sourceSlug = slugify(sourceType === "url" ? new URL(source).pathname : sourceType === "file" ? source : content.slice(0, 50));
|
|
725
39
|
const outputDir = options.output || join(EXPORTS_DIR, `export_${timestamp}_${sourceSlug}`);
|
|
726
40
|
ensureDir(outputDir);
|
|
727
41
|
|
|
728
42
|
log(`Output directory: ${outputDir}`);
|
|
729
43
|
|
|
730
|
-
// Generate posts
|
|
731
44
|
const generatedContent = await generateAllPosts(content, options);
|
|
732
45
|
|
|
733
|
-
// Export in requested format(s)
|
|
734
46
|
if (format === "json" || format === "text") {
|
|
735
47
|
exportJSON(generatedContent, join(outputDir, "posts.json"));
|
|
736
48
|
}
|
|
@@ -743,19 +55,17 @@ Examples:
|
|
|
743
55
|
exportText(generatedContent, outputDir);
|
|
744
56
|
}
|
|
745
57
|
|
|
746
|
-
// Summary
|
|
747
58
|
console.log(`\n⨠Social media posts generated successfully!`);
|
|
748
59
|
console.log(` š Output: ${outputDir}`);
|
|
749
|
-
console.log(` š Platforms: ${platforms.map(
|
|
60
|
+
console.log(` š Platforms: ${platforms.map((platform) => PLATFORM_CONFIGS[platform].name).join(", ")}`);
|
|
750
61
|
console.log(` š Total Posts: ${generatedContent.posts.length}`);
|
|
751
62
|
console.log(` š Log: ${join(LOGS_DIR, `log_${SESSION_TIMESTAMP}_${SESSION_ID}.log`)}`);
|
|
752
63
|
console.log(`\nš Posts by Platform:`);
|
|
753
64
|
|
|
754
|
-
platforms.forEach(platform => {
|
|
755
|
-
const
|
|
756
|
-
console.log(` ${PLATFORM_CONFIGS[platform].name}: ${
|
|
65
|
+
platforms.forEach((platform) => {
|
|
66
|
+
const postCount = generatedContent.posts.filter((post) => post.platform === platform).length;
|
|
67
|
+
console.log(` ${PLATFORM_CONFIGS[platform].name}: ${postCount} posts`);
|
|
757
68
|
});
|
|
758
|
-
|
|
759
69
|
} catch (error) {
|
|
760
70
|
log(`Error: ${error instanceof Error ? error.message : "Unknown error"}`, "error");
|
|
761
71
|
if (error instanceof Error && error.stack) {
|