@hasna/skills 0.1.21 → 0.1.23
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/bin/index.js +341 -287
- package/bin/mcp.js +297 -245
- package/dist/index.d.ts +1 -1
- package/dist/index.js +79 -24
- package/dist/lib/basic-skills.test.d.ts +1 -0
- package/dist/lib/registry.d.ts +5 -0
- package/dist/lib/search.d.ts +2 -2
- package/package.json +1 -1
- package/skills/skill-academic-journal-matcher/package.json +1 -7
- package/skills/skill-action-item-router/package.json +1 -7
- package/skills/skill-ad-creative-generator/package.json +1 -7
- package/skills/skill-advanced-math/package.json +1 -7
- package/skills/skill-anomaly-investigator/package.json +1 -7
- package/skills/skill-api-test-suite/package.json +1 -7
- package/skills/skill-apidocs/package.json +0 -6
- package/skills/skill-audio/SKILL.md +3 -1
- package/skills/skill-audio/package.json +0 -5
- package/skills/skill-audio/src/index-local.ts +4 -1
- package/skills/skill-audio/src/providers/minimax.ts +83 -0
- package/skills/skill-audio/src/types.ts +1 -1
- package/skills/skill-audio-cleanup-lab/package.json +1 -5
- package/skills/{skill-extract-audio → skill-audio-extract}/SKILL.md +3 -3
- package/skills/{skill-extract-audio → skill-audio-extract}/package.json +3 -7
- package/skills/skill-audiobook-chapter-proofer/package.json +1 -7
- package/skills/skill-banner-ad-suite/package.json +1 -7
- package/skills/skill-benchmark-finder/package.json +1 -7
- package/skills/skill-bio-sequence-tool/package.json +1 -7
- package/skills/skill-blog-topic-cluster/package.json +1 -7
- package/skills/skill-brand-voice-audit/package.json +1 -7
- package/skills/skill-browse/package.json +0 -5
- package/skills/skill-businessactivity/package.json +1 -3
- package/skills/skill-calendar-events/package.json +1 -7
- package/skills/skill-campaign-metric-brief/package.json +1 -7
- package/skills/skill-campaign-moodboard/package.json +1 -7
- package/skills/skill-caption-style-stylist/package.json +1 -7
- package/skills/skill-chemistry-calculator/package.json +1 -7
- package/skills/skill-churn-risk-notifier/package.json +1 -7
- package/skills/skill-citation-formatter/package.json +1 -7
- package/skills/skill-classroom-newsletter-kit/package.json +1 -7
- package/skills/skill-codefix/package.json +0 -4
- package/skills/skill-color-palette-harmonizer/package.json +1 -7
- package/skills/skill-colorextract/package.json +17 -5
- package/skills/skill-commitpush/package.json +0 -1
- package/skills/skill-commitpushpr/package.json +0 -1
- package/skills/skill-competitor-ad-analyzer/package.json +1 -7
- package/skills/skill-compliance-copy-check/package.json +1 -7
- package/skills/skill-compliance-report-pack/package.json +1 -7
- package/skills/skill-compress-video/package.json +1 -5
- package/skills/skill-consolelog/package.json +1 -7
- package/skills/skill-contract-plainlanguage/package.json +1 -7
- package/skills/skill-convert/SKILL.md +7 -0
- package/skills/skill-convert/package.json +0 -4
- package/skills/skill-copytone-translator/package.json +1 -7
- package/skills/skill-create-blog-article/package.json +1 -7
- package/skills/skill-create-ebook/package.json +1 -7
- package/skills/skill-crm-note-enhancer/package.json +1 -7
- package/skills/skill-customer-journey-mapper/package.json +1 -7
- package/skills/skill-dashboard-builder/package.json +1 -7
- package/skills/skill-dashboard-narrator/package.json +1 -7
- package/skills/skill-data-anonymizer/package.json +1 -7
- package/skills/skill-database-explorer/package.json +1 -7
- package/skills/skill-dataset-health-check/package.json +1 -7
- package/skills/skill-decision-journal/package.json +1 -7
- package/skills/skill-deepresearch/package.json +0 -5
- package/skills/skill-delegation-brief-writer/package.json +1 -7
- package/skills/skill-deploy/package.json +0 -4
- package/skills/skill-destination-briefing/package.json +1 -7
- package/skills/skill-diff-viewer/package.json +1 -7
- package/skills/{skill-generate-docx → skill-doc-generate}/SKILL.md +2 -2
- package/skills/{skill-generate-pdf → skill-doc-generate}/package.json +9 -4
- package/skills/{skill-generate-docx → skill-doc-generate}/src/index.ts +91 -28
- package/skills/skill-doc-read/SKILL.md +45 -0
- package/skills/skill-doc-read/package.json +29 -0
- package/skills/skill-doc-read/src/index.ts +324 -0
- package/skills/skill-doc-read/tsconfig.json +8 -0
- package/skills/skill-domainpurchase/package.json +1 -7
- package/skills/skill-domainsearch/package.json +1 -7
- package/skills/skill-e2bswarm/package.json +0 -6
- package/skills/skill-educational-resource-finder/package.json +1 -7
- package/skills/skill-email-campaign/package.json +1 -7
- package/skills/skill-emoji/package.json +0 -1
- package/skills/skill-exam-readiness-check/package.json +1 -7
- package/skills/skill-excel/SKILL.md +38 -0
- package/skills/skill-excel/package.json +30 -0
- package/skills/{skill-generate-excel → skill-excel}/src/index.ts +41 -14
- package/skills/skill-experiment-power-calculator/package.json +1 -7
- package/skills/skill-extract/package.json +0 -5
- package/skills/skill-extract-frames/package.json +1 -7
- package/skills/skill-extract-invoice/package.json +1 -7
- package/skills/skill-family-activity-curator/package.json +1 -7
- package/skills/skill-faq-packager/package.json +1 -7
- package/skills/skill-feedback-survey-designer/package.json +1 -7
- package/skills/skill-field-trip-planner/package.json +1 -7
- package/skills/skill-file-organizer/package.json +1 -7
- package/skills/skill-folder-tree/package.json +1 -7
- package/skills/skill-forecast-scenario-lab/package.json +1 -7
- package/skills/skill-form-filler/package.json +1 -7
- package/skills/skill-generate-api-client/package.json +1 -7
- package/skills/skill-generate-book-cover/package.json +1 -7
- package/skills/skill-generate-chart/package.json +1 -7
- package/skills/skill-generate-diagram/package.json +1 -7
- package/skills/skill-generate-dockerfile/package.json +1 -7
- package/skills/skill-generate-documentation/package.json +1 -7
- package/skills/skill-generate-env/package.json +1 -7
- package/skills/skill-generate-favicon/package.json +1 -7
- package/skills/skill-generate-mock-data/package.json +1 -7
- package/skills/skill-generate-pr-description/package.json +1 -7
- package/skills/skill-generate-presentation/package.json +1 -7
- package/skills/skill-generate-qrcode/package.json +1 -7
- package/skills/skill-generate-regex/package.json +1 -7
- package/skills/skill-generate-resume/package.json +1 -7
- package/skills/skill-generate-sitemap/package.json +1 -7
- package/skills/skill-generate-social-posts/package.json +1 -7
- package/skills/skill-generate-sql/package.json +1 -7
- package/skills/skill-gif-maker/package.json +1 -7
- package/skills/skill-github-manager/package.json +1 -7
- package/skills/skill-gmail/package.json +1 -7
- package/skills/skill-goal-quarterly-roadmap/package.json +1 -7
- package/skills/skill-grant-application-drafter/package.json +1 -7
- package/skills/skill-grocery-basket-optimizer/package.json +1 -7
- package/skills/skill-guest-communication-suite/package.json +1 -7
- package/skills/skill-habit-reflection-digest/package.json +1 -7
- package/skills/skill-highlight-reel-generator/package.json +1 -7
- package/skills/skill-homework-feedback-coach/package.json +1 -7
- package/skills/skill-hook/package.json +0 -6
- package/skills/skill-household-maintenance-mgr/package.json +1 -7
- package/skills/skill-http-server/package.json +1 -7
- package/skills/skill-image/SKILL.md +2 -0
- package/skills/skill-image/package.json +0 -5
- package/skills/skill-image/src/index-local.ts +5 -3
- package/skills/skill-image/src/providers/minimax.ts +94 -0
- package/skills/skill-image/src/types.ts +1 -1
- package/skills/skill-implementation/package.json +0 -6
- package/skills/skill-implementation-agent/package.json +1 -7
- package/skills/skill-implementation-plan/package.json +1 -7
- package/skills/skill-implementation-todo/package.json +1 -7
- package/skills/skill-inbox-priority-planner/package.json +1 -7
- package/skills/skill-invoice-dispute-helper/package.json +1 -7
- package/skills/skill-itinerary-architect/package.json +1 -7
- package/skills/skill-kpi-digest-generator/package.json +1 -7
- package/skills/skill-lab-notebook-formatter/package.json +1 -7
- package/skills/skill-landing-page-copy/package.json +1 -7
- package/skills/skill-latex-table-generator/package.json +1 -7
- package/skills/skill-learning-style-profiler/package.json +1 -7
- package/skills/skill-lesson-plan-customizer/package.json +1 -7
- package/skills/skill-livestream-runofshow/package.json +1 -7
- package/skills/skill-longform-structurer/package.json +1 -7
- package/skills/skill-lorem-generator/package.json +1 -7
- package/skills/skill-managehook/package.json +1 -3
- package/skills/skill-managemcp/package.json +1 -3
- package/skills/skill-manageskill/package.json +1 -3
- package/skills/skill-markdown-validator/package.json +1 -7
- package/skills/skill-mcp-builder/package.json +1 -7
- package/skills/skill-meal-plan-designer/package.json +1 -7
- package/skills/skill-meeting-insight-summarizer/package.json +1 -7
- package/skills/skill-merge-pdfs/package.json +1 -7
- package/skills/skill-microcopy-generator/package.json +1 -7
- package/skills/skill-mindfulness-prompt-cache/package.json +1 -7
- package/skills/skill-monitor/package.json +0 -1
- package/skills/skill-music/CLAUDE.md +9 -0
- package/skills/skill-music/SKILL.md +35 -0
- package/skills/{skill-generate-excel → skill-music}/package.json +4 -10
- package/skills/skill-music/src/index.ts +192 -0
- package/skills/skill-notion-manager/package.json +1 -7
- package/skills/skill-npmpublish/package.json +0 -5
- package/skills/skill-onboarding-sequence-builder/package.json +1 -7
- package/skills/skill-onsite-ops-checklist/package.json +1 -7
- package/skills/skill-outreach-cadence-designer/package.json +1 -7
- package/skills/skill-packaging-concept-studio/package.json +1 -7
- package/skills/skill-packing-plan-pro/package.json +1 -7
- package/skills/skill-parent-teacher-brief/package.json +1 -7
- package/skills/skill-partner-kit-assembler/package.json +1 -7
- package/skills/skill-payroll-change-prepper/package.json +1 -7
- package/skills/{skill-generate-pdf → skill-pdf-generate}/SKILL.md +2 -2
- package/skills/{skill-generate-docx → skill-pdf-generate}/package.json +6 -4
- package/skills/{skill-generate-pdf → skill-pdf-generate}/src/index.ts +109 -8
- package/skills/skill-pdf-read/SKILL.md +56 -0
- package/skills/skill-pdf-read/package.json +29 -0
- package/skills/skill-pdf-read/src/index.ts +320 -0
- package/skills/skill-pdf-read/tsconfig.json +8 -0
- package/skills/skill-persona-based-adwriter/package.json +1 -7
- package/skills/skill-persona-generator/package.json +1 -7
- package/skills/skill-personal-daily-ops/package.json +1 -7
- package/skills/skill-pet-care-scheduler/package.json +1 -7
- package/skills/skill-podcast-show-notes/package.json +1 -7
- package/skills/skill-presentation-theme-maker/package.json +1 -7
- package/skills/skill-press-release-drafter/package.json +1 -7
- package/skills/skill-print-collateral-designer/package.json +1 -7
- package/skills/skill-procurement-scorecard/package.json +1 -7
- package/skills/skill-product-demo-script/package.json +1 -7
- package/skills/skill-product-mockup/package.json +1 -7
- package/skills/skill-project-retro-companion/package.json +1 -7
- package/skills/skill-proposal-redline-advisor/package.json +1 -7
- package/skills/skill-read-csv/SKILL.md +1 -1
- package/skills/skill-read-csv/package.json +0 -1
- package/skills/skill-read-csv/src/index.ts +30 -5
- package/skills/skill-read-excel/SKILL.md +1 -1
- package/skills/skill-read-excel/package.json +0 -1
- package/skills/skill-read-excel/src/index.ts +21 -8
- package/skills/skill-read-image/SKILL.md +1 -1
- package/skills/skill-read-image/package.json +0 -1
- package/skills/skill-read-pdf/SKILL.md +1 -1
- package/skills/skill-read-pdf/package.json +0 -1
- package/skills/skill-read-pdf/src/index.ts +15 -3
- package/skills/skill-regex-tester/package.json +1 -7
- package/skills/skill-remove-background/package.json +1 -7
- package/skills/skill-risk-disclosure-kit/package.json +1 -7
- package/skills/skill-roi-comparison-tool/package.json +1 -7
- package/skills/skill-sales-call-recapper/package.json +1 -7
- package/skills/skill-scaffold-project/package.json +1 -7
- package/skills/skill-scancommitpr/package.json +0 -2
- package/skills/skill-scancommitpush/package.json +0 -2
- package/skills/skill-scholarship-tracker/package.json +1 -7
- package/skills/skill-scientific-figure-check/package.json +1 -7
- package/skills/skill-seating-chart-maker/package.json +1 -7
- package/skills/skill-security-audit/package.json +1 -7
- package/skills/skill-seo-brief-builder/package.json +1 -7
- package/skills/skill-siteanalyze/package.json +19 -5
- package/skills/skill-slack-assistant/package.json +1 -7
- package/skills/skill-sleep-routine-analyzer/package.json +1 -7
- package/skills/skill-sms/package.json +0 -1
- package/skills/skill-social-media-kit/package.json +1 -7
- package/skills/skill-sound-effects/SKILL.md +34 -0
- package/skills/{skill-jingle-composer → skill-sound-effects}/package.json +4 -10
- package/skills/skill-sound-effects/src/index.ts +172 -0
- package/skills/skill-sound-effects/tsconfig.json +8 -0
- package/skills/skill-split-pdf/package.json +1 -7
- package/skills/skill-sponsorship-proposal-lab/package.json +1 -7
- package/skills/skill-spreadsheet-cleanroom/package.json +1 -7
- package/skills/skill-statistical-test-selector/package.json +1 -7
- package/skills/skill-stress-relief-playbook/package.json +1 -7
- package/skills/skill-study-guide-builder/package.json +1 -7
- package/skills/skill-subscription-spend-watcher/package.json +1 -7
- package/skills/skill-subtitle/package.json +0 -6
- package/skills/skill-survey-insight-extractor/package.json +1 -7
- package/skills/skill-terraform-generator/package.json +1 -7
- package/skills/skill-testimonial-graphics/package.json +1 -7
- package/skills/skill-timesheet/package.json +0 -6
- package/skills/skill-tmux-session/package.json +0 -1
- package/skills/skill-transcript/SKILL.md +3 -1
- package/skills/skill-transcript/package.json +0 -5
- package/skills/skill-travel-budget-balancer/package.json +1 -7
- package/skills/skill-validate-config/package.json +1 -7
- package/skills/skill-video/SKILL.md +3 -1
- package/skills/skill-video/package.json +0 -5
- package/skills/skill-video/src/providers/index.ts +4 -1
- package/skills/skill-video/src/providers/minimax.ts +100 -0
- package/skills/skill-video/src/types.ts +1 -1
- package/skills/skill-video-cut-suggester/package.json +1 -7
- package/skills/skill-video-downloader/package.json +1 -7
- package/skills/skill-video-thumbnail/package.json +1 -7
- package/skills/skill-voiceover-casting-assistant/package.json +1 -7
- package/skills/skill-watermark/package.json +1 -7
- package/skills/skill-webcrawling/package.json +11 -8
- package/skills/skill-webinar-script-coach/package.json +1 -7
- package/skills/skill-wellness-progress-reporter/package.json +1 -7
- package/skills/skill-workout-cycle-planner/package.json +1 -7
- package/skills/skill-write/package.json +0 -5
- package/skills/skill-jingle-composer/CLAUDE.md +0 -19
- package/skills/skill-jingle-composer/src/index.ts +0 -250
- /package/skills/{skill-extract-audio → skill-audio-extract}/CLAUDE.md +0 -0
- /package/skills/{skill-extract-audio → skill-audio-extract}/src/index.ts +0 -0
- /package/skills/{skill-extract-audio → skill-audio-extract}/tsconfig.json +0 -0
- /package/skills/{skill-generate-docx → skill-doc-generate}/CLAUDE.md +0 -0
- /package/skills/{skill-generate-docx → skill-doc-generate}/tsconfig.json +0 -0
- /package/skills/{skill-generate-excel → skill-excel}/CLAUDE.md +0 -0
- /package/skills/{skill-generate-excel → skill-excel}/tsconfig.json +0 -0
- /package/skills/{skill-jingle-composer → skill-music}/tsconfig.json +0 -0
- /package/skills/{skill-generate-pdf → skill-pdf-generate}/CLAUDE.md +0 -0
- /package/skills/{skill-generate-pdf → skill-pdf-generate}/tsconfig.json +0 -0
|
@@ -1,31 +1,92 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
Document,
|
|
5
|
-
Packer,
|
|
6
|
-
Paragraph,
|
|
7
|
-
TextRun,
|
|
8
|
-
HeadingLevel,
|
|
9
|
-
Table,
|
|
10
|
-
TableRow,
|
|
11
|
-
TableCell,
|
|
12
|
-
WidthType,
|
|
13
|
-
AlignmentType,
|
|
14
|
-
BorderStyle,
|
|
15
|
-
PageNumber,
|
|
16
|
-
NumberFormat,
|
|
17
|
-
Header,
|
|
18
|
-
Footer,
|
|
19
|
-
TableOfContents,
|
|
20
|
-
ImageRun,
|
|
21
|
-
ExternalHyperlink,
|
|
22
|
-
PageBreak,
|
|
23
|
-
} from "docx";
|
|
24
3
|
import * as fs from "fs";
|
|
25
4
|
import * as path from "path";
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
5
|
+
|
|
6
|
+
let Document: any;
|
|
7
|
+
let Packer: any;
|
|
8
|
+
let Paragraph: any;
|
|
9
|
+
let TextRun: any;
|
|
10
|
+
let HeadingLevel: any;
|
|
11
|
+
let Table: any;
|
|
12
|
+
let TableRow: any;
|
|
13
|
+
let TableCell: any;
|
|
14
|
+
let WidthType: any;
|
|
15
|
+
let AlignmentType: any;
|
|
16
|
+
let BorderStyle: any;
|
|
17
|
+
let PageNumber: any;
|
|
18
|
+
let NumberFormat: any;
|
|
19
|
+
let Header: any;
|
|
20
|
+
let Footer: any;
|
|
21
|
+
let TableOfContents: any;
|
|
22
|
+
let PageBreak: any;
|
|
23
|
+
let marked: any;
|
|
24
|
+
|
|
25
|
+
function printHelpAndExit(): never {
|
|
26
|
+
console.log(`
|
|
27
|
+
Generate DOCX - Create Word documents from markdown or AI
|
|
28
|
+
|
|
29
|
+
Usage:
|
|
30
|
+
skill-doc-generate <markdown-file> [options]
|
|
31
|
+
skill-doc-generate --topic "Topic" [options]
|
|
32
|
+
skill-doc-generate --prompt "Prompt" [options]
|
|
33
|
+
|
|
34
|
+
Input Options:
|
|
35
|
+
<file> Input markdown file
|
|
36
|
+
--topic <text> Topic for AI to write about
|
|
37
|
+
--prompt <text> Direct prompt for AI generation
|
|
38
|
+
--text <text> Plain text content
|
|
39
|
+
|
|
40
|
+
Output Options:
|
|
41
|
+
-o, --output <path> Output file path
|
|
42
|
+
--dir <path> Output directory (default: .skills/exports)
|
|
43
|
+
--template <name> Template: default, report, letter, memo, resume, article
|
|
44
|
+
--help, -h Show this help
|
|
45
|
+
`);
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
50
|
+
printHelpAndExit();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function loadDocumentDeps(): Promise<void> {
|
|
54
|
+
if (Document && marked) return;
|
|
55
|
+
try {
|
|
56
|
+
const docx = await import("docx");
|
|
57
|
+
Document = docx.Document;
|
|
58
|
+
Packer = docx.Packer;
|
|
59
|
+
Paragraph = docx.Paragraph;
|
|
60
|
+
TextRun = docx.TextRun;
|
|
61
|
+
HeadingLevel = docx.HeadingLevel;
|
|
62
|
+
Table = docx.Table;
|
|
63
|
+
TableRow = docx.TableRow;
|
|
64
|
+
TableCell = docx.TableCell;
|
|
65
|
+
WidthType = docx.WidthType;
|
|
66
|
+
AlignmentType = docx.AlignmentType;
|
|
67
|
+
BorderStyle = docx.BorderStyle;
|
|
68
|
+
PageNumber = docx.PageNumber;
|
|
69
|
+
NumberFormat = docx.NumberFormat;
|
|
70
|
+
Header = docx.Header;
|
|
71
|
+
Footer = docx.Footer;
|
|
72
|
+
TableOfContents = docx.TableOfContents;
|
|
73
|
+
PageBreak = docx.PageBreak;
|
|
74
|
+
({ marked } = await import("marked"));
|
|
75
|
+
} catch {
|
|
76
|
+
throw new Error("Missing document generation dependencies. Run bun install in this skill directory.");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function createOpenAIClient(apiKey: string) {
|
|
81
|
+
try {
|
|
82
|
+
const { default: OpenAI } = await import("openai");
|
|
83
|
+
return new OpenAI({ apiKey });
|
|
84
|
+
} catch {
|
|
85
|
+
throw new Error("Missing dependency 'openai'. Run bun install in this skill directory.");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const minimist = (await import("minimist")).default;
|
|
29
90
|
|
|
30
91
|
// Types
|
|
31
92
|
interface DocOptions {
|
|
@@ -190,7 +251,7 @@ async function generateWithAI(topic: string, isPrompt: boolean = false): Promise
|
|
|
190
251
|
throw new Error("OPENAI_API_KEY environment variable is required for AI generation");
|
|
191
252
|
}
|
|
192
253
|
|
|
193
|
-
const openai =
|
|
254
|
+
const openai = await createOpenAIClient(apiKey);
|
|
194
255
|
|
|
195
256
|
const lengthGuide = {
|
|
196
257
|
short: "Keep it concise, around 500 words total.",
|
|
@@ -377,8 +438,8 @@ function parseMarkdown(markdown: string): ParsedContent {
|
|
|
377
438
|
}
|
|
378
439
|
|
|
379
440
|
// Parse inline formatting
|
|
380
|
-
function parseInlineFormatting(text: string):
|
|
381
|
-
const runs:
|
|
441
|
+
function parseInlineFormatting(text: string): any[] {
|
|
442
|
+
const runs: any[] = [];
|
|
382
443
|
let remaining = text;
|
|
383
444
|
|
|
384
445
|
// Simple regex-based parsing for bold, italic, code
|
|
@@ -429,7 +490,7 @@ function getPageSize(size: string): { width: number; height: number } {
|
|
|
429
490
|
}
|
|
430
491
|
|
|
431
492
|
// Build document from parsed content
|
|
432
|
-
function buildDocument(content: ParsedContent):
|
|
493
|
+
function buildDocument(content: ParsedContent): any {
|
|
433
494
|
const pageSize = getPageSize(options.pageSize);
|
|
434
495
|
const marginTwips = options.margins * 1440; // Convert inches to twips
|
|
435
496
|
|
|
@@ -698,6 +759,8 @@ async function main(): Promise<void> {
|
|
|
698
759
|
process.exit(1);
|
|
699
760
|
}
|
|
700
761
|
|
|
762
|
+
await loadDocumentDeps();
|
|
763
|
+
|
|
701
764
|
// Parse content
|
|
702
765
|
console.log("Parsing content...");
|
|
703
766
|
const content = parseMarkdown(markdown);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: doc-read
|
|
3
|
+
version: 0.1.0
|
|
4
|
+
description: Read and extract text from DOCX files with section parsing, metadata extraction, and multiple file support
|
|
5
|
+
category: Data & Analysis
|
|
6
|
+
tags:
|
|
7
|
+
- docx
|
|
8
|
+
- documents
|
|
9
|
+
- extraction
|
|
10
|
+
- reader
|
|
11
|
+
- word
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Doc Read
|
|
15
|
+
|
|
16
|
+
Read and extract content from DOCX files. Supports multiple files at once, preserves document structure (headings, paragraphs, lists, tables), and extracts metadata. Outputs plain text, JSON with structure, or markdown.
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- **Multiple Files**: Process many DOCX files in a single command
|
|
21
|
+
- **Structure Preservation**: Extracts headings, paragraphs, lists, and tables
|
|
22
|
+
- **Metadata Extraction**: Get title, author, creation date, word count
|
|
23
|
+
- **Parallel Processing**: Process multiple files concurrently
|
|
24
|
+
- **Output Formats**: Plain text, JSON with document structure, or markdown
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Read a single DOCX file
|
|
30
|
+
skill-doc-read read document.docx
|
|
31
|
+
|
|
32
|
+
# Read multiple files
|
|
33
|
+
skill-doc-read read file1.docx file2.docx file3.docx
|
|
34
|
+
|
|
35
|
+
# Output as JSON with structure
|
|
36
|
+
skill-doc-read read document.docx --format json --output result.json
|
|
37
|
+
|
|
38
|
+
# Get metadata only
|
|
39
|
+
skill-doc-read info document.docx
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Requirements
|
|
43
|
+
|
|
44
|
+
- Bun runtime
|
|
45
|
+
- mammoth (auto-installed)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hasnaxyz/skill-doc-read",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Read and extract text from DOCX files with section parsing and metadata extraction",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"skill-doc-read": "./src/index.ts"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "bun run src/index.ts",
|
|
11
|
+
"build": "bun build src/index.ts --outdir dist --target node",
|
|
12
|
+
"typecheck": "tsc --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"jszip": "^3.10.1"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/bun": "latest",
|
|
19
|
+
"typescript": "^5.7.0"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "restricted",
|
|
23
|
+
"registry": "https://registry.npmjs.org/"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"src",
|
|
27
|
+
"tsconfig.json"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { readFile, writeFile, stat, mkdir } from 'fs/promises';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
5
|
+
import { basename, extname, dirname, resolve } from 'path';
|
|
6
|
+
import { parseArgs } from 'util';
|
|
7
|
+
|
|
8
|
+
async function loadJSZip() {
|
|
9
|
+
try {
|
|
10
|
+
return (await import('jszip')).default;
|
|
11
|
+
} catch {
|
|
12
|
+
throw new Error("Missing dependency 'jszip'. Run bun install in this skill directory.");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface DocResult {
|
|
17
|
+
file: string;
|
|
18
|
+
text: string;
|
|
19
|
+
sections: DocSection[];
|
|
20
|
+
metadata: DocMetadata;
|
|
21
|
+
wordCount: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface DocSection {
|
|
25
|
+
type: 'heading' | 'paragraph' | 'list' | 'table';
|
|
26
|
+
level?: number;
|
|
27
|
+
text: string;
|
|
28
|
+
items?: string[];
|
|
29
|
+
rows?: string[][];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface DocMetadata {
|
|
33
|
+
title?: string;
|
|
34
|
+
author?: string;
|
|
35
|
+
lastModifiedBy?: string;
|
|
36
|
+
created?: string;
|
|
37
|
+
modified?: string;
|
|
38
|
+
description?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function extractDocxText(buffer: Buffer): Promise<{ text: string; sections: DocSection[] }> {
|
|
42
|
+
const JSZip = await loadJSZip();
|
|
43
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
44
|
+
|
|
45
|
+
const documentXml = await zip.file('word/document.xml')?.async('string');
|
|
46
|
+
if (!documentXml) throw new Error('Invalid DOCX: missing word/document.xml');
|
|
47
|
+
|
|
48
|
+
const sections: DocSection[] = [];
|
|
49
|
+
let fullText = '';
|
|
50
|
+
|
|
51
|
+
const paragraphs = documentXml.match(/<w:p[\s>][\s\S]*?<\/w:p>/g) || [];
|
|
52
|
+
|
|
53
|
+
for (const para of paragraphs) {
|
|
54
|
+
const textParts = para.match(/<w:t[^>]*>([\s\S]*?)<\/w:t>/g) || [];
|
|
55
|
+
const text = textParts
|
|
56
|
+
.map(t => t.replace(/<w:t[^>]*>/, '').replace(/<\/w:t>/, ''))
|
|
57
|
+
.join('');
|
|
58
|
+
|
|
59
|
+
if (!text.trim()) continue;
|
|
60
|
+
|
|
61
|
+
const headingMatch = para.match(/<w:pStyle w:val="Heading(\d)"/);
|
|
62
|
+
if (headingMatch) {
|
|
63
|
+
const level = parseInt(headingMatch[1]);
|
|
64
|
+
sections.push({ type: 'heading', level, text: text.trim() });
|
|
65
|
+
} else if (para.includes('<w:numPr>')) {
|
|
66
|
+
const lastSection = sections[sections.length - 1];
|
|
67
|
+
if (lastSection?.type === 'list') {
|
|
68
|
+
lastSection.items!.push(text.trim());
|
|
69
|
+
} else {
|
|
70
|
+
sections.push({ type: 'list', text: text.trim(), items: [text.trim()] });
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
sections.push({ type: 'paragraph', text: text.trim() });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fullText += text.trim() + '\n';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const tables = documentXml.match(/<w:tbl>[\s\S]*?<\/w:tbl>/g) || [];
|
|
80
|
+
for (const table of tables) {
|
|
81
|
+
const rows: string[][] = [];
|
|
82
|
+
const tableRows = table.match(/<w:tr[\s>][\s\S]*?<\/w:tr>/g) || [];
|
|
83
|
+
for (const row of tableRows) {
|
|
84
|
+
const cells = row.match(/<w:tc[\s>][\s\S]*?<\/w:tc>/g) || [];
|
|
85
|
+
const rowData = cells.map(cell => {
|
|
86
|
+
const cellTexts = cell.match(/<w:t[^>]*>([\s\S]*?)<\/w:t>/g) || [];
|
|
87
|
+
return cellTexts.map(t => t.replace(/<w:t[^>]*>/, '').replace(/<\/w:t>/, '')).join(' ');
|
|
88
|
+
});
|
|
89
|
+
rows.push(rowData);
|
|
90
|
+
}
|
|
91
|
+
if (rows.length > 0) {
|
|
92
|
+
sections.push({ type: 'table', text: '', rows });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { text: fullText, sections };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function extractDocxMetadata(buffer: Buffer): Promise<DocMetadata> {
|
|
100
|
+
const JSZip = await loadJSZip();
|
|
101
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
102
|
+
|
|
103
|
+
const coreXml = await zip.file('docProps/core.xml')?.async('string');
|
|
104
|
+
if (!coreXml) return {};
|
|
105
|
+
|
|
106
|
+
const getTag = (xml: string, tag: string): string | undefined => {
|
|
107
|
+
const match = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`));
|
|
108
|
+
return match?.[1]?.trim() || undefined;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
title: getTag(coreXml, 'dc:title'),
|
|
113
|
+
author: getTag(coreXml, 'dc:creator'),
|
|
114
|
+
lastModifiedBy: getTag(coreXml, 'cp:lastModifiedBy'),
|
|
115
|
+
created: getTag(coreXml, 'dcterms:created'),
|
|
116
|
+
modified: getTag(coreXml, 'dcterms:modified'),
|
|
117
|
+
description: getTag(coreXml, 'dc:description'),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function readSingleDocx(filePath: string): Promise<DocResult> {
|
|
122
|
+
const buffer = await readFile(filePath);
|
|
123
|
+
const { text, sections } = await extractDocxText(buffer);
|
|
124
|
+
const metadata = await extractDocxMetadata(buffer);
|
|
125
|
+
const wordCount = text.split(/\s+/).filter(w => w.length > 0).length;
|
|
126
|
+
|
|
127
|
+
return { file: filePath, text, sections, metadata, wordCount };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function readMultipleDocx(files: string[], concurrency = 4): Promise<DocResult[]> {
|
|
131
|
+
const results: DocResult[] = [];
|
|
132
|
+
const queue = [...files];
|
|
133
|
+
|
|
134
|
+
async function processNext(): Promise<void> {
|
|
135
|
+
while (queue.length > 0) {
|
|
136
|
+
const file = queue.shift()!;
|
|
137
|
+
console.log(`Reading: ${basename(file)}`);
|
|
138
|
+
const result = await readSingleDocx(file);
|
|
139
|
+
results.push(result);
|
|
140
|
+
console.log(` ${result.sections.length} sections, ${result.wordCount} words`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const workers = Array.from({ length: Math.min(concurrency, files.length) }, () => processNext());
|
|
145
|
+
await Promise.all(workers);
|
|
146
|
+
|
|
147
|
+
return results;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function formatText(results: DocResult[]): string {
|
|
151
|
+
return results.map(r => {
|
|
152
|
+
const header = `=== ${basename(r.file)} (${r.wordCount} words) ===\n`;
|
|
153
|
+
return header + r.text;
|
|
154
|
+
}).join('\n\n');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function formatJson(results: DocResult[]): string {
|
|
158
|
+
return JSON.stringify(results.map(r => ({
|
|
159
|
+
file: basename(r.file),
|
|
160
|
+
wordCount: r.wordCount,
|
|
161
|
+
metadata: r.metadata,
|
|
162
|
+
sections: r.sections,
|
|
163
|
+
})), null, 2);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function formatMarkdown(results: DocResult[]): string {
|
|
167
|
+
return results.map(r => {
|
|
168
|
+
const lines: string[] = [];
|
|
169
|
+
lines.push(`# ${basename(r.file)}`);
|
|
170
|
+
lines.push('');
|
|
171
|
+
if (r.metadata.title) lines.push(`**Title:** ${r.metadata.title}`);
|
|
172
|
+
if (r.metadata.author) lines.push(`**Author:** ${r.metadata.author}`);
|
|
173
|
+
lines.push(`**Words:** ${r.wordCount}`);
|
|
174
|
+
lines.push('');
|
|
175
|
+
|
|
176
|
+
for (const section of r.sections) {
|
|
177
|
+
switch (section.type) {
|
|
178
|
+
case 'heading':
|
|
179
|
+
lines.push(`${'#'.repeat((section.level || 1) + 1)} ${section.text}`);
|
|
180
|
+
lines.push('');
|
|
181
|
+
break;
|
|
182
|
+
case 'paragraph':
|
|
183
|
+
lines.push(section.text);
|
|
184
|
+
lines.push('');
|
|
185
|
+
break;
|
|
186
|
+
case 'list':
|
|
187
|
+
for (const item of section.items || []) {
|
|
188
|
+
lines.push(`- ${item}`);
|
|
189
|
+
}
|
|
190
|
+
lines.push('');
|
|
191
|
+
break;
|
|
192
|
+
case 'table':
|
|
193
|
+
if (section.rows && section.rows.length > 0) {
|
|
194
|
+
lines.push('| ' + section.rows[0].join(' | ') + ' |');
|
|
195
|
+
lines.push('| ' + section.rows[0].map(() => '---').join(' | ') + ' |');
|
|
196
|
+
for (const row of section.rows.slice(1)) {
|
|
197
|
+
lines.push('| ' + row.join(' | ') + ' |');
|
|
198
|
+
}
|
|
199
|
+
lines.push('');
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return lines.join('\n');
|
|
205
|
+
}).join('\n---\n\n');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function main() {
|
|
209
|
+
const { values, positionals } = parseArgs({
|
|
210
|
+
args: Bun.argv.slice(2),
|
|
211
|
+
options: {
|
|
212
|
+
format: { type: 'string', default: 'text' },
|
|
213
|
+
output: { type: 'string', short: 'o' },
|
|
214
|
+
concurrency: { type: 'string', default: '4' },
|
|
215
|
+
help: { type: 'boolean', short: 'h' },
|
|
216
|
+
},
|
|
217
|
+
allowPositionals: true,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const command = positionals[0];
|
|
221
|
+
const files = positionals.slice(1);
|
|
222
|
+
|
|
223
|
+
if (values.help || !command) {
|
|
224
|
+
console.log(`
|
|
225
|
+
Doc Read - Extract text from DOCX files
|
|
226
|
+
|
|
227
|
+
Usage:
|
|
228
|
+
skill-doc-read read <files...> [options]
|
|
229
|
+
skill-doc-read info <files...>
|
|
230
|
+
|
|
231
|
+
Commands:
|
|
232
|
+
read Extract text and structure from DOCX files
|
|
233
|
+
info Show document metadata
|
|
234
|
+
|
|
235
|
+
Read Options:
|
|
236
|
+
--format <fmt> Output format: text, json, markdown (default: text)
|
|
237
|
+
--output, -o <path> Write output to file
|
|
238
|
+
--concurrency <n> Parallel file processing (default: 4)
|
|
239
|
+
|
|
240
|
+
Examples:
|
|
241
|
+
skill-doc-read read document.docx
|
|
242
|
+
skill-doc-read read *.docx --format json --output extracted.json
|
|
243
|
+
skill-doc-read read report.docx --format markdown
|
|
244
|
+
skill-doc-read info document.docx
|
|
245
|
+
`);
|
|
246
|
+
process.exit(0);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (files.length === 0) {
|
|
250
|
+
console.error('Error: At least one DOCX file is required');
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
for (const file of files) {
|
|
255
|
+
if (!existsSync(file)) {
|
|
256
|
+
console.error(`File not found: ${file}`);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
const ext = extname(file).toLowerCase();
|
|
260
|
+
if (ext !== '.docx' && ext !== '.doc') {
|
|
261
|
+
console.error(`Not a DOCX file: ${file}`);
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
switch (command) {
|
|
267
|
+
case 'read': {
|
|
268
|
+
const concurrency = parseInt(values.concurrency as string) || 4;
|
|
269
|
+
|
|
270
|
+
console.log(`\nReading ${files.length} DOCX file(s)...\n`);
|
|
271
|
+
|
|
272
|
+
const results = await readMultipleDocx(files, concurrency);
|
|
273
|
+
|
|
274
|
+
let output: string;
|
|
275
|
+
switch (values.format) {
|
|
276
|
+
case 'json': output = formatJson(results); break;
|
|
277
|
+
case 'markdown': case 'md': output = formatMarkdown(results); break;
|
|
278
|
+
default: output = formatText(results); break;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (values.output) {
|
|
282
|
+
const outputPath = resolve(values.output as string);
|
|
283
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
284
|
+
await writeFile(outputPath, output);
|
|
285
|
+
console.log(`\nOutput saved to: ${outputPath}`);
|
|
286
|
+
} else {
|
|
287
|
+
console.log('\n' + output);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const totalWords = results.reduce((s, r) => s + r.wordCount, 0);
|
|
291
|
+
console.log(`\nProcessed: ${files.length} files, ${totalWords.toLocaleString()} words`);
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
case 'info': {
|
|
296
|
+
for (const file of files) {
|
|
297
|
+
const buffer = await readFile(file);
|
|
298
|
+
const metadata = await extractDocxMetadata(buffer);
|
|
299
|
+
const { text } = await extractDocxText(buffer);
|
|
300
|
+
const wordCount = text.split(/\s+/).filter(w => w.length > 0).length;
|
|
301
|
+
const fileStats = await stat(file);
|
|
302
|
+
|
|
303
|
+
console.log(`\n${basename(file)}:`);
|
|
304
|
+
console.log(` Size: ${(fileStats.size / 1024).toFixed(1)} KB`);
|
|
305
|
+
console.log(` Words: ${wordCount.toLocaleString()}`);
|
|
306
|
+
if (metadata.title) console.log(` Title: ${metadata.title}`);
|
|
307
|
+
if (metadata.author) console.log(` Author: ${metadata.author}`);
|
|
308
|
+
if (metadata.lastModifiedBy) console.log(` Last Modified By: ${metadata.lastModifiedBy}`);
|
|
309
|
+
if (metadata.created) console.log(` Created: ${metadata.created}`);
|
|
310
|
+
if (metadata.modified) console.log(` Modified: ${metadata.modified}`);
|
|
311
|
+
}
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
default:
|
|
316
|
+
console.error(`Unknown command: ${command}`);
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
main().catch(err => {
|
|
322
|
+
console.error('Error:', err.message);
|
|
323
|
+
process.exit(1);
|
|
324
|
+
});
|
|
@@ -16,10 +16,6 @@
|
|
|
16
16
|
"src",
|
|
17
17
|
"tsconfig.json"
|
|
18
18
|
],
|
|
19
|
-
"repository": {
|
|
20
|
-
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/hasnaxyz/skill-domainpurchase.git"
|
|
22
|
-
},
|
|
23
19
|
"homepage": "https://github.com/hasnaxyz/skill-domainpurchase#readme",
|
|
24
20
|
"bugs": {
|
|
25
21
|
"url": "https://github.com/hasnaxyz/skill-domainpurchase/issues"
|
|
@@ -35,7 +31,5 @@
|
|
|
35
31
|
"devDependencies": {
|
|
36
32
|
"@types/bun": "^1.1.14",
|
|
37
33
|
"typescript": "^5.7.2"
|
|
38
|
-
}
|
|
39
|
-
"author": "Hasna <dev@hasna.com>",
|
|
40
|
-
"license": "Apache-2.0"
|
|
34
|
+
}
|
|
41
35
|
}
|
|
@@ -16,10 +16,6 @@
|
|
|
16
16
|
"src",
|
|
17
17
|
"tsconfig.json"
|
|
18
18
|
],
|
|
19
|
-
"repository": {
|
|
20
|
-
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/hasnaxyz/skill-domainsearch.git"
|
|
22
|
-
},
|
|
23
19
|
"homepage": "https://github.com/hasnaxyz/skill-domainsearch#readme",
|
|
24
20
|
"bugs": {
|
|
25
21
|
"url": "https://github.com/hasnaxyz/skill-domainsearch/issues"
|
|
@@ -33,7 +29,5 @@
|
|
|
33
29
|
"devDependencies": {
|
|
34
30
|
"@types/bun": "^1.1.14",
|
|
35
31
|
"typescript": "^5.7.2"
|
|
36
|
-
}
|
|
37
|
-
"author": "Hasna <dev@hasna.com>",
|
|
38
|
-
"license": "Apache-2.0"
|
|
32
|
+
}
|
|
39
33
|
}
|
|
@@ -45,12 +45,6 @@
|
|
|
45
45
|
"ai-agent",
|
|
46
46
|
"swarm"
|
|
47
47
|
],
|
|
48
|
-
"author": "hasnaxyz",
|
|
49
|
-
"license": "Apache-2.0",
|
|
50
|
-
"repository": {
|
|
51
|
-
"type": "git",
|
|
52
|
-
"url": "https://github.com/hasnaxyz/skill-e2bswarm.git"
|
|
53
|
-
},
|
|
54
48
|
"homepage": "https://github.com/hasnaxyz/skill-e2bswarm#readme",
|
|
55
49
|
"bugs": {
|
|
56
50
|
"url": "https://github.com/hasnaxyz/skill-e2bswarm/issues"
|