@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,603 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { join, resolve
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { writeFileSync } from "fs";
|
|
4
|
+
import { basename, join, resolve } from "path";
|
|
5
|
+
import { parseArguments } from "./cli";
|
|
6
|
+
import { EXPORTS_DIR, SESSION_ID, SKILL_NAME, ensureDir, getOpenAIApiKey, log } from "./runtime";
|
|
7
|
+
import { extractInvoiceData } from "./extractor";
|
|
8
|
+
import { formatAsCSV, formatAsJSON, formatAsMarkdown } from "./formatters";
|
|
9
|
+
import { validateFiles } from "./file-utils";
|
|
10
|
+
import type { ExtractionResult } from "./types";
|
|
7
11
|
|
|
8
|
-
// Constants
|
|
9
|
-
const SKILL_NAME = "extract-invoice";
|
|
10
|
-
const SESSION_ID = randomUUID().slice(0, 8);
|
|
11
|
-
const SESSION_TIMESTAMP = new Date()
|
|
12
|
-
.toISOString()
|
|
13
|
-
.replace(/[:.]/g, "_")
|
|
14
|
-
.replace(/-/g, "_")
|
|
15
|
-
.slice(0, 19)
|
|
16
|
-
.toLowerCase();
|
|
17
|
-
|
|
18
|
-
// Environment
|
|
19
|
-
const SKILLS_OUTPUT_DIR = process.env.SKILLS_OUTPUT_DIR || join(process.cwd(), ".skills");
|
|
20
|
-
const EXPORTS_DIR = join(SKILLS_OUTPUT_DIR, "exports", SKILL_NAME, SESSION_ID);
|
|
21
|
-
const LOGS_DIR = join(SKILLS_OUTPUT_DIR, "logs", SKILL_NAME);
|
|
22
|
-
|
|
23
|
-
// API Configuration
|
|
24
|
-
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
|
|
25
|
-
const OPENAI_API_URL = "https://api.openai.com/v1/chat/completions";
|
|
26
|
-
|
|
27
|
-
// Types
|
|
28
|
-
interface InvoiceData {
|
|
29
|
-
invoice_number: string | null;
|
|
30
|
-
invoice_date: string | null;
|
|
31
|
-
due_date: string | null;
|
|
32
|
-
po_number: string | null;
|
|
33
|
-
payment_terms: string | null;
|
|
34
|
-
vendor: VendorInfo;
|
|
35
|
-
customer: CustomerInfo;
|
|
36
|
-
line_items: LineItem[];
|
|
37
|
-
subtotal: number | null;
|
|
38
|
-
tax: TaxInfo | null;
|
|
39
|
-
discount: DiscountInfo | null;
|
|
40
|
-
shipping: number | null;
|
|
41
|
-
total: number | null;
|
|
42
|
-
currency: string;
|
|
43
|
-
payment_info: PaymentInfo | null;
|
|
44
|
-
notes: string | null;
|
|
45
|
-
confidence: number;
|
|
46
|
-
raw_text?: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
interface VendorInfo {
|
|
50
|
-
name: string | null;
|
|
51
|
-
address: string | null;
|
|
52
|
-
phone: string | null;
|
|
53
|
-
email: string | null;
|
|
54
|
-
tax_id: string | null;
|
|
55
|
-
website: string | null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
interface CustomerInfo {
|
|
59
|
-
name: string | null;
|
|
60
|
-
address: string | null;
|
|
61
|
-
phone: string | null;
|
|
62
|
-
email: string | null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface LineItem {
|
|
66
|
-
description: string;
|
|
67
|
-
quantity: number | null;
|
|
68
|
-
unit: string | null;
|
|
69
|
-
unit_price: number | null;
|
|
70
|
-
tax_rate: number | null;
|
|
71
|
-
subtotal: number | null;
|
|
72
|
-
discount: number | null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
interface TaxInfo {
|
|
76
|
-
rate: number | null;
|
|
77
|
-
amount: number;
|
|
78
|
-
type?: string;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
interface DiscountInfo {
|
|
82
|
-
type: "percentage" | "fixed" | null;
|
|
83
|
-
value: number | null;
|
|
84
|
-
amount: number;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
interface PaymentInfo {
|
|
88
|
-
method: string | null;
|
|
89
|
-
bank_name: string | null;
|
|
90
|
-
account_number: string | null;
|
|
91
|
-
routing_number: string | null;
|
|
92
|
-
iban: string | null;
|
|
93
|
-
swift: string | null;
|
|
94
|
-
reference: string | null;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
interface ExtractionResult {
|
|
98
|
-
file: string;
|
|
99
|
-
success: boolean;
|
|
100
|
-
data: InvoiceData | null;
|
|
101
|
-
error?: string;
|
|
102
|
-
processing_time_ms: number;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
interface Options {
|
|
106
|
-
files: string[];
|
|
107
|
-
format: "json" | "csv" | "excel" | "markdown";
|
|
108
|
-
confidence: boolean;
|
|
109
|
-
currency?: string;
|
|
110
|
-
language?: string;
|
|
111
|
-
pages?: string;
|
|
112
|
-
batch: boolean;
|
|
113
|
-
output?: string;
|
|
114
|
-
verbose: boolean;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Supported file types
|
|
118
|
-
const SUPPORTED_EXTENSIONS = [".pdf", ".png", ".jpg", ".jpeg", ".tiff", ".tif", ".heic", ".webp"];
|
|
119
|
-
|
|
120
|
-
// Utility functions
|
|
121
|
-
function ensureDir(dir: string): void {
|
|
122
|
-
if (!existsSync(dir)) {
|
|
123
|
-
mkdirSync(dir, { recursive: true });
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function log(message: string, level: "info" | "error" | "success" | "warn" = "info"): void {
|
|
128
|
-
const timestamp = new Date().toISOString();
|
|
129
|
-
const logFile = join(LOGS_DIR, `log_${SESSION_TIMESTAMP}_${SESSION_ID}.log`);
|
|
130
|
-
|
|
131
|
-
ensureDir(LOGS_DIR);
|
|
132
|
-
|
|
133
|
-
const logEntry = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
|
|
134
|
-
appendFileSync(logFile, logEntry);
|
|
135
|
-
|
|
136
|
-
const prefixes: Record<string, string> = {
|
|
137
|
-
info: "[INFO]",
|
|
138
|
-
error: "[ERROR]",
|
|
139
|
-
success: "[SUCCESS]",
|
|
140
|
-
warn: "[WARN]",
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
console.log(`${prefixes[level]} ${message}`);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function parseArguments(): Options {
|
|
147
|
-
const { values, positionals } = parseArgs({
|
|
148
|
-
args: process.argv.slice(2),
|
|
149
|
-
options: {
|
|
150
|
-
format: { type: "string", default: "json" },
|
|
151
|
-
confidence: { type: "boolean", default: false },
|
|
152
|
-
currency: { type: "string" },
|
|
153
|
-
language: { type: "string" },
|
|
154
|
-
pages: { type: "string" },
|
|
155
|
-
batch: { type: "boolean", default: false },
|
|
156
|
-
output: { type: "string" },
|
|
157
|
-
verbose: { type: "boolean", default: false },
|
|
158
|
-
help: { type: "boolean", short: "h" },
|
|
159
|
-
},
|
|
160
|
-
allowPositionals: true,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
if (values.help) {
|
|
164
|
-
printHelp();
|
|
165
|
-
process.exit(0);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const files: string[] = [];
|
|
169
|
-
for (const arg of positionals) {
|
|
170
|
-
if (arg.includes("*")) {
|
|
171
|
-
const expandedFiles = expandGlob(arg);
|
|
172
|
-
files.push(...expandedFiles);
|
|
173
|
-
} else {
|
|
174
|
-
files.push(resolve(process.cwd(), arg));
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
files,
|
|
180
|
-
format: values.format as "json" | "csv" | "excel" | "markdown",
|
|
181
|
-
confidence: values.confidence as boolean,
|
|
182
|
-
currency: values.currency as string,
|
|
183
|
-
language: values.language as string,
|
|
184
|
-
pages: values.pages as string,
|
|
185
|
-
batch: values.batch as boolean,
|
|
186
|
-
output: values.output as string,
|
|
187
|
-
verbose: values.verbose as boolean,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function expandGlob(pattern: string): string[] {
|
|
192
|
-
const dir = pattern.includes("/") ? pattern.substring(0, pattern.lastIndexOf("/")) : ".";
|
|
193
|
-
const filePattern = pattern.includes("/") ? pattern.substring(pattern.lastIndexOf("/") + 1) : pattern;
|
|
194
|
-
const regex = new RegExp("^" + filePattern.replace(/\*/g, ".*") + "$");
|
|
195
|
-
|
|
196
|
-
const resolvedDir = resolve(process.cwd(), dir);
|
|
197
|
-
if (!existsSync(resolvedDir)) {
|
|
198
|
-
return [];
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return readdirSync(resolvedDir)
|
|
202
|
-
.filter((file) => regex.test(file))
|
|
203
|
-
.map((file) => join(resolvedDir, file))
|
|
204
|
-
.filter((file) => {
|
|
205
|
-
const ext = extname(file).toLowerCase();
|
|
206
|
-
return SUPPORTED_EXTENSIONS.includes(ext);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function printHelp(): void {
|
|
211
|
-
console.log(`
|
|
212
|
-
Extract Invoice - AI-powered invoice data extraction
|
|
213
|
-
|
|
214
|
-
Usage:
|
|
215
|
-
skills run extract-invoice -- <file(s)> [options]
|
|
216
|
-
|
|
217
|
-
Arguments:
|
|
218
|
-
file(s) Invoice file(s) to process (PDF, PNG, JPG, etc.)
|
|
219
|
-
|
|
220
|
-
Options:
|
|
221
|
-
--format <format> Output format: json, csv, excel, markdown (default: json)
|
|
222
|
-
--confidence Include confidence scores for extracted fields
|
|
223
|
-
--currency <code> Convert totals to specified currency (e.g., USD, EUR)
|
|
224
|
-
--language <lang> Document language hint (e.g., en, es, fr)
|
|
225
|
-
--pages <range> Pages to process (e.g., "1-3,5")
|
|
226
|
-
--batch Process multiple files and combine output
|
|
227
|
-
--output <file> Output file path
|
|
228
|
-
--verbose Show detailed progress
|
|
229
|
-
--help, -h Show this help
|
|
230
|
-
|
|
231
|
-
Examples:
|
|
232
|
-
skills run extract-invoice -- invoice.pdf
|
|
233
|
-
skills run extract-invoice -- receipt.jpg --format csv
|
|
234
|
-
skills run extract-invoice -- ./invoices/*.pdf --batch
|
|
235
|
-
skills run extract-invoice -- invoice.pdf --confidence --verbose
|
|
236
|
-
|
|
237
|
-
Supported file types:
|
|
238
|
-
PDF, PNG, JPG, JPEG, TIFF, HEIC, WebP
|
|
239
|
-
`);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function validateFiles(files: string[]): string[] {
|
|
243
|
-
const validFiles: string[] = [];
|
|
244
|
-
|
|
245
|
-
for (const file of files) {
|
|
246
|
-
if (!existsSync(file)) {
|
|
247
|
-
log(`File not found: ${file}`, "warn");
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const ext = extname(file).toLowerCase();
|
|
252
|
-
if (!SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
253
|
-
log(`Unsupported file type: ${file}`, "warn");
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
validFiles.push(file);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return validFiles;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function fileToBase64(filePath: string): string {
|
|
264
|
-
const buffer = readFileSync(filePath);
|
|
265
|
-
return buffer.toString("base64");
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function getMimeType(filePath: string): string {
|
|
269
|
-
const ext = extname(filePath).toLowerCase();
|
|
270
|
-
const mimeTypes: Record<string, string> = {
|
|
271
|
-
".pdf": "application/pdf",
|
|
272
|
-
".png": "image/png",
|
|
273
|
-
".jpg": "image/jpeg",
|
|
274
|
-
".jpeg": "image/jpeg",
|
|
275
|
-
".tiff": "image/tiff",
|
|
276
|
-
".tif": "image/tiff",
|
|
277
|
-
".heic": "image/heic",
|
|
278
|
-
".webp": "image/webp",
|
|
279
|
-
};
|
|
280
|
-
return mimeTypes[ext] || "application/octet-stream";
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
async function extractInvoiceData(filePath: string, options: Options): Promise<InvoiceData> {
|
|
284
|
-
if (!OPENAI_API_KEY) {
|
|
285
|
-
throw new Error("OPENAI_API_KEY environment variable is not set");
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const base64Content = fileToBase64(filePath);
|
|
289
|
-
const mimeType = getMimeType(filePath);
|
|
290
|
-
|
|
291
|
-
if (options.verbose) {
|
|
292
|
-
log(`Processing ${basename(filePath)} (${mimeType})...`);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const systemPrompt = `You are an expert invoice data extraction system. Extract all relevant information from the provided invoice image/document and return it as structured JSON.
|
|
296
|
-
|
|
297
|
-
Be thorough and extract:
|
|
298
|
-
- Invoice details (number, dates, PO number, payment terms)
|
|
299
|
-
- Vendor information (name, address, contact, tax ID)
|
|
300
|
-
- Customer/Bill-to information
|
|
301
|
-
- All line items with quantities, prices, and totals
|
|
302
|
-
- Tax calculations
|
|
303
|
-
- Discounts if any
|
|
304
|
-
- Grand total and currency
|
|
305
|
-
- Payment information (bank details, references)
|
|
306
|
-
- Any notes or special instructions
|
|
307
|
-
|
|
308
|
-
For amounts, extract numeric values without currency symbols.
|
|
309
|
-
For dates, use ISO format (YYYY-MM-DD) when possible.
|
|
310
|
-
Estimate your confidence in the extraction (0-100).
|
|
311
|
-
|
|
312
|
-
${options.language ? `The document is in ${options.language}.` : "Detect the document language automatically."}
|
|
313
|
-
${options.currency ? `Convert all amounts to ${options.currency} if possible.` : "Detect and preserve the original currency."}`;
|
|
314
|
-
|
|
315
|
-
const userPrompt = `Extract all invoice data from this document and return it as JSON matching this structure:
|
|
316
|
-
{
|
|
317
|
-
"invoice_number": "string or null",
|
|
318
|
-
"invoice_date": "YYYY-MM-DD or null",
|
|
319
|
-
"due_date": "YYYY-MM-DD or null",
|
|
320
|
-
"po_number": "string or null",
|
|
321
|
-
"payment_terms": "string or null",
|
|
322
|
-
"vendor": {
|
|
323
|
-
"name": "string or null",
|
|
324
|
-
"address": "string or null",
|
|
325
|
-
"phone": "string or null",
|
|
326
|
-
"email": "string or null",
|
|
327
|
-
"tax_id": "string or null",
|
|
328
|
-
"website": "string or null"
|
|
329
|
-
},
|
|
330
|
-
"customer": {
|
|
331
|
-
"name": "string or null",
|
|
332
|
-
"address": "string or null",
|
|
333
|
-
"phone": "string or null",
|
|
334
|
-
"email": "string or null"
|
|
335
|
-
},
|
|
336
|
-
"line_items": [
|
|
337
|
-
{
|
|
338
|
-
"description": "string",
|
|
339
|
-
"quantity": number or null,
|
|
340
|
-
"unit": "string or null",
|
|
341
|
-
"unit_price": number or null,
|
|
342
|
-
"tax_rate": number or null,
|
|
343
|
-
"subtotal": number or null,
|
|
344
|
-
"discount": number or null
|
|
345
|
-
}
|
|
346
|
-
],
|
|
347
|
-
"subtotal": number or null,
|
|
348
|
-
"tax": {
|
|
349
|
-
"rate": number or null,
|
|
350
|
-
"amount": number,
|
|
351
|
-
"type": "string or null"
|
|
352
|
-
},
|
|
353
|
-
"discount": {
|
|
354
|
-
"type": "percentage or fixed or null",
|
|
355
|
-
"value": number or null,
|
|
356
|
-
"amount": number
|
|
357
|
-
},
|
|
358
|
-
"shipping": number or null,
|
|
359
|
-
"total": number or null,
|
|
360
|
-
"currency": "USD, EUR, etc.",
|
|
361
|
-
"payment_info": {
|
|
362
|
-
"method": "string or null",
|
|
363
|
-
"bank_name": "string or null",
|
|
364
|
-
"account_number": "string or null (masked if sensitive)",
|
|
365
|
-
"routing_number": "string or null",
|
|
366
|
-
"iban": "string or null (masked)",
|
|
367
|
-
"swift": "string or null",
|
|
368
|
-
"reference": "string or null"
|
|
369
|
-
},
|
|
370
|
-
"notes": "string or null",
|
|
371
|
-
"confidence": number (0-100)
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
Return ONLY the JSON object, no markdown formatting or explanation.`;
|
|
375
|
-
|
|
376
|
-
const requestBody = {
|
|
377
|
-
model: "gpt-4o",
|
|
378
|
-
messages: [
|
|
379
|
-
{
|
|
380
|
-
role: "system",
|
|
381
|
-
content: systemPrompt,
|
|
382
|
-
},
|
|
383
|
-
{
|
|
384
|
-
role: "user",
|
|
385
|
-
content: [
|
|
386
|
-
{
|
|
387
|
-
type: "text",
|
|
388
|
-
text: userPrompt,
|
|
389
|
-
},
|
|
390
|
-
{
|
|
391
|
-
type: "image_url",
|
|
392
|
-
image_url: {
|
|
393
|
-
url: `data:${mimeType};base64,${base64Content}`,
|
|
394
|
-
detail: "high",
|
|
395
|
-
},
|
|
396
|
-
},
|
|
397
|
-
],
|
|
398
|
-
},
|
|
399
|
-
],
|
|
400
|
-
max_tokens: 4096,
|
|
401
|
-
temperature: 0.1,
|
|
402
|
-
};
|
|
403
|
-
|
|
404
|
-
const response = await fetch(OPENAI_API_URL, {
|
|
405
|
-
method: "POST",
|
|
406
|
-
headers: {
|
|
407
|
-
"Content-Type": "application/json",
|
|
408
|
-
Authorization: `Bearer ${OPENAI_API_KEY}`,
|
|
409
|
-
},
|
|
410
|
-
body: JSON.stringify(requestBody),
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
if (!response.ok) {
|
|
414
|
-
const error = await response.text();
|
|
415
|
-
throw new Error(`OpenAI API error (${response.status}): ${error}`);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
const result = await response.json();
|
|
419
|
-
const content = result.choices[0]?.message?.content;
|
|
420
|
-
|
|
421
|
-
if (!content) {
|
|
422
|
-
throw new Error("No response from OpenAI API");
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Parse the JSON response
|
|
426
|
-
try {
|
|
427
|
-
// Remove markdown code blocks if present
|
|
428
|
-
let jsonStr = content.trim();
|
|
429
|
-
if (jsonStr.startsWith("```json")) {
|
|
430
|
-
jsonStr = jsonStr.slice(7);
|
|
431
|
-
} else if (jsonStr.startsWith("```")) {
|
|
432
|
-
jsonStr = jsonStr.slice(3);
|
|
433
|
-
}
|
|
434
|
-
if (jsonStr.endsWith("```")) {
|
|
435
|
-
jsonStr = jsonStr.slice(0, -3);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
const invoiceData: InvoiceData = JSON.parse(jsonStr.trim());
|
|
439
|
-
return invoiceData;
|
|
440
|
-
} catch (parseError) {
|
|
441
|
-
log(`Failed to parse API response: ${content}`, "error");
|
|
442
|
-
throw new Error("Failed to parse invoice data from API response");
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function formatAsJSON(results: ExtractionResult[], options: Options): string {
|
|
447
|
-
if (results.length === 1 && !options.batch) {
|
|
448
|
-
const result = results[0];
|
|
449
|
-
if (result.success && result.data) {
|
|
450
|
-
if (!options.confidence) {
|
|
451
|
-
const { confidence, ...dataWithoutConfidence } = result.data;
|
|
452
|
-
return JSON.stringify(dataWithoutConfidence, null, 2);
|
|
453
|
-
}
|
|
454
|
-
return JSON.stringify(result.data, null, 2);
|
|
455
|
-
}
|
|
456
|
-
return JSON.stringify({ error: result.error }, null, 2);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// Batch output
|
|
460
|
-
const output = {
|
|
461
|
-
processed_at: new Date().toISOString(),
|
|
462
|
-
total_files: results.length,
|
|
463
|
-
successful: results.filter((r) => r.success).length,
|
|
464
|
-
failed: results.filter((r) => !r.success).length,
|
|
465
|
-
results: results.map((r) => ({
|
|
466
|
-
file: basename(r.file),
|
|
467
|
-
success: r.success,
|
|
468
|
-
data: r.data,
|
|
469
|
-
error: r.error,
|
|
470
|
-
processing_time_ms: r.processing_time_ms,
|
|
471
|
-
})),
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
return JSON.stringify(output, null, 2);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function formatAsCSV(results: ExtractionResult[]): string {
|
|
478
|
-
const headers = [
|
|
479
|
-
"file",
|
|
480
|
-
"invoice_number",
|
|
481
|
-
"invoice_date",
|
|
482
|
-
"due_date",
|
|
483
|
-
"vendor_name",
|
|
484
|
-
"vendor_address",
|
|
485
|
-
"customer_name",
|
|
486
|
-
"subtotal",
|
|
487
|
-
"tax_amount",
|
|
488
|
-
"total",
|
|
489
|
-
"currency",
|
|
490
|
-
"status",
|
|
491
|
-
];
|
|
492
|
-
|
|
493
|
-
const rows: string[][] = [headers];
|
|
494
|
-
|
|
495
|
-
for (const result of results) {
|
|
496
|
-
if (result.success && result.data) {
|
|
497
|
-
const d = result.data;
|
|
498
|
-
rows.push([
|
|
499
|
-
basename(result.file),
|
|
500
|
-
d.invoice_number || "",
|
|
501
|
-
d.invoice_date || "",
|
|
502
|
-
d.due_date || "",
|
|
503
|
-
d.vendor.name || "",
|
|
504
|
-
d.vendor.address || "",
|
|
505
|
-
d.customer.name || "",
|
|
506
|
-
d.subtotal?.toString() || "",
|
|
507
|
-
d.tax?.amount?.toString() || "",
|
|
508
|
-
d.total?.toString() || "",
|
|
509
|
-
d.currency || "",
|
|
510
|
-
"success",
|
|
511
|
-
]);
|
|
512
|
-
} else {
|
|
513
|
-
rows.push([
|
|
514
|
-
basename(result.file),
|
|
515
|
-
"", "", "", "", "", "", "", "", "", "",
|
|
516
|
-
`error: ${result.error}`,
|
|
517
|
-
]);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return rows.map((row) => row.map((cell) => `"${cell.replace(/"/g, '""')}"`).join(",")).join("\n");
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
function formatAsMarkdown(results: ExtractionResult[], options: Options): string {
|
|
525
|
-
let output = "# Invoice Extraction Results\n\n";
|
|
526
|
-
output += `Processed: ${new Date().toISOString()}\n\n`;
|
|
527
|
-
|
|
528
|
-
for (const result of results) {
|
|
529
|
-
output += `---\n\n`;
|
|
530
|
-
output += `## ${basename(result.file)}\n\n`;
|
|
531
|
-
|
|
532
|
-
if (!result.success) {
|
|
533
|
-
output += `**Error:** ${result.error}\n\n`;
|
|
534
|
-
continue;
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
const d = result.data!;
|
|
538
|
-
|
|
539
|
-
output += `### Invoice Details\n\n`;
|
|
540
|
-
output += `| Field | Value |\n`;
|
|
541
|
-
output += `|-------|-------|\n`;
|
|
542
|
-
output += `| Invoice Number | ${d.invoice_number || "N/A"} |\n`;
|
|
543
|
-
output += `| Date | ${d.invoice_date || "N/A"} |\n`;
|
|
544
|
-
output += `| Due Date | ${d.due_date || "N/A"} |\n`;
|
|
545
|
-
output += `| PO Number | ${d.po_number || "N/A"} |\n`;
|
|
546
|
-
output += `| Payment Terms | ${d.payment_terms || "N/A"} |\n\n`;
|
|
547
|
-
|
|
548
|
-
output += `### Vendor\n\n`;
|
|
549
|
-
output += `**${d.vendor.name || "Unknown Vendor"}**\n`;
|
|
550
|
-
if (d.vendor.address) output += `${d.vendor.address}\n`;
|
|
551
|
-
if (d.vendor.email) output += `Email: ${d.vendor.email}\n`;
|
|
552
|
-
if (d.vendor.phone) output += `Phone: ${d.vendor.phone}\n`;
|
|
553
|
-
if (d.vendor.tax_id) output += `Tax ID: ${d.vendor.tax_id}\n`;
|
|
554
|
-
output += "\n";
|
|
555
|
-
|
|
556
|
-
if (d.customer.name) {
|
|
557
|
-
output += `### Customer\n\n`;
|
|
558
|
-
output += `**${d.customer.name}**\n`;
|
|
559
|
-
if (d.customer.address) output += `${d.customer.address}\n`;
|
|
560
|
-
if (d.customer.email) output += `Email: ${d.customer.email}\n`;
|
|
561
|
-
output += "\n";
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
if (d.line_items.length > 0) {
|
|
565
|
-
output += `### Line Items\n\n`;
|
|
566
|
-
output += `| Description | Qty | Unit Price | Subtotal |\n`;
|
|
567
|
-
output += `|-------------|-----|------------|----------|\n`;
|
|
568
|
-
for (const item of d.line_items) {
|
|
569
|
-
output += `| ${item.description} | ${item.quantity || "-"} ${item.unit || ""} | ${item.unit_price?.toFixed(2) || "-"} | ${item.subtotal?.toFixed(2) || "-"} |\n`;
|
|
570
|
-
}
|
|
571
|
-
output += "\n";
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
output += `### Totals\n\n`;
|
|
575
|
-
if (d.subtotal) output += `- **Subtotal:** ${d.currency} ${d.subtotal.toFixed(2)}\n`;
|
|
576
|
-
if (d.tax) output += `- **Tax${d.tax.rate ? ` (${d.tax.rate}%)` : ""}:** ${d.currency} ${d.tax.amount.toFixed(2)}\n`;
|
|
577
|
-
if (d.discount) output += `- **Discount:** -${d.currency} ${d.discount.amount.toFixed(2)}\n`;
|
|
578
|
-
if (d.shipping) output += `- **Shipping:** ${d.currency} ${d.shipping.toFixed(2)}\n`;
|
|
579
|
-
output += `- **Total:** ${d.currency} ${d.total?.toFixed(2) || "N/A"}\n\n`;
|
|
580
|
-
|
|
581
|
-
if (d.notes) {
|
|
582
|
-
output += `### Notes\n\n${d.notes}\n\n`;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if (options.confidence) {
|
|
586
|
-
output += `*Extraction confidence: ${d.confidence}%*\n\n`;
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
return output;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// Main execution
|
|
594
12
|
async function main(): Promise<void> {
|
|
595
13
|
const startTime = Date.now();
|
|
596
14
|
|
|
597
15
|
log(`Starting ${SKILL_NAME} session: ${SESSION_ID}`);
|
|
598
16
|
|
|
599
|
-
|
|
600
|
-
if (!OPENAI_API_KEY) {
|
|
17
|
+
if (!getOpenAIApiKey()) {
|
|
601
18
|
console.error("Error: OPENAI_API_KEY environment variable is required.");
|
|
602
19
|
console.error("Get your API key from https://platform.openai.com/api-keys");
|
|
603
20
|
process.exit(1);
|
|
@@ -606,10 +23,9 @@ async function main(): Promise<void> {
|
|
|
606
23
|
const options = parseArguments();
|
|
607
24
|
|
|
608
25
|
if (options.verbose) {
|
|
609
|
-
log(`Options: ${JSON.stringify({ ...options, files: options.files.length
|
|
26
|
+
log(`Options: ${JSON.stringify({ ...options, files: `${options.files.length} file(s)` })}`);
|
|
610
27
|
}
|
|
611
28
|
|
|
612
|
-
// Validate input
|
|
613
29
|
if (options.files.length === 0) {
|
|
614
30
|
console.error("Error: Please specify at least one invoice file.");
|
|
615
31
|
console.error("\nExample: skills run extract-invoice -- invoice.pdf");
|
|
@@ -652,63 +68,62 @@ async function main(): Promise<void> {
|
|
|
652
68
|
}
|
|
653
69
|
}
|
|
654
70
|
|
|
655
|
-
|
|
656
|
-
let output: string;
|
|
657
|
-
let extension: string;
|
|
71
|
+
const { output, extension } = formatResults(results, options);
|
|
658
72
|
|
|
659
|
-
switch (options.format) {
|
|
660
|
-
case "csv":
|
|
661
|
-
output = formatAsCSV(results);
|
|
662
|
-
extension = "csv";
|
|
663
|
-
break;
|
|
664
|
-
case "excel":
|
|
665
|
-
// For Excel, we output CSV which can be opened in Excel
|
|
666
|
-
output = formatAsCSV(results);
|
|
667
|
-
extension = "csv";
|
|
668
|
-
log("Excel format outputs as CSV (compatible with Excel)", "info");
|
|
669
|
-
break;
|
|
670
|
-
case "markdown":
|
|
671
|
-
output = formatAsMarkdown(results, options);
|
|
672
|
-
extension = "md";
|
|
673
|
-
break;
|
|
674
|
-
default:
|
|
675
|
-
output = formatAsJSON(results, options);
|
|
676
|
-
extension = "json";
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// Ensure export directory exists
|
|
680
73
|
ensureDir(EXPORTS_DIR);
|
|
681
74
|
|
|
682
|
-
// Determine output filename
|
|
683
75
|
const outputFilename = options.output
|
|
684
76
|
? resolve(process.cwd(), options.output)
|
|
685
77
|
: join(EXPORTS_DIR, `invoice-data.${extension}`);
|
|
686
78
|
|
|
687
|
-
// Save to file
|
|
688
79
|
writeFileSync(outputFilename, output, "utf-8");
|
|
689
80
|
log(`Output saved to: ${outputFilename}`, "success");
|
|
690
81
|
|
|
691
|
-
|
|
82
|
+
printSummary(results, output, outputFilename, options.batch);
|
|
83
|
+
|
|
84
|
+
const duration = Date.now() - startTime;
|
|
85
|
+
log(`Completed in ${duration}ms`, "success");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function formatResults(
|
|
89
|
+
results: ExtractionResult[],
|
|
90
|
+
options: ReturnType<typeof parseArguments>,
|
|
91
|
+
): { output: string; extension: string } {
|
|
92
|
+
switch (options.format) {
|
|
93
|
+
case "csv":
|
|
94
|
+
return { output: formatAsCSV(results), extension: "csv" };
|
|
95
|
+
case "excel":
|
|
96
|
+
log("Excel format outputs as CSV (compatible with Excel)", "info");
|
|
97
|
+
return { output: formatAsCSV(results), extension: "csv" };
|
|
98
|
+
case "markdown":
|
|
99
|
+
return { output: formatAsMarkdown(results, options), extension: "md" };
|
|
100
|
+
default:
|
|
101
|
+
return { output: formatAsJSON(results, options), extension: "json" };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function printSummary(
|
|
106
|
+
results: ExtractionResult[],
|
|
107
|
+
output: string,
|
|
108
|
+
outputFilename: string,
|
|
109
|
+
isBatch: boolean,
|
|
110
|
+
): void {
|
|
692
111
|
console.log("\n" + "=".repeat(60) + "\n");
|
|
693
112
|
|
|
694
|
-
const successful = results.filter((
|
|
695
|
-
const failed = results.filter((
|
|
113
|
+
const successful = results.filter((result) => result.success).length;
|
|
114
|
+
const failed = results.filter((result) => !result.success).length;
|
|
696
115
|
|
|
697
|
-
console.log(
|
|
116
|
+
console.log("Extraction Summary:");
|
|
698
117
|
console.log(` Total files: ${results.length}`);
|
|
699
118
|
console.log(` Successful: ${successful}`);
|
|
700
119
|
console.log(` Failed: ${failed}`);
|
|
701
120
|
console.log("");
|
|
702
121
|
|
|
703
|
-
|
|
704
|
-
if (results.length === 1 && !options.batch) {
|
|
122
|
+
if (results.length === 1 && !isBatch) {
|
|
705
123
|
console.log(output);
|
|
706
124
|
} else {
|
|
707
125
|
console.log(`Results saved to: ${outputFilename}`);
|
|
708
126
|
}
|
|
709
|
-
|
|
710
|
-
const duration = Date.now() - startTime;
|
|
711
|
-
log(`Completed in ${duration}ms`, "success");
|
|
712
127
|
}
|
|
713
128
|
|
|
714
129
|
main();
|