@bestend/confluence-cli 1.16.0 → 1.16.2

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.
@@ -35,4 +35,4 @@ jobs:
35
35
  run: npm ci
36
36
 
37
37
  - name: Publish with provenance via OIDC
38
- run: npm publish --provenance --access public
38
+ run: npm publish --provenance --access public --tag latest
package/bin/confluence.js CHANGED
@@ -194,8 +194,8 @@ program
194
194
  console.log(`ID: ${chalk.blue(result.id)}`);
195
195
  }
196
196
  console.log(`Space: ${chalk.blue(result.space.name)} (${result.space.key})`);
197
- console.log(`URL: ${chalk.gray(`https://${config.domain}/wiki${result._links.webui}`)}`);
198
-
197
+ console.log(`URL: ${chalk.gray(client.pageUrl(result._links.webui))}`);
198
+
199
199
  analytics.track('create', true);
200
200
  } catch (error) {
201
201
  analytics.track('create', false);
@@ -249,8 +249,8 @@ program
249
249
  console.log(`ID: ${chalk.blue(result.id)}`);
250
250
  console.log(`Parent: ${chalk.blue(parentInfo.title)} (${parentId})`);
251
251
  console.log(`Space: ${chalk.blue(result.space.name)} (${result.space.key})`);
252
- console.log(`URL: ${chalk.gray(`https://${config.domain}/wiki${result._links.webui}`)}`);
253
-
252
+ console.log(`URL: ${chalk.gray(client.pageUrl(result._links.webui))}`);
253
+
254
254
  analytics.track('create_child', true);
255
255
  } catch (error) {
256
256
  analytics.track('create_child', false);
@@ -301,8 +301,8 @@ program
301
301
  console.log(`Title: ${chalk.blue(result.title)}`);
302
302
  console.log(`ID: ${chalk.blue(result.id)}`);
303
303
  console.log(`Version: ${chalk.blue(result.version.number)}`);
304
- console.log(`URL: ${chalk.gray(`https://${config.domain}/wiki${result._links.webui}`)}`);
305
-
304
+ console.log(`URL: ${chalk.gray(client.pageUrl(result._links.webui))}`);
305
+
306
306
  analytics.track('update', true);
307
307
  } catch (error) {
308
308
  analytics.track('update', false);
@@ -407,8 +407,8 @@ program
407
407
  console.log(`Title: ${chalk.green(pageInfo.title)}`);
408
408
  console.log(`ID: ${chalk.green(pageInfo.id)}`);
409
409
  console.log(`Space: ${chalk.green(pageInfo.space.name)} (${pageInfo.space.key})`);
410
- console.log(`URL: ${chalk.gray(`https://${config.domain}/wiki${pageInfo.url}`)}`);
411
-
410
+ console.log(`URL: ${chalk.gray(client.pageUrl(pageInfo.url))}`);
411
+
412
412
  analytics.track('find', true);
413
413
  } catch (error) {
414
414
  analytics.track('find', false);
@@ -1084,7 +1084,7 @@ program
1084
1084
  console.log(` - ...and ${result.failures.length - 10} more`);
1085
1085
  }
1086
1086
  }
1087
- console.log(`URL: ${chalk.gray(`https://${config.domain}/wiki${result.rootPage._links.webui}`)}`);
1087
+ console.log(`URL: ${chalk.gray(client.pageUrl(result.rootPage._links.webui))}`);
1088
1088
  if (options.failOnError && result.failures?.length) {
1089
1089
  analytics.track('copy_tree', false);
1090
1090
  console.error(chalk.red('Completed with failures and --fail-on-error is set.'));
@@ -1146,7 +1146,7 @@ program
1146
1146
  type: page.type,
1147
1147
  status: page.status,
1148
1148
  spaceKey: page.space?.key,
1149
- url: `https://${config.domain}/wiki/spaces/${page.space?.key}/pages/${page.id}`,
1149
+ url: client.pageUrl(`/spaces/${page.space?.key}/pages/${page.id}`),
1150
1150
  parentId: page.parentId || resolvedPageId
1151
1151
  }))
1152
1152
  };
@@ -1158,7 +1158,7 @@ program
1158
1158
 
1159
1159
  // Build tree structure
1160
1160
  const tree = buildTree(children, resolvedPageId);
1161
- printTree(tree, config, options, 1);
1161
+ printTree(tree, client, options, 1);
1162
1162
 
1163
1163
  console.log('');
1164
1164
  console.log(chalk.gray(`Total: ${children.length} child page${children.length === 1 ? '' : 's'}`));
@@ -1175,7 +1175,7 @@ program
1175
1175
  }
1176
1176
 
1177
1177
  if (options.showUrl) {
1178
- const url = `https://${config.domain}/wiki/spaces/${page.space?.key}/pages/${page.id}`;
1178
+ const url = client.pageUrl(`/spaces/${page.space?.key}/pages/${page.id}`);
1179
1179
  output += `\n ${chalk.gray(url)}`;
1180
1180
  }
1181
1181
 
@@ -1227,27 +1227,27 @@ function buildTree(pages, rootId) {
1227
1227
  }
1228
1228
 
1229
1229
  // Helper function to print tree
1230
- function printTree(nodes, config, options, depth = 1) {
1230
+ function printTree(nodes, client, options, depth = 1) {
1231
1231
  nodes.forEach((node, index) => {
1232
1232
  const isLast = index === nodes.length - 1;
1233
1233
  const indent = ' '.repeat(depth - 1);
1234
1234
  const prefix = isLast ? '└── ' : '├── ';
1235
-
1235
+
1236
1236
  let output = `${indent}${prefix}📄 ${chalk.green(node.title)}`;
1237
-
1237
+
1238
1238
  if (options.showId) {
1239
1239
  output += ` ${chalk.gray(`(ID: ${node.id})`)}`;
1240
1240
  }
1241
-
1241
+
1242
1242
  if (options.showUrl) {
1243
- const url = `https://${config.domain}/wiki/spaces/${node.space?.key}/pages/${node.id}`;
1243
+ const url = client.pageUrl(`/spaces/${node.space?.key}/pages/${node.id}`);
1244
1244
  output += `\n${indent}${isLast ? ' ' : '│ '}${chalk.gray(url)}`;
1245
1245
  }
1246
-
1246
+
1247
1247
  console.log(output);
1248
-
1248
+
1249
1249
  if (node.children && node.children.length > 0) {
1250
- printTree(node.children, config, options, depth + 1);
1250
+ printTree(node.children, client, options, depth + 1);
1251
1251
  }
1252
1252
  });
1253
1253
  }
@@ -23,6 +23,25 @@ class ConfluenceClient {
23
23
  baseURL: this.baseURL,
24
24
  headers
25
25
  });
26
+
27
+ // Auto-detect context path (e.g., "/wiki" or "") from first API response
28
+ this._contextPath = null;
29
+ this.client.interceptors.response.use((response) => {
30
+ if (this._contextPath === null && response.data?._links?.context !== undefined) {
31
+ this._contextPath = response.data._links.context;
32
+ }
33
+ return response;
34
+ });
35
+ }
36
+
37
+ /**
38
+ * Build a full page URL from a webui path (e.g., /spaces/SPACE/pages/123)
39
+ * Context path is auto-detected from API responses.
40
+ */
41
+ pageUrl(path) {
42
+ if (!path) return '';
43
+ const context = this._contextPath || '';
44
+ return `https://${this.domain}${context}${path}`;
26
45
  }
27
46
 
28
47
  sanitizeStorageContent(content, options = {}) {
@@ -373,7 +392,7 @@ class ConfluenceClient {
373
392
  const webui = page._links?.webui || '';
374
393
  return {
375
394
  title: page.title,
376
- url: webui ? `https://${this.domain}/wiki${webui}` : ''
395
+ url: this.pageUrl(webui)
377
396
  };
378
397
  }
379
398
  return null;
@@ -467,7 +486,7 @@ class ConfluenceClient {
467
486
  // Format: - [Page Title](URL)
468
487
  const childPagesList = childPages.map(page => {
469
488
  const webui = page._links?.webui || '';
470
- const url = webui ? `https://${this.domain}/wiki${webui}` : '';
489
+ const url = this.pageUrl(webui);
471
490
  if (url) {
472
491
  return `- [${page.title}](${url})`;
473
492
  } else {
@@ -859,7 +878,7 @@ class ConfluenceClient {
859
878
  // - pre/code → ac:structured-macro code blocks with CDATA
860
879
  // - blockquote → info/warning/note macros
861
880
  // - th/td content wrapped in p
862
- // - hr → self-closing hr /
881
+ // - hr → removed (Confluence does not use horizontal rules)
863
882
  let storage = html;
864
883
 
865
884
  // Wrap li content in p tags (Confluence requirement)
@@ -915,8 +934,8 @@ class ConfluenceClient {
915
934
 
916
935
  // Links: keep <a href> as-is (compatible with both Cloud and Server/Data Center)
917
936
 
918
- // Convert horizontal rules
919
- storage = storage.replace(/<hr\s*\/?>/g, '<hr />');
937
+ // Remove horizontal rules (Confluence does not use them)
938
+ storage = storage.replace(/<hr\s*\/?>/g, '');
920
939
 
921
940
  return storage;
922
941
  }
@@ -1135,12 +1154,12 @@ class ConfluenceClient {
1135
1154
  markdown = markdown.replace(/<ac:structured-macro ac:name="include"[^>]*>[\s\S]*?<ac:parameter ac:name="">[\s\S]*?<ac:link>[\s\S]*?<ri:page\s+ri:space-key="([^"]+)"\s+ri:content-title="([^"]+)"[^>]*\/>[\s\S]*?<\/ac:link>[\s\S]*?<\/ac:parameter>[\s\S]*?<\/ac:structured-macro>/g, (_, spaceKey, title) => {
1136
1155
  // Try to build a proper URL - if spaceKey starts with ~, it's a user space
1137
1156
  if (spaceKey.startsWith('~')) {
1138
- const spacePath = `display/${spaceKey}/${encodeURIComponent(title)}`;
1139
- return `\n> 📄 **${labels.includePage}**: [${title}](https://${this.domain}/wiki/${spacePath})\n`;
1157
+ const spacePath = `/display/${spaceKey}/${encodeURIComponent(title)}`;
1158
+ return `\n> 📄 **${labels.includePage}**: [${title}](${this.pageUrl(spacePath)})\n`;
1140
1159
  } else {
1141
1160
  // For non-user spaces, we cannot construct a valid link without the page ID.
1142
1161
  // Document that manual correction is required.
1143
- return `\n> 📄 **${labels.includePage}**: [${title}](https://${this.domain}/wiki/spaces/${spaceKey}/pages/[PAGE_ID_HERE]) _(manual link correction required)_\n`;
1162
+ return `\n> 📄 **${labels.includePage}**: [${title}](${this.pageUrl(`/spaces/${spaceKey}/pages/[PAGE_ID_HERE]`)}) _(manual link correction required)_\n`;
1144
1163
  }
1145
1164
  });
1146
1165
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bestend/confluence-cli",
3
- "version": "1.16.0",
3
+ "version": "1.16.2",
4
4
  "description": "A command-line interface for Atlassian Confluence with page creation and editing capabilities",
5
5
  "main": "index.js",
6
6
  "bin": {