devendra-skill-package 1.0.2
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/.github/skills/boiler-project-generator/SKILL.md +103 -0
- package/.github/skills/boiler-project-generator/assets/templates/android/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/angular/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/flutter/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/ios/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/api-setup.ts +76 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/component-primary-button.tsx +29 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/env-config.env +4 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-auth-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-dashboard-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-profile-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/hook-use-app-boot.ts +11 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/navigation-setup.tsx +25 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/project-structure.md +24 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-hooks.ts +5 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-session-slice.ts +29 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-store.ts +15 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/theme-index.ts +23 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/utils-helpers.ts +7 -0
- package/.github/skills/boiler-project-generator/metadata.yaml +29 -0
- package/.github/skills/boiler-project-generator/references/android.md +19 -0
- package/.github/skills/boiler-project-generator/references/angular.md +14 -0
- package/.github/skills/boiler-project-generator/references/flutter.md +17 -0
- package/.github/skills/boiler-project-generator/references/ios.md +17 -0
- package/.github/skills/boiler-project-generator/references/react-native.md +103 -0
- package/.github/skills/boiler-project-generator/references/react.md +17 -0
- package/.github/skills/boiler-project-generator/scripts/angular.js +43 -0
- package/.github/skills/boiler-project-generator/scripts/generate-project.mjs +107 -0
- package/.github/skills/boiler-project-generator/scripts/init.js +105 -0
- package/.github/skills/boiler-project-generator/scripts/react-native.js +1041 -0
- package/.github/skills/boiler-project-generator/scripts/react.js +32 -0
- package/.github/skills/clean-architecture-generator/SKILL.md +235 -0
- package/.github/skills/clean-architecture-generator/references/architecture-core.md +126 -0
- package/.github/skills/clean-architecture-generator/references/platform-angular.md +374 -0
- package/.github/skills/clean-architecture-generator/references/platform-flutter.md +366 -0
- package/.github/skills/clean-architecture-generator/references/platform-react-native.md +590 -0
- package/.github/skills/clean-architecture-generator/references/platform-react.md +261 -0
- package/.github/skills/code-test-coverage-analyzer/SKILL.md +1358 -0
- package/.github/skills/code-test-coverage-analyzer/assets/config-questionnaire.md +118 -0
- package/.github/skills/code-test-coverage-analyzer/assets/conflict-resolution-protocol.md +99 -0
- package/.github/skills/code-test-coverage-analyzer/assets/coverage-calculation-rules.md +294 -0
- package/.github/skills/code-test-coverage-analyzer/assets/multi-strategy-search.md +145 -0
- package/.github/skills/code-test-coverage-analyzer/assets/output-file-contracts.md +651 -0
- package/.github/skills/code-test-coverage-analyzer/assets/status-definitions.md +273 -0
- package/.github/skills/code-test-coverage-analyzer/examples/example-invocation.md +208 -0
- package/.github/skills/code-test-coverage-analyzer/references/android-patterns.md +229 -0
- package/.github/skills/code-test-coverage-analyzer/references/angular-patterns.md +177 -0
- package/.github/skills/code-test-coverage-analyzer/references/backend-patterns.md +383 -0
- package/.github/skills/code-test-coverage-analyzer/references/flutter-patterns.md +254 -0
- package/.github/skills/code-test-coverage-analyzer/references/ios-patterns.md +228 -0
- package/.github/skills/code-test-coverage-analyzer/references/react-native-patterns.md +431 -0
- package/.github/skills/code-test-coverage-analyzer/references/react-patterns.md +206 -0
- package/.github/skills/code-test-coverage-analyzer/scripts/detect-platform.ps1 +261 -0
- package/.github/skills/code-test-coverage-analyzer/scripts/scan-repository.ps1 +242 -0
- package/.github/skills/code-test-coverage-analyzer/templates/brd-compliance-row.md +107 -0
- package/.github/skills/code-test-coverage-analyzer/templates/test-case-row.md +130 -0
- package/.github/skills/code-test-coverage-analyzer/templates/user-story-compliance-row.md +170 -0
- package/.github/skills/custom-font-integrator/SKILL.md +373 -0
- package/.github/skills/custom-font-integrator/assets/FontTestScreen.js +150 -0
- package/.github/skills/custom-font-integrator/references/example-info-plist.xml +21 -0
- package/.github/skills/custom-font-integrator/scripts/setup-fonts.sh +99 -0
- package/.github/skills/encryption-decryption-utility/Instructions.md +282 -0
- package/.github/skills/encryption-decryption-utility/README.md +222 -0
- package/.github/skills/encryption-decryption-utility/SKILL.md +645 -0
- package/.github/skills/encryption-decryption-utility/assets/encryption-config-template.json +13 -0
- package/.github/skills/encryption-decryption-utility/assets/platform-matrix.json +180 -0
- package/.github/skills/encryption-decryption-utility/metadata.yaml +51 -0
- package/.github/skills/encryption-decryption-utility/references/android-crypto.md +157 -0
- package/.github/skills/encryption-decryption-utility/references/angular-crypto.md +130 -0
- package/.github/skills/encryption-decryption-utility/references/approach-1-webcrypto.md +95 -0
- package/.github/skills/encryption-decryption-utility/references/approach-2-rsa-aes-cbc.md +111 -0
- package/.github/skills/encryption-decryption-utility/references/approach-3-aes-sharedkey.md +114 -0
- package/.github/skills/encryption-decryption-utility/references/architecture.md +233 -0
- package/.github/skills/encryption-decryption-utility/references/backend-alignment.md +506 -0
- package/.github/skills/encryption-decryption-utility/references/dependency-guidance.md +234 -0
- package/.github/skills/encryption-decryption-utility/references/ec-implementation.md +832 -0
- package/.github/skills/encryption-decryption-utility/references/error-handling-playbook.md +234 -0
- package/.github/skills/encryption-decryption-utility/references/flutter-crypto.md +105 -0
- package/.github/skills/encryption-decryption-utility/references/ios-crypto.md +338 -0
- package/.github/skills/encryption-decryption-utility/references/native-rsa-implementation.md +373 -0
- package/.github/skills/encryption-decryption-utility/references/node-crypto.md +86 -0
- package/.github/skills/encryption-decryption-utility/references/react-crypto.md +105 -0
- package/.github/skills/encryption-decryption-utility/references/react-native-crypto.md +1001 -0
- package/.github/skills/encryption-decryption-utility/references/react-web-crypto.md +668 -0
- package/.github/skills/encryption-decryption-utility/references/security-checklist.md +176 -0
- package/.github/skills/encryption-decryption-utility/references/web-crypto.md +74 -0
- package/.github/skills/encryption-decryption-utility/scripts/detect.js +128 -0
- package/.github/skills/encryption-decryption-utility/scripts/install.js +1713 -0
- package/.github/skills/encryption-decryption-utility/scripts/setup.js +800 -0
- package/.github/skills/encryption-decryption-utility/template.md +241 -0
- package/.github/skills/encryption-decryption-utility/templates/config-questionnaire.md +467 -0
- package/.github/skills/encryption-decryption-utility/templates/delivery-checklist.md +206 -0
- package/.github/skills/encryption-decryption-utility/templates/implementation-plan.md +304 -0
- package/.github/skills/feature-generator/SKILL.MD +2741 -0
- package/.github/skills/feature-generator/assets/fingerprint-schema.json +385 -0
- package/.github/skills/feature-generator/assets/spec-template.md +172 -0
- package/.github/skills/feature-generator/assets/transform-rules.json +82 -0
- package/.github/skills/feature-generator/references/api-envelope-patterns.md +327 -0
- package/.github/skills/feature-generator/references/screen-logic-patterns.md +399 -0
- package/.github/skills/feature-generator/references/state-library-patterns.md +464 -0
- package/.github/skills/figma-ui-mapper/README.md +34 -0
- package/.github/skills/figma-ui-mapper/SKILL.md +101 -0
- package/.github/skills/figma-ui-mapper/assets/templates/component-map-template.md +30 -0
- package/.github/skills/figma-ui-mapper/assets/templates/generation-report-template.md +49 -0
- package/.github/skills/figma-ui-mapper/metadata.yaml +22 -0
- package/.github/skills/figma-ui-mapper/references/android.md +11 -0
- package/.github/skills/figma-ui-mapper/references/angular.md +18 -0
- package/.github/skills/figma-ui-mapper/references/capacitor.md +18 -0
- package/.github/skills/figma-ui-mapper/references/common.md +23 -0
- package/.github/skills/figma-ui-mapper/references/expo.md +18 -0
- package/.github/skills/figma-ui-mapper/references/flutter.md +18 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/angular/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/capacitor/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/expo/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/flutter/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/ionic/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/kotlin-multiplatform/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/native-android/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/native-ios/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/next/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/nuxt/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/react/rules.md +19 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/react-native/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/svelte/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/vue/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/ionic.md +18 -0
- package/.github/skills/figma-ui-mapper/references/ios.md +11 -0
- package/.github/skills/figma-ui-mapper/references/kotlin-multiplatform.md +18 -0
- package/.github/skills/figma-ui-mapper/references/native-android.md +18 -0
- package/.github/skills/figma-ui-mapper/references/native-ios.md +18 -0
- package/.github/skills/figma-ui-mapper/references/next.md +18 -0
- package/.github/skills/figma-ui-mapper/references/nuxt.md +18 -0
- package/.github/skills/figma-ui-mapper/references/react-figma-guideline.md +21 -0
- package/.github/skills/figma-ui-mapper/references/react-native.md +18 -0
- package/.github/skills/figma-ui-mapper/references/react.md +18 -0
- package/.github/skills/figma-ui-mapper/references/script-usage.md +46 -0
- package/.github/skills/figma-ui-mapper/references/svelte.md +18 -0
- package/.github/skills/figma-ui-mapper/references/vue.md +18 -0
- package/.github/skills/figma-ui-mapper/references/workflow.md +74 -0
- package/.github/skills/figma-ui-mapper/scripts/generate-page-through-figma.js +635 -0
- package/.github/skills/figma-ui-mapper/scripts/generate-react-page-through-figma.js +4 -0
- package/.github/skills/frontend-task-breakdown/SKILL.md +734 -0
- package/.github/skills/md-file-converter/SKILL.md +291 -0
- package/.github/skills/md-file-converter/config/formats.json +114 -0
- package/.github/skills/md-file-converter/extractors/extract-docx.sh +120 -0
- package/.github/skills/md-file-converter/extractors/extract-eml.py +108 -0
- package/.github/skills/md-file-converter/extractors/extract-pdf.sh +97 -0
- package/.github/skills/md-file-converter/extractors/extract-pptx.py +143 -0
- package/.github/skills/md-file-converter/extractors/extract-xlsx.py +175 -0
- package/.github/skills/md-file-converter/scripts/check-tools.sh +47 -0
- package/.github/skills/md-file-converter/scripts/extract-archive.sh +83 -0
- package/.github/skills/md-file-converter/scripts/extract-ocr.sh +77 -0
- package/.github/skills/md-file-converter/scripts/get-metadata.sh +57 -0
- package/.github/skills/md-file-converter/templates/output.md +73 -0
- package/.github/skills/md-file-converter/templates/unsupported-object.md +6 -0
- package/.github/skills/mockAPI-contract-generator/SKILL.md +607 -0
- package/.github/skills/test-case-validator/CHANGELOG.md +155 -0
- package/.github/skills/test-case-validator/CONFIGURATION.md +130 -0
- package/.github/skills/test-case-validator/EXAMPLES.md +50 -0
- package/.github/skills/test-case-validator/QUALITY_SCORING.md +98 -0
- package/.github/skills/test-case-validator/README.md +111 -0
- package/.github/skills/test-case-validator/REPORT_TEMPLATE.md +116 -0
- package/.github/skills/test-case-validator/SKILL.md +209 -0
- package/.github/skills/test-case-validator/SYSTEM_PROMPT.md +127 -0
- package/.github/skills/test-case-validator/TRACEABILITY_ENGINE.md +152 -0
- package/.github/skills/test-case-validator/VALIDATION_RULES.md +411 -0
- package/.github/skills/test-case-validator/config/default.config.yaml +62 -0
- package/.github/skills/test-case-validator/docs/ARCHITECTURE.md +66 -0
- package/.github/skills/test-case-validator/docs/EXTENDING.md +85 -0
- package/.github/skills/test-case-validator/docs/FAQ.md +88 -0
- package/.github/skills/test-case-validator/docs/VERSIONING.md +55 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-brd.md +43 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-test-cases.csv +9 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-user-story.md +29 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/output-report.md +303 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/input-spec.md +43 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/input-test-files-index.md +56 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/output-report.md +274 -0
- package/.github/skills/test-case-validator/prompts/00-applicability-resolution.md +61 -0
- package/.github/skills/test-case-validator/prompts/01-extraction-user-story.md +58 -0
- package/.github/skills/test-case-validator/prompts/02-extraction-brd.md +64 -0
- package/.github/skills/test-case-validator/prompts/03-extraction-test-cases.md +92 -0
- package/.github/skills/test-case-validator/prompts/04-traceability-matrix.md +41 -0
- package/.github/skills/test-case-validator/prompts/05-coverage-analysis.md +46 -0
- package/.github/skills/test-case-validator/prompts/06-missing-scenario-detection.md +32 -0
- package/.github/skills/test-case-validator/prompts/07-duplicate-detection.md +36 -0
- package/.github/skills/test-case-validator/prompts/08-risk-analysis.md +39 -0
- package/.github/skills/test-case-validator/prompts/09-gated-wiring-validation.md +53 -0
- package/.github/skills/test-case-validator/prompts/10-observation-report.md +56 -0
- package/.github/skills/test-case-validator/prompts/11-final-report-assembly.md +57 -0
- package/.github/skills/test-case-validator/templates/coverage-table.md +25 -0
- package/.github/skills/test-case-validator/templates/executive-summary.md +38 -0
- package/.github/skills/test-case-validator/templates/final-summary-block.md +87 -0
- package/.github/skills/test-case-validator/templates/observation-entry.md +41 -0
- package/.github/skills/test-case-validator/templates/rtm-row.md +25 -0
- package/.github/skills/validation-engine-builder/README.md +50 -0
- package/.github/skills/validation-engine-builder/SKILL.md +241 -0
- package/.github/skills/validation-engine-builder/references/core.md +158 -0
- package/.github/skills/validation-engine-builder/references/platform-angular.md +166 -0
- package/.github/skills/validation-engine-builder/references/platform-flutter.md +118 -0
- package/.github/skills/validation-engine-builder/references/platform-react-native.md +170 -0
- package/.github/skills/validation-engine-builder/references/platform-react.md +94 -0
- package/.github/skills/validation-engine-builder/scripts/apply-to-project.js +80 -0
- package/.github/skills/validation-engine-builder/scripts/generate-angular.js +271 -0
- package/.github/skills/validation-engine-builder/scripts/generate-flutter.js +298 -0
- package/.github/skills/validation-engine-builder/scripts/generate-react-native.js +217 -0
- package/.github/skills/validation-engine-builder/scripts/generate-react.js +163 -0
- package/.github/skills/validation-engine-builder/scripts/install-deps.js +53 -0
- package/.github/skills/validation-engine-builder/scripts/shared/detect-platform.js +68 -0
- package/.github/skills/validation-engine-builder/scripts/shared/npm-deps.js +103 -0
- package/.github/skills/validation-engine-builder/scripts/shared/rhf-hook.js +43 -0
- package/.github/skills/validation-engine-builder/scripts/shared/ts-messages-regex.js +62 -0
- package/.github/skills/validation-engine-builder/scripts/shared/util.js +44 -0
- package/.github/skills/validation-engine-builder/scripts/shared/yup-schemas.js +80 -0
- package/.github/skills/validation-engine-builder/template.md +73 -0
- package/.github/skills/validation-engine-builder/templates/messages.json +22 -0
- package/.github/skills/validation-engine-builder/templates/regex.json +16 -0
- package/.github/skills/validation-engine-builder/templates/schemas.json +48 -0
- package/bin/index.js +145 -0
- package/package.json +22 -0
- package/readme.md +0 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: md-file-converter
|
|
3
|
+
description: Convert any supported file (PDF, DOCX, XLSX, PPTX, images, code, CSV, HTML, JSON, YAML, archives, logs, etc.) into a Markdown (.md) document with zero information loss. Use when asked to convert, transform, or export a file to Markdown format.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Universal File to Markdown Conversion Skill
|
|
7
|
+
|
|
8
|
+
## Role
|
|
9
|
+
|
|
10
|
+
You are a **Universal File-to-Markdown Conversion Engine**.
|
|
11
|
+
|
|
12
|
+
Convert any supported file into a `.md` document with **zero information loss**.
|
|
13
|
+
You are NOT a summarizer, editor, or formatter — you are a document preservation engine.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Skill Directory Layout
|
|
18
|
+
|
|
19
|
+
All supporting files for this skill live alongside this SKILL.md:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
.github/skills/md-file-generator/
|
|
23
|
+
├── SKILL.md ← you are here (orchestration logic)
|
|
24
|
+
├── config/
|
|
25
|
+
│ └── formats.json ← format→strategy mapping, chunk sizes, tool priority
|
|
26
|
+
├── extractors/
|
|
27
|
+
│ ├── extract-pdf.sh ← PDF (pdftotext → pandoc → PyPDF2)
|
|
28
|
+
│ ├── extract-docx.sh ← DOCX/ODT/RTF (pandoc → unzip+XML)
|
|
29
|
+
│ ├── extract-xlsx.py ← Excel (openpyxl → xlrd)
|
|
30
|
+
│ ├── extract-pptx.py ← PowerPoint (python-pptx)
|
|
31
|
+
│ └── extract-eml.py ← Email (.eml, stdlib only)
|
|
32
|
+
├── scripts/
|
|
33
|
+
│ ├── check-tools.sh ← detect all available CLI tools
|
|
34
|
+
│ ├── extract-archive.sh ← ZIP/TAR/7Z/GZ/RAR extraction
|
|
35
|
+
│ ├── get-metadata.sh ← universal file metadata
|
|
36
|
+
│ └── extract-ocr.sh ← tesseract → easyocr OCR
|
|
37
|
+
└── templates/
|
|
38
|
+
├── output.md ← output structure with {{placeholders}}
|
|
39
|
+
└── unsupported-object.md ← block template for unreadable objects
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Step 1 — Determine Input File
|
|
45
|
+
|
|
46
|
+
If the user provided a file path, upload, or pasted content → use it directly.
|
|
47
|
+
|
|
48
|
+
If no file was provided, ask exactly:
|
|
49
|
+
|
|
50
|
+
> **"Which file would you like me to convert into Markdown? Please upload the file or provide its path."**
|
|
51
|
+
|
|
52
|
+
Never guess. Never search the project automatically.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Step 2 — Detect Available Tools
|
|
57
|
+
|
|
58
|
+
Run this first. It determines which extraction strategy to use.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bash .github/skills/md-file-generator/scripts/check-tools.sh
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Read `config/formats.json` to understand which extractor maps to which format and what fallback order applies.
|
|
65
|
+
|
|
66
|
+
If Bash is unavailable and the file is binary, tell the user:
|
|
67
|
+
|
|
68
|
+
> "I cannot read `<filename>` (binary `<format>`) without Bash tool access.
|
|
69
|
+
> Please either enable Bash or paste the file contents directly."
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Step 3 — Validate the File
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
test -f "<path>" && echo "EXISTS" || echo "NOT FOUND"
|
|
77
|
+
file --mime-type "<path>"
|
|
78
|
+
wc -c "<path>"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Check if it is an archive (`.zip`, `.tar`, `.gz`, `.7z`, `.rar`).
|
|
82
|
+
Check if it is password-protected (attempt read; catch error).
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Step 4 — Extract Metadata
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
bash .github/skills/md-file-generator/scripts/get-metadata.sh "<path>"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Use the output to fill the Metadata section in `templates/output.md`.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Step 5 — Choose Extraction Strategy
|
|
97
|
+
|
|
98
|
+
Consult `config/formats.json` to classify the file:
|
|
99
|
+
|
|
100
|
+
| Category | Strategy | Tool needed |
|
|
101
|
+
|---------------|-------------------------------------------|-----------------|
|
|
102
|
+
| Text formats | Read tool directly | Read tool |
|
|
103
|
+
| Binary docs | Run the matching extractor script | Bash |
|
|
104
|
+
| Images | See OCR Strategy below | Vision or Bash |
|
|
105
|
+
| Archives | Extract first, then convert each file | Bash |
|
|
106
|
+
|
|
107
|
+
### Text formats (Read tool)
|
|
108
|
+
|
|
109
|
+
Extensions listed under `text_formats.extensions` in `formats.json`.
|
|
110
|
+
|
|
111
|
+
Read the file directly with the Read tool. No extractor script needed.
|
|
112
|
+
|
|
113
|
+
### Binary documents (Bash extractors)
|
|
114
|
+
|
|
115
|
+
| Format | Extractor script |
|
|
116
|
+
|--------------------|------------------------------------------|
|
|
117
|
+
| PDF | `extractors/extract-pdf.sh <file>` |
|
|
118
|
+
| DOCX / DOC / ODT / RTF | `extractors/extract-docx.sh <file>` |
|
|
119
|
+
| XLSX / XLS / ODS | `python3 extractors/extract-xlsx.py <file>` |
|
|
120
|
+
| PPTX / PPT | `python3 extractors/extract-pptx.py <file>` |
|
|
121
|
+
| EML | `python3 extractors/extract-eml.py <file>` |
|
|
122
|
+
|
|
123
|
+
Each extractor tries its primary tool first, then falls through its fallback chain automatically. Check `config/formats.json` for the priority order per format.
|
|
124
|
+
|
|
125
|
+
### Archives
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
bash .github/skills/md-file-generator/scripts/extract-archive.sh "<archive>" "<output_dir>"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
After extraction, list all files and convert each one independently using its own strategy. Generate `index.md` mapping the archive tree to converted files.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Step 6 — OCR Strategy
|
|
136
|
+
|
|
137
|
+
**Never claim OCR was performed when it was not.**
|
|
138
|
+
|
|
139
|
+
| Situation | Action |
|
|
140
|
+
|----------------------------------------|-----------------------------------------------------|
|
|
141
|
+
| Image uploaded directly into chat | Use Claude vision — extract all visible text |
|
|
142
|
+
| Image file path + Bash available | `bash scripts/extract-ocr.sh "<image>" [lang]` |
|
|
143
|
+
| Neither vision nor Bash available | Document limitation; do not invent text |
|
|
144
|
+
|
|
145
|
+
When vision is used, output:
|
|
146
|
+
|
|
147
|
+
```markdown
|
|
148
|
+

|
|
149
|
+
|
|
150
|
+
**Extracted Text (Vision):**
|
|
151
|
+
<full text exactly as seen>
|
|
152
|
+
|
|
153
|
+
**Visual Description:**
|
|
154
|
+
<describe charts, diagrams, layout, colours, icons>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
When OCR is not possible, output:
|
|
158
|
+
|
|
159
|
+
```markdown
|
|
160
|
+

|
|
161
|
+
|
|
162
|
+
> **OCR Not Possible:** No vision input and no OCR tool in this session.
|
|
163
|
+
> Upload the image directly into chat, or enable Bash with tesseract installed.
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Step 7 — Large File Chunking
|
|
169
|
+
|
|
170
|
+
Check size before reading:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
wc -c "<file>" # bytes
|
|
174
|
+
wc -l "<file>" # lines (text files)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
If the file exceeds **100 KB** of extracted text, process in chunks using thresholds from `config/formats.json`:
|
|
178
|
+
|
|
179
|
+
| Format | Default chunk size |
|
|
180
|
+
|-------------|------------------------|
|
|
181
|
+
| Text files | 500 lines per chunk |
|
|
182
|
+
| PDF | 20 pages per chunk |
|
|
183
|
+
| Slide decks | 10 slides per chunk |
|
|
184
|
+
| Spreadsheets| 1 worksheet per chunk |
|
|
185
|
+
|
|
186
|
+
Name output files: `document.part01.md`, `document.part02.md`, …
|
|
187
|
+
|
|
188
|
+
After each part, tell the user:
|
|
189
|
+
|
|
190
|
+
> "Part N written to `document.partNN.md` (range: X–Y). Type **continue** to process the next chunk."
|
|
191
|
+
|
|
192
|
+
Wait for confirmation before processing the next chunk.
|
|
193
|
+
|
|
194
|
+
If context pressure hits mid-conversion, stop at a clean boundary, save the part, and report the resume point. **Never drop content silently.**
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Step 8 — Convert to Markdown
|
|
199
|
+
|
|
200
|
+
Use `templates/output.md` as the structure. Replace all `{{placeholders}}` with real values.
|
|
201
|
+
|
|
202
|
+
### Formatting rules
|
|
203
|
+
|
|
204
|
+
| Element | Markdown syntax |
|
|
205
|
+
|--------------|------------------------------------------|
|
|
206
|
+
| Headings | `# H1` `## H2` `### H3` |
|
|
207
|
+
| Bold | `**bold**` |
|
|
208
|
+
| Italic | `*italic*` |
|
|
209
|
+
| Underline | `<u>text</u>` |
|
|
210
|
+
| Strike | `~~text~~` |
|
|
211
|
+
| Blockquote | `> quote` |
|
|
212
|
+
| Hyperlink | Markdown link syntax — never plain text |
|
|
213
|
+
| Equation | `$inline$` or `$$block$$` LaTeX |
|
|
214
|
+
| Code | Fenced block with language identifier |
|
|
215
|
+
|
|
216
|
+
### Tables
|
|
217
|
+
|
|
218
|
+
Use Markdown tables where possible. Use HTML `<table>` for merged/spanned cells. Never flatten to plain text.
|
|
219
|
+
|
|
220
|
+
### Images
|
|
221
|
+
|
|
222
|
+
Every image must appear. Apply OCR Strategy (Step 6). Never discard images.
|
|
223
|
+
|
|
224
|
+
### Code / Source files
|
|
225
|
+
|
|
226
|
+
Never modify, format, lint, or remove comments. Wrap in fenced blocks with the correct language identifier only.
|
|
227
|
+
|
|
228
|
+
### Unsupported objects
|
|
229
|
+
|
|
230
|
+
For any object that cannot be converted, use `templates/unsupported-object.md`:
|
|
231
|
+
|
|
232
|
+
```markdown
|
|
233
|
+
## Unsupported Object
|
|
234
|
+
- **Type:** <type>
|
|
235
|
+
- **Location:** <page/slide/sheet/position>
|
|
236
|
+
- **Reason:** <why>
|
|
237
|
+
- **Original Metadata:** <any available>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Step 9 — Output File Location
|
|
243
|
+
|
|
244
|
+
Write the `.md` file next to the source file, preserving folder structure:
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
docs/api/specification.pdf → docs/api/specification.md
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
If `output.md` already exists, generate `output_v2.md`, `output_v3.md`, etc., unless the user explicitly asks to overwrite.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Step 10 — Validation Checklist
|
|
255
|
+
|
|
256
|
+
Before completing, verify:
|
|
257
|
+
|
|
258
|
+
- [ ] Tool availability detected and recorded
|
|
259
|
+
- [ ] All pages / slides / sheets processed (or chunked with user confirmation)
|
|
260
|
+
- [ ] Every heading preserved
|
|
261
|
+
- [ ] Every table preserved (not flattened)
|
|
262
|
+
- [ ] Every image represented (OCR or documented limitation)
|
|
263
|
+
- [ ] Archives extracted via Bash (or user notified)
|
|
264
|
+
- [ ] Metadata captured from `get-metadata.sh`
|
|
265
|
+
- [ ] Hyperlinks preserved as Markdown link syntax — never plain text
|
|
266
|
+
- [ ] Code unchanged
|
|
267
|
+
- [ ] Reading order maintained
|
|
268
|
+
- [ ] All technical limitations documented in Conversion Report
|
|
269
|
+
- [ ] No content silently omitted
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Zero Information Loss Policy
|
|
274
|
+
|
|
275
|
+
Never intentionally: summarize, shorten, paraphrase, simplify, rewrite, remove duplicates, skip pages, skip sections, skip images, skip tables, skip metadata.
|
|
276
|
+
|
|
277
|
+
If content cannot be extracted due to a technical limitation, document it in the Conversion Report. **Never silently drop it.**
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Success Message
|
|
282
|
+
|
|
283
|
+
After conversion, report:
|
|
284
|
+
|
|
285
|
+
- Source file(s) processed and output file(s) location
|
|
286
|
+
- Extraction method used (Read / Bash extractor / Vision)
|
|
287
|
+
- OCR method used (Vision / tesseract / easyocr / None)
|
|
288
|
+
- Whether archive extraction ran
|
|
289
|
+
- Whether chunking was used and how many parts
|
|
290
|
+
- Any unsupported objects found
|
|
291
|
+
- Any technical limitations encountered
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"text_formats": {
|
|
3
|
+
"description": "Readable directly with the Read tool — no binary parsing needed",
|
|
4
|
+
"tool": "read",
|
|
5
|
+
"chunk_lines": 500,
|
|
6
|
+
"extensions": [
|
|
7
|
+
".txt", ".md", ".markdown",
|
|
8
|
+
".csv", ".tsv",
|
|
9
|
+
".json", ".yaml", ".yml", ".toml", ".ini", ".properties",
|
|
10
|
+
".xml", ".html", ".htm", ".xhtml",
|
|
11
|
+
".css", ".scss", ".less", ".sass",
|
|
12
|
+
".svg",
|
|
13
|
+
".log",
|
|
14
|
+
".sql",
|
|
15
|
+
".sh", ".bash", ".zsh", ".fish",
|
|
16
|
+
".ps1", ".psm1", ".psd1",
|
|
17
|
+
".js", ".mjs", ".cjs",
|
|
18
|
+
".ts", ".tsx", ".jsx",
|
|
19
|
+
".java", ".kt", ".kts",
|
|
20
|
+
".swift", ".m", ".mm",
|
|
21
|
+
".c", ".h", ".cpp", ".cc", ".cxx", ".hpp",
|
|
22
|
+
".cs",
|
|
23
|
+
".go",
|
|
24
|
+
".rs",
|
|
25
|
+
".py", ".pyw",
|
|
26
|
+
".php",
|
|
27
|
+
".rb",
|
|
28
|
+
".dart",
|
|
29
|
+
".r", ".rmd",
|
|
30
|
+
".lua",
|
|
31
|
+
".pl", ".pm",
|
|
32
|
+
".ex", ".exs",
|
|
33
|
+
".clj", ".cljs",
|
|
34
|
+
".hs",
|
|
35
|
+
".erl",
|
|
36
|
+
".scala",
|
|
37
|
+
".groovy",
|
|
38
|
+
".tf", ".tfvars",
|
|
39
|
+
".dockerfile",
|
|
40
|
+
".makefile",
|
|
41
|
+
".gitignore", ".env", ".editorconfig",
|
|
42
|
+
".bat", ".cmd"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"binary_formats": {
|
|
46
|
+
"description": "Require Bash tool + CLI extractors. Fallback chain tried in order.",
|
|
47
|
+
"pdf": {
|
|
48
|
+
"extractor": "extractors/extract-pdf.sh",
|
|
49
|
+
"chunk_pages": 20,
|
|
50
|
+
"primary_tool": "pdftotext",
|
|
51
|
+
"fallbacks": ["pandoc", "python-pypdf2"],
|
|
52
|
+
"metadata_tool": "pdfinfo"
|
|
53
|
+
},
|
|
54
|
+
"docx": {
|
|
55
|
+
"extractor": "extractors/extract-docx.sh",
|
|
56
|
+
"primary_tool": "pandoc",
|
|
57
|
+
"fallbacks": ["unzip+xml-parse"],
|
|
58
|
+
"extensions": [".docx", ".doc", ".odt", ".rtf"]
|
|
59
|
+
},
|
|
60
|
+
"xlsx": {
|
|
61
|
+
"extractor": "extractors/extract-xlsx.py",
|
|
62
|
+
"primary_tool": "openpyxl",
|
|
63
|
+
"fallbacks": ["xlrd"],
|
|
64
|
+
"chunk_by": "worksheet",
|
|
65
|
+
"extensions": [".xlsx", ".xls", ".ods"]
|
|
66
|
+
},
|
|
67
|
+
"pptx": {
|
|
68
|
+
"extractor": "extractors/extract-pptx.py",
|
|
69
|
+
"primary_tool": "python-pptx",
|
|
70
|
+
"fallbacks": ["unzip+xml-parse"],
|
|
71
|
+
"chunk_slides": 10,
|
|
72
|
+
"extensions": [".pptx", ".ppt", ".odp"]
|
|
73
|
+
},
|
|
74
|
+
"eml": {
|
|
75
|
+
"extractor": "extractors/extract-eml.py",
|
|
76
|
+
"primary_tool": "python-email",
|
|
77
|
+
"fallbacks": [],
|
|
78
|
+
"extensions": [".eml", ".msg"]
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"image_formats": {
|
|
82
|
+
"description": "OCR required. Strategy depends on how the image is provided.",
|
|
83
|
+
"ocr_extractor": "scripts/extract-ocr.sh",
|
|
84
|
+
"extensions": [".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".tif", ".webp", ".heic"],
|
|
85
|
+
"strategies": {
|
|
86
|
+
"vision_upload": "User uploaded image into chat — use Claude vision directly",
|
|
87
|
+
"file_path_bash": "Image at path + Bash available — run tesseract or easyocr",
|
|
88
|
+
"no_tools": "Document limitation in Conversion Report, do not invent text"
|
|
89
|
+
},
|
|
90
|
+
"ocr_tools_priority": ["tesseract", "easyocr"]
|
|
91
|
+
},
|
|
92
|
+
"archive_formats": {
|
|
93
|
+
"description": "Bash tool required. Extract first, then convert each file.",
|
|
94
|
+
"extractor": "scripts/extract-archive.sh",
|
|
95
|
+
"extensions": [".zip", ".tar", ".tar.gz", ".tgz", ".gz", ".7z", ".rar", ".tar.bz2", ".tar.xz"],
|
|
96
|
+
"commands": {
|
|
97
|
+
".zip": "unzip -o <file> -d <output_dir>",
|
|
98
|
+
".tar": "tar -xf <file> -C <output_dir>",
|
|
99
|
+
".tar.gz": "tar -xzf <file> -C <output_dir>",
|
|
100
|
+
".tgz": "tar -xzf <file> -C <output_dir>",
|
|
101
|
+
".tar.bz2": "tar -xjf <file> -C <output_dir>",
|
|
102
|
+
".tar.xz": "tar -xJf <file> -C <output_dir>",
|
|
103
|
+
".gz": "gunzip -k <file>",
|
|
104
|
+
".7z": "7z x <file> -o<output_dir>",
|
|
105
|
+
".rar": "unrar x <file> <output_dir>"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"chunk_thresholds": {
|
|
109
|
+
"text_lines_per_chunk": 500,
|
|
110
|
+
"pdf_pages_per_chunk": 20,
|
|
111
|
+
"slides_per_chunk": 10,
|
|
112
|
+
"max_bytes_before_chunking": 102400
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# DOCX / DOC / ODT / RTF extractor. Tries pandoc → unzip+XML in order.
|
|
3
|
+
# Usage: bash extractors/extract-docx.sh <file>
|
|
4
|
+
|
|
5
|
+
FILE="$1"
|
|
6
|
+
|
|
7
|
+
if [ -z "$FILE" ]; then
|
|
8
|
+
echo "Usage: extract-docx.sh <file>"
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
if [ ! -f "$FILE" ]; then
|
|
13
|
+
echo "Error: File not found: $FILE"
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
EXT_LOWER=$(echo "${FILE##*.}" | tr '[:upper:]' '[:lower:]')
|
|
18
|
+
|
|
19
|
+
echo "=== Document Extraction ==="
|
|
20
|
+
echo "File : $FILE"
|
|
21
|
+
echo "Format : $EXT_LOWER"
|
|
22
|
+
echo ""
|
|
23
|
+
|
|
24
|
+
# Strategy 1: pandoc (best quality — preserves headings, tables, lists)
|
|
25
|
+
if command -v pandoc >/dev/null 2>&1; then
|
|
26
|
+
echo "Method: pandoc"
|
|
27
|
+
echo ""
|
|
28
|
+
echo "--- Content ---"
|
|
29
|
+
pandoc "$FILE" -t markdown --wrap=none --extract-media=./extracted-media 2>/dev/null
|
|
30
|
+
EXIT_CODE=$?
|
|
31
|
+
if [ $EXIT_CODE -eq 0 ]; then
|
|
32
|
+
echo ""
|
|
33
|
+
echo "Extraction Status: SUCCESS (pandoc)"
|
|
34
|
+
# List any extracted media
|
|
35
|
+
if [ -d "./extracted-media" ]; then
|
|
36
|
+
echo ""
|
|
37
|
+
echo "=== Extracted Media Files ==="
|
|
38
|
+
find ./extracted-media -type f | sort
|
|
39
|
+
fi
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
echo "pandoc failed (exit $EXIT_CODE), trying fallback..."
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Strategy 2: unzip + XML parsing (DOCX/PPTX/XLSX are ZIP archives)
|
|
46
|
+
if [ "$EXT_LOWER" = "docx" ] || [ "$EXT_LOWER" = "odt" ]; then
|
|
47
|
+
if command -v unzip >/dev/null 2>&1 && command -v python3 >/dev/null 2>&1; then
|
|
48
|
+
echo "Method: unzip + XML parse"
|
|
49
|
+
echo ""
|
|
50
|
+
TMPDIR_XML=$(mktemp -d)
|
|
51
|
+
unzip -q "$FILE" -d "$TMPDIR_XML" 2>/dev/null
|
|
52
|
+
echo "--- Content (raw XML text extraction) ---"
|
|
53
|
+
python3 - "$TMPDIR_XML" <<'PYEOF'
|
|
54
|
+
import os, sys, re
|
|
55
|
+
from xml.etree import ElementTree as ET
|
|
56
|
+
|
|
57
|
+
base = sys.argv[1]
|
|
58
|
+
|
|
59
|
+
# DOCX uses word/document.xml; ODT uses content.xml
|
|
60
|
+
candidates = [
|
|
61
|
+
os.path.join(base, "word", "document.xml"),
|
|
62
|
+
os.path.join(base, "content.xml"),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
ns = {
|
|
66
|
+
'w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
|
|
67
|
+
'text':'urn:oasis:names:tc:opendocument:xmlns:text:1.0',
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
def extract_docx(path):
|
|
71
|
+
tree = ET.parse(path)
|
|
72
|
+
root = tree.getroot()
|
|
73
|
+
for para in root.iter('{http://schemas.openxmlformats.org/wordprocessingml/2006/main}p'):
|
|
74
|
+
texts = [t.text or '' for t in para.iter('{http://schemas.openxmlformats.org/wordprocessingml/2006/main}t')]
|
|
75
|
+
line = ''.join(texts).strip()
|
|
76
|
+
if line:
|
|
77
|
+
print(line)
|
|
78
|
+
|
|
79
|
+
def extract_odt(path):
|
|
80
|
+
tree = ET.parse(path)
|
|
81
|
+
root = tree.getroot()
|
|
82
|
+
for elem in root.iter():
|
|
83
|
+
if elem.text and elem.text.strip():
|
|
84
|
+
print(elem.text.strip())
|
|
85
|
+
|
|
86
|
+
for c in candidates:
|
|
87
|
+
if os.path.exists(c):
|
|
88
|
+
try:
|
|
89
|
+
if 'document.xml' in c:
|
|
90
|
+
extract_docx(c)
|
|
91
|
+
else:
|
|
92
|
+
extract_odt(c)
|
|
93
|
+
break
|
|
94
|
+
except Exception as e:
|
|
95
|
+
print(f"XML parse failed: {e}")
|
|
96
|
+
PYEOF
|
|
97
|
+
rm -rf "$TMPDIR_XML"
|
|
98
|
+
echo ""
|
|
99
|
+
echo "Extraction Status: PARTIAL (unzip+XML — formatting not preserved)"
|
|
100
|
+
exit 0
|
|
101
|
+
fi
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Strategy 3: RTF via unrtf
|
|
105
|
+
if [ "$EXT_LOWER" = "rtf" ] && command -v unrtf >/dev/null 2>&1; then
|
|
106
|
+
echo "Method: unrtf"
|
|
107
|
+
echo ""
|
|
108
|
+
echo "--- Content ---"
|
|
109
|
+
unrtf --text "$FILE" 2>/dev/null
|
|
110
|
+
echo ""
|
|
111
|
+
echo "Extraction Status: SUCCESS (unrtf)"
|
|
112
|
+
exit 0
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
echo "Extraction Status: FAILED"
|
|
116
|
+
echo "No document extractor available."
|
|
117
|
+
echo "Install options:"
|
|
118
|
+
echo " pandoc : https://pandoc.org/installing.html"
|
|
119
|
+
echo " unrtf : sudo apt install unrtf"
|
|
120
|
+
exit 1
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Email extractor for .eml files. Uses Python stdlib — no dependencies needed.
|
|
4
|
+
Captures: headers, plain text body, HTML body (converted), attachments list.
|
|
5
|
+
Usage: python3 extractors/extract-eml.py <file.eml>
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
import email
|
|
11
|
+
import email.policy
|
|
12
|
+
import html
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
FILE = sys.argv[1] if len(sys.argv) > 1 else None
|
|
16
|
+
|
|
17
|
+
if not FILE:
|
|
18
|
+
print("Usage: extract-eml.py <file.eml>")
|
|
19
|
+
sys.exit(1)
|
|
20
|
+
|
|
21
|
+
if not os.path.exists(FILE):
|
|
22
|
+
print(f"Error: File not found: {FILE}")
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
|
|
25
|
+
print(f"=== Email Extraction ===")
|
|
26
|
+
print(f"File : {FILE}")
|
|
27
|
+
print("")
|
|
28
|
+
|
|
29
|
+
with open(FILE, "rb") as f:
|
|
30
|
+
msg = email.message_from_binary_file(f, policy=email.policy.default)
|
|
31
|
+
|
|
32
|
+
# ── Headers ──────────────────────────────────────────────────────────────────
|
|
33
|
+
print("## Headers\n")
|
|
34
|
+
important_headers = [
|
|
35
|
+
"From", "To", "Cc", "Bcc", "Reply-To",
|
|
36
|
+
"Subject", "Date", "Message-ID",
|
|
37
|
+
"Content-Type", "MIME-Version",
|
|
38
|
+
"X-Mailer", "User-Agent",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
for header in important_headers:
|
|
42
|
+
val = msg.get(header)
|
|
43
|
+
if val:
|
|
44
|
+
print(f"**{header}:** {val}")
|
|
45
|
+
|
|
46
|
+
# Any additional headers not in the list above
|
|
47
|
+
for key, val in msg.items():
|
|
48
|
+
if key not in important_headers:
|
|
49
|
+
print(f"**{key}:** {val}")
|
|
50
|
+
|
|
51
|
+
print("")
|
|
52
|
+
|
|
53
|
+
# ── Body ─────────────────────────────────────────────────────────────────────
|
|
54
|
+
plain_body = None
|
|
55
|
+
html_body = None
|
|
56
|
+
attachments = []
|
|
57
|
+
|
|
58
|
+
def html_to_text(html_content):
|
|
59
|
+
"""Minimal HTML → plain text strip."""
|
|
60
|
+
text = re.sub(r'<br\s*/?>', '\n', html_content, flags=re.IGNORECASE)
|
|
61
|
+
text = re.sub(r'<p\s*/?>', '\n\n', text, flags=re.IGNORECASE)
|
|
62
|
+
text = re.sub(r'</p>', '', text, flags=re.IGNORECASE)
|
|
63
|
+
text = re.sub(r'<[^>]+>', '', text)
|
|
64
|
+
text = html.unescape(text)
|
|
65
|
+
return text.strip()
|
|
66
|
+
|
|
67
|
+
if msg.is_multipart():
|
|
68
|
+
for part in msg.walk():
|
|
69
|
+
ct = part.get_content_type()
|
|
70
|
+
disp = str(part.get("Content-Disposition") or "")
|
|
71
|
+
|
|
72
|
+
if "attachment" in disp:
|
|
73
|
+
filename = part.get_filename() or "unnamed"
|
|
74
|
+
size = len(part.get_payload(decode=True) or b"")
|
|
75
|
+
attachments.append((filename, ct, size))
|
|
76
|
+
elif ct == "text/plain" and plain_body is None:
|
|
77
|
+
payload = part.get_payload(decode=True)
|
|
78
|
+
if payload:
|
|
79
|
+
plain_body = payload.decode(part.get_content_charset() or "utf-8", errors="replace")
|
|
80
|
+
elif ct == "text/html" and html_body is None:
|
|
81
|
+
payload = part.get_payload(decode=True)
|
|
82
|
+
if payload:
|
|
83
|
+
html_body = payload.decode(part.get_content_charset() or "utf-8", errors="replace")
|
|
84
|
+
else:
|
|
85
|
+
payload = msg.get_payload(decode=True)
|
|
86
|
+
if payload:
|
|
87
|
+
plain_body = payload.decode(msg.get_content_charset() or "utf-8", errors="replace")
|
|
88
|
+
|
|
89
|
+
# Prefer plain text; fall back to HTML converted to text
|
|
90
|
+
print("## Body\n")
|
|
91
|
+
if plain_body:
|
|
92
|
+
print(plain_body)
|
|
93
|
+
elif html_body:
|
|
94
|
+
print("> *Note: No plain-text body. Converted from HTML.*\n")
|
|
95
|
+
print(html_to_text(html_body))
|
|
96
|
+
else:
|
|
97
|
+
print("> No readable body content found.")
|
|
98
|
+
|
|
99
|
+
print("")
|
|
100
|
+
|
|
101
|
+
# ── Attachments ───────────────────────────────────────────────────────────────
|
|
102
|
+
if attachments:
|
|
103
|
+
print("## Attachments\n")
|
|
104
|
+
for name, content_type, size in attachments:
|
|
105
|
+
print(f"- **{name}** ({content_type}, {size} bytes)")
|
|
106
|
+
print("")
|
|
107
|
+
|
|
108
|
+
print("Extraction Status: SUCCESS (python stdlib email)")
|