confluence-exporter 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/.eslintrc.cjs +18 -0
  2. package/.github/copilot-instructions.md +3 -0
  3. package/.github/prompts/analyze.prompt.md +101 -0
  4. package/.github/prompts/clarify.prompt.md +158 -0
  5. package/.github/prompts/constitution.prompt.md +73 -0
  6. package/.github/prompts/implement.prompt.md +56 -0
  7. package/.github/prompts/plan.prompt.md +50 -0
  8. package/.github/prompts/specify.prompt.md +21 -0
  9. package/.github/prompts/tasks.prompt.md +69 -0
  10. package/LICENSE +21 -0
  11. package/README.md +332 -0
  12. package/agents.md +1174 -0
  13. package/dist/api.d.ts +73 -0
  14. package/dist/api.js +387 -0
  15. package/dist/api.js.map +1 -0
  16. package/dist/commands/download.command.d.ts +18 -0
  17. package/dist/commands/download.command.js +257 -0
  18. package/dist/commands/download.command.js.map +1 -0
  19. package/dist/commands/executor.d.ts +22 -0
  20. package/dist/commands/executor.js +52 -0
  21. package/dist/commands/executor.js.map +1 -0
  22. package/dist/commands/help.command.d.ts +8 -0
  23. package/dist/commands/help.command.js +68 -0
  24. package/dist/commands/help.command.js.map +1 -0
  25. package/dist/commands/index.command.d.ts +14 -0
  26. package/dist/commands/index.command.js +95 -0
  27. package/dist/commands/index.command.js.map +1 -0
  28. package/dist/commands/index.d.ts +13 -0
  29. package/dist/commands/index.js +13 -0
  30. package/dist/commands/index.js.map +1 -0
  31. package/dist/commands/plan.command.d.ts +54 -0
  32. package/dist/commands/plan.command.js +272 -0
  33. package/dist/commands/plan.command.js.map +1 -0
  34. package/dist/commands/registry.d.ts +12 -0
  35. package/dist/commands/registry.js +32 -0
  36. package/dist/commands/registry.js.map +1 -0
  37. package/dist/commands/transform.command.d.ts +69 -0
  38. package/dist/commands/transform.command.js +951 -0
  39. package/dist/commands/transform.command.js.map +1 -0
  40. package/dist/commands/types.d.ts +12 -0
  41. package/dist/commands/types.js +5 -0
  42. package/dist/commands/types.js.map +1 -0
  43. package/dist/commands/update.command.d.ts +10 -0
  44. package/dist/commands/update.command.js +201 -0
  45. package/dist/commands/update.command.js.map +1 -0
  46. package/dist/constants.d.ts +1 -0
  47. package/dist/constants.js +2 -0
  48. package/dist/constants.js.map +1 -0
  49. package/dist/index.d.ts +5 -0
  50. package/dist/index.js +110 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/logger.d.ts +15 -0
  53. package/dist/logger.js +52 -0
  54. package/dist/logger.js.map +1 -0
  55. package/dist/types.d.ts +167 -0
  56. package/dist/types.js +5 -0
  57. package/dist/types.js.map +1 -0
  58. package/dist/utils.d.ts +56 -0
  59. package/dist/utils.js +178 -0
  60. package/dist/utils.js.map +1 -0
  61. package/eslint.config.js +29 -0
  62. package/jest.config.cjs +25 -0
  63. package/migrate-meta.js +132 -0
  64. package/package.json +53 -0
  65. package/src/api.ts +469 -0
  66. package/src/commands/download.command.ts +324 -0
  67. package/src/commands/executor.ts +62 -0
  68. package/src/commands/help.command.ts +72 -0
  69. package/src/commands/index.command.ts +111 -0
  70. package/src/commands/index.ts +14 -0
  71. package/src/commands/plan.command.ts +318 -0
  72. package/src/commands/registry.ts +39 -0
  73. package/src/commands/transform.command.ts +1103 -0
  74. package/src/commands/types.ts +16 -0
  75. package/src/commands/update.command.ts +229 -0
  76. package/src/constants.ts +0 -0
  77. package/src/index.ts +120 -0
  78. package/src/logger.ts +60 -0
  79. package/src/test.sh +66 -0
  80. package/src/types.ts +176 -0
  81. package/src/utils.ts +204 -0
  82. package/tests/commands/README.md +123 -0
  83. package/tests/commands/download.command.test.ts +8 -0
  84. package/tests/commands/help.command.test.ts +8 -0
  85. package/tests/commands/index.command.test.ts +8 -0
  86. package/tests/commands/plan.command.test.ts +15 -0
  87. package/tests/commands/transform.command.test.ts +8 -0
  88. package/tests/fixtures/_index.yaml +38 -0
  89. package/tests/fixtures/mock-pages.ts +62 -0
  90. package/tsconfig.json +25 -0
  91. package/vite.config.ts +45 -0
package/agents.md ADDED
@@ -0,0 +1,1174 @@
1
+ # Agents Guide: Confluence to Markdown Exporter
2
+
3
+ This document provides comprehensive guidance for AI agents (like GitHub Copilot) working on this project. It includes architecture, patterns, conventions, and implementation details.
4
+
5
+ > **⚠️ IMPORTANT: Keep This Document Updated**
6
+ > When making changes to project structure, architecture, CLI commands, API methods, or core logic, **ALWAYS update this agents.md file** to reflect those changes. This ensures AI agents have accurate context for future development work.
7
+
8
+ ---
9
+
10
+ ## Project Overview
11
+
12
+ **Name:** Confluence to Markdown Exporter
13
+ **Type:** CLI Tool
14
+ **Language:** TypeScript 5.x
15
+ **Runtime:** Node.js 18+
16
+ **Purpose:** Export Confluence spaces to Markdown files with metadata preservation
17
+
18
+ ### Key Features
19
+ - ✅ Minimal dependencies (uses native Node.js fetch)
20
+ - ✅ Command-based CLI with five commands: `help`, `index`, `plan`, `download`, `transform`
21
+ - ✅ Four-phase export workflow (indexing → planning → downloading → transforming)
22
+ - ✅ **Hierarchical folder structure** based on page tree (mirrors Confluence hierarchy)
23
+ - ✅ Separate HTML download and Markdown transformation for flexibility
24
+ - ✅ HTML to Markdown transformation with Confluence macro support
25
+ - ✅ User link resolution with intelligent caching
26
+ - ✅ Image/attachment downloading with automatic slugification
27
+ - ✅ YAML-based indexing with resume capability
28
+ - ✅ Prettier formatting for consistent output
29
+
30
+ ### Quick Start
31
+
32
+ ```bash
33
+ # Full space export (4-phase workflow)
34
+ npm run dev -- index plan download transform -u URL -n USER -p TOKEN -s SPACE -o ./output
35
+
36
+ # Full space export with limit (process first 10 pages only)
37
+ npm run dev -- index plan download transform -u URL -n USER -p TOKEN -s SPACE -o ./output -l 10
38
+
39
+ # Single page HTML download only
40
+ npm run dev -- download -i PAGE_ID -u URL -n USER -p TOKEN -s SPACE -o ./output
41
+
42
+ # Transform existing HTML files to Markdown
43
+ npm run dev -- transform -u URL -n USER -p TOKEN -s SPACE -o ./output
44
+
45
+ # Resume from existing index
46
+ npm run dev -- plan download transform -u URL -n USER -p TOKEN -s SPACE -o ./output
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Architecture
52
+
53
+ ### Core Components
54
+
55
+ ```
56
+ src/
57
+ ├── index.ts # CLI entry point (arg parsing, config validation)
58
+ ├── types.ts # TypeScript type definitions
59
+ ├── api.ts # Confluence REST API client
60
+ ├── transformer.ts # HTML → Markdown conversion
61
+ ├── cleaner.ts # Post-processing cleanup
62
+ └── commands/ # Command handlers (modular architecture)
63
+ ├── types.ts # Command-related type definitions
64
+ ├── help.command.ts # Help command handler
65
+ ├── index.command.ts # Index command handler
66
+ ├── plan.command.ts # Plan command handler
67
+ ├── download.command.ts # Download command handler (HTML only)
68
+ ├── transform.command.ts # Transform command handler (HTML → MD)
69
+ ├── registry.ts # Command registry (maps commands to handlers)
70
+ ├── executor.ts # Command executor (orchestrates execution)
71
+ └── index.ts # Exports for easy importing
72
+ ```
73
+
74
+ ### Data Flow
75
+
76
+ ```mermaid
77
+ flowchart TD
78
+ A[CLI Args/Env] --> B[Config Validation]
79
+ B --> C[CommandExecutor]
80
+
81
+ C --> D[Phase 1: IndexCommand]
82
+ C --> E[Phase 2: PlanCommand]
83
+ C --> F[Phase 3: DownloadCommand]
84
+ C --> G[Phase 4: TransformCommand]
85
+
86
+ D --> D1[API.getAllPages]
87
+ D1 --> D2[_index.yaml]
88
+
89
+ E --> E1{Has pageId?}
90
+ E1 -->|Yes| E2[API.getChildPages recursively]
91
+ E1 -->|No| E3[Read _index.yaml]
92
+ E2 --> E4[_queue.yaml + _tree.yaml]
93
+ E3 --> E4
94
+
95
+ F --> F1[Read _queue.yaml]
96
+ F1 --> F2[For each page]
97
+ F2 --> F3[API.getPage]
98
+ F3 --> F4[Save .html]
99
+
100
+ G --> G1[Read HTML files]
101
+ G1 --> G2{MD exists?}
102
+ G2 -->|No| G3[Transformer.transform]
103
+ G2 -->|Yes| G4[Skip]
104
+ G3 --> G5[Download images]
105
+ G5 --> G6[Apply cleaner]
106
+ G6 --> G7[Prettier format]
107
+ G7 --> G8[Save .md]
108
+
109
+ style D fill:#e1f5ff
110
+ style E fill:#fff4e1
111
+ style F fill:#e8f5e9
112
+ style G fill:#f3e5f5
113
+ ```
114
+
115
+ **Workflow Summary:**
116
+ 1. **Index Phase** - Scan space and create `_index.yaml` with all page metadata
117
+ 2. **Plan Phase** - Create `_queue.yaml` from index or specific page tree
118
+ 3. **Download Phase** - Process queue and download HTML files
119
+ 4. **Transform Phase** - Convert HTML to Markdown (skips existing MD files)
120
+
121
+ ### Key Design Patterns
122
+
123
+ #### 1. Command Pattern
124
+ Each command is a separate class implementing `CommandHandler` interface:
125
+ - **Benefits:** Separation of concerns, testable, extensible
126
+ - **Registry:** `CommandRegistry` maps command names to handlers
127
+ - **Executor:** `CommandExecutor` orchestrates command execution
128
+ - **Commands:** `help`, `index`, `plan`, `download`, `transform`
129
+
130
+ #### 2. Four-Phase Export Workflow
131
+ Separates concerns for resumability and transparency:
132
+ - **Phase 1 (Index):** Scan space → `_index.yaml` with metadata
133
+ - **Phase 2 (Plan):** Create `_queue.yaml` from index or page tree
134
+ - **Phase 3 (Download):** Process queue → download HTML files only
135
+ - **Phase 4 (Transform):** Convert HTML to Markdown (checks for existing MD files)
136
+
137
+ #### 3. Async Generators
138
+ Memory-efficient pagination in `api.getAllPages()`:
139
+ - Yields pages one at a time
140
+ - Avoids loading entire space into memory
141
+ - Enables progress tracking
142
+
143
+ #### 4. Smart Caching
144
+ Optimizes API calls:
145
+ - User lookups cached in `Map<string, User>`
146
+ - Prevents duplicate API requests
147
+ - Reduces export time
148
+
149
+ #### 5. Error Handling Strategy
150
+ - **Non-fatal:** Logged as warnings (e.g., failed image downloads)
151
+ - **Fatal:** Throw error and exit with code 1 (e.g., API auth failure)
152
+
153
+ ---
154
+
155
+ ## Type System
156
+
157
+ ### Configuration
158
+ ```typescript
159
+ interface ConfluenceConfig {
160
+ baseUrl: string; // Confluence instance URL
161
+ username: string; // Email/username
162
+ password: string; // API token
163
+ spaceKey: string; // Space identifier
164
+ outputDir: string; // Export destination
165
+ pageId?: string; // Optional: single page export
166
+ pageSize?: number; // Optional: pagination size (default: 25)
167
+ limit?: number; // Optional: limit number of pages to process
168
+ }
169
+ ```
170
+
171
+ ### Core Domain
172
+ ```typescript
173
+ interface Page {
174
+ id: string;
175
+ title: string;
176
+ body: string; // HTML storage format
177
+ version?: number;
178
+ parentId?: string;
179
+ modifiedDate?: string;
180
+ }
181
+
182
+ interface PageIndexEntry {
183
+ id: string;
184
+ title: string;
185
+ version?: number;
186
+ parentId?: string;
187
+ modifiedDate?: string;
188
+ indexedDate: string; // When indexed
189
+ pageNumber: number; // API page number
190
+ }
191
+
192
+ interface PageTreeNode {
193
+ id: string;
194
+ title: string;
195
+ version?: number;
196
+ parentId?: string;
197
+ modifiedDate?: string;
198
+ children?: PageTreeNode[]; // Hierarchical structure
199
+ }
200
+ ```
201
+
202
+ ### Transformation
203
+ ```typescript
204
+ interface MarkdownResult {
205
+ content: string; // Markdown body
206
+ frontMatter: { // YAML front matter
207
+ title: string;
208
+ id: string;
209
+ version?: number;
210
+ parentId?: string;
211
+ };
212
+ images: Array<{ // Downloaded images
213
+ filename: string;
214
+ data: Buffer;
215
+ }>;
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## API Client (api.ts)
222
+
223
+ ### Authentication
224
+ - Uses HTTP Basic Auth with base64-encoded credentials
225
+ - Token stored in `authHeader` property
226
+
227
+ ### Key Methods
228
+
229
+ #### `getPage(pageId: string): Promise<Page>`
230
+ Fetches a single page with full content.
231
+ - Expands: `body.storage`, `version`, `history.lastUpdated`
232
+ - Returns: Normalized `Page` object
233
+
234
+ #### `listPages(spaceKey, start, limit): Promise<PaginatedResponse<Page>>`
235
+ Fetches paginated page list from a space.
236
+ - Includes body content (use for small exports only)
237
+ - Returns: Results + pagination metadata
238
+
239
+ #### `getAllPages(spaceKey, pageSize, startFrom): AsyncGenerator<Page & {apiPageNumber}>`
240
+ Memory-efficient async generator for all pages.
241
+ - Handles pagination automatically
242
+ - Yields pages one at a time
243
+ - Tracks API page number for logging
244
+ - **Resume support:** `startFrom` parameter allows starting from a specific position (efficient resume without fetching already-indexed pages)
245
+
246
+ #### `getChildPages(pageId): Promise<Page[]>`
247
+ Fetches child pages for hierarchy resolution.
248
+ - Used by `list-children` macro transformation
249
+ - Returns page IDs and titles only (no body)
250
+
251
+ #### `downloadAttachment(pageId, filename): Promise<Buffer | null>`
252
+ Downloads binary attachment data.
253
+ - Returns null on failure (non-fatal)
254
+ - Used for image downloads
255
+
256
+ #### `getUserByUsername(username): Promise<User | null>`
257
+ #### `getUserByKey(userKey): Promise<User | null>`
258
+ Resolve user links to display names.
259
+ - Results cached in `userCache` Map
260
+ - Returns null on failure (falls back to username)
261
+
262
+ ---
263
+
264
+ ## Commands (src/commands/)
265
+
266
+ The application uses a modular command architecture where each command is self-contained.
267
+
268
+ ### Command Reference
269
+
270
+ | Command | Purpose | Output | Resume Support |
271
+ |---------|---------|--------|----------------|
272
+ | `help` | Display usage information | Console output | N/A |
273
+ | `index` | Create page inventory | `_index.yaml` | ✅ Yes |
274
+ | `plan` | Create download queue and tree | `_queue.yaml` + `_tree.yaml` | ❌ No |
275
+ | `download` | Download HTML pages | `.html` files | ❌ No |
276
+ | `transform` | Transform HTML to Markdown | `.md` files + images | ✅ Yes (skips existing) |
277
+
278
+ ### Command Handlers
279
+
280
+ #### HelpCommand (`help.command.ts`)
281
+ ```bash
282
+ npm run dev -- help
283
+ ```
284
+ Displays usage information, options, and examples.
285
+
286
+ #### IndexCommand (`index.command.ts`)
287
+ ```bash
288
+ npm run dev -- index -u URL -n USER -p TOKEN -s SPACE -o ./output
289
+
290
+ # With limit (index only first 10 pages)
291
+ npm run dev -- index -u URL -n USER -p TOKEN -s SPACE -o ./output -l 10
292
+ ```
293
+ **Purpose:** Create complete page inventory (Phase 1)
294
+
295
+ **Behavior:**
296
+ - Creates output directory if missing
297
+ - Streams all pages via `api.getAllPages()` (memory-efficient)
298
+ - Appends each page to `_index.yaml` as YAML array entry
299
+ - **Resume:** Automatically resumes from where it left off by calculating the start position from existing pages (does NOT re-fetch already-indexed pages)
300
+ - **Limit:** If `--limit` is specified, stops after indexing that many pages
301
+ - **Logging:** `[N] Indexed: Title (ID) [API Page N]`
302
+
303
+ **Output:** `_index.yaml` with metadata for all pages in space
304
+
305
+ #### PlanCommand (`plan.command.ts`)
306
+ ```bash
307
+ # Plan entire space (from index)
308
+ npm run dev -- plan -u URL -n USER -p TOKEN -s SPACE -o ./output
309
+
310
+ # Plan specific page tree
311
+ npm run dev -- plan -i PAGE_ID -u URL -n USER -p TOKEN -s SPACE -o ./output
312
+
313
+ # Plan with limit (first 10 pages from index)
314
+ npm run dev -- plan -u URL -n USER -p TOKEN -s SPACE -o ./output -l 10
315
+ ```
316
+ **Purpose:** Create download queue and tree structure (Phase 2)
317
+
318
+ **Behavior:**
319
+ - **Mode A (No pageId):** Reads `_index.yaml` → creates `_queue.yaml` (flat) + `_tree.yaml` (hierarchical)
320
+ - **Mode B (With pageId):** Fetches page tree recursively → creates `_queue.yaml` + `_tree.yaml`
321
+ - Uses `collectPageTree()` for recursive hierarchy traversal
322
+ - Uses `buildTreeFromIndex()` to construct tree from flat index
323
+ - **Limit:** If `--limit` is specified, only includes first N pages in queue
324
+ - **Logging:** `[N] Found: Title (ID)` (indented for hierarchy)
325
+
326
+ **Output:**
327
+ - `_queue.yaml` - Flat list of pages to download (depth-first order)
328
+ - `_tree.yaml` - Hierarchical tree structure showing parent-child relationships
329
+
330
+ #### DownloadCommand (`download.command.ts`)
331
+ ```bash
332
+ # Download from queue (hierarchical structure if _tree.yaml exists)
333
+ npm run dev -- download -u URL -n USER -p TOKEN -s SPACE -o ./output
334
+
335
+ # Download single page directly
336
+ npm run dev -- download -i PAGE_ID -u URL -n USER -p TOKEN -s SPACE -o ./output
337
+ ```
338
+ **Purpose:** Download HTML pages (Phase 3)
339
+
340
+ **Behavior:**
341
+ - **Mode A (No pageId):**
342
+ - Checks for `_tree.yaml` first (preferred for hierarchical structure)
343
+ - If `_tree.yaml` exists:
344
+ - Creates root folder: `{outputDir}/{spaceKey}/`
345
+ - Recursively downloads pages following tree hierarchy
346
+ - For pages with children: creates both HTML file AND folder with same name
347
+ - Children are downloaded into parent's folder
348
+ - If `_tree.yaml` not found:
349
+ - Falls back to `_queue.yaml` (flat structure)
350
+ - Downloads all to `outputDir` (throws error if missing)
351
+ - **Mode B (With pageId):** Downloads single page directly (no queue needed)
352
+ - For each page:
353
+ 1. Fetch via `api.getPage(id)`
354
+ 2. Format HTML with Prettier
355
+ 3. Save `.html` file in appropriate directory
356
+ 4. If page has children (in tree mode), create folder for children
357
+ - **Limit:** If `--limit` is specified, only downloads first N pages from queue
358
+ - **Logging:** `[N] Downloading: Title (ID)` (indented for hierarchy in tree mode)
359
+
360
+ **Output:** HTML files in hierarchical folder structure (if `_tree.yaml` exists) or flat structure
361
+
362
+ #### TransformCommand (`transform.command.ts`)
363
+ ```bash
364
+ # Transform all HTML files recursively in output directory
365
+ npm run dev -- transform -u URL -n USER -p TOKEN -s SPACE -o ./output
366
+ ```
367
+ **Purpose:** Transform HTML to Markdown (Phase 4)
368
+
369
+ **Behavior:**
370
+ - Recursively scans output directory for `.html` files (walks folder tree)
371
+ - Skips `_*` files and `images` folders during traversal
372
+ - For each HTML file:
373
+ 1. Check if corresponding `.md` file exists in same directory
374
+ 2. If `.md` exists, skip (no overwrite)
375
+ 3. If `.md` missing, transform HTML to Markdown
376
+ 4. Download images to `images/` subdirectory (relative to page)
377
+ 5. Apply cleaner and format with Prettier
378
+ 6. Save `.md` file in same directory as HTML
379
+ - **Limit:** If `--limit` is specified, only processes first N HTML files
380
+ - **Logging:** `[N/Total] Checking: relative/path/to/file.html`
381
+ - **Smart Skip:** Only transforms pages missing Markdown files
382
+
383
+ **Output:** Markdown files and downloaded images in hierarchical structure (skips existing MD files)
384
+
385
+ ### Export Modes
386
+
387
+ #### Mode 1: Single Page Export
388
+ When `config.pageId` is set (via `download` command):
389
+ 1. Fetch single page via `api.getPage(pageId)`
390
+ 2. Save .html file
391
+ 3. Run `transform` command separately to generate .md
392
+
393
+ #### Mode 2: Full Space Export
394
+ When `config.pageId` is undefined (via `index`, `plan`, `download`, and `transform` commands):
395
+
396
+ **Phase 1: Create Index** (`IndexCommand`)
397
+ 1. Check if `_index.yaml` exists (resume if found)
398
+ 2. Stream pages via `api.getAllPages()`
399
+ 3. Append each page as YAML array entry
400
+ 4. Log: `[N] Indexed: Title (ID) [API Page N]`
401
+
402
+ **Phase 2: Create Queue** (`PlanCommand`)
403
+ 1. Option A: From _index.yaml (no pageId)
404
+ - Read `_index.yaml`
405
+ - Copy to `_queue.yaml`
406
+ 2. Option B: From specific page tree (with pageId)
407
+ - Fetch page via `api.getPage(pageId)`
408
+ - Recursively fetch all children via `api.getChildPages()`
409
+ - Write to `_queue.yaml`
410
+
411
+ **Phase 3: Download Pages** (`DownloadCommand`)
412
+ 1. Check for `_tree.yaml` (preferred) or `_queue.yaml` (fallback)
413
+ 2. If `_tree.yaml` exists:
414
+ - Create root folder: `{outputDir}/{spaceKey}/`
415
+ - Recursively process tree structure:
416
+ - Download page via `api.getPage(id)` to current directory
417
+ - Format with Prettier
418
+ - Save `.html` file
419
+ - If page has children, create folder `{pageId}-{slug}/` and recurse
420
+ 3. If only `_queue.yaml` exists:
421
+ - Download pages to flat structure in `outputDir`
422
+ - For each entry:
423
+ - Fetch full page via `api.getPage(id)`
424
+ - Format with Prettier
425
+ - Save .html file
426
+ 4. Log: `[N] Downloading: Title (ID)` (indented for hierarchy)
427
+
428
+ **Phase 4: Transform Pages** (`TransformCommand`)
429
+ 1. Recursively scan output directory for `.html` files
430
+ 2. Skip `_*` files and `images` folders
431
+ 3. For each HTML file:
432
+ - Check if `.md` exists in same directory (skip if found)
433
+ - Transform HTML to markdown
434
+ - Download images to `images/` folder (relative to page)
435
+ - Apply cleaner
436
+ - Format with Prettier
437
+ - Save `.md` file in same directory
438
+ 4. Log: `[N/Total] Checking: relative/path/file.html`
439
+
440
+ ### Common Workflows
441
+
442
+ ```bash
443
+ # Workflow 1: Full space export (all phases)
444
+ npm run dev -- index plan download transform -u URL -n USER -p TOKEN -s SPACE -o ./output
445
+
446
+ # Workflow 2: Resume from existing index
447
+ npm run dev -- plan download transform -u URL -n USER -p TOKEN -s SPACE -o ./output
448
+
449
+ # Workflow 3: Export specific page and children
450
+ npm run dev -- plan download transform -i PAGE_ID -u URL -n USER -p TOKEN -s SPACE -o ./output
451
+
452
+ # Workflow 4: Single page only (fastest)
453
+ npm run dev -- download -i PAGE_ID -u URL -n USER -p TOKEN -s SPACE -o ./output
454
+
455
+ # Workflow 5: Re-index space (update metadata)
456
+ rm ./output/_index.yaml
457
+ npm run dev -- index -u URL -n USER -p TOKEN -s SPACE -o ./output
458
+ ```
459
+
460
+ ### File Structure
461
+
462
+ **Hierarchical Structure (when `_tree.yaml` exists):**
463
+ ```
464
+ outputDir/
465
+ ├── _index.yaml # Page index (YAML array)
466
+ ├── _queue.yaml # Download queue (YAML array)
467
+ ├── _tree.yaml # Hierarchical page tree structure
468
+ └── PR000299/ # Root folder (space key)
469
+ ├── 95956404-fcs-fidelity-charitable.html
470
+ ├── 95956404-fcs-fidelity-charitable.md
471
+ └── 95956404-fcs-fidelity-charitable/ # Folder for children
472
+ ├── images/ # Images for child pages
473
+ │ └── logo.png
474
+ ├── 115361447-agile-and-resource-center.html
475
+ ├── 115361447-agile-and-resource-center.md
476
+ └── 115361447-agile-and-resource-center/ # Nested children
477
+ ├── 95956405-getting-started.html
478
+ ├── 95956405-getting-started.md
479
+ └── 95956405-getting-started/
480
+ ├── 95956406-making-a-template.html
481
+ └── 95956406-making-a-template.md
482
+ ```
483
+
484
+ **Flat Structure (fallback when only `_queue.yaml` exists):**
485
+ ```
486
+ outputDir/
487
+ ├── _index.yaml # Page index (YAML array)
488
+ ├── _queue.yaml # Download queue (YAML array)
489
+ ├── page-title-1.md # Formatted markdown
490
+ ├── page-title-1.html # Original HTML (formatted)
491
+ ├── page-title-2.md
492
+ ├── page-title-2.html
493
+ └── images/ # Shared images folder
494
+ ├── image-1.png
495
+ └── image-2.jpg
496
+ ```
497
+
498
+ ### Filename Slugification
499
+ ```typescript
500
+ slugify(text: string): string {
501
+ return text
502
+ .toLowerCase()
503
+ .replace(/[^\w\s-]/g, '') // Remove special chars
504
+ .replace(/\s+/g, '-') // Spaces → hyphens
505
+ .replace(/-+/g, '-') // Collapse hyphens
506
+ .trim();
507
+ }
508
+ ```
509
+
510
+ ### Front Matter Format
511
+ ```yaml
512
+ ---
513
+ title: "Page Title"
514
+ id: "123456789"
515
+ url: "https://site.atlassian.net/pages/viewpage.action?pageId=123456789"
516
+ version: 5
517
+ parentId: "987654321"
518
+ ---
519
+ ```
520
+
521
+ ### Prettier Formatting
522
+
523
+ **Markdown:**
524
+ - `printWidth: 120`
525
+ - `proseWrap: 'preserve'` (don't reflow text)
526
+ - `tabWidth: 2`
527
+
528
+ **HTML:**
529
+ - `printWidth: 120`
530
+ - `htmlWhitespaceSensitivity: 'ignore'`
531
+ - Consistent 2-space indentation
532
+
533
+ Formatting failures are non-fatal (saves unformatted with warning).
534
+
535
+ ---
536
+
537
+ ## CLI (index.ts)
538
+
539
+ ### Command Structure
540
+ The CLI uses a command-based architecture with five commands:
541
+
542
+ | Command | Purpose | Required Files | Output |
543
+ |---------|---------|----------------|--------|
544
+ | `help` | Display help | None | Console |
545
+ | `index` | Scan space pages | None | `_index.yaml` |
546
+ | `plan` | Create download queue | `_index.yaml` (if no pageId) | `_queue.yaml` |
547
+ | `download` | Download HTML pages | `_queue.yaml` (if no pageId) | `.html` files |
548
+ | `transform` | Transform HTML to MD | `.html` files | `.md` files + images |
549
+
550
+ **Chaining:** Commands can be chained to run in sequence:
551
+ ```bash
552
+ npm run dev -- index plan download transform -u URL -n USER -p TOKEN -s SPACE
553
+ ```
554
+
555
+ ### Argument Parsing
556
+ Uses `minimist` for flexible CLI arguments.
557
+
558
+ ```bash
559
+ # Full sync workflow (no commands provided)
560
+ node index.js -u https://site.atlassian.net \
561
+ -n user@example.com \
562
+ -p token123 \
563
+ -s MYSPACE \
564
+ -o ./export
565
+
566
+ # Show help
567
+ node index.js help
568
+ node index.js --help
569
+
570
+ # Create index only (Phase 1)
571
+ node index.js index -u https://site.atlassian.net \
572
+ -n user@example.com \
573
+ -p token123 \
574
+ -s MYSPACE \
575
+ -o ./export
576
+
577
+ # Create queue from existing index
578
+ node index.js plan -u https://site.atlassian.net \
579
+ -n user@example.com \
580
+ -p token123 \
581
+ -s MYSPACE \
582
+ -o ./export
583
+
584
+ # Create queue for specific page and all children
585
+ node index.js plan -i 123456789 -u https://site.atlassian.net \
586
+ -n user@example.com \
587
+ -p token123 \
588
+ -s MYSPACE \
589
+ -o ./export
590
+
591
+ # Download from existing queue or index (Phase 2)
592
+ node index.js download -u https://site.atlassian.net \
593
+ -n user@example.com \
594
+ -p token123 \
595
+ -s MYSPACE \
596
+ -o ./export
597
+
598
+ # Run both phases in sequence
599
+ node index.js index download -u URL -n USER -p PASS -s SPACE
600
+
601
+ # Download single page (no index/queue needed)
602
+ node index.js download -i 123456789 -u URL -n USER -p PASS -s SPACE
603
+
604
+ # Short flags
605
+ node index.js download -u URL -n USER -p PASS -s SPACE -o DIR -i ID
606
+ ```
607
+
608
+ ### Command Behavior
609
+
610
+ 1. **No commands provided**: Runs full sync workflow (update index if exists or create new, then plan, download, transform)
611
+ 2. **Invalid command**: Shows error + help and exits with code 1
612
+ 3. **Multiple commands**: Executes in sequence with visual separators
613
+ 4. **`help` command**: Shows help and exits (other commands ignored)
614
+ 5. **`plan` with pageId**: Creates _queue.yaml with specified page and all children
615
+ 6. **`plan` without pageId**: Creates _queue.yaml from existing _index.yaml
616
+ 7. **`download`**: Requires _queue.yaml to exist (errors if missing with instruction to run plan)
617
+ 8. **`transform`**: Scans for .html files and creates .md files (skips if .md exists)
618
+
619
+ ### Options
620
+
621
+ | Flag | Long Form | Description | Default |
622
+ |------|-----------|-------------|---------|
623
+ | `-u` | `--url` | Confluence base URL | env: `CONFLUENCE_BASE_URL` |
624
+ | `-n` | `--username` | Username/email | env: `CONFLUENCE_USERNAME` |
625
+ | `-p` | `--password` | API token | env: `CONFLUENCE_PASSWORD` |
626
+ | `-s` | `--space` | Space key | env: `CONFLUENCE_SPACE_KEY` |
627
+ | `-o` | `--output` | Output directory | `./output` or env: `OUTPUT_DIR` |
628
+ | `-i` | `--pageId` | Single page ID (optional) | none |
629
+ | `-l` | `--limit` | Limit number of pages to process | none |
630
+ | | `--pageSize` | API page size | `25` |
631
+ | `-h` | `--help` | Show help | |
632
+
633
+ ### Environment Variables
634
+ Fallback if CLI args not provided:
635
+ - `CONFLUENCE_BASE_URL`
636
+ - `CONFLUENCE_USERNAME`
637
+ - `CONFLUENCE_PASSWORD`
638
+ - `CONFLUENCE_SPACE_KEY`
639
+ - `OUTPUT_DIR`
640
+
641
+ ### Validation
642
+ Required fields (for `index`, `download`, and `transform` commands):
643
+ - `baseUrl`
644
+ - `username`
645
+ - `password`
646
+ - `spaceKey`
647
+
648
+ Exits with code 1 and error message if missing.
649
+
650
+ ### Help Text
651
+ ```bash
652
+ node index.js
653
+ node index.js help
654
+ node index.js --help
655
+ ```
656
+ Shows usage, commands, options, environment variables, and examples.
657
+
658
+ ---
659
+
660
+ ## Development Workflow
661
+
662
+ ### Build & Run
663
+
664
+ ```bash
665
+ # Build TypeScript
666
+ npm run build # Uses Vite
667
+ npm run build:tsc # Uses tsc directly
668
+
669
+ # Run compiled
670
+ npm start -- [args]
671
+
672
+ # Development mode
673
+ npm run dev -- [args] # Run once
674
+ npm run dev:watch -- [args] # Watch mode
675
+ ```
676
+
677
+ ### Testing
678
+
679
+ ```bash
680
+ npm test # Run all tests
681
+ npm run test:watch # Watch mode
682
+ npm run test:coverage # With coverage
683
+ ```
684
+
685
+ ### Linting & Type Checking
686
+
687
+ ```bash
688
+ npm run lint # ESLint
689
+ npm run typecheck # TypeScript --noEmit
690
+ ```
691
+
692
+ ### Cleaning
693
+
694
+ ```bash
695
+ npm run clean # Remove dist/
696
+ npm run rebuild # Clean + build
697
+ ```
698
+
699
+ ---
700
+
701
+ ## Coding Conventions
702
+
703
+ ### TypeScript Style
704
+
705
+ 1. **Explicit Types**
706
+ - Always type function parameters
707
+ - Always type function return values
708
+ - Use interfaces for objects, type aliases for unions
709
+
710
+ 2. **Imports**
711
+ - Use `.js` extension in imports (ES modules)
712
+ - Import types with `import type {}`
713
+ - Order: types, then classes, then functions
714
+
715
+ 3. **Async/Await**
716
+ - Prefer async/await over Promises
717
+ - Use `for await...of` for async generators
718
+ - Handle errors with try/catch
719
+
720
+ 4. **Error Handling**
721
+ - Throw `Error` objects with descriptive messages
722
+ - Log warnings to console for non-fatal errors
723
+ - Return null for optional operations that fail
724
+
725
+ 5. **Naming**
726
+ - Classes: PascalCase (e.g., `ConfluenceApi`)
727
+ - Functions/methods: camelCase (e.g., `getPage`)
728
+ - Constants: UPPER_SNAKE_CASE (e.g., `DEFAULT_PAGE_SIZE`)
729
+ - Interfaces: PascalCase (e.g., `ConfluenceConfig`)
730
+
731
+ ### Documentation
732
+
733
+ ```typescript
734
+ /**
735
+ * Brief description of function/class
736
+ *
737
+ * Detailed explanation if needed.
738
+ *
739
+ * @param paramName - Description
740
+ * @returns Description
741
+ * @throws ErrorType - When error occurs
742
+ */
743
+ ```
744
+
745
+ ### Diagrams
746
+
747
+ **Using Mermaid:**
748
+ When documenting architecture, data flows, or complex relationships, use Mermaid diagrams in markdown files. Mermaid is supported by GitHub, VS Code, and many markdown viewers.
749
+
750
+ **Supported Diagram Types:**
751
+ - `flowchart` / `graph` - Flow diagrams and directed graphs
752
+ - `sequenceDiagram` - Sequence/interaction diagrams
753
+ - `classDiagram` - Class relationships
754
+ - `stateDiagram` - State machines
755
+ - `erDiagram` - Entity-relationship diagrams
756
+ - `gantt` - Gantt charts for timelines
757
+ - `architecture-beta` - Architecture diagrams (experimental)
758
+
759
+ **Example - Architecture Diagram:**
760
+ ```mermaid
761
+ architecture-beta
762
+ service user(mdi:account)[User]
763
+ service cli(logos:terminal)[CLI]
764
+ service api(logos:aws-lambda)[Confluence API]
765
+ service transformer(mdi:transform)[Transformer]
766
+ service files(mdi:file-document)[Output Files]
767
+
768
+ user:R --> L:cli
769
+ cli:R --> L:api
770
+ cli:R --> L:transformer
771
+ transformer:R --> L:files
772
+ ```
773
+
774
+ **Example - Flow Diagram:**
775
+ ```mermaid
776
+ flowchart TD
777
+ A[CLI Args] --> B{Validate Config}
778
+ B -->|Valid| C[Command Executor]
779
+ B -->|Invalid| D[Show Error]
780
+ C --> E[Index Command]
781
+ C --> F[Plan Command]
782
+ C --> G[Download Command]
783
+ E --> H[_index.yaml]
784
+ F --> I[_queue.yaml]
785
+ G --> J[.md/.html files]
786
+ ```
787
+
788
+ **Example - Sequence Diagram:**
789
+ ```mermaid
790
+ sequenceDiagram
791
+ participant User
792
+ participant CLI
793
+ participant API
794
+ participant Transformer
795
+
796
+ User->>CLI: Run download command
797
+ CLI->>API: getPage(id)
798
+ API-->>CLI: HTML content
799
+ CLI->>Transformer: transform(html)
800
+ Transformer->>API: downloadAttachment(image)
801
+ API-->>Transformer: image data
802
+ Transformer-->>CLI: Markdown + images
803
+ CLI->>User: Save files
804
+ ```
805
+
806
+ **Best Practices:**
807
+ 1. Use diagrams to complement text documentation, not replace it
808
+ 2. Keep diagrams simple and focused on one concept
809
+ 3. Add descriptive labels to nodes and edges
810
+ 4. Place diagrams near the relevant text explanation
811
+ 5. Use consistent naming with code (class names, method names)
812
+ 6. Test diagram rendering in your markdown viewer
813
+
814
+ ### File Organization
815
+
816
+ ```typescript
817
+ // 1. Imports
818
+ import type { TypeA, TypeB } from './types.js';
819
+ import { ClassA } from './class-a.js';
820
+
821
+ // 2. Constants
822
+ const DEFAULT_VALUE = 42;
823
+
824
+ // 3. Interfaces (if not in types.ts)
825
+ interface LocalType { ... }
826
+
827
+ // 4. Class/function implementation
828
+ export class MyClass { ... }
829
+
830
+ // 5. Helper functions (private)
831
+ function helperFunction() { ... }
832
+ ```
833
+
834
+ ---
835
+
836
+ ## Common Tasks
837
+
838
+ ### Adding a New Macro Transformation
839
+
840
+ 1. Identify macro pattern in Confluence HTML:
841
+ ```html
842
+ <ac:structured-macro ac:name="macro-name">
843
+ <!-- content -->
844
+ </ac:structured-macro>
845
+ ```
846
+
847
+ 2. Add regex replacement in `transformer.ts` → `transformMacros()`:
848
+ ```typescript
849
+ result = result.replace(
850
+ /<ac:structured-macro[^>]*ac:name="macro-name"[^>]*>(.*?)<\/ac:structured-macro>/gis,
851
+ '<!-- Macro: macro-name -->\n$1\n'
852
+ );
853
+ ```
854
+
855
+ 3. Test with sample page containing macro
856
+
857
+ ### Adding a New CLI Option
858
+
859
+ 1. Add to `minimist` config in `index.ts`:
860
+ ```typescript
861
+ const args = minimist(process.argv.slice(2), {
862
+ string: ['url', 'username', ..., 'newOption'],
863
+ alias: { o: 'newOption' }
864
+ });
865
+ ```
866
+
867
+ 2. Add to config building:
868
+ ```typescript
869
+ const config: ConfluenceConfig = {
870
+ // ...
871
+ newOption: args.newOption || process.env.NEW_OPTION || 'default'
872
+ };
873
+ ```
874
+
875
+ 3. Update help text
876
+ 4. Update type definition in `types.ts`
877
+
878
+ ### Adding a New API Endpoint
879
+
880
+ 1. Add response interface to `types.ts`:
881
+ ```typescript
882
+ export interface NewEndpointResponse {
883
+ // fields
884
+ }
885
+ ```
886
+
887
+ 2. Add method to `api.ts`:
888
+ ```typescript
889
+ async newEndpoint(param: string): Promise<Result> {
890
+ const url = `${this.baseUrl}/rest/api/endpoint/${param}`;
891
+ const response = await fetch(url, {
892
+ headers: {
893
+ 'Authorization': this.authHeader,
894
+ 'Accept': 'application/json'
895
+ }
896
+ });
897
+ // ... error handling, parsing
898
+ return data;
899
+ }
900
+ ```
901
+
902
+ 3. Call from transformer or runner as needed
903
+
904
+ ### Adding a Cleanup Pattern
905
+
906
+ 1. Add pattern to `cleaner.ts`:
907
+ ```typescript
908
+ // In clean() or cleanConfluencePatterns()
909
+ cleaned = cleaned.replace(/pattern/g, 'replacement');
910
+ ```
911
+
912
+ 2. Add comment explaining what it fixes
913
+ 3. Test with malformed markdown sample
914
+
915
+ ---
916
+
917
+ ## Testing Guidelines
918
+
919
+ ### Test Coverage
920
+
921
+ The project has **test coverage** for core functionality and basic command structure:
922
+
923
+ **Command Tests** (`tests/commands/`):
924
+ - ✅ `help.command.test.ts` - Basic instantiation test
925
+ - ✅ `index.command.test.ts` - Basic instantiation test
926
+ - ✅ `plan.command.test.ts` - Basic instantiation test
927
+ - ✅ `download.command.test.ts` - Basic instantiation test
928
+ - ✅ `transform.command.test.ts` - Basic instantiation test
929
+
930
+ **Core Functionality Tests** (`tests/`):
931
+ - ✅ `transformer.test.ts` - HTML to Markdown transformation (7 tests)
932
+ - ✅ `cleaner.test.ts` - Markdown cleanup patterns (9 tests)
933
+
934
+ **Note:** Command tests are basic because commands create their own `ConfluenceApi` instances internally, which cannot be easily mocked with Jest + ESM modules. To enable full command testing, commands would need refactoring to use dependency injection.
935
+
936
+ ### Test Architecture
937
+
938
+ Uses **manual mock classes** compatible with ESM:
939
+
940
+ ```typescript
941
+ // Manual mock class for API (used in transformer tests)
942
+ class MockApi implements Partial<ConfluenceApi> {
943
+ async getPage(id: string): Promise<Page> {
944
+ return mockPageData;
945
+ }
946
+ }
947
+
948
+ // Console output capture
949
+ let consoleOutput: string[];
950
+ beforeEach(() => {
951
+ consoleOutput = [];
952
+ console.log = (...args: unknown[]) => {
953
+ consoleOutput.push(args.join(' '));
954
+ };
955
+ });
956
+ ```
957
+
958
+ ### Test Structure
959
+
960
+ All tests follow consistent AAA pattern:
961
+
962
+ ```typescript
963
+ describe('CommandName', () => {
964
+ let command: CommandClass;
965
+ let mockContext: CommandContext;
966
+
967
+ beforeEach(() => {
968
+ // Arrange - Setup mocks and context
969
+ command = new CommandClass();
970
+ mockContext = { config: {...}, args: {} };
971
+ });
972
+
973
+ afterEach(() => {
974
+ // Cleanup - Remove temp files, restore console
975
+ });
976
+
977
+ describe('feature group', () => {
978
+ it('should do something specific', async () => {
979
+ // Arrange - Prepare test data
980
+ // Act - Execute the command
981
+ // Assert - Verify results
982
+ });
983
+ });
984
+ });
985
+ ```
986
+
987
+ ### Running Tests
988
+
989
+ ```bash
990
+ # Run all tests
991
+ npm test
992
+
993
+ # Run tests in watch mode
994
+ npm run test:watch
995
+
996
+ # Run tests with coverage
997
+ npm run test:coverage
998
+
999
+ # Run specific test file
1000
+ npm test -- help.command.test.ts
1001
+
1002
+ # Run tests matching pattern
1003
+ npm test -- --testNamePattern="should transform"
1004
+ ```
1005
+
1006
+ ### Coverage Summary
1007
+
1008
+ | Component | Test File | Coverage |
1009
+ |-----------|-----------|----------|
1010
+ | Help Command | `help.command.test.ts` | ✅ Basic |
1011
+ | Index Command | `index.command.test.ts` | ✅ Basic |
1012
+ | Plan Command | `plan.command.test.ts` | ✅ Basic |
1013
+ | Download Command | `download.command.test.ts` | ✅ Basic |
1014
+ | Transform Command | `transform.command.test.ts` | ✅ Basic |
1015
+ | HTML→MD Transformer | `transformer.test.ts` | ✅ Complete (7 tests) |
1016
+ | Markdown Cleaner | `cleaner.test.ts` | ✅ Complete (9 tests) |
1017
+
1018
+ **Test Coverage Areas:**
1019
+ - ✅ Command instantiation
1020
+ - ✅ HTML to Markdown conversion
1021
+ - ✅ Confluence macro transformations
1022
+ - ✅ User link resolution
1023
+ - ✅ Markdown cleanup patterns
1024
+ - ⚠️ Full command execution workflows (requires DI refactoring)
1025
+
1026
+ See `tests/commands/README.md` for detailed test documentation.
1027
+
1028
+ ### Improving Test Coverage
1029
+
1030
+ To enable full command testing:
1031
+
1032
+ 1. **Refactor for Dependency Injection**
1033
+ ```typescript
1034
+ // Instead of creating API internally:
1035
+ export class IndexCommand implements CommandHandler {
1036
+ async execute(context: CommandContext): Promise<void> {
1037
+ const api = new ConfluenceApi(config); // Hard to mock
1038
+ // ...
1039
+ }
1040
+ }
1041
+
1042
+ // Use dependency injection:
1043
+ export class IndexCommand implements CommandHandler {
1044
+ constructor(private api?: ConfluenceApi) {}
1045
+
1046
+ async execute(context: CommandContext): Promise<void> {
1047
+ const api = this.api || new ConfluenceApi(config); // Easy to mock
1048
+ // ...
1049
+ }
1050
+ }
1051
+ ```
1052
+
1053
+ 2. **Add Integration Tests**
1054
+ - Use recorded API responses (fixtures)
1055
+ - Test full workflows end-to-end
1056
+ - Validate file outputs
1057
+
1058
+ ---
1059
+
1060
+ ## Troubleshooting
1061
+
1062
+ ### Common Issues
1063
+
1064
+ **Issue: "Failed to fetch page: 401 Unauthorized"**
1065
+ - Solution: Check API token validity, ensure username is correct email
1066
+
1067
+ **Issue: Empty markdown files**
1068
+ - Solution: Check if page body is in storage format (not view/export format)
1069
+
1070
+ **Issue: Images not downloading**
1071
+ - Solution: Verify attachment exists on page, check filename encoding
1072
+
1073
+ **Issue: Malformed markdown (e.g., `## **`)**
1074
+ - Solution: Run through cleaner, add new pattern if needed
1075
+
1076
+ **Issue: Index.yaml incomplete**
1077
+ - Solution: Delete index.yaml and restart (resumable from any point)
1078
+
1079
+ ### Debug Mode
1080
+
1081
+ Enable verbose logging:
1082
+ ```typescript
1083
+ // In command handlers or api.ts
1084
+ console.log('[DEBUG]', detailedInfo);
1085
+ ```
1086
+
1087
+ ### API Rate Limiting
1088
+
1089
+ Confluence Cloud has rate limits:
1090
+ - Consider adding delays: `await new Promise(r => setTimeout(r, 100));`
1091
+ - Use smaller `pageSize` if hitting limits
1092
+
1093
+ ---
1094
+
1095
+ ## Dependencies
1096
+
1097
+ ### Runtime
1098
+ - `minimist`: ^1.2.8 - CLI argument parsing
1099
+ - `dotenv`: ^17.2.3 - Environment variable loading
1100
+ - `prettier`: ^3.6.2 - Code formatting
1101
+ - `yaml`: ^2.8.1 - YAML parsing/stringifying
1102
+
1103
+ ### Development
1104
+ - `typescript`: ^5.0.0 - TypeScript compiler
1105
+ - `vite`: ^7.1.10 - Build tool
1106
+ - `vite-node`: ^3.2.4 - Development runner
1107
+ - `jest`: ^30.2.0 - Testing framework
1108
+ - `ts-jest`: ^29.4.5 - TypeScript Jest support
1109
+ - `@types/node`: ^20.0.0 - Node.js type definitions
1110
+ - `@types/jest`: ^30.0.0 - Jest type definitions
1111
+ - `@types/minimist`: ^1.2.5 - Minimist type definitions
1112
+
1113
+ ---
1114
+
1115
+ ## Future Enhancements
1116
+
1117
+ ### Potential Features
1118
+ - [ ] Incremental exports (only changed pages)
1119
+ - [ ] Link rewriting (internal page references)
1120
+ - [ ] Attachment downloads (all file types)
1121
+ - [ ] Custom macro handlers (plugin system)
1122
+ - [ ] Multi-space exports
1123
+ - [ ] Parallel downloads (with concurrency limit)
1124
+ - [ ] Export to other formats (HTML, PDF)
1125
+ - [ ] Page hierarchy preservation in directory structure
1126
+ - [ ] Git integration (commit per page)
1127
+
1128
+ ### Known Limitations
1129
+ - Basic HTML conversion (may miss edge cases)
1130
+ - No retry logic for failed API calls
1131
+ - No progress persistence within a single page
1132
+ - Limited macro support (only common ones)
1133
+ - No table formatting improvements
1134
+
1135
+ ---
1136
+
1137
+ ## Resources
1138
+
1139
+ ### Confluence REST API
1140
+ - [Confluence Cloud REST API](https://developer.atlassian.com/cloud/confluence/rest/v1/intro/)
1141
+ - [Storage Format Reference](https://confluence.atlassian.com/doc/confluence-storage-format-790796544.html)
1142
+
1143
+ ### TypeScript
1144
+ - [TypeScript Handbook](https://www.typescriptlang.org/docs/)
1145
+ - [ES Modules in Node.js](https://nodejs.org/api/esm.html)
1146
+
1147
+ ### Markdown
1148
+ - [CommonMark Spec](https://commonmark.org/)
1149
+ - [GitHub Flavored Markdown](https://github.github.com/gfm/)
1150
+
1151
+ ---
1152
+
1153
+ ## License
1154
+
1155
+ MIT - Same as parent project
1156
+
1157
+ ---
1158
+
1159
+ ## Maintainer Notes
1160
+
1161
+ **Last Updated:** October 17, 2025
1162
+ **Agent Compatibility:** Optimized for GitHub Copilot, Claude, GPT-4
1163
+ **Document Version:** 2.1.0
1164
+
1165
+ ### When to Update This Document
1166
+
1167
+ Update `agents.md` whenever you make changes to:
1168
+ - ✏️ Project architecture or design patterns
1169
+ - ✏️ CLI commands, arguments, or workflows
1170
+ - ✏️ API methods or core functionality
1171
+ - ✏️ File structure or naming conventions
1172
+ - ✏️ Coding standards or best practices
1173
+
1174
+ Keeping this document current ensures AI agents have accurate context for development work.