confluence-cli 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.
package/.eslintrc.js ADDED
@@ -0,0 +1,23 @@
1
+ module.exports = {
2
+ env: {
3
+ es2021: true,
4
+ node: true,
5
+ jest: true
6
+ },
7
+ extends: [
8
+ 'eslint:recommended'
9
+ ],
10
+ parserOptions: {
11
+ ecmaVersion: 12,
12
+ sourceType: 'module'
13
+ },
14
+ rules: {
15
+ 'indent': ['error', 2],
16
+ 'linebreak-style': ['error', 'unix'],
17
+ 'quotes': ['error', 'single'],
18
+ 'semi': ['error', 'always'],
19
+ 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
20
+ 'no-console': 'off',
21
+ 'no-process-exit': 'off'
22
+ }
23
+ };
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: '[BUG] '
5
+ labels: bug
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Describe the bug**
11
+ A clear and concise description of what the bug is.
12
+
13
+ **To Reproduce**
14
+ Steps to reproduce the behavior:
15
+ 1. Run command '...'
16
+ 2. See error
17
+
18
+ **Expected behavior**
19
+ A clear and concise description of what you expected to happen.
20
+
21
+ **Screenshots**
22
+ If applicable, add screenshots to help explain your problem.
23
+
24
+ **Environment (please complete the following information):**
25
+ - OS: [e.g. macOS, Windows, Linux]
26
+ - Node.js version: [e.g. 18.17.0]
27
+ - confluence-cli version: [e.g. 1.0.0]
28
+ - Confluence version: [e.g. Cloud, Server 8.5]
29
+
30
+ **Additional context**
31
+ Add any other context about the problem here.
32
+
33
+ **Error logs**
34
+ If applicable, add error logs or stack traces.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest an idea for this project
4
+ title: '[FEATURE] '
5
+ labels: enhancement
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ **Is your feature request related to a problem? Please describe.**
11
+ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12
+
13
+ **Describe the solution you'd like**
14
+ A clear and concise description of what you want to happen.
15
+
16
+ **Describe alternatives you've considered**
17
+ A clear and concise description of any alternative solutions or features you've considered.
18
+
19
+ **Use case**
20
+ Describe how this feature would be used and who would benefit from it.
21
+
22
+ **Additional context**
23
+ Add any other context or screenshots about the feature request here.
24
+
25
+ **Implementation suggestions**
26
+ If you have ideas about how this could be implemented, please share them here.
@@ -0,0 +1,31 @@
1
+ ## Pull Request Template
2
+
3
+ ### Description
4
+ Brief description of what this PR does.
5
+
6
+ ### Type of Change
7
+ - [ ] Bug fix (non-breaking change which fixes an issue)
8
+ - [ ] New feature (non-breaking change which adds functionality)
9
+ - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
10
+ - [ ] Documentation update
11
+ - [ ] Performance improvement
12
+ - [ ] Code refactoring
13
+
14
+ ### Testing
15
+ - [ ] Tests pass locally with my changes
16
+ - [ ] I have added tests that prove my fix is effective or that my feature works
17
+ - [ ] New and existing unit tests pass locally with my changes
18
+
19
+ ### Checklist
20
+ - [ ] My code follows the style guidelines of this project
21
+ - [ ] I have performed a self-review of my own code
22
+ - [ ] I have commented my code, particularly in hard-to-understand areas
23
+ - [ ] I have made corresponding changes to the documentation
24
+ - [ ] My changes generate no new warnings
25
+ - [ ] Any dependent changes have been merged and published in downstream modules
26
+
27
+ ### Screenshots (if applicable)
28
+ Add screenshots to help explain your changes.
29
+
30
+ ### Additional Context
31
+ Add any other context about the pull request here.
@@ -0,0 +1,58 @@
1
+ name: CI/CD
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, develop ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ matrix:
15
+ node-version: [16.x, 18.x, 20.x]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v3
19
+
20
+ - name: Use Node.js ${{ matrix.node-version }}
21
+ uses: actions/setup-node@v3
22
+ with:
23
+ node-version: ${{ matrix.node-version }}
24
+ cache: 'npm'
25
+
26
+ - run: npm ci
27
+ - run: npm run lint
28
+ - run: npm test
29
+
30
+ security:
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v3
34
+ - name: Run npm audit
35
+ run: npm audit --audit-level moderate
36
+
37
+ publish:
38
+ needs: [test, security]
39
+ runs-on: ubuntu-latest
40
+ if: github.ref == 'refs/heads/main'
41
+
42
+ steps:
43
+ - uses: actions/checkout@v3
44
+
45
+ - name: Setup Node.js
46
+ uses: actions/setup-node@v3
47
+ with:
48
+ node-version: '18'
49
+ registry-url: 'https://registry.npmjs.org'
50
+
51
+ - run: npm ci
52
+ - run: npm test
53
+
54
+ - name: Semantic Release
55
+ uses: cycjimmy/semantic-release-action@v3
56
+ env:
57
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
58
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
package/.releaserc ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "branches": ["main"],
3
+ "plugins": [
4
+ "@semantic-release/commit-analyzer",
5
+ "@semantic-release/release-notes-generator",
6
+ "@semantic-release/changelog",
7
+ "@semantic-release/npm",
8
+ "@semantic-release/github",
9
+ [
10
+ "@semantic-release/git",
11
+ {
12
+ "assets": ["package.json", "CHANGELOG.md"],
13
+ "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
14
+ }
15
+ ]
16
+ ]
17
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ # Confluence CLI Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2025-06-26
9
+
10
+ ### Added
11
+ - Initial release of Confluence CLI
12
+ - Read Confluence pages by ID or URL
13
+ - Search functionality with customizable limits
14
+ - Page information display
15
+ - List all Confluence spaces
16
+ - Interactive configuration setup
17
+ - Environment variable support
18
+ - HTML and text output formats
19
+ - Comprehensive README with examples
20
+ - MIT License
21
+
22
+ ### Features
23
+ - `confluence init` - Interactive configuration setup
24
+ - `confluence read <pageId>` - Read page content with format options
25
+ - `confluence info <pageId>` - Display page information
26
+ - `confluence search <query>` - Search pages with optional limit
27
+ - `confluence spaces` - List all available spaces
28
+
29
+ ### Dependencies
30
+ - commander for CLI framework
31
+ - axios for HTTP requests
32
+ - chalk for colored output
33
+ - inquirer for interactive prompts
34
+ - html-to-text for content conversion
35
+ - ora for loading indicators
@@ -0,0 +1,220 @@
1
+ # Contributing to Confluence CLI
2
+
3
+ Thank you for your interest in contributing to Confluence CLI! This document provides guidelines and information about contributing to this project.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Code of Conduct](#code-of-conduct)
8
+ - [Getting Started](#getting-started)
9
+ - [Development Setup](#development-setup)
10
+ - [Making Changes](#making-changes)
11
+ - [Testing](#testing)
12
+ - [Submitting Changes](#submitting-changes)
13
+ - [Coding Standards](#coding-standards)
14
+
15
+ ## Code of Conduct
16
+
17
+ This project adheres to a code of conduct. By participating, you are expected to uphold this code. Please be respectful and considerate in all interactions.
18
+
19
+ ## Getting Started
20
+
21
+ 1. Fork the repository on GitHub
22
+ 2. Clone your fork locally
23
+ 3. Create a branch for your changes
24
+ 4. Make your changes
25
+ 5. Test your changes
26
+ 6. Submit a pull request
27
+
28
+ ## Development Setup
29
+
30
+ ```bash
31
+ # Clone your fork
32
+ git clone https://github.com/your-username/confluence-cli.git
33
+ cd confluence-cli
34
+
35
+ # Install dependencies
36
+ npm install
37
+
38
+ # Set up your test environment
39
+ export CONFLUENCE_DOMAIN="your-test-domain.atlassian.net"
40
+ export CONFLUENCE_API_TOKEN="your-test-token"
41
+
42
+ # Test the CLI locally
43
+ node bin/confluence.js --help
44
+ ```
45
+
46
+ ## Making Changes
47
+
48
+ ### Branch Naming
49
+
50
+ Use descriptive branch names:
51
+ - `feature/add-page-creation` - for new features
52
+ - `fix/search-pagination` - for bug fixes
53
+ - `docs/update-readme` - for documentation updates
54
+ - `refactor/client-architecture` - for refactoring
55
+
56
+ ### Commit Messages
57
+
58
+ Write clear, descriptive commit messages:
59
+ ```
60
+ feat: add page creation functionality
61
+
62
+ - Add create command to CLI
63
+ - Implement createPage method in client
64
+ - Add tests for page creation
65
+ - Update README with new command
66
+ ```
67
+
68
+ Use conventional commit format:
69
+ - `feat:` - new features
70
+ - `fix:` - bug fixes
71
+ - `docs:` - documentation changes
72
+ - `style:` - formatting changes
73
+ - `refactor:` - code refactoring
74
+ - `test:` - adding tests
75
+ - `chore:` - maintenance tasks
76
+
77
+ ## Testing
78
+
79
+ ```bash
80
+ # Run all tests
81
+ npm test
82
+
83
+ # Run tests in watch mode
84
+ npm run test:watch
85
+
86
+ # Check test coverage
87
+ npm run test:coverage
88
+
89
+ # Manual testing
90
+ node bin/confluence.js read 123456789
91
+ ```
92
+
93
+ ### Test Guidelines
94
+
95
+ - Write tests for new functionality
96
+ - Ensure existing tests pass
97
+ - Aim for good test coverage
98
+ - Use descriptive test names
99
+ - Mock external API calls
100
+
101
+ ## Submitting Changes
102
+
103
+ 1. **Push your changes** to your fork
104
+ 2. **Create a pull request** against the main branch
105
+ 3. **Fill out the PR template** with:
106
+ - Description of changes
107
+ - Type of change (bug fix, feature, etc.)
108
+ - Testing performed
109
+ - Screenshots (if applicable)
110
+
111
+ ### Pull Request Guidelines
112
+
113
+ - Keep PRs focused and atomic
114
+ - Include tests for new functionality
115
+ - Update documentation as needed
116
+ - Ensure CI passes
117
+ - Request review from maintainers
118
+
119
+ ## Coding Standards
120
+
121
+ ### JavaScript Style
122
+
123
+ - Use ES6+ features when appropriate
124
+ - Follow existing code style
125
+ - Use meaningful variable names
126
+ - Add comments for complex logic
127
+ - Keep functions small and focused
128
+
129
+ ### File Structure
130
+
131
+ ```
132
+ bin/ # CLI entry points
133
+ lib/ # Core library code
134
+ ├── confluence-client.js
135
+ ├── config.js
136
+ └── utils.js
137
+ tests/ # Test files
138
+ docs/ # Additional documentation
139
+ ```
140
+
141
+ ### Error Handling
142
+
143
+ - Always handle errors gracefully
144
+ - Provide helpful error messages
145
+ - Use appropriate exit codes
146
+ - Log errors appropriately
147
+
148
+ ### Documentation
149
+
150
+ - Update README for new features
151
+ - Add JSDoc comments for functions
152
+ - Update CHANGELOG for releases
153
+ - Include usage examples
154
+
155
+ ## Feature Requests
156
+
157
+ Before implementing major features:
158
+
159
+ 1. **Check existing issues** to avoid duplication
160
+ 2. **Create an issue** to discuss the feature
161
+ 3. **Get maintainer feedback** before starting work
162
+ 4. **Follow the agreed approach** in implementation
163
+
164
+ ## Bug Reports
165
+
166
+ When reporting bugs:
167
+
168
+ 1. **Check existing issues** first
169
+ 2. **Provide reproduction steps**
170
+ 3. **Include environment details**:
171
+ - Node.js version
172
+ - OS and version
173
+ - CLI version
174
+ 4. **Share error messages** and logs
175
+
176
+ ## Development Tips
177
+
178
+ ### Local Testing
179
+
180
+ ```bash
181
+ # Test against your Confluence instance
182
+ export CONFLUENCE_DOMAIN="your-domain.atlassian.net"
183
+ export CONFLUENCE_API_TOKEN="your-token"
184
+
185
+ # Test commands
186
+ node bin/confluence.js spaces
187
+ node bin/confluence.js search "test"
188
+ node bin/confluence.js read 123456789
189
+ ```
190
+
191
+ ### Debugging
192
+
193
+ ```bash
194
+ # Enable debug mode
195
+ DEBUG=confluence-cli node bin/confluence.js read 123456789
196
+
197
+ # Use Node.js debugger
198
+ node --inspect-brk bin/confluence.js read 123456789
199
+ ```
200
+
201
+ ## Release Process
202
+
203
+ For maintainers:
204
+
205
+ 1. Update version in `package.json`
206
+ 2. Update `CHANGELOG.md`
207
+ 3. Create git tag
208
+ 4. Push to npm
209
+ 5. Create GitHub release
210
+
211
+ ## Questions?
212
+
213
+ If you have questions about contributing:
214
+
215
+ 1. Check existing documentation
216
+ 2. Search closed issues
217
+ 3. Ask in a new issue
218
+ 4. Contact maintainers
219
+
220
+ Thank you for contributing to Confluence CLI! 🚀
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Confluence CLI Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # Confluence CLI
2
+
3
+ A powerful command-line interface for Atlassian Confluence that allows you to read, search, and manage your Confluence content from the terminal.
4
+
5
+ ## Features
6
+
7
+ - 📖 **Read pages** - Get page content in text or HTML format
8
+ - 🔍 **Search** - Find pages using Confluence's powerful search
9
+ - ℹ️ **Page info** - Get detailed information about pages
10
+ - 🏠 **List spaces** - View all available Confluence spaces
11
+ - 🔧 **Easy setup** - Simple configuration with environment variables or interactive setup
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install -g confluence-cli
17
+ ```
18
+
19
+ Or run directly with npx:
20
+ ```bash
21
+ npx confluence-cli
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ 1. **Initialize configuration:**
27
+ ```bash
28
+ confluence init
29
+ ```
30
+
31
+ 2. **Read a page:**
32
+ ```bash
33
+ confluence read 123456789
34
+ ```
35
+
36
+ 3. **Search for pages:**
37
+ ```bash
38
+ confluence search "my search term"
39
+ ```
40
+
41
+ ## Configuration
42
+
43
+ ### Option 1: Interactive Setup
44
+ ```bash
45
+ confluence init
46
+ ```
47
+
48
+ ### Option 2: Environment Variables
49
+ ```bash
50
+ export CONFLUENCE_DOMAIN="your-domain.atlassian.net"
51
+ export CONFLUENCE_API_TOKEN="your-api-token"
52
+ ```
53
+
54
+ ### Getting Your API Token
55
+
56
+ 1. Go to [Atlassian Account Settings](https://id.atlassian.com/manage-profile/security/api-tokens)
57
+ 2. Click "Create API token"
58
+ 3. Give it a label (e.g., "confluence-cli")
59
+ 4. Copy the generated token
60
+
61
+ ## Usage
62
+
63
+ ### Read a Page
64
+ ```bash
65
+ # Read by page ID
66
+ confluence read 123456789
67
+
68
+ # Read with HTML format
69
+ confluence read 123456789 --format html
70
+
71
+ # Read by URL (with pageId parameter)
72
+ confluence read "https://yourcompany.atlassian.net/wiki/spaces/SPACE/pages/123456789/Page+Title"
73
+ ```
74
+
75
+ ### Get Page Information
76
+ ```bash
77
+ confluence info 123456789
78
+ ```
79
+
80
+ ### Search Pages
81
+ ```bash
82
+ # Basic search
83
+ confluence search "search term"
84
+
85
+ # Limit results
86
+ confluence search "search term" --limit 5
87
+ ```
88
+
89
+ ### List Spaces
90
+ ```bash
91
+ confluence spaces
92
+ ```
93
+
94
+ ## Commands
95
+
96
+ | Command | Description | Options |
97
+ |---------|-------------|---------|
98
+ | `init` | Initialize CLI configuration | - |
99
+ | `read <pageId>` | Read page content | `--format <html\|text>` |
100
+ | `info <pageId>` | Get page information | - |
101
+ | `search <query>` | Search for pages | `--limit <number>` |
102
+ | `spaces` | List all spaces | - |
103
+
104
+ ## Examples
105
+
106
+ ```bash
107
+ # Setup
108
+ confluence init
109
+
110
+ # Read a page as text
111
+ confluence read 123456789
112
+
113
+ # Read a page as HTML
114
+ confluence read 123456789 --format html
115
+
116
+ # Get page details
117
+ confluence info 123456789
118
+
119
+ # Search with limit
120
+ confluence search "API documentation" --limit 3
121
+
122
+ # List all spaces
123
+ confluence spaces
124
+ ```
125
+
126
+ ## Development
127
+
128
+ ```bash
129
+ # Clone the repository
130
+ git clone https://github.com/pchuri/confluence-cli.git
131
+ cd confluence-cli
132
+
133
+ # Install dependencies
134
+ npm install
135
+
136
+ # Run locally
137
+ npm start -- --help
138
+
139
+ # Run tests
140
+ npm test
141
+
142
+ # Lint code
143
+ npm run lint
144
+ ```
145
+
146
+ ## Contributing
147
+
148
+ 1. Fork the repository
149
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
150
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
151
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
152
+ 5. Open a Pull Request
153
+
154
+ ## License
155
+
156
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
157
+
158
+ ## Roadmap
159
+
160
+ - [ ] Create and update pages
161
+ - [ ] Page templates
162
+ - [ ] Bulk operations
163
+ - [ ] Export pages to different formats
164
+ - [ ] Integration with other Atlassian tools (Jira)
165
+ - [ ] Page attachments management
166
+ - [ ] Comments and reviews
167
+
168
+ ## Support
169
+
170
+ If you encounter any issues or have questions:
171
+
172
+ 1. Check the [Issues](https://github.com/pchuri/confluence-cli/issues) page
173
+ 2. Create a new issue if your problem isn't already reported
174
+ 3. Provide detailed information about your environment and the issue
175
+
176
+ ---
177
+
178
+ Made with ❤️ for the Confluence community
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { program } = require('commander');
4
+ const chalk = require('chalk');
5
+ const ConfluenceClient = require('../lib/confluence-client');
6
+ const { getConfig, initConfig } = require('../lib/config');
7
+
8
+ program
9
+ .name('confluence')
10
+ .description('CLI tool for Atlassian Confluence')
11
+ .version('1.0.0');
12
+
13
+ // Init command
14
+ program
15
+ .command('init')
16
+ .description('Initialize Confluence CLI configuration')
17
+ .action(async () => {
18
+ await initConfig();
19
+ });
20
+
21
+ // Read command
22
+ program
23
+ .command('read <pageId>')
24
+ .description('Read a Confluence page by ID or URL')
25
+ .option('-f, --format <format>', 'Output format (html, text)', 'text')
26
+ .action(async (pageId, options) => {
27
+ try {
28
+ const config = getConfig();
29
+ const client = new ConfluenceClient(config);
30
+ const content = await client.readPage(pageId, options.format);
31
+ console.log(content);
32
+ } catch (error) {
33
+ console.error(chalk.red('Error:'), error.message);
34
+ process.exit(1);
35
+ }
36
+ });
37
+
38
+ // Info command
39
+ program
40
+ .command('info <pageId>')
41
+ .description('Get information about a Confluence page')
42
+ .action(async (pageId) => {
43
+ try {
44
+ const config = getConfig();
45
+ const client = new ConfluenceClient(config);
46
+ const info = await client.getPageInfo(pageId);
47
+ console.log(chalk.blue('Page Information:'));
48
+ console.log(`Title: ${chalk.green(info.title)}`);
49
+ console.log(`ID: ${chalk.green(info.id)}`);
50
+ console.log(`Type: ${chalk.green(info.type)}`);
51
+ console.log(`Status: ${chalk.green(info.status)}`);
52
+ if (info.space) {
53
+ console.log(`Space: ${chalk.green(info.space.name)} (${info.space.key})`);
54
+ }
55
+ } catch (error) {
56
+ console.error(chalk.red('Error:'), error.message);
57
+ process.exit(1);
58
+ }
59
+ });
60
+
61
+ // Search command
62
+ program
63
+ .command('search <query>')
64
+ .description('Search for Confluence pages')
65
+ .option('-l, --limit <limit>', 'Limit number of results', '10')
66
+ .action(async (query, options) => {
67
+ try {
68
+ const config = getConfig();
69
+ const client = new ConfluenceClient(config);
70
+ const results = await client.search(query, parseInt(options.limit));
71
+
72
+ if (results.length === 0) {
73
+ console.log(chalk.yellow('No results found.'));
74
+ return;
75
+ }
76
+
77
+ console.log(chalk.blue(`Found ${results.length} results:`));
78
+ results.forEach((result, index) => {
79
+ console.log(`${index + 1}. ${chalk.green(result.title)} (ID: ${result.id})`);
80
+ if (result.excerpt) {
81
+ console.log(` ${chalk.gray(result.excerpt)}`);
82
+ }
83
+ });
84
+ } catch (error) {
85
+ console.error(chalk.red('Error:'), error.message);
86
+ process.exit(1);
87
+ }
88
+ });
89
+
90
+ // List spaces command
91
+ program
92
+ .command('spaces')
93
+ .description('List all Confluence spaces')
94
+ .action(async () => {
95
+ try {
96
+ const config = getConfig();
97
+ const client = new ConfluenceClient(config);
98
+ const spaces = await client.getSpaces();
99
+
100
+ console.log(chalk.blue('Available spaces:'));
101
+ spaces.forEach(space => {
102
+ console.log(`${chalk.green(space.key)} - ${space.name}`);
103
+ });
104
+ } catch (error) {
105
+ console.error(chalk.red('Error:'), error.message);
106
+ process.exit(1);
107
+ }
108
+ });
109
+
110
+ program.parse();
package/bin/index.js ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * confluence-cli
5
+ * A powerful command-line interface for Atlassian Confluence
6
+ *
7
+ * @author Your Name
8
+ * @license MIT
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ // Make sure we're using a supported Node.js version
14
+ const nodeVersion = process.version;
15
+ const requiredVersion = '14.0.0';
16
+
17
+ if (!nodeVersion.startsWith('v') ||
18
+ parseInt(nodeVersion.slice(1).split('.')[0]) < parseInt(requiredVersion.split('.')[0])) {
19
+ console.error(`Error: Node.js ${requiredVersion} or higher is required. You are using ${nodeVersion}.`);
20
+ process.exit(1);
21
+ }
22
+
23
+ // Load the main CLI application
24
+ require('./confluence.js');
@@ -0,0 +1,43 @@
1
+ #!/bin/bash
2
+
3
+ # Example script showing how to use confluence-cli
4
+
5
+ echo "🚀 Confluence CLI Examples"
6
+ echo "========================="
7
+
8
+ # Check if confluence command is available
9
+ if ! command -v confluence &> /dev/null; then
10
+ echo "❌ confluence command not found. Please install confluence-cli first:"
11
+ echo " npm install -g confluence-cli"
12
+ exit 1
13
+ fi
14
+
15
+ echo ""
16
+ echo "📋 Listing all spaces..."
17
+ confluence spaces
18
+
19
+ echo ""
20
+ echo "🔍 Searching for 'API' documentation..."
21
+ confluence search "API" --limit 5
22
+
23
+ echo ""
24
+ echo "ℹ️ Getting information about a specific page..."
25
+ # Replace this with an actual page ID from your Confluence
26
+ read -p "Enter a page ID to get info: " PAGE_ID
27
+ if [ ! -z "$PAGE_ID" ]; then
28
+ confluence info "$PAGE_ID"
29
+
30
+ echo ""
31
+ read -p "Do you want to read this page? (y/N): " READ_PAGE
32
+ if [ "$READ_PAGE" = "y" ] || [ "$READ_PAGE" = "Y" ]; then
33
+ echo ""
34
+ echo "📖 Reading page content..."
35
+ confluence read "$PAGE_ID" | head -20
36
+ echo ""
37
+ echo "(Showing first 20 lines only)"
38
+ fi
39
+ fi
40
+
41
+ echo ""
42
+ echo "✅ Examples completed!"
43
+ echo "💡 Run 'confluence --help' for more commands"
package/jest.config.js ADDED
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ testEnvironment: 'node',
3
+ collectCoverageFrom: [
4
+ 'lib/**/*.js',
5
+ 'bin/**/*.js',
6
+ '!node_modules/**'
7
+ ],
8
+ coverageDirectory: 'coverage',
9
+ coverageReporters: ['text', 'lcov', 'html'],
10
+ testMatch: [
11
+ '**/tests/**/*.test.js'
12
+ ]
13
+ };
package/lib/config.js ADDED
@@ -0,0 +1,96 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+ const inquirer = require('inquirer');
5
+ const chalk = require('chalk');
6
+
7
+ const CONFIG_DIR = path.join(os.homedir(), '.confluence-cli');
8
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
9
+
10
+ /**
11
+ * Initialize configuration
12
+ */
13
+ async function initConfig() {
14
+ console.log(chalk.blue('🚀 Confluence CLI Configuration'));
15
+ console.log('Please provide your Confluence connection details:\n');
16
+
17
+ const answers = await inquirer.prompt([
18
+ {
19
+ type: 'input',
20
+ name: 'domain',
21
+ message: 'Confluence domain (e.g., yourcompany.atlassian.net):',
22
+ validate: (input) => {
23
+ if (!input.trim()) {
24
+ return 'Domain is required';
25
+ }
26
+ return true;
27
+ }
28
+ },
29
+ {
30
+ type: 'password',
31
+ name: 'token',
32
+ message: 'API Token:',
33
+ validate: (input) => {
34
+ if (!input.trim()) {
35
+ return 'API Token is required';
36
+ }
37
+ return true;
38
+ }
39
+ }
40
+ ]);
41
+
42
+ // Create config directory if it doesn't exist
43
+ if (!fs.existsSync(CONFIG_DIR)) {
44
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
45
+ }
46
+
47
+ // Save configuration
48
+ const config = {
49
+ domain: answers.domain.trim(),
50
+ token: answers.token.trim()
51
+ };
52
+
53
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
54
+
55
+ console.log(chalk.green('✅ Configuration saved successfully!'));
56
+ console.log(`Config file location: ${chalk.gray(CONFIG_FILE)}`);
57
+ console.log(chalk.yellow('\n💡 Tip: You can regenerate this config anytime by running "confluence init"'));
58
+ }
59
+
60
+ /**
61
+ * Get configuration
62
+ */
63
+ function getConfig() {
64
+ // First check for environment variables
65
+ const envDomain = process.env.CONFLUENCE_DOMAIN || process.env.CONFLUENCE_HOST;
66
+ const envToken = process.env.CONFLUENCE_API_TOKEN;
67
+
68
+ if (envDomain && envToken) {
69
+ return {
70
+ domain: envDomain,
71
+ token: envToken
72
+ };
73
+ }
74
+
75
+ // Check for config file
76
+ if (!fs.existsSync(CONFIG_FILE)) {
77
+ console.error(chalk.red('❌ No configuration found!'));
78
+ console.log(chalk.yellow('Please run "confluence init" to set up your configuration.'));
79
+ console.log(chalk.gray('Or set environment variables: CONFLUENCE_DOMAIN and CONFLUENCE_API_TOKEN'));
80
+ process.exit(1);
81
+ }
82
+
83
+ try {
84
+ const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
85
+ return config;
86
+ } catch (error) {
87
+ console.error(chalk.red('❌ Error reading configuration file:'), error.message);
88
+ console.log(chalk.yellow('Please run "confluence init" to recreate your configuration.'));
89
+ process.exit(1);
90
+ }
91
+ }
92
+
93
+ module.exports = {
94
+ initConfig,
95
+ getConfig
96
+ };
@@ -0,0 +1,137 @@
1
+ const axios = require('axios');
2
+ const { convert } = require('html-to-text');
3
+
4
+ class ConfluenceClient {
5
+ constructor(config) {
6
+ this.baseURL = `https://${config.domain}/rest/api`;
7
+ this.token = config.token;
8
+ this.domain = config.domain;
9
+
10
+ this.client = axios.create({
11
+ baseURL: this.baseURL,
12
+ headers: {
13
+ 'Authorization': `Bearer ${this.token}`,
14
+ 'Content-Type': 'application/json'
15
+ }
16
+ });
17
+ }
18
+
19
+ /**
20
+ * Extract page ID from URL or return the ID if it's already a number
21
+ */
22
+ extractPageId(pageIdOrUrl) {
23
+ if (typeof pageIdOrUrl === 'number' || /^\d+$/.test(pageIdOrUrl)) {
24
+ return pageIdOrUrl;
25
+ }
26
+
27
+ // Check if it's a Confluence URL
28
+ if (pageIdOrUrl.includes(this.domain)) {
29
+ // Extract pageId from URL parameter
30
+ const pageIdMatch = pageIdOrUrl.match(/pageId=(\d+)/);
31
+ if (pageIdMatch) {
32
+ return pageIdMatch[1];
33
+ }
34
+
35
+ // Handle display URLs - would need to search by space and title
36
+ const displayMatch = pageIdOrUrl.match(/\/display\/([^/]+)\/(.+)/);
37
+ if (displayMatch) {
38
+ throw new Error('Display URLs not yet supported. Please use page ID or viewpage URL with pageId parameter.');
39
+ }
40
+ }
41
+
42
+ return pageIdOrUrl;
43
+ }
44
+
45
+ /**
46
+ * Read a Confluence page content
47
+ */
48
+ async readPage(pageIdOrUrl, format = 'text') {
49
+ const pageId = this.extractPageId(pageIdOrUrl);
50
+
51
+ const response = await this.client.get(`/content/${pageId}`, {
52
+ params: {
53
+ expand: 'body.storage'
54
+ }
55
+ });
56
+
57
+ const htmlContent = response.data.body.storage.value;
58
+
59
+ if (format === 'html') {
60
+ return htmlContent;
61
+ }
62
+
63
+ // Convert HTML to text
64
+ return convert(htmlContent, {
65
+ wordwrap: 80,
66
+ selectors: [
67
+ { selector: 'h1', options: { uppercase: false } },
68
+ { selector: 'h2', options: { uppercase: false } },
69
+ { selector: 'h3', options: { uppercase: false } },
70
+ { selector: 'table', options: { uppercaseHeaderCells: false } }
71
+ ]
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Get page information
77
+ */
78
+ async getPageInfo(pageIdOrUrl) {
79
+ const pageId = this.extractPageId(pageIdOrUrl);
80
+
81
+ const response = await this.client.get(`/content/${pageId}`, {
82
+ params: {
83
+ expand: 'space'
84
+ }
85
+ });
86
+
87
+ return {
88
+ title: response.data.title,
89
+ id: response.data.id,
90
+ type: response.data.type,
91
+ status: response.data.status,
92
+ space: response.data.space
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Search for pages
98
+ */
99
+ async search(query, limit = 10) {
100
+ const response = await this.client.get('/search', {
101
+ params: {
102
+ cql: `text ~ "${query}"`,
103
+ limit: limit
104
+ }
105
+ });
106
+
107
+ return response.data.results.map(result => {
108
+ // Handle different result structures
109
+ const content = result.content || result;
110
+ return {
111
+ id: content.id || 'Unknown',
112
+ title: content.title || 'Untitled',
113
+ type: content.type || 'Unknown',
114
+ excerpt: result.excerpt || content.excerpt || ''
115
+ };
116
+ }).filter(item => item.id !== 'Unknown'); // Filter out items without valid IDs
117
+ }
118
+
119
+ /**
120
+ * Get all spaces
121
+ */
122
+ async getSpaces() {
123
+ const response = await this.client.get('/space', {
124
+ params: {
125
+ limit: 500
126
+ }
127
+ });
128
+
129
+ return response.data.results.map(space => ({
130
+ key: space.key,
131
+ name: space.name,
132
+ type: space.type
133
+ }));
134
+ }
135
+ }
136
+
137
+ module.exports = ConfluenceClient;
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "confluence-cli",
3
+ "version": "1.0.0",
4
+ "description": "A command-line interface for Atlassian Confluence",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "confluence": "./bin/index.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node bin/confluence.js",
11
+ "test": "jest",
12
+ "lint": "eslint .",
13
+ "lint:fix": "eslint . --fix"
14
+ },
15
+ "keywords": [
16
+ "confluence",
17
+ "atlassian",
18
+ "cli",
19
+ "wiki",
20
+ "documentation"
21
+ ],
22
+ "author": "Your Name",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "commander": "^11.1.0",
26
+ "axios": "^1.6.2",
27
+ "chalk": "^4.1.2",
28
+ "inquirer": "^8.2.6",
29
+ "ora": "^5.4.1",
30
+ "html-to-text": "^9.0.5"
31
+ },
32
+ "devDependencies": {
33
+ "eslint": "^8.55.0",
34
+ "jest": "^29.7.0",
35
+ "@types/node": "^20.10.0"
36
+ },
37
+ "engines": {
38
+ "node": ">=14.0.0"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/pchuri/confluence-cli.git"
43
+ },
44
+ "bugs": {
45
+ "url": "https://github.com/pchuri/confluence-cli/issues"
46
+ },
47
+ "homepage": "https://github.com/pchuri/confluence-cli#readme"
48
+ }
@@ -0,0 +1,29 @@
1
+ const ConfluenceClient = require('../lib/confluence-client');
2
+
3
+ describe('ConfluenceClient', () => {
4
+ let client;
5
+
6
+ beforeEach(() => {
7
+ client = new ConfluenceClient({
8
+ domain: 'test.atlassian.net',
9
+ token: 'test-token'
10
+ });
11
+ });
12
+
13
+ describe('extractPageId', () => {
14
+ test('should return numeric page ID as is', () => {
15
+ expect(client.extractPageId('123456789')).toBe('123456789');
16
+ expect(client.extractPageId(123456789)).toBe(123456789);
17
+ });
18
+
19
+ test('should extract page ID from URL with pageId parameter', () => {
20
+ const url = 'https://test.atlassian.net/wiki/spaces/TEST/pages/123456789/Page+Title';
21
+ expect(client.extractPageId(url + '?pageId=987654321')).toBe('987654321');
22
+ });
23
+
24
+ test('should throw error for display URLs', () => {
25
+ const displayUrl = 'https://test.atlassian.net/display/TEST/Page+Title';
26
+ expect(() => client.extractPageId(displayUrl)).toThrow('Display URLs not yet supported');
27
+ });
28
+ });
29
+ });