confluence-cli 1.31.0 → 1.32.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.
package/README.md CHANGED
@@ -304,6 +304,9 @@ For **read-only** usage, select at minimum: `read:confluence-content.all`, `read
304
304
  # Read by page ID
305
305
  confluence read 123456789
306
306
 
307
+ # Read native Confluence storage content
308
+ confluence read 123456789 --format storage
309
+
307
310
  # Read in markdown format
308
311
  confluence read 123456789 --format markdown
309
312
 
@@ -311,9 +314,28 @@ confluence read 123456789 --format markdown
311
314
  confluence read "https://your-domain.atlassian.net/wiki/viewpage.action?pageId=123456789"
312
315
  ```
313
316
 
317
+ Use `--format storage` when you need Confluence's native storage representation, especially for macros and other Confluence-specific markup.
318
+
314
319
  ### Get Page Information
315
320
  ```bash
316
321
  confluence info 123456789
322
+
323
+ # Emit machine-readable metadata
324
+ confluence info 123456789 --format json
325
+ ```
326
+
327
+ Example JSON shape:
328
+ ```json
329
+ {
330
+ "id": "123456789",
331
+ "title": "Architecture Overview",
332
+ "type": "page",
333
+ "status": "current",
334
+ "spaceKey": "ENG",
335
+ "parentId": "100200300",
336
+ "version": 7,
337
+ "url": "https://your-domain.atlassian.net/wiki/spaces/ENG/pages/123456789/Architecture+Overview"
338
+ }
317
339
  ```
318
340
 
319
341
  ### Search Pages
@@ -444,6 +466,36 @@ confluence children 123456789 --recursive --max-depth 3
444
466
  confluence children 123456789 --recursive --format json > children.json
445
467
  ```
446
468
 
469
+ `children --format json` returns structured metadata for each page, including `id`, `title`, `type`, `status`, `spaceKey`, `parentId`, `version`, and `url`. Recursive output also includes `depth`, and when available, `ancestors`.
470
+
471
+ Example recursive JSON item:
472
+ ```json
473
+ {
474
+ "pageId": "123456789",
475
+ "childCount": 2,
476
+ "children": [
477
+ {
478
+ "id": "200300400",
479
+ "title": "Child Page",
480
+ "type": "page",
481
+ "status": "current",
482
+ "spaceKey": "ENG",
483
+ "parentId": "123456789",
484
+ "version": 4,
485
+ "url": "https://your-domain.atlassian.net/wiki/spaces/ENG/pages/200300400/Child+Page",
486
+ "depth": 1,
487
+ "ancestors": [
488
+ {
489
+ "id": "123456789",
490
+ "type": "page",
491
+ "title": "Architecture Overview"
492
+ }
493
+ ]
494
+ }
495
+ ]
496
+ }
497
+ ```
498
+
447
499
  ### Find a Page by Title
448
500
  ```bash
449
501
  # Find page by title
@@ -612,8 +664,8 @@ confluence stats
612
664
  | Command | Description | Options |
613
665
  |---|---|---|
614
666
  | `init` | Initialize CLI configuration | `--read-only` |
615
- | `read <pageId_or_url>` | Read page content | `--format <html\|text\|markdown>` |
616
- | `info <pageId_or_url>` | Get page information | |
667
+ | `read <pageId_or_url>` | Read page content | `--format <html\|text\|storage\|markdown>` |
668
+ | `info <pageId_or_url>` | Get page information | `--format <text\|json>` |
617
669
  | `search <query>` | Search for pages | `--limit <number>` |
618
670
  | `spaces` | List all available spaces | |
619
671
  | `find <title>` | Find a page by its title | `--space <spaceKey>` |
package/bin/confluence.js CHANGED
@@ -63,7 +63,7 @@ program
63
63
  program
64
64
  .command('read <pageId>')
65
65
  .description('Read a Confluence page by ID or URL')
66
- .option('-f, --format <format>', 'Output format (html, text, markdown)', 'text')
66
+ .option('-f, --format <format>', 'Output format (html, text, storage, markdown)', 'text')
67
67
  .action(async (pageId, options) => {
68
68
  const analytics = new Analytics();
69
69
  try {
@@ -80,18 +80,24 @@ program
80
80
  program
81
81
  .command('info <pageId>')
82
82
  .description('Get information about a Confluence page')
83
- .action(async (pageId) => {
83
+ .option('-f, --format <format>', 'Output format (text, json)', 'text')
84
+ .action(async (pageId, options) => {
84
85
  const analytics = new Analytics();
85
86
  try {
86
87
  const client = new ConfluenceClient(getConfig(getProfileName()));
87
88
  const info = await client.getPageInfo(pageId);
88
- console.log(chalk.blue('Page Information:'));
89
- console.log(`Title: ${chalk.green(info.title)}`);
90
- console.log(`ID: ${chalk.green(info.id)}`);
91
- console.log(`Type: ${chalk.green(info.type)}`);
92
- console.log(`Status: ${chalk.green(info.status)}`);
93
- if (info.space) {
94
- console.log(`Space: ${chalk.green(info.space.name)} (${info.space.key})`);
89
+
90
+ if ((options.format || 'text').toLowerCase() === 'json') {
91
+ console.log(JSON.stringify(info, null, 2));
92
+ } else {
93
+ console.log(chalk.blue('Page Information:'));
94
+ console.log(`Title: ${chalk.green(info.title)}`);
95
+ console.log(`ID: ${chalk.green(info.id)}`);
96
+ console.log(`Type: ${chalk.green(info.type)}`);
97
+ console.log(`Status: ${chalk.green(info.status)}`);
98
+ if (info.space) {
99
+ console.log(`Space: ${chalk.green(info.space.name)} (${info.space.key})`);
100
+ }
95
101
  }
96
102
  analytics.track('info', true);
97
103
  } catch (error) {
@@ -1739,6 +1745,7 @@ program
1739
1745
  try {
1740
1746
  const config = getConfig(getProfileName());
1741
1747
  const client = new ConfluenceClient(config);
1748
+ const format = (options.format || 'list').toLowerCase();
1742
1749
 
1743
1750
  // Extract page ID from URL if needed
1744
1751
  const resolvedPageId = await client.extractPageId(pageId);
@@ -1747,34 +1754,56 @@ program
1747
1754
  let children;
1748
1755
  if (options.recursive) {
1749
1756
  const maxDepth = parseInt(options.maxDepth) || 10;
1750
- children = await client.getAllDescendantPages(resolvedPageId, maxDepth);
1757
+ children = await client.getAllDescendantPages(
1758
+ resolvedPageId,
1759
+ maxDepth,
1760
+ { includeAncestors: format === 'json' }
1761
+ );
1751
1762
  } else {
1752
1763
  children = await client.getChildPages(resolvedPageId);
1753
1764
  }
1754
1765
 
1755
1766
  if (children.length === 0) {
1756
- console.log(chalk.yellow('No child pages found.'));
1767
+ if (format === 'json') {
1768
+ console.log(JSON.stringify({
1769
+ pageId: String(resolvedPageId),
1770
+ childCount: 0,
1771
+ children: []
1772
+ }, null, 2));
1773
+ } else {
1774
+ console.log(chalk.yellow('No child pages found.'));
1775
+ }
1757
1776
  analytics.track('children', true);
1758
1777
  return;
1759
1778
  }
1760
1779
 
1761
- // Format output
1762
- const format = options.format.toLowerCase();
1763
-
1764
1780
  if (format === 'json') {
1765
1781
  // JSON output
1766
1782
  const output = {
1767
- pageId: resolvedPageId,
1783
+ pageId: String(resolvedPageId),
1768
1784
  childCount: children.length,
1769
- children: children.map(page => ({
1770
- id: page.id,
1771
- title: page.title,
1772
- type: page.type,
1773
- status: page.status,
1774
- spaceKey: page.space?.key,
1775
- url: `${client.buildUrl(`${client.webUrlPrefix}/spaces/${page.space?.key}/pages/${page.id}`)}`,
1776
- parentId: page.parentId || resolvedPageId
1777
- }))
1785
+ children: children.map(page => {
1786
+ const record = {
1787
+ id: page.id,
1788
+ title: page.title,
1789
+ type: page.type,
1790
+ status: page.status,
1791
+ spaceKey: page.spaceKey || page.space?.key || null,
1792
+ parentId: page.parentId || String(resolvedPageId),
1793
+ version: page.version ?? null,
1794
+ url: page.url || null
1795
+ };
1796
+
1797
+ if (options.recursive && page.depth !== undefined) {
1798
+ record.depth = page.depth;
1799
+ }
1800
+
1801
+ if (options.recursive && Array.isArray(page.ancestors) && page.ancestors.length > 0) {
1802
+ record.ancestors = page.ancestors;
1803
+ }
1804
+
1805
+ return record;
1806
+ })
1778
1807
  };
1779
1808
  console.log(JSON.stringify(output, null, 2));
1780
1809
  } else if (format === 'tree' && options.recursive) {