confluence-cli 1.27.4 → 1.27.6

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.
@@ -197,16 +197,17 @@ confluence find "API Reference" --space MYSPACE
197
197
  Search pages using a keyword or CQL expression.
198
198
 
199
199
  ```sh
200
- confluence search <query> [--limit <number>]
200
+ confluence search <query> [--limit <number>] [--cql]
201
201
  ```
202
202
 
203
203
  | Option | Default | Description |
204
204
  |---|---|---|
205
205
  | `--limit` | `10` | Maximum number of results |
206
+ | `--cql` | false | Pass query as raw CQL instead of text search |
206
207
 
207
208
  ```sh
208
209
  confluence search "deployment pipeline"
209
- confluence search "type=page AND space=MYSPACE" --limit 50
210
+ confluence search --cql 'siteSearch ~ "deployment pipeline" and space = "MYSPACE"' --limit 50
210
211
  ```
211
212
 
212
213
  ---
@@ -697,7 +698,7 @@ confluence children 123456789 --recursive --format json | jq '.[].id'
697
698
  ### Search and process results
698
699
 
699
700
  ```sh
700
- confluence search "release notes" --limit 20
701
+ confluence search --cql 'siteSearch ~ "release notes" and space = "MYSPACE"' --limit 20
701
702
  ```
702
703
 
703
704
  ---
package/bin/confluence.js CHANGED
@@ -8,11 +8,6 @@ const { getConfig, initConfig, listProfiles, setActiveProfile, deleteProfile, is
8
8
  const Analytics = require('../lib/analytics');
9
9
  const pkg = require('../package.json');
10
10
 
11
- function buildPageUrl(config, path) {
12
- const protocol = config.protocol || 'https';
13
- return `${protocol}://${config.domain}${path}`;
14
- }
15
-
16
11
  function assertWritable(config) {
17
12
  if (config.readOnly) {
18
13
  console.error(chalk.red('Error: This profile is in read-only mode. Write operations are not allowed.'));
@@ -240,8 +235,8 @@ program
240
235
  console.log(`Title: ${chalk.blue(result.title)}`);
241
236
  console.log(`ID: ${chalk.blue(result.id)}`);
242
237
  console.log(`Space: ${chalk.blue(result.space.name)} (${result.space.key})`);
243
- console.log(`URL: ${chalk.gray(`${buildPageUrl(config, `/wiki${result._links.webui}`)}`)}`);
244
-
238
+ console.log(`URL: ${chalk.gray(`${client.buildUrl(`${client.webUrlPrefix}${result._links.webui}`)}`)}`);
239
+
245
240
  analytics.track('create', true);
246
241
  } catch (error) {
247
242
  analytics.track('create', false);
@@ -289,8 +284,8 @@ program
289
284
  console.log(`ID: ${chalk.blue(result.id)}`);
290
285
  console.log(`Parent: ${chalk.blue(parentInfo.title)} (${parentId})`);
291
286
  console.log(`Space: ${chalk.blue(result.space.name)} (${result.space.key})`);
292
- console.log(`URL: ${chalk.gray(`${buildPageUrl(config, `/wiki${result._links.webui}`)}`)}`);
293
-
287
+ console.log(`URL: ${chalk.gray(`${client.buildUrl(`${client.webUrlPrefix}${result._links.webui}`)}`)}`);
288
+
294
289
  analytics.track('create_child', true);
295
290
  } catch (error) {
296
291
  analytics.track('create_child', false);
@@ -337,8 +332,8 @@ program
337
332
  console.log(`Title: ${chalk.blue(result.title)}`);
338
333
  console.log(`ID: ${chalk.blue(result.id)}`);
339
334
  console.log(`Version: ${chalk.blue(result.version.number)}`);
340
- console.log(`URL: ${chalk.gray(`${buildPageUrl(config, `/wiki${result._links.webui}`)}`)}`);
341
-
335
+ console.log(`URL: ${chalk.gray(`${client.buildUrl(`${client.webUrlPrefix}${result._links.webui}`)}`)}`);
336
+
342
337
  analytics.track('update', true);
343
338
  } catch (error) {
344
339
  analytics.track('update', false);
@@ -365,7 +360,7 @@ program
365
360
  console.log(`ID: ${chalk.blue(result.id)}`);
366
361
  console.log(`New Parent: ${chalk.blue(newParentId)}`);
367
362
  console.log(`Version: ${chalk.blue(result.version.number)}`);
368
- console.log(`URL: ${chalk.gray(`${buildPageUrl(config, `/wiki${result._links.webui}`)}`)}`);
363
+ console.log(`URL: ${chalk.gray(`${client.buildUrl(`${client.webUrlPrefix}${result._links.webui}`)}`)}`);
369
364
 
370
365
  analytics.track('move', true);
371
366
  } catch (error) {
@@ -473,8 +468,8 @@ program
473
468
  console.log(`Title: ${chalk.green(pageInfo.title)}`);
474
469
  console.log(`ID: ${chalk.green(pageInfo.id)}`);
475
470
  console.log(`Space: ${chalk.green(pageInfo.space.name)} (${pageInfo.space.key})`);
476
- console.log(`URL: ${chalk.gray(`${buildPageUrl(config, `/wiki${pageInfo.url}`)}`)}`);
477
-
471
+ console.log(`URL: ${chalk.gray(`${client.buildUrl(`${client.webUrlPrefix}${pageInfo.url}`)}`)}`);
472
+
478
473
  analytics.track('find', true);
479
474
  } catch (error) {
480
475
  analytics.track('find', false);
@@ -1713,7 +1708,7 @@ program
1713
1708
  console.log(` - ...and ${result.failures.length - 10} more`);
1714
1709
  }
1715
1710
  }
1716
- console.log(`URL: ${chalk.gray(`${buildPageUrl(config, `/wiki${result.rootPage._links.webui}`)}`)}`);
1711
+ console.log(`URL: ${chalk.gray(`${client.buildUrl(`${client.webUrlPrefix}${result.rootPage._links.webui}`)}`)}`);
1717
1712
  if (options.failOnError && result.failures?.length) {
1718
1713
  analytics.track('copy_tree', false);
1719
1714
  console.error(chalk.red('Completed with failures and --fail-on-error is set.'));
@@ -1775,7 +1770,7 @@ program
1775
1770
  type: page.type,
1776
1771
  status: page.status,
1777
1772
  spaceKey: page.space?.key,
1778
- url: `${buildPageUrl(config, `/wiki/spaces/${page.space?.key}/pages/${page.id}`)}`,
1773
+ url: `${client.buildUrl(`${client.webUrlPrefix}/spaces/${page.space?.key}/pages/${page.id}`)}`,
1779
1774
  parentId: page.parentId || resolvedPageId
1780
1775
  }))
1781
1776
  };
@@ -1787,7 +1782,7 @@ program
1787
1782
 
1788
1783
  // Build tree structure
1789
1784
  const tree = buildTree(children, resolvedPageId);
1790
- printTree(tree, config, options, 1);
1785
+ printTree(tree, client, config, options, 1);
1791
1786
 
1792
1787
  console.log('');
1793
1788
  console.log(chalk.gray(`Total: ${children.length} child page${children.length === 1 ? '' : 's'}`));
@@ -1804,7 +1799,7 @@ program
1804
1799
  }
1805
1800
 
1806
1801
  if (options.showUrl) {
1807
- const url = `${buildPageUrl(config, `/wiki/spaces/${page.space?.key}/pages/${page.id}`)}`;
1802
+ const url = `${client.buildUrl(`${client.webUrlPrefix}/spaces/${page.space?.key}/pages/${page.id}`)}`;
1808
1803
  output += `\n ${chalk.gray(url)}`;
1809
1804
  }
1810
1805
 
@@ -1856,7 +1851,7 @@ function buildTree(pages, rootId) {
1856
1851
  }
1857
1852
 
1858
1853
  // Helper function to print tree
1859
- function printTree(nodes, config, options, depth = 1) {
1854
+ function printTree(nodes, client, config, options, depth = 1) {
1860
1855
  nodes.forEach((node, index) => {
1861
1856
  const isLast = index === nodes.length - 1;
1862
1857
  const indent = ' '.repeat(depth - 1);
@@ -1869,14 +1864,14 @@ function printTree(nodes, config, options, depth = 1) {
1869
1864
  }
1870
1865
 
1871
1866
  if (options.showUrl) {
1872
- const url = `${buildPageUrl(config, `/wiki/spaces/${node.space?.key}/pages/${node.id}`)}`;
1867
+ const url = `${client.buildUrl(`${client.webUrlPrefix}/spaces/${node.space?.key}/pages/${node.id}`)}`;
1873
1868
  output += `\n${indent}${isLast ? ' ' : '│ '}${chalk.gray(url)}`;
1874
1869
  }
1875
1870
 
1876
1871
  console.log(output);
1877
-
1872
+
1878
1873
  if (node.children && node.children.length > 0) {
1879
- printTree(node.children, config, options, depth + 1);
1874
+ printTree(node.children, client, config, options, depth + 1);
1880
1875
  }
1881
1876
  });
1882
1877
  }
@@ -35,6 +35,7 @@ class ConfluenceClient {
35
35
  this.email = config.email;
36
36
  this.authType = (config.authType || (this.email ? 'basic' : 'bearer')).toLowerCase();
37
37
  this.apiPath = this.sanitizeApiPath(config.apiPath);
38
+ this.webUrlPrefix = this.apiPath.startsWith('/wiki/') ? '/wiki' : '';
38
39
  this.baseURL = `${this.protocol}://${this.domain}${this.apiPath}`;
39
40
  this.markdown = new MarkdownIt();
40
41
  this.setupConfluenceMarkdownExtensions();
@@ -412,7 +413,7 @@ class ConfluenceClient {
412
413
  const webui = page._links?.webui || '';
413
414
  return {
414
415
  title: page.title,
415
- url: webui ? this.buildUrl(`/wiki${webui}`) : ''
416
+ url: webui ? this.buildUrl(`${this.webUrlPrefix}${webui}`) : ''
416
417
  };
417
418
  }
418
419
  return null;
@@ -506,7 +507,7 @@ class ConfluenceClient {
506
507
  // Format: - [Page Title](URL)
507
508
  const childPagesList = childPages.map(page => {
508
509
  const webui = page._links?.webui || '';
509
- const url = webui ? this.buildUrl(`/wiki${webui}`) : '';
510
+ const url = webui ? this.buildUrl(`${this.webUrlPrefix}${webui}`) : '';
510
511
  if (url) {
511
512
  return `- [${page.title}](${url})`;
512
513
  } else {
@@ -1073,10 +1074,11 @@ class ConfluenceClient {
1073
1074
  // so they appear as literal characters in the CDATA output
1074
1075
  const decodedCode = code.replace(/\n$/, '')
1075
1076
  .replace(/&quot;/g, '"')
1076
- .replace(/&amp;/g, '&')
1077
1077
  .replace(/&lt;/g, '<')
1078
- .replace(/&gt;/g, '>');
1079
- return `<ac:structured-macro ac:name="code"><ac:parameter ac:name="language">${language}</ac:parameter><ac:plain-text-body><![CDATA[${decodedCode}]]></ac:plain-text-body></ac:structured-macro>`;
1078
+ .replace(/&gt;/g, '>')
1079
+ .replace(/&amp;/g, '&'); // & last to avoid double-decoding
1080
+ const safeCode = decodedCode.replace(/]]>/g, ']]]]><![CDATA[>');
1081
+ return `<ac:structured-macro ac:name="code"><ac:parameter ac:name="language">${language}</ac:parameter><ac:plain-text-body><![CDATA[${safeCode}]]></ac:plain-text-body></ac:structured-macro>`;
1080
1082
  });
1081
1083
 
1082
1084
  // Convert inline code
@@ -1351,11 +1353,11 @@ class ConfluenceClient {
1351
1353
  // Try to build a proper URL - if spaceKey starts with ~, it's a user space
1352
1354
  if (spaceKey.startsWith('~')) {
1353
1355
  const spacePath = `display/${spaceKey}/${encodeURIComponent(title)}`;
1354
- return `\n> 📄 **${labels.includePage}**: [${title}](${this.buildUrl(`/wiki/${spacePath}`)})\n`;
1356
+ return `\n> 📄 **${labels.includePage}**: [${title}](${this.buildUrl(`${this.webUrlPrefix}/${spacePath}`)})\n`;
1355
1357
  } else {
1356
1358
  // For non-user spaces, we cannot construct a valid link without the page ID.
1357
1359
  // Document that manual correction is required.
1358
- return `\n> 📄 **${labels.includePage}**: [${title}](${this.buildUrl(`/wiki/spaces/${spaceKey}/pages/[PAGE_ID_HERE]`)}) _(manual link correction required)_\n`;
1360
+ return `\n> 📄 **${labels.includePage}**: [${title}](${this.buildUrl(`${this.webUrlPrefix}/spaces/${spaceKey}/pages/[PAGE_ID_HERE]`)}) _(manual link correction required)_\n`;
1359
1361
  }
1360
1362
  });
1361
1363
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "confluence-cli",
3
- "version": "1.27.4",
3
+ "version": "1.27.6",
4
4
  "description": "A command-line interface for Atlassian Confluence with page creation and editing capabilities",
5
5
  "main": "index.js",
6
6
  "bin": {