From acdae521d2fceed7b6739e38704a7f8288a119d2 Mon Sep 17 00:00:00 2001 From: parveen-dotnet Date: Fri, 1 May 2026 05:59:26 +0530 Subject: [PATCH] feat: Add Project Documenter Plugin with agents and skills (#1436) * feat: Add Project Documenter Plugin with agents and skills - Auto-discovers technology stack and project structure - Generates architecture diagrams with draw.io - Creates professional Word (.docx) output with embedded PNG images - Includes agents for orchestration and skills for functionality * chore: moved agents, skills and scripts to respective folders * chore: ran npm run build for readme updates * Update plugins/project-documenter/.github/plugin/plugin.json Co-authored-by: Aaron Powell * fix: readme.agent.md file * fix: added the missing agent file and updated readme for the same --------- Co-authored-by: Aaron Powell --- .github/plugin/marketplace.json | 6 + agents/project-documenter.agent.md | 300 ++++++++++++ docs/README.agents.md | 1 + docs/README.plugins.md | 1 + docs/README.skills.md | 2 + .../.github/plugin/plugin.json | 28 ++ plugins/project-documenter/README.md | 126 +++++ skills/drawio/SKILL.md | 96 ++++ skills/drawio/scripts/drawio-to-png.mjs | 361 ++++++++++++++ skills/drawio/scripts/package.json | 8 + skills/md-to-docx/SKILL.md | 74 +++ skills/md-to-docx/scripts/md-to-docx.mjs | 440 ++++++++++++++++++ skills/md-to-docx/scripts/package.json | 9 + 13 files changed, 1452 insertions(+) create mode 100644 agents/project-documenter.agent.md create mode 100644 plugins/project-documenter/.github/plugin/plugin.json create mode 100644 plugins/project-documenter/README.md create mode 100644 skills/drawio/SKILL.md create mode 100644 skills/drawio/scripts/drawio-to-png.mjs create mode 100644 skills/drawio/scripts/package.json create mode 100644 skills/md-to-docx/SKILL.md create mode 100644 skills/md-to-docx/scripts/md-to-docx.mjs create mode 100644 skills/md-to-docx/scripts/package.json diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json index 3c631ac5..bbf1c166 100644 --- a/.github/plugin/marketplace.json +++ b/.github/plugin/marketplace.json @@ -471,6 +471,12 @@ "description": "Complete toolkit for developing Power Platform custom connectors with Model Context Protocol integration for Microsoft Copilot Studio", "version": "1.0.0" }, + { + "name": "project-documenter", + "source": "project-documenter", + "description": "Generate professional project documentation with draw.io architecture diagrams and Word (.docx) output with embedded images. Automatically discovers any project's technology stack and produces Markdown, diagrams, PNG exports, and a formatted Word document.", + "version": "1.0.0" + }, { "name": "project-planning", "source": "project-planning", diff --git a/agents/project-documenter.agent.md b/agents/project-documenter.agent.md new file mode 100644 index 00000000..46e8b6ec --- /dev/null +++ b/agents/project-documenter.agent.md @@ -0,0 +1,300 @@ +--- +name: "Project Documenter" +description: "Generates professional MS Word project documentation with draw.io architecture diagrams and embedded PNG images. Automatically discovers any project's technology stack, architecture, and code structure. Produces Markdown, draw.io diagrams, PNG exports, and .docx output." +tools: + [ + "execute/runInTerminal", + "read/readFile", + "read/problems", + "read/terminalSelection", + "read/terminalLastCommand", + "edit/createDirectory", + "edit/createFile", + "edit/editFiles", + "search/codebase", + "search/fileSearch", + "search/listDirectory", + "search/textSearch", + "todo", + ] +--- + +# Project Documentation Agent + +You are a **documentation agent** that generates professional, Confluence-ready project summaries for **any software project**. You automatically discover the project's technology stack, architecture, components, data flow, and deployment model by analyzing the codebase — then produce comprehensive documentation with architecture diagrams and a Word document with embedded images. + +You are **project-agnostic**. You do not assume any specific language, framework, or architecture. You discover everything dynamically from the repository. + +Before starting, check for these optional context sources (read them if they exist, skip if they don't): +- `Agents.md` or `AGENTS.md` at the repository root — may contain authoritative service rules and contracts +- `README.md` — project overview and setup instructions +- `ARCHITECTURE.md`, `docs/architecture.md`, or similar — existing architecture documentation +- `.github/copilot-instructions.md` — project-specific AI instructions + +--- + +## Purpose + +This agent **generates comprehensive project documentation** with professional architecture diagrams and Word document output. It does NOT write, modify, or generate any production code. Its output is: + +1. **Markdown document** (`docs/project-summary.md`) — the source document +2. **Draw.io diagrams** (`docs/diagrams/*.drawio`) — editable architecture diagrams +3. **PNG exports** (`docs/diagrams/*.drawio.png`) — rendered diagram images +4. **Word document** (`docs/project-summary.docx`) — professional `.docx` with embedded diagram images + +This agent is a **standalone utility** — invoke it on any repository to produce or refresh project documentation. + +--- + +## Writing Framework + +### Diátaxis Framework + +The generated document combines two Diátaxis quadrants: +- **Reference** (primary) — information-oriented technical description of the project's machinery, contracts, and structure. +- **Explanation** (secondary) — understanding-oriented discussion of *how* and *why* for pipeline, architecture decisions, and extension patterns. + +### Writing Principles + +- **Clarity first**: Use simple words for complex ideas. Define technical terms on first use. +- **Active voice**: "The service processes requests" not "Requests are processed by the service." +- **Progressive disclosure**: Start with the overview, then drill into details (simple → complex). +- **Direct address**: Use "you" when instructing on extension patterns and how-to sections. +- **One idea per paragraph**: Keep paragraphs focused and scannable. +- **Concrete over abstract**: Use specific class names, file paths, and code patterns discovered from the actual codebase. + +### Audience + +- **Primary**: Senior engineers and architects who need to understand the project quickly. +- **Secondary**: Non-technical stakeholders (Executive Summary section only). +- **Tertiary**: New developers onboarding to the codebase. + +### Architecture Documentation (C4 Model) + +Structure documentation and diagrams using C4 Model abstraction levels: + +| Level | Scope | Maps to | +|-------|-------|---------| +| **Context** | System in its environment | Section 2: Architecture Overview | +| **Container** | Internal components and data flow | Section 3: Processing Pipeline | +| **Component** | Class/module-level relationships | Section 4: Core Components | +| **Infrastructure** | Deployment and runtime | Section 6: Infrastructure | + +--- + +## Workflow + +Execute these steps **in order**. Use the todo list to track progress. + +### Step 1: Discover and Analyze Project Context + +Build a complete understanding of the codebase before writing anything. + +#### 1a. Read Context Sources + +Check for and read (if they exist): +1. `Agents.md` or `AGENTS.md` at the repository root +2. `README.md` +3. `.github/copilot-instructions.md` +4. `ARCHITECTURE.md`, `docs/` directory, `CONTRIBUTING.md` + +#### 1b. Detect Technology Stack + +| Signal | What to Look For | +|--------|-----------------| +| **Language** | `.csproj`/`.sln` (.NET), `pom.xml`/`build.gradle` (Java), `package.json` (Node.js), `requirements.txt`/`pyproject.toml` (Python), `go.mod` (Go), `Cargo.toml` (Rust) | +| **Framework** | ASP.NET, Spring Boot, Express, FastAPI, Django, Gin, etc. | +| **Architecture** | Worker service, Web API, CLI, library, microservice, monolith | +| **Messaging** | SQS, RabbitMQ, Kafka, Azure Service Bus | +| **Database** | Entity Framework, Hibernate, Prisma, SQLAlchemy | +| **Cloud** | AWS SDK, Azure SDK, GCP client libraries | +| **Container** | `Dockerfile`, `docker-compose.yml`, Helm charts | +| **CI/CD** | `.github/workflows/`, `.gitlab-ci.yml`, `Jenkinsfile` | +| **Testing** | xUnit, NUnit, JUnit, Jest, pytest | + +#### 1c. Map the Codebase + +1. List the directory structure (up to 3 levels deep) +2. Find entry points (`Program.cs`, `Main.java`, `index.ts`, `main.py`, etc.) +3. Find configuration files (`appsettings.json`, `application.yml`, `.env`, etc.) +4. Discover interfaces/contracts +5. Map implementations (factories, services, handlers) +6. Find models/entities +7. Read the package manifest for dependencies +8. Review Dockerfile (if present) +9. Read the 10-20 most important source files + +#### 1d. Identify Architecture Patterns + +- **Communication**: HTTP API, message queue, event-driven, gRPC, CLI +- **Design patterns**: Factory, Strategy, Repository, Mediator, Pipeline +- **Data flow**: Input → Processing → Output chain +- **Cross-cutting**: Logging, tracing, auth, caching, error handling +- **Extension points**: Where and how to add new features + +### Step 2: Generate Draw.io Diagrams + +Create the `docs/diagrams/` directory. Generate **3-5 professional diagrams** using draw.io XML (`mxGraphModel` format). + +#### Required Diagrams + +**Diagram 1: High-Level Architecture (C4 Context)** +- File: `docs/diagrams/high-level-architecture.drawio` +- Show: the project (highlighted `#dae8fc`), upstream systems, downstream systems, external dependencies, communication channels +- Use: swimlane containers, rounded rectangles, labeled arrows + +**Diagram 2: Processing Pipeline (C4 Container)** +- File: `docs/diagrams/processing-pipeline.drawio` +- Show: entry point → each processing stage → output +- Color progression: input (`#dae8fc` blue) → processing (`#d5e8d4` green) → output (`#fff2cc` orange) +- Use: vertical flow layout (top to bottom) + +**Diagram 3: Component Relationships (C4 Component)** +- File: `docs/diagrams/component-relationships.drawio` +- Show: core interfaces, implementations, factory/strategy patterns, DI relationships +- Group by functional area with distinct colors + +#### Optional Diagrams + +- **Deployment & Infrastructure** — if `Dockerfile` or Kubernetes config found +- **Data Model** — if significant entity/DTO hierarchy found + +#### Draw.io XML Format + +Generate valid `mxGraphModel` XML. Use these style conventions: + +```xml + + + + + + + + + + + +``` + +#### Diagram Export to PNG + +After generating `.drawio` files, export to PNG using the **bundled export script**: + +```bash +# Install dependencies (one-time) +cd skills/drawio && npm install + +# Export all diagrams +node skills/drawio/drawio-to-png.mjs --dir docs/diagrams + +# Or export a single diagram +node skills/drawio/drawio-to-png.mjs docs/diagrams/.drawio +``` + +The script tries (in order): +1. **draw.io CLI** — if draw.io desktop is installed +2. **Headless browser** — uses Edge/Chrome + official draw.io viewer JS + +If neither is available, keep the `.drawio` files and use **Mermaid fallback** — embed Mermaid code blocks in the Markdown instead of PNG references. + +### Step 3: Write Markdown Document + +Create `docs/project-summary.md` with these sections: + +**Front matter:** +```markdown +--- +title: — Project Summary +date: +version: 1.0 +audience: Engineering Team, Architects, Stakeholders +--- +``` + +#### Sections + +1. **Executive Summary** — 3-5 sentences: what, where, how, key capabilities +2. **Architecture Overview** — embed high-level architecture PNG + description +3. **Processing Pipeline** — embed pipeline PNG + step-by-step flow walkthrough +4. **Core Components** — embed component PNG + interface/implementation tables +5. **API Contracts / Message Schemas** — input/output property tables +6. **Infrastructure & Deployment** — Docker, CI/CD, cloud config +7. **Extension Patterns** — step-by-step how-to with file paths +8. **Rules & Anti-Patterns** — do's and don'ts from `Agents.md` or inferred +9. **Dependencies** — categorized package table with versions +10. **Code Structure** — annotated directory tree (2-3 levels deep) + +**Image references** in the Markdown (these get embedded in the Word document): +```markdown +![High-Level Architecture](diagrams/high-level-architecture.drawio.png) +![Processing Pipeline](diagrams/processing-pipeline.drawio.png) +![Component Relationships](diagrams/component-relationships.drawio.png) +``` + +### Step 4: Convert to Word Document + +Use the **bundled md-to-docx converter** to produce a `.docx` with embedded images: + +```bash +# Install dependencies (one-time) +cd skills/md-to-docx && npm install + +# Convert +node skills/md-to-docx/md-to-docx.mjs docs/project-summary.md docs/project-summary.docx +``` + +The converter: +- Extracts YAML front-matter for title page metadata +- Generates a title page and table of contents +- **Embeds PNG images** referenced via `![alt](path)` syntax — diagrams appear inline in the Word document +- Produces professionally formatted `.docx` with Calibri styling, colored headings, and styled tables + +### Step 5: Verify and Report + +#### Quality Checklist + +- [ ] All class/method names match actual source code +- [ ] All file paths exist in the repository +- [ ] Diagrams accurately reflect the real architecture +- [ ] PNG images are generated and embedded in the Word document +- [ ] No credentials, tokens, or secrets in documentation +- [ ] Document is scannable with clear headings and tables + +#### Report Generated Files + +``` +Generated Documentation: +├── docs/project-summary.md # Source document (Markdown) +├── docs/project-summary.docx # Word document with embedded images +└── docs/diagrams/ + ├── high-level-architecture.drawio # C4 Context diagram (editable) + ├── high-level-architecture.drawio.png # Rendered PNG + ├── processing-pipeline.drawio # C4 Container diagram + ├── processing-pipeline.drawio.png + ├── component-relationships.drawio # C4 Component diagram + ├── component-relationships.drawio.png + └── [deployment-infrastructure.drawio] # Optional +``` + +--- + +## Behavioral Rules + +- **Read-only on source code**: NEVER modify any file outside `docs/`. Only create files in `docs/`. +- **Discover, don't assume**: Never hardcode project-specific details. Discover from the repository. +- **Fresh regeneration**: Regenerate all content from scratch each run. +- **No secrets**: Never include credentials, tokens, API keys, or connection strings. +- **Graceful fallbacks**: If draw.io export fails, use Mermaid fallback. If md-to-docx fails, report the error. +- **Verify accuracy**: Spot-check at least 5 file/class references against actual source files. + +--- + +## Error Recovery + +| Problem | Action | +|---------|--------| +| draw.io export fails | Use Mermaid fallback diagrams in Markdown | +| md-to-docx fails | Report error; the `.md` file is still usable | +| Source file not found | Note the gap, continue with available files | +| Unrecognized tech stack | Document what you can observe, note gaps | diff --git a/docs/README.agents.md b/docs/README.agents.md index bf7fb28b..6b37f6ba 100644 --- a/docs/README.agents.md +++ b/docs/README.agents.md @@ -168,6 +168,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-agents) for guidelines on how to | [Power Platform MCP Integration Expert](../agents/power-platform-mcp-integration-expert.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fpower-platform-mcp-integration-expert.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fpower-platform-mcp-integration-expert.agent.md) | Expert in Power Platform custom connector development with MCP integration for Copilot Studio - comprehensive knowledge of schemas, protocols, and integration patterns | | | [Principal software engineer](../agents/principal-software-engineer.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fprincipal-software-engineer.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fprincipal-software-engineer.agent.md) | Provide principal-level software engineering guidance with focus on engineering excellence, technical leadership, and pragmatic implementation. | | | [Project Architecture Planner](../agents/project-architecture-planner.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fproject-architecture-planner.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fproject-architecture-planner.agent.md) | Holistic software architecture planner that evaluates tech stacks, designs scalability roadmaps, performs cloud-agnostic cost analysis, reviews existing codebases, and delivers interactive Mermaid diagrams with HTML preview and draw.io export | | +| [Project Documenter](../agents/project-documenter.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fproject-documenter.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fproject-documenter.agent.md) | Generates professional MS Word project documentation with draw.io architecture diagrams and embedded PNG images. Automatically discovers any project's technology stack, architecture, and code structure. Produces Markdown, draw.io diagrams, PNG exports, and .docx output. | | | [Prompt Builder](../agents/prompt-builder.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fprompt-builder.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fprompt-builder.agent.md) | Expert prompt engineering and validation system for creating high-quality prompts - Brought to you by microsoft/edge-ai | | | [Prompt Engineer](../agents/prompt-engineer.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fprompt-engineer.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fprompt-engineer.agent.md) | A specialized chat mode for analyzing and improving prompts. Every user input is treated as a prompt to be improved. It first provides a detailed analysis of the original prompt within a tag, evaluating it against a systematic framework based on OpenAI's prompt engineering best practices. Following the analysis, it generates a new, improved prompt. | | | [PySpark Expert Agent](../agents/spark-performance.agent.md)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fspark-performance.agent.md)
[![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://aka.ms/awesome-copilot/install/agent?url=vscode-insiders%3Achat-agent%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fagents%2Fspark-performance.agent.md) | Diagnose PySpark performance bottlenecks, distributed execution pitfalls, and suggest Spark-native rewrites and safer distributed patterns (incl. mapInPandas guidance). | | diff --git a/docs/README.plugins.md b/docs/README.plugins.md index 6791cbe6..2353524c 100644 --- a/docs/README.plugins.md +++ b/docs/README.plugins.md @@ -72,6 +72,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-plugins) for guidelines on how t | [power-bi-development](../plugins/power-bi-development/README.md) | Comprehensive Power BI development resources including data modeling, DAX optimization, performance tuning, visualization design, security best practices, and DevOps/ALM guidance for building enterprise-grade Power BI solutions. | 8 items | power-bi, dax, data-modeling, performance, visualization, security, devops, business-intelligence | | [power-platform-architect](../plugins/power-platform-architect/README.md) | Solution Architect for the Microsoft Power Platform, turning business requirements into functioning Power Platform solution architectures. | 1 items | power-platform, power-platform-architect, power-apps, dataverse, power-automate, power-pages, power-bi | | [power-platform-mcp-connector-development](../plugins/power-platform-mcp-connector-development/README.md) | Complete toolkit for developing Power Platform custom connectors with Model Context Protocol integration for Microsoft Copilot Studio | 3 items | power-platform, mcp, copilot-studio, custom-connector, json-rpc | +| [project-documenter](../plugins/project-documenter/README.md) | Generate professional project documentation with draw.io architecture diagrams and Word (.docx) output with embedded images. Automatically discovers any project's technology stack and produces Markdown, diagrams, PNG exports, and a formatted Word document. | 3 items | documentation, architecture-diagrams, drawio, word-document, docx, png-images, c4-model, project-summary, auto-discovery | | [project-planning](../plugins/project-planning/README.md) | Tools and guidance for software project planning, feature breakdown, epic management, implementation planning, and task organization for development teams. | 15 items | planning, project-management, epic, feature, implementation, task, architecture, technical-spike | | [python-mcp-development](../plugins/python-mcp-development/README.md) | Complete toolkit for building Model Context Protocol (MCP) servers in Python using the official SDK with FastMCP. Includes instructions for best practices, a prompt for generating servers, and an expert chat mode for guidance. | 2 items | python, mcp, model-context-protocol, fastmcp, server-development | | [react18-upgrade](../plugins/react18-upgrade/README.md) | Enterprise React 18 migration toolkit with specialized agents and skills for upgrading React 16/17 class-component codebases to React 18.3.1. Includes auditor, dependency surgeon, class component migration specialist, automatic batching fixer, and test guardian. | 13 items | react18, react, migration, upgrade, class-components, lifecycle, batching | diff --git a/docs/README.skills.md b/docs/README.skills.md index 9d68471c..830360ab 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -139,6 +139,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [dotnet-upgrade](../skills/dotnet-upgrade/SKILL.md)
`gh skills install github/awesome-copilot dotnet-upgrade` | Ready-to-use prompts for comprehensive .NET framework upgrade analysis and execution | None | | [doublecheck](../skills/doublecheck/SKILL.md)
`gh skills install github/awesome-copilot doublecheck` | Three-layer verification pipeline for AI output. Extracts verifiable claims, finds supporting or contradicting sources via web search, runs adversarial review for hallucination patterns, and produces a structured verification report with source links for human review. | `assets/verification-report-template.md` | | [draw-io-diagram-generator](../skills/draw-io-diagram-generator/SKILL.md)
`gh skills install github/awesome-copilot draw-io-diagram-generator` | Use when creating, editing, or generating draw.io diagram files (.drawio, .drawio.svg, .drawio.png). Covers mxGraph XML authoring, shape libraries, style strings, flowcharts, system architecture, sequence diagrams, ER diagrams, UML class diagrams, network topology, layout strategy, the hediet.vscode-drawio VS Code extension, and the full agent workflow from request to a ready-to-open file. | `assets/templates`
`references/drawio-xml-schema.md`
`references/shape-libraries.md`
`references/style-reference.md`
`scripts/.gitignore`
`scripts/README.md`
`scripts/add-shape.py`
`scripts/validate-drawio.py` | +| [drawio](../skills/drawio/SKILL.md)
`gh skills install github/awesome-copilot drawio` | Generate draw.io diagrams as .drawio files and export to PNG/SVG/PDF with embedded XML | `scripts/drawio-to-png.mjs`
`scripts/package.json` | | [editorconfig](../skills/editorconfig/SKILL.md)
`gh skills install github/awesome-copilot editorconfig` | Generates a comprehensive and best-practice-oriented .editorconfig file based on project analysis and user preferences. | None | | [ef-core](../skills/ef-core/SKILL.md)
`gh skills install github/awesome-copilot ef-core` | Get best practices for Entity Framework Core | None | | [email-drafter](../skills/email-drafter/SKILL.md)
`gh skills install github/awesome-copilot email-drafter` | Draft and review professional emails that match your personal writing style. Analyzes your sent emails for tone, greeting, structure, and sign-off patterns via WorkIQ, then generates context-aware drafts for any recipient. USE FOR: draft email, write email, compose email, reply email, follow-up email, analyze email tone, email style. | None | @@ -214,6 +215,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [mcp-create-declarative-agent](../skills/mcp-create-declarative-agent/SKILL.md)
`gh skills install github/awesome-copilot mcp-create-declarative-agent` | Skill converted from mcp-create-declarative-agent.prompt.md | None | | [mcp-deploy-manage-agents](../skills/mcp-deploy-manage-agents/SKILL.md)
`gh skills install github/awesome-copilot mcp-deploy-manage-agents` | Skill converted from mcp-deploy-manage-agents.prompt.md | None | | [mcp-security-audit](../skills/mcp-security-audit/SKILL.md)
`gh skills install github/awesome-copilot mcp-security-audit` | Audit MCP (Model Context Protocol) server configurations for security issues. Use this skill when:
- Reviewing .mcp.json files for security risks
- Checking MCP server args for hardcoded secrets or shell injection patterns
- Validating that MCP servers use pinned versions (not @latest)
- Detecting unpinned dependencies in MCP server configurations
- Auditing which MCP servers a project registers and whether they're on an approved list
- Checking for environment variable usage vs. hardcoded credentials in MCP configs
- Any request like "is my MCP config secure?", "audit my MCP servers", or "check .mcp.json"
keywords: [mcp, security, audit, secrets, shell-injection, supply-chain, governance] | None | +| [md-to-docx](../skills/md-to-docx/SKILL.md)
`gh skills install github/awesome-copilot md-to-docx` | Convert Markdown files to professionally formatted Word (.docx) documents with embedded PNG images — pure JavaScript, no external tools required | `scripts/md-to-docx.mjs`
`scripts/package.json` | | [meeting-minutes](../skills/meeting-minutes/SKILL.md)
`gh skills install github/awesome-copilot meeting-minutes` | Generate concise, actionable meeting minutes for internal meetings. Includes metadata, attendees, agenda, decisions, action items (owner + due date), and follow-up steps. | None | | [memory-merger](../skills/memory-merger/SKILL.md)
`gh skills install github/awesome-copilot memory-merger` | Merges mature lessons from a domain memory file into its instruction file. Syntax: `/memory-merger >domain [scope]` where scope is `global` (default), `user`, `workspace`, or `ws`. | None | | [mentoring-juniors](../skills/mentoring-juniors/SKILL.md)
`gh skills install github/awesome-copilot mentoring-juniors` | Socratic mentoring for junior developers and AI newcomers. Guides through questions, never answers. Triggers: "help me understand", "explain this code", "I'm stuck", "Im stuck", "I'm confused", "Im confused", "I don't understand", "I dont understand", "can you teach me", "teach me", "mentor me", "guide me", "what does this error mean", "why doesn't this work", "why does not this work", "I'm a beginner", "Im a beginner", "I'm learning", "Im learning", "I'm new to this", "Im new to this", "walk me through", "how does this work", "what's wrong with my code", "what's wrong", "can you break this down", "ELI5", "step by step", "where do I start", "what am I missing", "newbie here", "junior dev", "first time using", "how do I", "what is", "is this right", "not sure", "need help", "struggling", "show me", "help me debug", "best practice", "too complex", "overwhelmed", "lost", "debug this", "/socratic", "/hint", "/concept", "/pseudocode". Progressive clue systems, teaching techniques, and success metrics. | None | diff --git a/plugins/project-documenter/.github/plugin/plugin.json b/plugins/project-documenter/.github/plugin/plugin.json new file mode 100644 index 00000000..f1b48957 --- /dev/null +++ b/plugins/project-documenter/.github/plugin/plugin.json @@ -0,0 +1,28 @@ +{ + "name": "project-documenter", + "description": "Generate professional project documentation with draw.io architecture diagrams and Word (.docx) output with embedded images. Automatically discovers any project's technology stack and produces Markdown, diagrams, PNG exports, and a formatted Word document.", + "version": "1.0.0", + "author": { + "name": "Awesome Copilot Community" + }, + "repository": "https://github.com/github/awesome-copilot", + "license": "MIT", + "keywords": [ + "documentation", + "architecture-diagrams", + "drawio", + "word-document", + "docx", + "png-images", + "c4-model", + "project-summary", + "auto-discovery" + ], + "agents": [ + "./agents/project-documenter.md" + ], + "skills": [ + "./skills/drawio/", + "./skills/md-to-docx/" + ] +} diff --git a/plugins/project-documenter/README.md b/plugins/project-documenter/README.md new file mode 100644 index 00000000..a668cf73 --- /dev/null +++ b/plugins/project-documenter/README.md @@ -0,0 +1,126 @@ +# Project Documenter Plugin + +Generate professional project documentation with draw.io architecture diagrams and Word (.docx) output with embedded PNG images. Works on any software project — automatically discovers the technology stack, architecture, and code structure. + +## Installation + +```bash +# Using Copilot CLI +copilot plugin install project-documenter@awesome-copilot +``` + +## What It Does + +Point the **Project Documenter** agent at any repository and it produces: + +1. **Markdown document** — 10-section project summary with embedded diagram references +2. **Draw.io diagrams** — C4 Context, Pipeline, and Component relationship diagrams (`.drawio` + `.drawio.png`) +3. **Word document** — professionally formatted `.docx` with title page, table of contents, and embedded PNG architecture images + +## What's Included + +### Agent + +| Agent | Description | +|-------|-------------| +| `project-documenter` | Generates professional project documentation with draw.io architecture diagrams and Word document output with embedded images. Auto-discovers any project's technology stack and architecture. | + +### Skills + +| Skill | Description | +|-------|-------------| +| `drawio` | Generate draw.io diagrams as `.drawio` files and export to PNG via bundled Node.js script (uses draw.io CLI or headless browser) | +| `md-to-docx` | Convert Markdown to Word (`.docx`) with embedded PNG images — pure JavaScript, no Pandoc required | + +## How It Works + +### Step 1: Discover + +The agent scans your repository to understand: +- Technology stack (`.csproj`, `package.json`, `pom.xml`, `go.mod`, etc.) +- Architecture pattern (API, worker service, CLI, library) +- Design patterns (factory, strategy, repository, pipeline) +- Interfaces, implementations, models, configuration +- Dependencies, Docker setup, CI/CD + +### Step 2: Generate Diagrams + +Creates 3-5 professional draw.io diagrams following the C4 Model: + +| Diagram | C4 Level | Shows | +|---------|----------|-------| +| High-Level Architecture | Context | System in its environment — upstream, downstream, external deps | +| Processing Pipeline | Container | Internal data flow — entry point → stages → output | +| Component Relationships | Component | Interfaces, implementations, factories, DI graph | +| Deployment (optional) | Infrastructure | Docker, Kubernetes, scaling, cloud services | +| Data Model (optional) | Component | Entity/DTO hierarchy (if significant) | + +Each diagram is exported to PNG using the bundled `drawio-to-png.mjs` script. + +### Step 3: Write Markdown + +Produces `docs/project-summary.md` with 10 sections: + +1. Executive Summary +2. Architecture Overview (with embedded diagram) +3. Processing Pipeline (with embedded diagram) +4. Core Components (with embedded diagram) +5. API Contracts / Message Schemas +6. Infrastructure & Deployment +7. Extension Patterns +8. Rules & Anti-Patterns +9. Dependencies +10. Code Structure + +### Step 4: Word Document + +Converts the Markdown to a formatted `.docx` using the bundled `md-to-docx.mjs` script: + +- Title page with project name, date, version, audience +- Auto-generated table of contents +- **PNG diagram images embedded inline** in the Word document +- Calibri font, colored headings, styled tables with alternating rows +- Code blocks in Consolas with shaded background + +### Step 5: Verify + +Spot-checks class names, file paths, and diagram accuracy against the actual codebase. Reports all generated files. + +## Generated Output + +``` +docs/ +├── project-summary.md # Source document (Markdown) +├── project-summary.docx # Word document with embedded images +└── diagrams/ + ├── high-level-architecture.drawio # C4 Context diagram (editable) + ├── high-level-architecture.drawio.png # Rendered PNG + ├── processing-pipeline.drawio # C4 Container diagram + ├── processing-pipeline.drawio.png + ├── component-relationships.drawio # C4 Component diagram + └── component-relationships.drawio.png +``` + +## Prerequisites + +| Requirement | Purpose | Required? | +|-------------|---------|-----------| +| Node.js 18+ | Run bundled export scripts | Yes | +| Edge or Chrome | Headless browser for diagram rendering | One of: this OR draw.io desktop | +| draw.io desktop | CLI diagram export (faster alternative) | Optional (browser fallback available) | + +## Technology Agnostic + +Works with any stack. The agent auto-detects: +- **.NET** (`.csproj`, `.sln`), **Java** (`pom.xml`, `build.gradle`), **Node.js** (`package.json`), **Python** (`pyproject.toml`), **Go** (`go.mod`), **Rust** (`Cargo.toml`) +- Docker, Kubernetes, GitHub Actions, GitLab CI +- Any messaging system (SQS, RabbitMQ, Kafka, Azure Service Bus) +- Any database ORM (EF, Hibernate, Prisma, SQLAlchemy) + +## Source + +This plugin is part of [Awesome Copilot](https://github.com/github/awesome-copilot), a community-driven collection of GitHub Copilot extensions. + +## License + +MIT diff --git a/skills/drawio/SKILL.md b/skills/drawio/SKILL.md new file mode 100644 index 00000000..d3fe012a --- /dev/null +++ b/skills/drawio/SKILL.md @@ -0,0 +1,96 @@ +--- +name: drawio +description: Generate draw.io diagrams as .drawio files and export to PNG/SVG/PDF with embedded XML +--- + +# Draw.io Diagram Skill + +Generate draw.io diagrams as native `.drawio` files and export them to PNG images that can be embedded in Word documents. + +## How to Create a Diagram + +1. **Generate draw.io XML** in `mxGraphModel` format for the requested diagram +2. **Write the XML** to a `.drawio` file using the create/edit file tool +3. **Export to PNG** using the bundled export script + +## Bundled Export Script + +This skill includes `drawio-to-png.mjs`, a Node.js export script with two rendering backends: + +1. **draw.io CLI** (pixel-perfect, fastest) — used automatically if draw.io desktop is installed +2. **Official draw.io viewer in headless browser** (pixel-perfect, needs Chromium/Edge) — fallback when CLI is unavailable + +### Usage + +```bash +# Install dependencies (one-time, from the scripts folder) +cd skills/drawio/scripts && npm install + +# Export a single diagram +node skills/drawio/scripts/drawio-to-png.mjs [output.png] + +# Export all .drawio files in a directory +node skills/drawio/scripts/drawio-to-png.mjs --dir + +# Force a specific renderer +node skills/drawio/scripts/drawio-to-png.mjs --renderer=cli|viewer|auto +``` + +### Skill Folder Contents + +| File | Purpose | +|------|---------| +| `SKILL.md` | This instruction file | +| `scripts/drawio-to-png.mjs` | Node.js export script (CLI + browser fallback) | +| `scripts/package.json` | Dependencies (`puppeteer-core`) | + +## Supported Export Formats + +| Format | Embed XML | Notes | +|--------|-----------|-------| +| `png` | Yes | Viewable everywhere, editable in draw.io | +| `svg` | Yes | Scalable, editable in draw.io | +| `pdf` | Yes | Printable, editable in draw.io | + +## Draw.io XML Style Conventions + +Use these styles for consistent, professional diagrams: + +```xml + + + + + + + + + + + + + + + + + + + + +``` + +## Locating the draw.io CLI + +Try `drawio` first (works if on PATH), then fall back: + +- **Windows**: `"C:\Program Files\draw.io\draw.io.exe"` +- **macOS**: `/Applications/draw.io.app/Contents/MacOS/draw.io` +- **Linux**: `drawio` (via snap/apt/flatpak) + +### CLI Export Command + +```bash +drawio -x -f png -e -b 10 -o +``` + +Flags: `-x` (export), `-f` (format), `-e` (embed diagram XML), `-b` (border), `-o` (output path). diff --git a/skills/drawio/scripts/drawio-to-png.mjs b/skills/drawio/scripts/drawio-to-png.mjs new file mode 100644 index 00000000..a4a91280 --- /dev/null +++ b/skills/drawio/scripts/drawio-to-png.mjs @@ -0,0 +1,361 @@ +/** + * drawio-to-png.mjs - Convert .drawio files to PNG with accurate rendering. + * + * Rendering priority: + * 1. draw.io CLI (if installed) — pixel-perfect, fastest + * 2. Official draw.io viewer JS in headless browser — pixel-perfect, needs network + * + * Usage: node drawio-to-png.mjs [output.png] + * node drawio-to-png.mjs --dir (converts all .drawio files in directory) + * node drawio-to-png.mjs --renderer=cli|viewer|auto [output.png] + */ + +import { readFileSync, writeFileSync, readdirSync, statSync } from "fs"; +import { join, basename, dirname, resolve } from "path"; +import { spawnSync } from "child_process"; +import { inflateRawSync } from "zlib"; +import puppeteer from "puppeteer-core"; + +// --- Build HTML that uses the official draw.io viewer for rendering --- +function buildViewerHtml(rawFileContent) { + // Escape for embedding in a JS template literal + const escaped = rawFileContent + .replace(/\\/g, "\\\\") + .replace(/`/g, "\\`") + .replace(/\$/g, "\\$"); + + // The official draw.io viewer (viewer-static.min.js) contains the full mxGraph + // rendering engine — it handles orthogonal edge routing, all shape types, + // container layouts, and compressed/uncompressed diagram formats. + return ` + + + + + + +
+ + +`; +} + +// --- Extract mxGraph XML from .drawio input (supports mxGraphModel and mxfile) --- +function extractMxGraphModelXml(inputXml) { + const trimmed = inputXml.trim(); + + if (trimmed.startsWith("]*>([\s\S]*?)<\/diagram>/i); + if (!diagramMatch) { + throw new Error("Unsupported .drawio format: missing or content"); + } + + const diagramContent = diagramMatch[1].trim(); + + if (diagramContent.startsWith(" content: ${err.message}`); + } +} + +function resolveRenderer(rawArgs) { + let renderer = "auto"; + const args = []; + + for (const arg of rawArgs) { + if (arg.startsWith("--renderer=")) { + renderer = arg.substring("--renderer=".length).trim().toLowerCase(); + continue; + } + args.push(arg); + } + + if (!["auto", "cli", "viewer"].includes(renderer)) { + throw new Error(`Invalid renderer '${renderer}'. Use auto, cli, or viewer.`); + } + + return { renderer, args }; +} + +function findDrawioCliPath() { + const envPath = process.env.DRAWIO_PATH; + if (envPath) { + try { + if (statSync(envPath).isFile()) return envPath; + } catch { /* ignore */ } + } + + const candidates = [ + "C:\\Program Files\\draw.io\\draw.io.exe", + "C:\\Program Files (x86)\\draw.io\\draw.io.exe", + "/Applications/draw.io.app/Contents/MacOS/draw.io", + "/usr/bin/drawio", + "/usr/local/bin/drawio", + ]; + + for (const p of candidates) { + try { + if (statSync(p).isFile()) return p; + } catch { /* ignore */ } + } + + const locator = process.platform === "win32" ? "where" : "which"; + const names = process.platform === "win32" ? ["drawio", "draw.io"] : ["drawio"]; + + for (const name of names) { + const probe = spawnSync(locator, [name], { encoding: "utf-8" }); + if (probe.status === 0 && probe.stdout) { + const first = probe.stdout.split(/\r?\n/).map(line => line.trim()).find(Boolean); + if (first) return first; + } + } + + return null; +} + +function exportWithDrawioCli(drawioPath, input, output) { + const args = ["-x", "-f", "png", "-e", "-b", "10", "-o", output, input]; + const result = spawnSync(drawioPath, args, { encoding: "utf-8" }); + if (result.status !== 0) { + const stderr = (result.stderr || "").trim(); + const stdout = (result.stdout || "").trim(); + throw new Error(stderr || stdout || `draw.io CLI failed with exit code ${result.status}`); + } +} + +// --- Main --- +async function main() { + const parsed = resolveRenderer(process.argv.slice(2)); + const renderer = parsed.renderer; + const args = parsed.args; + + let files = []; + if (args[0] === "--dir") { + const dir = resolve(args[1] || "."); + files = readdirSync(dir) + .filter(f => f.endsWith(".drawio")) + .map(f => ({ + input: join(dir, f), + output: join(dir, f.replace(/\.drawio$/, ".drawio.png")) + })); + } else if (args[0]) { + const input = resolve(args[0]); + const output = args[1] || input.replace(/\.drawio$/, ".drawio.png"); + files = [{ input, output }]; + } else { + console.error("Usage: node drawio-to-png.mjs [output.png]"); + console.error(" node drawio-to-png.mjs --dir "); + console.error(" node drawio-to-png.mjs --renderer=cli|auto|custom [output.png]"); + process.exit(1); + } + + if (files.length === 0) { + console.log("No .drawio files found."); + return; + } + + const drawioCliPath = findDrawioCliPath(); + + // --- Path 1: draw.io CLI (best fidelity, no network needed) --- + if (renderer === "cli" || (renderer === "auto" && drawioCliPath)) { + if (!drawioCliPath) { + console.error("draw.io CLI not found. Install draw.io desktop or set DRAWIO_PATH."); + process.exit(1); + } + console.log(`Using renderer: draw.io CLI (${basename(drawioCliPath)})`); + for (const { input, output } of files) { + console.log(`Rendering: ${basename(input)}`); + try { + exportWithDrawioCli(drawioCliPath, input, output); + let kb = "?"; + try { + kb = (statSync(output).size / 1024).toFixed(0); + } catch { /* ignore size read errors */ } + console.log(` -> ${basename(output)} (${kb} KB)`); + } catch (err) { + console.error(` Error rendering ${basename(input)}: ${err.message}`); + } + } + console.log("Done."); + return; + } + + // --- Path 2: Official draw.io viewer in headless browser --- + // Find browser + const browserPaths = [ + process.env.CHROME_PATH, + process.env.EDGE_PATH, + "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", + "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe", + "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", + "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", + "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", + "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge", + "/usr/bin/google-chrome", + "/usr/bin/chromium-browser", + "/usr/bin/microsoft-edge", + ].filter(Boolean); + + let execPath; + for (const p of browserPaths) { + try { + if (statSync(p).isFile()) { execPath = p; break; } + } catch { /* not found */ } + } + + if (!execPath) { + console.error("No browser found. Set CHROME_PATH or EDGE_PATH environment variable."); + process.exit(1); + } + + console.log(`Using renderer: draw.io viewer (${basename(execPath)})`); + + const browser = await puppeteer.launch({ + executablePath: execPath, + headless: true, + args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-gpu"], + }); + + for (const { input, output } of files) { + console.log(`Rendering: ${basename(input)}`); + try { + const rawContent = readFileSync(input, "utf-8"); + const html = buildViewerHtml(rawContent); + + const page = await browser.newPage(); + await page.setViewport({ width: 2400, height: 1600, deviceScaleFactor: 2 }); + + // Set HTML content first (sets up the .mxgraph div with diagram XML) + await page.setContent(html, { waitUntil: "domcontentloaded" }); + + // Load the official draw.io viewer JS via addScriptTag (more reliable than inline src) + const VIEWER_URL = "https://viewer.diagrams.net/js/viewer-static.min.js"; + try { + await page.addScriptTag({ url: VIEWER_URL }); + } catch (scriptErr) { + throw new Error(`Failed to load draw.io viewer JS: ${scriptErr.message}`); + } + + // Start polling for the rendered diagram + await page.evaluate(() => window.__startPoll()); + + // Wait for the viewer to finish rendering + await page.waitForFunction(() => window.__renderComplete === true, { timeout: 30000 }); + + // Check rendering succeeded + const viewerOk = await page.evaluate(() => window.__renderWidth > 0); + if (!viewerOk) { + throw new Error("draw.io viewer failed to load or render (check network access)"); + } + + // Take element screenshot of just the diagram div for exact bounds + const containerHandle = await page.$('.mxgraph'); + let pngBuffer; + + if (containerHandle) { + pngBuffer = await containerHandle.screenshot({ type: "png" }); + } else { + // Fallback: full-page screenshot + const dims = await page.evaluate(() => ({ + w: Math.ceil(window.__renderWidth), + h: Math.ceil(window.__renderHeight) + })); + pngBuffer = await page.screenshot({ + type: "png", + clip: { x: 0, y: 0, width: dims.w + 20, height: dims.h + 20 }, + }); + } + + writeFileSync(output, pngBuffer); + console.log(` -> ${basename(output)} (${(pngBuffer.length / 1024).toFixed(0)} KB)`); + + await page.close(); + } catch (err) { + console.error(` Error rendering ${basename(input)}: ${err.message}`); + } + } + + await browser.close(); + console.log("Done."); +} + +main().catch(err => { console.error(err); process.exit(1); }); diff --git a/skills/drawio/scripts/package.json b/skills/drawio/scripts/package.json new file mode 100644 index 00000000..f3468fbf --- /dev/null +++ b/skills/drawio/scripts/package.json @@ -0,0 +1,8 @@ +{ + "private": true, + "type": "module", + "description": "Dependencies for the draw.io diagram export skill", + "dependencies": { + "puppeteer-core": "^24.39.1" + } +} diff --git a/skills/md-to-docx/SKILL.md b/skills/md-to-docx/SKILL.md new file mode 100644 index 00000000..59e9a142 --- /dev/null +++ b/skills/md-to-docx/SKILL.md @@ -0,0 +1,74 @@ +--- +name: md-to-docx +description: Convert Markdown files to professionally formatted Word (.docx) documents with embedded PNG images — pure JavaScript, no external tools required +--- + +# Markdown to Word (.docx) Skill + +Convert Markdown (`.md`) files into professionally formatted Word (`.docx`) documents with embedded PNG images. Uses **pure JavaScript** via the `docx` and `marked` npm packages — no Pandoc, LibreOffice, or any native binary required. + +## How to Convert + +```bash +# Install dependencies (one-time, from the scripts folder) +cd skills/md-to-docx/scripts && npm install + +# Convert (run from workspace root) +node skills/md-to-docx/scripts/md-to-docx.mjs [output.docx] +``` + +If `output.docx` is omitted, it defaults to `.docx` in the current directory. + +## Skill Folder Contents + +| File | Purpose | +|------|---------| +| `SKILL.md` | This instruction file | +| `scripts/md-to-docx.mjs` | Node.js Markdown-to-Word converter | +| `scripts/package.json` | Dependencies (`docx`, `marked`) | + +## Prerequisites + +| Requirement | Version | Notes | +|-------------|---------|-------| +| **Node.js** | 18+ | Required runtime | +| **`docx`** | 9+ | Pure JS Word document generator | +| **`marked`** | 15+ | Markdown parser | + +No native binaries. No system-level installs. Works on Windows, macOS, and Linux. + +## Features + +The converter: + +- **Extracts YAML front-matter** — uses `title`, `date`, `version`, `audience` for the title page +- **Generates a title page** — with project name, subtitle, date, version, and audience +- **Generates a table of contents** — built from H1-H3 headings +- **Embeds PNG images** — resolves `![alt](path)` references relative to the input `.md` file, reads the PNG, and embeds it inline in the Word document +- **Styled output** — Calibri font, colored headings (`#1F3864`), styled tables with alternating row colors, code blocks in Consolas +- **Handles all Markdown elements** — headings, paragraphs, tables, code blocks, lists, images, links, horizontal rules + +## Image Embedding + +The converter automatically embeds PNG images referenced in the Markdown: + +```markdown +![High-Level Architecture](diagrams/high-level-architecture.drawio.png) +``` + +The image path is resolved **relative to the input Markdown file**. The PNG is read, dimensions are extracted from the PNG header, and the image is scaled to fit within 6 inches width while preserving aspect ratio. + +If an image file is not found, a placeholder `[Image not found: ]` is inserted. + +## Front-Matter Format + +```yaml +--- +title: Project Name — Project Summary +date: 2025-01-15 +version: 1.0 +audience: Engineering Team, Architects, Stakeholders +--- +``` + +The title is split on `—` or `–` into main title and subtitle for the title page. diff --git a/skills/md-to-docx/scripts/md-to-docx.mjs b/skills/md-to-docx/scripts/md-to-docx.mjs new file mode 100644 index 00000000..c0b2ea7f --- /dev/null +++ b/skills/md-to-docx/scripts/md-to-docx.mjs @@ -0,0 +1,440 @@ +/** + * md-to-docx.mjs - Markdown to Word converter + * Pure JavaScript, no external tools required. + * Usage: node md-to-docx.mjs [output.docx] + */ + +import { readFileSync, writeFileSync, existsSync } from "fs"; +import { dirname, join, resolve } from "path"; +import { marked } from "marked"; +import { + Document, Packer, Paragraph, TextRun, HeadingLevel, ImageRun, + TableRow, TableCell, Table, WidthType, BorderStyle, + AlignmentType, ShadingType, PageBreak +} from "docx"; + +// --- Image dimensions from PNG header --- +function pngDimensions(buffer) { + // PNG signature check + IHDR chunk at offset 16 (width) and 20 (height) + if (buffer[0] === 0x89 && buffer[1] === 0x50) { + return { + width: buffer.readUInt32BE(16), + height: buffer.readUInt32BE(20), + }; + } + return { width: 600, height: 400 }; // fallback +} + +// --- CLI argument parsing --- +const inputPath = process.argv[2]; +if (!inputPath) { + console.error("Usage: node md-to-docx.mjs [output.docx]"); + process.exit(1); +} +const outputPath = process.argv[3] || inputPath.replace(/\.md$/i, ".docx"); +const inputDir = dirname(resolve(inputPath)); + +const mdSource = readFileSync(inputPath, "utf-8"); + +// --- Extract YAML front-matter metadata --- +let title = "Document"; +let subtitle = ""; +let date = new Date().toISOString().slice(0, 10); +let version = "1.0"; +let audience = ""; + +const fmMatch = mdSource.match(/^---\n([\s\S]*?)\n---/m); +if (fmMatch) { + const fm = fmMatch[1]; + title = fm.match(/^title:\s*(.+)$/m)?.[1]?.trim().replace(/^["']|["']$/g, "") || title; + date = fm.match(/^date:\s*(.+)$/m)?.[1]?.trim() || date; + version = fm.match(/^version:\s*(.+)$/m)?.[1]?.trim() || version; + audience = fm.match(/^audience:\s*(.+)$/m)?.[1]?.trim() || ""; +} + +// Strip front-matter from markdown content +const md = mdSource.replace(/^---[\s\S]*?---\n*/m, ""); + +// Derive title / subtitle from front-matter title or first H1 +const titleParts = title.split(/\s*[—–]\s*/); +const mainTitle = titleParts[0] || title; +subtitle = titleParts[1] || ""; +if (!subtitle) { + const h1Match = md.match(/^#\s+(.+)$/m); + if (h1Match) { + const h1Parts = h1Match[1].split(/\s*[—–]\s*/); + if (h1Parts.length > 1) { + subtitle = h1Parts[1]; + if (!mainTitle || mainTitle === "Document") title = h1Parts[0]; + } + } +} + +// --- Parse Markdown tokens --- +const tokens = marked.lexer(md); + +// --- Style constants --- +const FONT = "Calibri"; +const HEADER_COLOR = "1F3864"; +const ACCENT_COLOR = "2E75B6"; +const TABLE_HEADER_BG = "D6E4F0"; +const TABLE_ALT_BG = "F2F7FB"; +const CODE_BG = "F5F5F5"; +const CODE_FONT = "Consolas"; +const BORDER_COLOR = "B4C6E7"; + +const tableBorder = { style: BorderStyle.SINGLE, size: 1, color: BORDER_COLOR }; +const tableBorders = { + top: tableBorder, bottom: tableBorder, + left: tableBorder, right: tableBorder, + insideHorizontal: tableBorder, insideVertical: tableBorder, +}; + +// --- Utility: decode HTML entities --- +function decodeEntities(str) { + return str + .replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") + .replace(/"/g, '"').replace(/'/g, "'"); +} + +// --- Inline tokens to TextRun[] --- +function inlineToRuns(inlineTokens, parentBold = false, parentItalic = false) { + const runs = []; + if (!inlineTokens) return runs; + for (const t of inlineTokens) { + switch (t.type) { + case "text": + runs.push(new TextRun({ + text: decodeEntities(t.text || t.raw || ""), + bold: parentBold, italics: parentItalic, font: FONT, size: 22, + })); + break; + case "strong": + runs.push(...inlineToRuns(t.tokens, true, parentItalic)); + break; + case "em": + runs.push(...inlineToRuns(t.tokens, parentBold, true)); + break; + case "codespan": + runs.push(new TextRun({ + text: t.text, font: CODE_FONT, size: 20, bold: parentBold, + shading: { type: ShadingType.SOLID, color: CODE_BG, fill: CODE_BG }, + })); + break; + case "link": + runs.push(new TextRun({ + text: t.text || t.href, bold: parentBold, italics: parentItalic, + font: FONT, size: 22, color: ACCENT_COLOR, underline: {}, + })); + break; + case "image": + // Images handled at paragraph level; skip inline + break; + case "br": + runs.push(new TextRun({ break: 1, font: FONT })); + break; + default: + if (t.raw) { + runs.push(new TextRun({ + text: decodeEntities(t.raw), bold: parentBold, italics: parentItalic, + font: FONT, size: 22, + })); + } + break; + } + } + return runs; +} + +// --- Paragraph inline runs --- +function paragraphRuns(token) { + if (token.tokens) return inlineToRuns(token.tokens); + return [new TextRun({ text: token.text || token.raw || "", font: FONT, size: 22 })]; +} + +// --- Table builder --- +function buildTable(token) { + const rows = []; + if (token.header) { + rows.push(new TableRow({ + tableHeader: true, + children: token.header.map(cell => new TableCell({ + shading: { type: ShadingType.SOLID, color: TABLE_HEADER_BG, fill: TABLE_HEADER_BG }, + children: [new Paragraph({ + children: inlineToRuns(cell.tokens, true), + spacing: { before: 40, after: 40 }, + })], + })), + })); + } + if (token.rows) { + token.rows.forEach((row, idx) => { + rows.push(new TableRow({ + children: row.map(cell => new TableCell({ + shading: idx % 2 === 1 + ? { type: ShadingType.SOLID, color: TABLE_ALT_BG, fill: TABLE_ALT_BG } + : undefined, + children: [new Paragraph({ + children: inlineToRuns(cell.tokens), + spacing: { before: 30, after: 30 }, + })], + })), + })); + }); + } + return new Table({ + rows, width: { size: 100, type: WidthType.PERCENTAGE }, borders: tableBorders, + }); +} + +// --- Code block builder --- +function buildCodeBlock(token) { + const lines = (token.text || "").split("\n"); + return lines.map(line => new Paragraph({ + children: [new TextRun({ text: line || " ", font: CODE_FONT, size: 18 })], + spacing: { before: 20, after: 20 }, + shading: { type: ShadingType.SOLID, color: CODE_BG, fill: CODE_BG }, + indent: { left: 360 }, + })); +} + +// --- List builder --- +function buildList(token, level = 0) { + const items = []; + for (const item of token.items) { + const textTokens = item.tokens?.find(t => t.type === "text"); + const bullet = token.ordered ? `${item.raw?.match(/^\d+/)?.[0] || "1"}.` : "\u2022"; + const indent = 720 + level * 360; + items.push(new Paragraph({ + children: [ + new TextRun({ text: `${bullet} `, font: FONT, size: 22 }), + ...(textTokens ? inlineToRuns(textTokens.tokens) : [new TextRun({ + text: decodeEntities(item.text || ""), font: FONT, size: 22, + })]), + ], + spacing: { before: 40, after: 40 }, + indent: { left: indent }, + })); + const nestedList = item.tokens?.find(t => t.type === "list"); + if (nestedList) items.push(...buildList(nestedList, level + 1)); + } + return items; +} + +// --- Build document children --- +const children = []; + +// Title page (from front-matter metadata) +children.push( + new Paragraph({ spacing: { before: 2400 } }), + new Paragraph({ + children: [new TextRun({ text: mainTitle, font: FONT, size: 56, bold: true, color: HEADER_COLOR })], + alignment: AlignmentType.CENTER, + }), +); +if (subtitle) { + children.push(new Paragraph({ + children: [new TextRun({ text: subtitle, font: FONT, size: 36, color: ACCENT_COLOR })], + alignment: AlignmentType.CENTER, spacing: { after: 400 }, + })); +} +children.push( + new Paragraph({ + children: [new TextRun({ + text: `Date: ${date} | Version: ${version}`, + font: FONT, size: 22, color: "666666", + })], + alignment: AlignmentType.CENTER, + }), +); +if (audience) { + children.push(new Paragraph({ + children: [new TextRun({ text: `Audience: ${audience}`, font: FONT, size: 22, color: "666666" })], + alignment: AlignmentType.CENTER, spacing: { after: 600 }, + })); +} +children.push(new Paragraph({ children: [new PageBreak()] })); + +// Table of Contents (static, built from headings found in the markdown) +children.push( + new Paragraph({ + children: [new TextRun({ text: "Table of Contents", font: FONT, size: 32, bold: true, color: HEADER_COLOR })], + spacing: { before: 200, after: 400 }, + }), +); + +// Pre-scan tokens for headings to build the TOC +for (const tok of tokens) { + if (tok.type !== "heading" || tok.depth > 3) continue; + // Skip the first H1 title and the TOC heading itself + if (tok.depth === 1 && mainTitle !== "Document" && + decodeEntities(tok.text || "").includes(mainTitle)) continue; + if (tok.text === "Table of Contents") continue; + + const indent = (tok.depth - 1) * 360; + const tocSize = tok.depth === 1 ? 24 : tok.depth === 2 ? 22 : 20; + const tocBold = tok.depth <= 2; + const tocColor = tok.depth <= 2 ? HEADER_COLOR : ACCENT_COLOR; + + children.push(new Paragraph({ + children: [new TextRun({ + text: decodeEntities(tok.text), + font: FONT, size: tocSize, bold: tocBold, color: tocColor, + })], + spacing: { before: tok.depth === 2 ? 80 : 40, after: 40 }, + indent: { left: indent }, + })); +} + +children.push(new Paragraph({ children: [new PageBreak()] })); + +// --- Token walker --- +let skipToc = false; + +for (const token of tokens) { + switch (token.type) { + case "heading": { + // Skip first H1 if it matches the front-matter title (already on title page) + if (token.depth === 1 && mainTitle !== "Document" && + decodeEntities(token.text || "").includes(mainTitle)) { + continue; + } + // Skip markdown TOC section + if (token.text === "Table of Contents") { skipToc = true; continue; } + if (skipToc && token.depth > 2) continue; + skipToc = false; + + const headingMap = { + 1: HeadingLevel.HEADING_1, 2: HeadingLevel.HEADING_2, + 3: HeadingLevel.HEADING_3, 4: HeadingLevel.HEADING_4, + }; + children.push(new Paragraph({ + heading: headingMap[token.depth] || HeadingLevel.HEADING_4, + children: [new TextRun({ + text: decodeEntities(token.text), + font: FONT, bold: true, + color: token.depth <= 2 ? HEADER_COLOR : ACCENT_COLOR, + size: token.depth === 2 ? 32 : token.depth === 3 ? 26 : 24, + })], + spacing: { before: token.depth === 2 ? 360 : 240, after: 120 }, + })); + break; + } + case "paragraph": { + if (skipToc) continue; + // Check if the paragraph is a standalone image + const imgToken = token.tokens && token.tokens.length === 1 && token.tokens[0].type === "image" + ? token.tokens[0] : null; + if (imgToken) { + const href = imgToken.href || ""; + const imgPath = resolve(inputDir, href); + if (existsSync(imgPath)) { + const imgBuf = readFileSync(imgPath); + const dims = pngDimensions(imgBuf); + const maxW = 580; // max width in points (~6 inches) + const scale = dims.width > maxW ? maxW / dims.width : 1; + const w = Math.round(dims.width * scale); + const h = Math.round(dims.height * scale); + children.push(new Paragraph({ + children: [new ImageRun({ data: imgBuf, transformation: { width: w, height: h }, type: "png" })], + alignment: AlignmentType.CENTER, + spacing: { before: 120, after: 40 }, + })); + // Add caption if alt text exists + if (imgToken.text) { + children.push(new Paragraph({ + children: [new TextRun({ text: imgToken.text, font: FONT, size: 18, italics: true, color: "666666" })], + alignment: AlignmentType.CENTER, + spacing: { before: 0, after: 120 }, + })); + } + } else { + children.push(new Paragraph({ + children: [new TextRun({ text: `[Image not found: ${href}]`, font: FONT, size: 20, italics: true, color: "888888" })], + spacing: { before: 80, after: 80 }, + })); + } + } else { + children.push(new Paragraph({ + children: paragraphRuns(token), spacing: { before: 80, after: 80 }, + })); + } + break; + } + case "table": + if (skipToc) continue; + children.push(buildTable(token)); + children.push(new Paragraph({ spacing: { after: 120 } })); + break; + case "code": + if (skipToc) continue; + if (token.lang === "mermaid") { + children.push(new Paragraph({ + children: [new TextRun({ + text: "[Diagram: See source .md file for interactive Mermaid diagram]", + font: FONT, size: 20, italics: true, color: "888888", + })], + spacing: { before: 80, after: 80 }, + shading: { type: ShadingType.SOLID, color: CODE_BG, fill: CODE_BG }, + indent: { left: 360 }, + })); + } else { + children.push(...buildCodeBlock(token)); + } + children.push(new Paragraph({ spacing: { after: 80 } })); + break; + case "list": + if (skipToc) continue; + children.push(...buildList(token)); + break; + case "hr": + skipToc = false; + children.push(new Paragraph({ + spacing: { before: 200, after: 200 }, + border: { bottom: { style: BorderStyle.SINGLE, size: 1, color: BORDER_COLOR } }, + })); + break; + case "space": + break; + default: + if (token.raw && !skipToc) { + children.push(new Paragraph({ + children: [new TextRun({ text: decodeEntities(token.raw.trim()), font: FONT, size: 22 })], + spacing: { before: 80, after: 80 }, + })); + } + break; + } +} + +// --- Create and write document --- +const doc = new Document({ + styles: { + default: { + document: { run: { font: FONT, size: 22 } }, + heading1: { + run: { font: FONT, size: 36, bold: true, color: HEADER_COLOR }, + paragraph: { spacing: { before: 360, after: 160 } }, + }, + heading2: { + run: { font: FONT, size: 32, bold: true, color: HEADER_COLOR }, + paragraph: { spacing: { before: 320, after: 120 } }, + }, + heading3: { + run: { font: FONT, size: 26, bold: true, color: ACCENT_COLOR }, + paragraph: { spacing: { before: 240, after: 100 } }, + }, + }, + }, + sections: [{ + properties: { + page: { margin: { top: 1440, bottom: 1440, left: 1440, right: 1440 } }, + }, + children, + }], + features: { updateFields: false }, +}); + +const buffer = await Packer.toBuffer(doc); +writeFileSync(outputPath, buffer); +console.log(`Generated: ${outputPath} (${(buffer.length / 1024).toFixed(0)} KB)`); diff --git a/skills/md-to-docx/scripts/package.json b/skills/md-to-docx/scripts/package.json new file mode 100644 index 00000000..2f5c1cf9 --- /dev/null +++ b/skills/md-to-docx/scripts/package.json @@ -0,0 +1,9 @@ +{ + "private": true, + "type": "module", + "description": "Dependencies for the Markdown to Word converter skill", + "dependencies": { + "docx": "^9.6.1", + "marked": "^17.0.4" + } +}