@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.
Files changed (270) hide show
  1. package/bin/index.js +341 -287
  2. package/bin/mcp.js +297 -245
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +79 -24
  5. package/dist/lib/basic-skills.test.d.ts +1 -0
  6. package/dist/lib/registry.d.ts +5 -0
  7. package/dist/lib/search.d.ts +2 -2
  8. package/package.json +1 -1
  9. package/skills/skill-academic-journal-matcher/package.json +1 -7
  10. package/skills/skill-action-item-router/package.json +1 -7
  11. package/skills/skill-ad-creative-generator/package.json +1 -7
  12. package/skills/skill-advanced-math/package.json +1 -7
  13. package/skills/skill-anomaly-investigator/package.json +1 -7
  14. package/skills/skill-api-test-suite/package.json +1 -7
  15. package/skills/skill-apidocs/package.json +0 -6
  16. package/skills/skill-audio/SKILL.md +3 -1
  17. package/skills/skill-audio/package.json +0 -5
  18. package/skills/skill-audio/src/index-local.ts +4 -1
  19. package/skills/skill-audio/src/providers/minimax.ts +83 -0
  20. package/skills/skill-audio/src/types.ts +1 -1
  21. package/skills/skill-audio-cleanup-lab/package.json +1 -5
  22. package/skills/{skill-extract-audio → skill-audio-extract}/SKILL.md +3 -3
  23. package/skills/{skill-extract-audio → skill-audio-extract}/package.json +3 -7
  24. package/skills/skill-audiobook-chapter-proofer/package.json +1 -7
  25. package/skills/skill-banner-ad-suite/package.json +1 -7
  26. package/skills/skill-benchmark-finder/package.json +1 -7
  27. package/skills/skill-bio-sequence-tool/package.json +1 -7
  28. package/skills/skill-blog-topic-cluster/package.json +1 -7
  29. package/skills/skill-brand-voice-audit/package.json +1 -7
  30. package/skills/skill-browse/package.json +0 -5
  31. package/skills/skill-businessactivity/package.json +1 -3
  32. package/skills/skill-calendar-events/package.json +1 -7
  33. package/skills/skill-campaign-metric-brief/package.json +1 -7
  34. package/skills/skill-campaign-moodboard/package.json +1 -7
  35. package/skills/skill-caption-style-stylist/package.json +1 -7
  36. package/skills/skill-chemistry-calculator/package.json +1 -7
  37. package/skills/skill-churn-risk-notifier/package.json +1 -7
  38. package/skills/skill-citation-formatter/package.json +1 -7
  39. package/skills/skill-classroom-newsletter-kit/package.json +1 -7
  40. package/skills/skill-codefix/package.json +0 -4
  41. package/skills/skill-color-palette-harmonizer/package.json +1 -7
  42. package/skills/skill-colorextract/package.json +17 -5
  43. package/skills/skill-commitpush/package.json +0 -1
  44. package/skills/skill-commitpushpr/package.json +0 -1
  45. package/skills/skill-competitor-ad-analyzer/package.json +1 -7
  46. package/skills/skill-compliance-copy-check/package.json +1 -7
  47. package/skills/skill-compliance-report-pack/package.json +1 -7
  48. package/skills/skill-compress-video/package.json +1 -5
  49. package/skills/skill-consolelog/package.json +1 -7
  50. package/skills/skill-contract-plainlanguage/package.json +1 -7
  51. package/skills/skill-convert/SKILL.md +7 -0
  52. package/skills/skill-convert/package.json +0 -4
  53. package/skills/skill-copytone-translator/package.json +1 -7
  54. package/skills/skill-create-blog-article/package.json +1 -7
  55. package/skills/skill-create-ebook/package.json +1 -7
  56. package/skills/skill-crm-note-enhancer/package.json +1 -7
  57. package/skills/skill-customer-journey-mapper/package.json +1 -7
  58. package/skills/skill-dashboard-builder/package.json +1 -7
  59. package/skills/skill-dashboard-narrator/package.json +1 -7
  60. package/skills/skill-data-anonymizer/package.json +1 -7
  61. package/skills/skill-database-explorer/package.json +1 -7
  62. package/skills/skill-dataset-health-check/package.json +1 -7
  63. package/skills/skill-decision-journal/package.json +1 -7
  64. package/skills/skill-deepresearch/package.json +0 -5
  65. package/skills/skill-delegation-brief-writer/package.json +1 -7
  66. package/skills/skill-deploy/package.json +0 -4
  67. package/skills/skill-destination-briefing/package.json +1 -7
  68. package/skills/skill-diff-viewer/package.json +1 -7
  69. package/skills/{skill-generate-docx → skill-doc-generate}/SKILL.md +2 -2
  70. package/skills/{skill-generate-pdf → skill-doc-generate}/package.json +9 -4
  71. package/skills/{skill-generate-docx → skill-doc-generate}/src/index.ts +91 -28
  72. package/skills/skill-doc-read/SKILL.md +45 -0
  73. package/skills/skill-doc-read/package.json +29 -0
  74. package/skills/skill-doc-read/src/index.ts +324 -0
  75. package/skills/skill-doc-read/tsconfig.json +8 -0
  76. package/skills/skill-domainpurchase/package.json +1 -7
  77. package/skills/skill-domainsearch/package.json +1 -7
  78. package/skills/skill-e2bswarm/package.json +0 -6
  79. package/skills/skill-educational-resource-finder/package.json +1 -7
  80. package/skills/skill-email-campaign/package.json +1 -7
  81. package/skills/skill-emoji/package.json +0 -1
  82. package/skills/skill-exam-readiness-check/package.json +1 -7
  83. package/skills/skill-excel/SKILL.md +38 -0
  84. package/skills/skill-excel/package.json +30 -0
  85. package/skills/{skill-generate-excel → skill-excel}/src/index.ts +41 -14
  86. package/skills/skill-experiment-power-calculator/package.json +1 -7
  87. package/skills/skill-extract/package.json +0 -5
  88. package/skills/skill-extract-frames/package.json +1 -7
  89. package/skills/skill-extract-invoice/package.json +1 -7
  90. package/skills/skill-family-activity-curator/package.json +1 -7
  91. package/skills/skill-faq-packager/package.json +1 -7
  92. package/skills/skill-feedback-survey-designer/package.json +1 -7
  93. package/skills/skill-field-trip-planner/package.json +1 -7
  94. package/skills/skill-file-organizer/package.json +1 -7
  95. package/skills/skill-folder-tree/package.json +1 -7
  96. package/skills/skill-forecast-scenario-lab/package.json +1 -7
  97. package/skills/skill-form-filler/package.json +1 -7
  98. package/skills/skill-generate-api-client/package.json +1 -7
  99. package/skills/skill-generate-book-cover/package.json +1 -7
  100. package/skills/skill-generate-chart/package.json +1 -7
  101. package/skills/skill-generate-diagram/package.json +1 -7
  102. package/skills/skill-generate-dockerfile/package.json +1 -7
  103. package/skills/skill-generate-documentation/package.json +1 -7
  104. package/skills/skill-generate-env/package.json +1 -7
  105. package/skills/skill-generate-favicon/package.json +1 -7
  106. package/skills/skill-generate-mock-data/package.json +1 -7
  107. package/skills/skill-generate-pr-description/package.json +1 -7
  108. package/skills/skill-generate-presentation/package.json +1 -7
  109. package/skills/skill-generate-qrcode/package.json +1 -7
  110. package/skills/skill-generate-regex/package.json +1 -7
  111. package/skills/skill-generate-resume/package.json +1 -7
  112. package/skills/skill-generate-sitemap/package.json +1 -7
  113. package/skills/skill-generate-social-posts/package.json +1 -7
  114. package/skills/skill-generate-sql/package.json +1 -7
  115. package/skills/skill-gif-maker/package.json +1 -7
  116. package/skills/skill-github-manager/package.json +1 -7
  117. package/skills/skill-gmail/package.json +1 -7
  118. package/skills/skill-goal-quarterly-roadmap/package.json +1 -7
  119. package/skills/skill-grant-application-drafter/package.json +1 -7
  120. package/skills/skill-grocery-basket-optimizer/package.json +1 -7
  121. package/skills/skill-guest-communication-suite/package.json +1 -7
  122. package/skills/skill-habit-reflection-digest/package.json +1 -7
  123. package/skills/skill-highlight-reel-generator/package.json +1 -7
  124. package/skills/skill-homework-feedback-coach/package.json +1 -7
  125. package/skills/skill-hook/package.json +0 -6
  126. package/skills/skill-household-maintenance-mgr/package.json +1 -7
  127. package/skills/skill-http-server/package.json +1 -7
  128. package/skills/skill-image/SKILL.md +2 -0
  129. package/skills/skill-image/package.json +0 -5
  130. package/skills/skill-image/src/index-local.ts +5 -3
  131. package/skills/skill-image/src/providers/minimax.ts +94 -0
  132. package/skills/skill-image/src/types.ts +1 -1
  133. package/skills/skill-implementation/package.json +0 -6
  134. package/skills/skill-implementation-agent/package.json +1 -7
  135. package/skills/skill-implementation-plan/package.json +1 -7
  136. package/skills/skill-implementation-todo/package.json +1 -7
  137. package/skills/skill-inbox-priority-planner/package.json +1 -7
  138. package/skills/skill-invoice-dispute-helper/package.json +1 -7
  139. package/skills/skill-itinerary-architect/package.json +1 -7
  140. package/skills/skill-kpi-digest-generator/package.json +1 -7
  141. package/skills/skill-lab-notebook-formatter/package.json +1 -7
  142. package/skills/skill-landing-page-copy/package.json +1 -7
  143. package/skills/skill-latex-table-generator/package.json +1 -7
  144. package/skills/skill-learning-style-profiler/package.json +1 -7
  145. package/skills/skill-lesson-plan-customizer/package.json +1 -7
  146. package/skills/skill-livestream-runofshow/package.json +1 -7
  147. package/skills/skill-longform-structurer/package.json +1 -7
  148. package/skills/skill-lorem-generator/package.json +1 -7
  149. package/skills/skill-managehook/package.json +1 -3
  150. package/skills/skill-managemcp/package.json +1 -3
  151. package/skills/skill-manageskill/package.json +1 -3
  152. package/skills/skill-markdown-validator/package.json +1 -7
  153. package/skills/skill-mcp-builder/package.json +1 -7
  154. package/skills/skill-meal-plan-designer/package.json +1 -7
  155. package/skills/skill-meeting-insight-summarizer/package.json +1 -7
  156. package/skills/skill-merge-pdfs/package.json +1 -7
  157. package/skills/skill-microcopy-generator/package.json +1 -7
  158. package/skills/skill-mindfulness-prompt-cache/package.json +1 -7
  159. package/skills/skill-monitor/package.json +0 -1
  160. package/skills/skill-music/CLAUDE.md +9 -0
  161. package/skills/skill-music/SKILL.md +35 -0
  162. package/skills/{skill-generate-excel → skill-music}/package.json +4 -10
  163. package/skills/skill-music/src/index.ts +192 -0
  164. package/skills/skill-notion-manager/package.json +1 -7
  165. package/skills/skill-npmpublish/package.json +0 -5
  166. package/skills/skill-onboarding-sequence-builder/package.json +1 -7
  167. package/skills/skill-onsite-ops-checklist/package.json +1 -7
  168. package/skills/skill-outreach-cadence-designer/package.json +1 -7
  169. package/skills/skill-packaging-concept-studio/package.json +1 -7
  170. package/skills/skill-packing-plan-pro/package.json +1 -7
  171. package/skills/skill-parent-teacher-brief/package.json +1 -7
  172. package/skills/skill-partner-kit-assembler/package.json +1 -7
  173. package/skills/skill-payroll-change-prepper/package.json +1 -7
  174. package/skills/{skill-generate-pdf → skill-pdf-generate}/SKILL.md +2 -2
  175. package/skills/{skill-generate-docx → skill-pdf-generate}/package.json +6 -4
  176. package/skills/{skill-generate-pdf → skill-pdf-generate}/src/index.ts +109 -8
  177. package/skills/skill-pdf-read/SKILL.md +56 -0
  178. package/skills/skill-pdf-read/package.json +29 -0
  179. package/skills/skill-pdf-read/src/index.ts +320 -0
  180. package/skills/skill-pdf-read/tsconfig.json +8 -0
  181. package/skills/skill-persona-based-adwriter/package.json +1 -7
  182. package/skills/skill-persona-generator/package.json +1 -7
  183. package/skills/skill-personal-daily-ops/package.json +1 -7
  184. package/skills/skill-pet-care-scheduler/package.json +1 -7
  185. package/skills/skill-podcast-show-notes/package.json +1 -7
  186. package/skills/skill-presentation-theme-maker/package.json +1 -7
  187. package/skills/skill-press-release-drafter/package.json +1 -7
  188. package/skills/skill-print-collateral-designer/package.json +1 -7
  189. package/skills/skill-procurement-scorecard/package.json +1 -7
  190. package/skills/skill-product-demo-script/package.json +1 -7
  191. package/skills/skill-product-mockup/package.json +1 -7
  192. package/skills/skill-project-retro-companion/package.json +1 -7
  193. package/skills/skill-proposal-redline-advisor/package.json +1 -7
  194. package/skills/skill-read-csv/SKILL.md +1 -1
  195. package/skills/skill-read-csv/package.json +0 -1
  196. package/skills/skill-read-csv/src/index.ts +30 -5
  197. package/skills/skill-read-excel/SKILL.md +1 -1
  198. package/skills/skill-read-excel/package.json +0 -1
  199. package/skills/skill-read-excel/src/index.ts +21 -8
  200. package/skills/skill-read-image/SKILL.md +1 -1
  201. package/skills/skill-read-image/package.json +0 -1
  202. package/skills/skill-read-pdf/SKILL.md +1 -1
  203. package/skills/skill-read-pdf/package.json +0 -1
  204. package/skills/skill-read-pdf/src/index.ts +15 -3
  205. package/skills/skill-regex-tester/package.json +1 -7
  206. package/skills/skill-remove-background/package.json +1 -7
  207. package/skills/skill-risk-disclosure-kit/package.json +1 -7
  208. package/skills/skill-roi-comparison-tool/package.json +1 -7
  209. package/skills/skill-sales-call-recapper/package.json +1 -7
  210. package/skills/skill-scaffold-project/package.json +1 -7
  211. package/skills/skill-scancommitpr/package.json +0 -2
  212. package/skills/skill-scancommitpush/package.json +0 -2
  213. package/skills/skill-scholarship-tracker/package.json +1 -7
  214. package/skills/skill-scientific-figure-check/package.json +1 -7
  215. package/skills/skill-seating-chart-maker/package.json +1 -7
  216. package/skills/skill-security-audit/package.json +1 -7
  217. package/skills/skill-seo-brief-builder/package.json +1 -7
  218. package/skills/skill-siteanalyze/package.json +19 -5
  219. package/skills/skill-slack-assistant/package.json +1 -7
  220. package/skills/skill-sleep-routine-analyzer/package.json +1 -7
  221. package/skills/skill-sms/package.json +0 -1
  222. package/skills/skill-social-media-kit/package.json +1 -7
  223. package/skills/skill-sound-effects/SKILL.md +34 -0
  224. package/skills/{skill-jingle-composer → skill-sound-effects}/package.json +4 -10
  225. package/skills/skill-sound-effects/src/index.ts +172 -0
  226. package/skills/skill-sound-effects/tsconfig.json +8 -0
  227. package/skills/skill-split-pdf/package.json +1 -7
  228. package/skills/skill-sponsorship-proposal-lab/package.json +1 -7
  229. package/skills/skill-spreadsheet-cleanroom/package.json +1 -7
  230. package/skills/skill-statistical-test-selector/package.json +1 -7
  231. package/skills/skill-stress-relief-playbook/package.json +1 -7
  232. package/skills/skill-study-guide-builder/package.json +1 -7
  233. package/skills/skill-subscription-spend-watcher/package.json +1 -7
  234. package/skills/skill-subtitle/package.json +0 -6
  235. package/skills/skill-survey-insight-extractor/package.json +1 -7
  236. package/skills/skill-terraform-generator/package.json +1 -7
  237. package/skills/skill-testimonial-graphics/package.json +1 -7
  238. package/skills/skill-timesheet/package.json +0 -6
  239. package/skills/skill-tmux-session/package.json +0 -1
  240. package/skills/skill-transcript/SKILL.md +3 -1
  241. package/skills/skill-transcript/package.json +0 -5
  242. package/skills/skill-travel-budget-balancer/package.json +1 -7
  243. package/skills/skill-validate-config/package.json +1 -7
  244. package/skills/skill-video/SKILL.md +3 -1
  245. package/skills/skill-video/package.json +0 -5
  246. package/skills/skill-video/src/providers/index.ts +4 -1
  247. package/skills/skill-video/src/providers/minimax.ts +100 -0
  248. package/skills/skill-video/src/types.ts +1 -1
  249. package/skills/skill-video-cut-suggester/package.json +1 -7
  250. package/skills/skill-video-downloader/package.json +1 -7
  251. package/skills/skill-video-thumbnail/package.json +1 -7
  252. package/skills/skill-voiceover-casting-assistant/package.json +1 -7
  253. package/skills/skill-watermark/package.json +1 -7
  254. package/skills/skill-webcrawling/package.json +11 -8
  255. package/skills/skill-webinar-script-coach/package.json +1 -7
  256. package/skills/skill-wellness-progress-reporter/package.json +1 -7
  257. package/skills/skill-workout-cycle-planner/package.json +1 -7
  258. package/skills/skill-write/package.json +0 -5
  259. package/skills/skill-jingle-composer/CLAUDE.md +0 -19
  260. package/skills/skill-jingle-composer/src/index.ts +0 -250
  261. /package/skills/{skill-extract-audio → skill-audio-extract}/CLAUDE.md +0 -0
  262. /package/skills/{skill-extract-audio → skill-audio-extract}/src/index.ts +0 -0
  263. /package/skills/{skill-extract-audio → skill-audio-extract}/tsconfig.json +0 -0
  264. /package/skills/{skill-generate-docx → skill-doc-generate}/CLAUDE.md +0 -0
  265. /package/skills/{skill-generate-docx → skill-doc-generate}/tsconfig.json +0 -0
  266. /package/skills/{skill-generate-excel → skill-excel}/CLAUDE.md +0 -0
  267. /package/skills/{skill-generate-excel → skill-excel}/tsconfig.json +0 -0
  268. /package/skills/{skill-jingle-composer → skill-music}/tsconfig.json +0 -0
  269. /package/skills/{skill-generate-pdf → skill-pdf-generate}/CLAUDE.md +0 -0
  270. /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
- import minimist from "minimist";
27
- import { marked } from "marked";
28
- import OpenAI from "openai";
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 = new OpenAI({ apiKey });
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): TextRun[] {
381
- const runs: TextRun[] = [];
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): Document {
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
+ });
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"]
8
+ }
@@ -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"
@@ -23,11 +23,5 @@
23
23
  "files": [
24
24
  "src",
25
25
  "tsconfig.json"
26
- ],
27
- "repository": {
28
- "type": "git",
29
- "url": "https://github.com/hasnaxyz/skill-educational-resource-finder.git"
30
- },
31
- "author": "Hasna",
32
- "license": "Apache-2.0"
26
+ ]
33
27
  }
@@ -23,11 +23,5 @@
23
23
  "files": [
24
24
  "src",
25
25
  "tsconfig.json"
26
- ],
27
- "repository": {
28
- "type": "git",
29
- "url": "https://github.com/hasnaxyz/skill-email-campaign.git"
30
- },
31
- "author": "Hasna",
32
- "license": "Apache-2.0"
26
+ ]
33
27
  }
@@ -22,7 +22,6 @@
22
22
  "emoji-pack"
23
23
  ],
24
24
  "author": "",
25
- "license": "Apache-2.0",
26
25
  "devDependencies": {
27
26
  "@types/bun": "latest"
28
27
  },
@@ -23,11 +23,5 @@
23
23
  "files": [
24
24
  "src",
25
25
  "tsconfig.json"
26
- ],
27
- "repository": {
28
- "type": "git",
29
- "url": "https://github.com/hasnaxyz/skill-exam-readiness-check.git"
30
- },
31
- "author": "Hasna",
32
- "license": "Apache-2.0"
26
+ ]
33
27
  }