diff --git a/docs/COPILOT-PROMPT.md b/docs/COPILOT-PROMPT.md index 4c7f480..ff16eb2 100644 --- a/docs/COPILOT-PROMPT.md +++ b/docs/COPILOT-PROMPT.md @@ -6,6 +6,21 @@ Create an Obsidian plugin that extracts outstanding tasks from Markdown files an This iteration builds upon Iteration 1 (C# Console App) by integrating the task export functionality directly into Obsidian as a plugin, providing on-demand and automatic export capabilities. +**Related Repository**: [markdown-task-export](https://github.com/tailormade-eu/markdown-task-export) - C# Console Application (Iteration 1) + +**⚠️ IMPORTANT FOR IMPLEMENTATION:** +The C# console application is a **fully working reference implementation** with: +- ✅ Complete task extraction logic (`MarkdownParser.cs`) +- ✅ Hierarchical header parsing with unlimited depth +- ✅ CSV generation with compression support (`CsvExporter.cs`) +- ✅ Customer/Project name extraction (`TaskExtractor.cs`) +- ✅ All edge cases handled (nested tasks, special characters, escaping) + +**Use the C# code as a reference** for implementing the TypeScript plugin. The logic should be **identical**, just ported to TypeScript/Obsidian API. + +**📋 Detailed Specifications:** +See `docs/REQUIREMENTS.md` for comprehensive technical requirements, API usage, cross-platform considerations, and project structure. + ## Requirements ### 1. Plugin Features @@ -39,11 +54,13 @@ Find all unchecked tasks marked with `- [ ]` (checkbox syntax in markdown) ### 5. CSV Output Format (Same as Iteration 1) -- Header row: `CustomerName,ProjectName,Header1,Header2,Header3,Task` -- **Only include header columns that have values** (no empty trailing commas) -- If Header2 doesn't exist, row should be: `CustomerName,ProjectName,Header1,Task` (skip empty Header2 and Header3 columns) +- Header row: `CustomerName,ProjectName,Level1,Level2,Level3,...,Task` +- **Dynamic columns**: Automatically adapts to maximum header depth +- **Compression mode**: Optional removal of empty hierarchy columns (--compress-levels equivalent) +- **Header control**: Option to include or exclude CSV header row - Handle commas within task text by properly escaping with quotes - Handle quotes within task text by doubling them +- UTF-8 with BOM encoding for Excel compatibility ### 6. Output File @@ -60,12 +77,15 @@ Create `outstanding_tasks.csv` in the configurable location (default: vault root ```typescript interface TaskExportSettings { - outputPath: string; // Path for CSV output + outputPath: string; // Path for CSV output (relative to vault) customersFolder: string; // Root folder for customer files autoExport: boolean; // Enable automatic export exportOnSave: boolean; // Export when files are saved exportOnModify: boolean; // Export when files are modified showNotifications: boolean; // Show notifications on export + compressLevels: boolean; // Compress empty levels (like --compress-levels) + includeHeader: boolean; // Include CSV header row (like --no-header) + debounceDelay: number; // Debounce delay in seconds (1-30) } ``` @@ -85,24 +105,64 @@ interface TaskExportSettings { ## Technical Details -- Use **TypeScript** with Obsidian API +### Cross-Platform Support + +**Platform Compatibility:** +- ✅ Windows, macOS, Linux (desktop) +- ✅ Android, iOS (mobile) +- ✅ Web version +- **One codebase works everywhere** - Obsidian uses web technologies on all platforms + +**Technology Stack:** +- **TypeScript** - Primary language +- **Obsidian Plugin API** - Use exclusively for file operations +- **Node.js** - Development only (not required by users) +- **esbuild** - Fast bundling + +**Important API Usage:** +- ✅ Use `this.app.vault.adapter.write()` for file operations +- ✅ Use `this.app.vault.adapter.read()` for reading files +- ✅ Use `normalizePath()` for cross-platform path handling +- ❌ Avoid Node.js modules (`fs`, `path`, `os`) - desktop only +- ❌ Never use absolute paths outside vault on mobile + +**Platform Detection:** +```typescript +if (Platform.isMobile) { + // Mobile: limit to vault directory +} else { + // Desktop: allow custom paths +} +``` + +### Best Practices + - Follow Obsidian plugin development best practices -- Use `obsidian` module for API access -- Properly handle file system operations through Obsidian's API +- Properly handle file system operations through Obsidian's API only - Implement proper error handling and logging - Add progress indicators for large exports +- Test on multiple platforms before release ## Plugin Structure ``` -task-export-plugin/ -├── main.ts // Plugin entry point -├── settings.ts // Settings interface and tab -├── export.ts // Core export logic -├── parser.ts // Markdown parsing logic -├── csv-writer.ts // CSV generation -├── manifest.json // Plugin manifest -└── styles.css // Optional styling +obsidian-task-export-plugin/ +├── src/ +│ ├── main.ts // Plugin entry point +│ ├── settings.ts // Settings interface and tab +│ ├── exporter.ts // Core export logic +│ ├── parser.ts // Markdown parsing logic +│ ├── csv-writer.ts // CSV generation +│ ├── file-watcher.ts // File monitoring +│ └── types.ts // TypeScript interfaces +├── manifest.json // Plugin metadata +├── versions.json // Version compatibility +├── package.json // Dependencies +├── tsconfig.json // TypeScript config +├── esbuild.config.mjs // Build configuration +├── styles.css // Optional styling +├── README.md +└── LICENSE ``` ## Example User Workflows diff --git a/docs/REQUIREMENTS.md b/docs/REQUIREMENTS.md index 3f45a08..bc2d6eb 100644 --- a/docs/REQUIREMENTS.md +++ b/docs/REQUIREMENTS.md @@ -6,6 +6,17 @@ Automatically export outstanding tasks from Obsidian vault to CSV for ManicTime An Obsidian plugin that integrates task export functionality directly into Obsidian, providing both on-demand and automatic export capabilities with a native user experience. +**Related Repository**: [markdown-task-export](https://github.com/tailormade-eu/markdown-task-export) - C# Console Application (Iteration 1) + +**⚠️ REFERENCE IMPLEMENTATION:** +This plugin is a **port of the working C# console application**. Use the C# codebase as a reference: +- `src/MarkdownParser.cs` - Complete parsing logic with all edge cases +- `src/CsvExporter.cs` - CSV generation with compression and header control +- `src/TaskExtractor.cs` - Customer/Project extraction and file enumeration +- `src/Models/TaskItem.cs` - Data structure for tasks + +The TypeScript implementation should produce **identical CSV output** to the C# version. + ## Functional Requirements ### 1. Plugin Integration @@ -61,10 +72,18 @@ An Obsidian plugin that integrates task export functionality directly into Obsid - Multi-line task descriptions **Parsing Logic** -- Use same extraction rules as console app -- Extract hierarchical headers (##, ###, ####) +- Use same extraction rules as console app (reference: `MarkdownParser.cs`) +- Extract hierarchical headers (##, ###, ####, etc.) - unlimited depth - Associate tasks with parent headers - Handle nested task patterns +- Preserve hierarchy when parent tasks have sub-tasks + +**Key Parsing Details from C# Implementation:** +- Headers start at `##` (H2), `#` (H1) is ignored +- Empty header levels are tracked to preserve structure +- Parent tasks (tasks with sub-tasks) become additional header levels +- Indentation-based nesting detection +- Skip tasks with checkmark emojis in the text ### 4. Export Functionality @@ -101,6 +120,8 @@ interface TaskExportSettings { exportOnSave: boolean; // Trigger on file save exportOnModify: boolean; // Trigger on file modify showNotifications: boolean; // Show export notifications + compressLevels: boolean; // Remove empty hierarchy columns + includeHeader: boolean; // Include CSV header row debounceDelay: number; // Debounce delay in seconds (1-30) } ``` @@ -112,6 +133,8 @@ interface TaskExportSettings { - exportOnSave: `true` - exportOnModify: `false` - showNotifications: `true` +- compressLevels: `false` +- includeHeader: `true` - debounceDelay: `3` **Settings Persistence** @@ -123,16 +146,26 @@ interface TaskExportSettings { ### 6. CSV Output (Same as Console App) **Format** -- Header: `CustomerName,ProjectName,Header1,Header2,Header3,Task` -- Dynamic columns (no empty trailing commas) -- Proper CSV escaping -- UTF-8 with BOM +- Header: `CustomerName,ProjectName,Level1,Level2,Level3,...,Task` +- **Dynamic columns**: Unlimited depth support (Level1, Level2, Level3, etc.) +- **Compression mode**: Optional `compressLevels` setting to remove empty columns + - When enabled: Each row only outputs non-empty levels (no padding) + - When disabled: All rows padded to maximum depth with empty columns +- **Header control**: Optional `includeHeader` setting to exclude header row +- Proper CSV escaping (commas, quotes, newlines) +- UTF-8 with BOM encoding for Excel compatibility + +**CSV Escaping Rules (from C# implementation):** +- Wrap in quotes if field contains: comma, quote, newline, or carriage return +- Double any quotes inside the field: `"` becomes `""` +- Example: `Task with "quotes"` becomes `"Task with ""quotes"""` **File Writing** -- Use Obsidian's `vault.adapter.write()` API -- Atomic write (write to temp, then rename) +- Use Obsidian's `vault.adapter.write()` API (cross-platform compatible) +- Atomic write (write to temp, then rename) - optional for reliability - Handle write failures gracefully -- Output path relative to vault root +- Output path relative to vault root (mobile-friendly) +- Support absolute paths on desktop only ### 7. Error Handling @@ -176,16 +209,26 @@ interface TaskExportSettings { **Obsidian Version** - Minimum: Obsidian 1.0.0 - Tested on latest stable release -- API compatibility with mobile (future consideration) +- Full API compatibility across all platforms -**Operating Systems** -- Windows 10/11 -- macOS 11+ -- Linux (major distributions) +**Platforms (Cross-Platform Support)** +- ✅ Windows 10/11 +- ✅ macOS 11+ +- ✅ Linux (major distributions) +- ✅ Android 8.0+ +- ✅ iOS 13+ +- ✅ Web version +- **One codebase works on all platforms** + +**Platform-Specific Considerations:** +- Desktop: Full file system access (can save CSV outside vault) +- Mobile: Limited to vault directory only +- Use Obsidian's Vault API exclusively (not Node.js `fs` module) +- Detect platform with `Platform.isMobile`, `Platform.isDesktop` **Vault Types** - Local vaults -- Synced vaults (Dropbox, OneDrive, etc.) +- Synced vaults (Dropbox, OneDrive, iCloud, etc.) - Git-based vaults ### Usability @@ -221,40 +264,83 @@ interface TaskExportSettings { ### Technology Stack +**Development Environment** +- **Visual Studio Code** - Primary IDE +- **Microsoft Stack** - Preferred tooling where applicable +- **Extensions**: + - ESLint - Code quality + - Prettier - Code formatting + - TypeScript - Language support + - Obsidian Plugin Dev Tools (if available) + **Required** - TypeScript 4.0+ - Obsidian Plugin API (latest) -- Node.js 16+ (development only) -- Rollup (bundling) +- Node.js 16+ (development only, not needed by users) +- esbuild (fast bundling, replaces Rollup) + +**Cross-Platform Compatibility** +- ✅ Use Obsidian's Vault API exclusively +- ✅ Use `normalizePath()` for path handling +- ✅ Use `app.vault.adapter.read()` for file reading +- ✅ Use `app.vault.adapter.write()` for file writing +- ❌ Avoid Node.js modules: `fs`, `path`, `os` (desktop-only) +- ❌ Never use absolute paths outside vault on mobile + +**API Examples:** +```typescript +// ✅ Good - cross-platform +const content = await this.app.vault.adapter.read(filePath); +await this.app.vault.adapter.write(outputPath, csvContent); +const normalized = normalizePath(userPath); + +// ❌ Bad - desktop only +import * as fs from 'fs'; +fs.readFileSync(filePath); +``` **Optional Libraries** - None required (use vanilla TypeScript/Obsidian API) -- Consider: `csv-stringify` for robust CSV generation +- Consider: Built-in CSV generation (no external dependencies) ### Project Structure +**Directory Layout:** ``` -obsidian-task-export-plugin/ -├── src/ -│ ├── main.ts # Plugin entry, command registration -│ ├── settings.ts # Settings interface and tab -│ ├── exporter.ts # Core export logic -│ ├── parser.ts # Markdown parsing -│ ├── csv-writer.ts # CSV generation -│ ├── file-watcher.ts # File monitoring and debouncing -│ └── types.ts # TypeScript interfaces +obsidian-task-export-plugin/ ← Repository root +├── .vscode/ ← VS Code settings +│ ├── settings.json +│ └── extensions.json +├── src/ ← All source code here +│ ├── main.ts # Plugin entry, command registration +│ ├── settings.ts # Settings interface and tab +│ ├── exporter.ts # Core export logic +│ ├── parser.ts # Markdown parsing +│ ├── csv-writer.ts # CSV generation +│ ├── file-watcher.ts # File monitoring and debouncing +│ └── types.ts # TypeScript interfaces ├── tests/ │ ├── exporter.test.ts │ ├── parser.test.ts -│ └── fixtures/ # Test markdown files -├── manifest.json # Plugin metadata -├── package.json # Dependencies -├── tsconfig.json # TypeScript config -├── rollup.config.js # Build configuration +│ └── fixtures/ # Test markdown files +├── manifest.json ← Plugin metadata (root level) +├── versions.json ← Version compatibility (root level) +├── package.json ← Dependencies (root level) +├── tsconfig.json ← TypeScript config (root level) +├── esbuild.config.mjs ← Build configuration (root level) +├── styles.css ← Optional styling (root level) +├── .eslintrc.json ← Linting config +├── .prettierrc ← Formatting config ├── README.md └── LICENSE ``` +**Project Structure Rules:** +- ✅ All source code in `src/` folder +- ✅ Configuration files at root level +- ✅ No solution file needed (TypeScript project, not .NET) +- ✅ Use VS Code workspace for development + ### Build System **Development** @@ -273,6 +359,8 @@ npm test # Run unit tests npm run test:coverage # Generate coverage report ``` +**Build Tool**: esbuild (fast, modern bundler) + ### Plugin Manifest ```json @@ -297,6 +385,7 @@ npm run test:coverage # Generate coverage report - Registers commands, ribbon icon, status bar - Manages file watcher lifecycle - Handles settings loading/saving +- Reference C# `Program.cs` for command-line argument patterns **TaskExportSettings (settings.ts)** - Extends `PluginSettingTab` @@ -310,17 +399,21 @@ npm run test:coverage # Generate coverage report - Calls parser for each file - Aggregates results - Writes CSV output +- Reference C# `TaskExtractor.cs` for logic **MarkdownParser (parser.ts)** - Parses markdown content - Extracts headers and tasks - Maintains hierarchical context - Returns structured data +- **Port directly from C# `MarkdownParser.cs`** - proven logic with all edge cases **CsvWriter (csv-writer.ts)** - Formats data as CSV -- Handles escaping +- Handles escaping (use RFC 4180 standard) - Writes to file via Obsidian API +- Implements compression mode +- **Port directly from C# `CsvExporter.cs`** **FileWatcher (file-watcher.ts)** - Subscribes to file events